跟着刘二大人学pytorch(第---12---节课之RNN基础篇)

文章目录

  • 0 前言
    • 0.1 课程视频链接:
    • 0.2 课件下载地址:
  • 1 Basic RNN
    • 1.1 复习DNN和CNN
    • 1.2 直观认识RNN
    • 1.3 RNN Cell的内部计算方式
  • 2 具体什么是一个RNN?
  • 3 使用pytorch构造一个RNN
    • 3.1 手动构造一个RNN Cell来实现RNN
    • 3.2 直接使用torch中现有的RNN模块来实现RNN
      • input维度
      • h0维度
      • output维度
      • hn维度
      • numLayers的解释
      • 代码注释
        • 参数配置
        • 模型构造
        • 输入序列的构造
        • 隐藏层的构造
        • 输出的解释
        • 最后一个隐藏层输出的解释
        • 执行代码的结果
  • 例子1:训练一个RNN 做seq2seq任务
    • 第1步 字符向量化
    • 参数配置
    • 准备数据
    • 设计模型
    • 构造损失函数和优化器
    • 设置训练Cycle
    • 改变数据
    • Embedding
  • 例12-3 使用embedding和线性层的RNN
  • 构造模型、损失函数、优化器
  • 训练
  • 练习1:LSTM
  • 联系2:GRU

0 前言

0.1 课程视频链接:

《PyTorch深度学习实践》完结合集
大佬的笔记:大佬的笔记
pytorch=0.4

0.2 课件下载地址:

链接:https://pan.baidu.com/s/1_J1f5VSyYl-Jj2qIuc1pXw
提取码:wyhu

1 Basic RNN

在这里插入图片描述

1.1 复习DNN和CNN

全连接网络也称为稠密网络,Dense Network,也称为Deep Neural Network
在这里插入图片描述
现在有一个表,里面的数据是每天每隔一个小时的天气数据,平均温度,气压,预测目标是是否下雨

根据某一时刻的温度和气压数据预测该时刻是否下雨,这件事情意义不太大,预测下雨这件事应提前进行预测。

我们需要若干天(如3天)的数据作为模型的输入,其中每一天的数据应该包含若干个(如3个)特征。
在这里插入图片描述
使用全连接进行预测。如果序列很长且x1,x2,x3的维度很高的话,这对网络的训练是一个很大的挑战,原因是全连接网络是稠密的网络,里面的权重是最多的。
CNN中输入通道是128,输出通道是64,使用的是5×5的卷积,权重为25×2^13=20w,
全连接层假设输入是4096,输出是1024,则全连接权重为4096*1024=420w,这样的比较CNN使用的参数要少得多
因此在使用神经网络时需要明确一点:全连接网络的参数在神经网络中所占的比例是最大的,所以之后计算存储、推理很大的瓶颈是来自全连接层
CNN中使用的参数为什么较少呢:有 权重共享的概念

假如在处理视频时,每一帧的图像如果都使用全连接网络去处理,那参数量将是天文数字,这种方法是不可行的
RNN是专门处理序列型的数据,也会使用权重共享的概念,减少需要训练的权重的数量

x1,x2,x3是一个序列,是有先后顺序,x2部分依赖x1,x3部分依赖x2,RNN来处理序列相关的数据,类似于语言、天气、股票

理解语言需要依赖文字的顺序
在这里插入图片描述

回顾一下CNN
在这里插入图片描述

1.2 直观认识RNN

例如输入xt的维度是3维的,经过RNN Cell之后输出的ht是5维的,那么RNN Cell本质上还是一个线性层,但是和普通的线性层的区别是RNN Cell这个线性层的权重是共享的。
h0是先验知识,如果有先验知识的话就需要将先验知识作为h0输入给RNN,如图生文本,CNN+FC处理图像,生成h0,再传给RNN,此时即可做“看图说话”
如果没有先验知识的话,直接将h0的维度设置为和ht的维度一样,然后设置成0向量即可。
在这里插入图片描述
上图中的RNN Cell是同一个
在这里插入图片描述
用代码来表示是上面这样的,x是需要从X中循环的

1.3 RNN Cell的内部计算方式

在这里插入图片描述
Whhht-1+bhh 和Wihxt+bih是两个线性层,他们可以合并成一个线性层,见上图的红色公式
在这里插入图片描述
即上式可以简写。

2 具体什么是一个RNN?

把RNN Cell以循环的方法,把序列送进去,依次算出隐层的过程称为一个循环神经网络。
在这里插入图片描述

3 使用pytorch构造一个RNN

两种方法:1、自己构造RNN Cell,然后写来处理序列的循环 2、直接使用RNN

3.1 手动构造一个RNN Cell来实现RNN

创建一个Cell的方式
创建一个RNN Cell需要的参数:输入的维度,隐藏层的维度
在这里插入图片描述
构造完cell之后,一个cell的输入是x和上一个隐藏状态,两者的维度要求见下图
在这里插入图片描述
例如一个RNNCell的配置为
在这里插入图片描述
因此输入的构造见下图
在这里插入图片描述
隐藏状态的构造见下图
在这里插入图片描述
序列数据的维度的构造应该如下
在这里插入图片描述
代码:
在这里插入图片描述
torch.randn用法:torch.randn()函数
示例代码:

import torch


# 定义配置项
batch_size = 5
seq_len = 3
input_size = 4
hidden_size = 2

# 构造一个RNN Cell
cell = torch.nn.RNNCell(input_size = input_size, hidden_size = hidden_size)

print(cell)

# 生成5个序列长度为3,每个token的为4的张量作为1个batch
dataset = torch.randn(seq_len, batch_size, input_size)
print(dataset)

hidden = torch.zeros(batch_size, hidden_size)
print(hidden)

for idx, input in enumerate(dataset):
    print("="*20, idx, "="*20)
    print("input size:", input.shape)
    hidden = cell(input, hidden)

    print("output size:", hidden.shape)
    print(hidden)

输出:

D:\Anaconda3\envs\env_pytorch04\python.exe "D:/000 简历/000 自己的项目/3 刘二教程/第12节课 手动定义一个RNN Cell.py"
RNNCell(4, 2)
tensor([[[ 0.4408, -0.7577,  0.9077, -0.0779],
         [ 0.5080, -0.1057,  0.5581, -0.4546],
         [ 0.8382,  1.3444,  1.1445, -2.0313],
         [ 0.4016,  1.0184,  0.0556,  0.6046],
         [ 1.9827,  0.6735, -0.6609, -0.0764]],

        [[-0.8133, -1.3837, -0.6933, -0.6390],
         [ 0.7617, -0.2478, -0.1682, -1.2478],
         [ 0.1389, -0.5334,  1.7906,  0.8992],
         [-0.7540,  0.0293, -0.5835,  1.0606],
         [-0.5817,  0.2823, -1.0507,  0.3087]],

        [[-0.5872,  0.1241, -0.2446, -0.5430],
         [-0.6749,  0.6816, -0.1754, -1.1233],
         [ 0.1708, -1.6483,  0.8012,  0.3567],
         [-0.1961, -1.0277, -0.2133, -0.7144],
         [-1.3309,  0.6177,  1.5205, -0.4169]]])
tensor([[0., 0.],
        [0., 0.],
        [0., 0.],
        [0., 0.],
        [0., 0.]])
==================== 0 ====================
input size: torch.Size([5, 4])
output size: torch.Size([5, 2])
tensor([[-0.2558, -0.4498],
        [-0.3951,  0.0840],
        [ 0.1652,  0.9352],
        [-0.8041, -0.1019],
        [-0.6620,  0.7436]], grad_fn=<TanhBackward0>)
==================== 1 ====================
input size: torch.Size([5, 4])
output size: torch.Size([5, 2])
tensor([[-0.8441, -0.6020],
        [-0.6114,  0.6291],
        [-0.3331, -0.8504],
        [-0.9706, -0.8207],
        [-0.9807, -0.4315]], grad_fn=<TanhBackward0>)
==================== 2 ====================
input size: torch.Size([5, 4])
output size: torch.Size([5, 2])
tensor([[-0.8825, -0.1003],
        [-0.9137,  0.3993],
        [-0.2900, -0.8324],
        [-0.7844, -0.2764],
        [-0.7202, -0.4915]], grad_fn=<TanhBackward0>)

进程已结束,退出代码为 0

注意:输出中的下列张量,每一个块儿是一个batch,一个块儿是5个向量,表示1个batch是5个输入

tensor([[[ 0.4408, -0.7577,  0.9077, -0.0779],
         [ 0.5080, -0.1057,  0.5581, -0.4546],
         [ 0.8382,  1.3444,  1.1445, -2.0313],
         [ 0.4016,  1.0184,  0.0556,  0.6046],
         [ 1.9827,  0.6735, -0.6609, -0.0764]],

        [[-0.8133, -1.3837, -0.6933, -0.6390],
         [ 0.7617, -0.2478, -0.1682, -1.2478],
         [ 0.1389, -0.5334,  1.7906,  0.8992],
         [-0.7540,  0.0293, -0.5835,  1.0606],
         [-0.5817,  0.2823, -1.0507,  0.3087]],

        [[-0.5872,  0.1241, -0.2446, -0.5430],
         [-0.6749,  0.6816, -0.1754, -1.1233],
         [ 0.1708, -1.6483,  0.8012,  0.3567],
         [-0.1961, -1.0277, -0.2133, -0.7144],
         [-1.3309,  0.6177,  1.5205, -0.4169]]])

假如有数据集:
1、我爱你
2、我恨你
3、我吃了
4、我没吃
5、我饿了
。。。。还有其他数据
分词之后:
1、“我”,“爱”,“你”
2、“我”,“恨”,“你”
3、“我”,“吃”,“了”
4、“我”,“没”,“吃”
5、“我”,“饿”,“了”

每个词有各自的词向量
配置项中设置每个batch的大小是5,选择前5句话作为1个batch,每句话的序列长度都是3,其中每个词的维度都是4
则1个batch用数字表示就是

tensor([[[ 0.4408, -0.7577,  0.9077, -0.0779],   # 我 【1】
         [ 0.5080, -0.1057,  0.5581, -0.4546],   # 我         
         [ 0.8382,  1.3444,  1.1445, -2.0313],   # 我
         [ 0.4016,  1.0184,  0.0556,  0.6046],   # 我
         [ 1.9827,  0.6735, -0.6609, -0.0764]],  # 我

        [[-0.8133, -1.3837, -0.6933, -0.6390],   # 爱 【1】
         [ 0.7617, -0.2478, -0.1682, -1.2478],   # 恨
         [ 0.1389, -0.5334,  1.7906,  0.8992],   # 吃
         [-0.7540,  0.0293, -0.5835,  1.0606],   # 没
         [-0.5817,  0.2823, -1.0507,  0.3087]],  # 饿

        [[-0.5872,  0.1241, -0.2446, -0.5430],   # 你 【1】
         [-0.6749,  0.6816, -0.1754, -1.1233],   # 你
         [ 0.1708, -1.6483,  0.8012,  0.3567],   # 了
         [-0.1961, -1.0277, -0.2133, -0.7144],   # 吃 
         [-1.3309,  0.6177,  1.5205, -0.4169]]]) # 了

暂时忽略同一个词不同词向量这个问题,以上只示意

3.2 直接使用torch中现有的RNN模块来实现RNN

cell = torch.nn.RNN(input_size = inputsize, hidden_size = hidden_size, num_layers = num_layers)
num_layers可以设置RNN是多少层的,层数也不能选太多,因为比较耗时

out,hidden = cell(inputs,hidden)
inputs是包含整个输入序列,out就是输出的整个序列(h1,h2,…,hN),第1个hidden就是hN,第2个hidden就是h0,具体可以见下图
在这里插入图片描述
总结:上图中cell输入h0,x1,x2,…,xN,输出h1,h2,…,hN和hN

维度要求,见下图:
在这里插入图片描述
其中numLayers指的就是RNN是多少层的,这个确实有指明的必要,因为RNN有多少层,h就得有多少层

input维度

在这里插入图片描述

h0维度

在这里插入图片描述

output维度

在这里插入图片描述

hn维度

在这里插入图片描述

numLayers的解释

同一种颜色的cell是同一个cell,下面例子中的模型看着很复杂,实际就只是3个线性层
在这里插入图片描述

代码注释

参数配置

在这里插入图片描述

模型构造

在这里插入图片描述

输入序列的构造

在这里插入图片描述

隐藏层的构造

在这里插入图片描述

输出的解释

在这里插入图片描述

最后一个隐藏层输出的解释

在这里插入图片描述

执行代码的结果

在这里插入图片描述
batch_first设置为True的话,在构造数据时需要将batch_size和seq_len进行交换,为什么有这个选项,是因为有些时候这种方式更方便构造数据集(具体原因可再细查),见下图
在这里插入图片描述
将batch_first设置为True的情况,代码和代码执行结果见下图:
在这里插入图片描述
可以看出batch_size和seq_len交换了位置

例子1:训练一个RNN 做seq2seq任务

任务训练一个RNN模型,输入是hello,输出是ohlol
在这里插入图片描述

第1步 字符向量化

使用one-hot表示,每个字符使用词表大小的向量来表示
在这里插入图片描述
inputsize = 4
输入的向量维度为4,输出的应该是这4个字符的类别,因此可以令输出向量的维度也为4,这样通过一个softmax即可进行多分类,下图中的输出上写的数字是每个每个输出应该被分类的类别,如o应该被归为第3类,l应该被归类为第1类,等等
在这里插入图片描述
预测的向量与真实的向量做一个交叉熵损失值,如下图
在这里插入图片描述

参数配置

在这里插入图片描述

准备数据

idx2char是一个字典,值为字符,可使用索引作为键
lookup是一个查询表,例如:词表中e的索引为0,则e使用one-hot表示就是lookup中第0行的向量,o的索引为3,则o使用one-hot表示就是lookup中第3行的向量
x_one_hot是将x_data中每个索引对应的字符都表示为one-hot向量,它的维度应该是seq_len×inputsize,因为x_data的维度是seq_len,one-hot向量的维度是inputsize
在这里插入图片描述
下面这个图中所写的(seqLen,1)应该是写错了,没有写batchsize的大小,
在这里插入图片描述
实际上应该写成(seqLen,batchSize,hiddenSize),即(-1,1,4),为什么这么写的原因可以见下图:
在这里插入图片描述

设计模型

1、初始化参数
在这里插入图片描述
2、RNNCell的输入输出维度要求
在这里插入图片描述
3、初始化h0
在这里插入图片描述
这里面的参数有一个batch_size,只有在构造h0的时候才会需要用到,在初始化和forward的时候不会用到这个参数

构造损失函数和优化器

使用交叉熵作为损失函数,Adam作为优化器
在这里插入图片描述

设置训练Cycle

optimizer.zero_grad():优化器的梯度归零
每一个epoch开始之后先算一个h0,对于每一步的损失值都加到一起,loss.backup进行梯度的反向传播,参数更新
在这里插入图片描述
注意下列数据的维度大小
在这里插入图片描述
在这里插入图片描述
lable只要给出类别数字即可,不需要one-hot,原因在于交叉熵的过程,这个地方需要查一下CrossEntropyLoss()的操作
在这里插入图片描述
hidden.max()就是找hidden中的找最大值,hidden是4维的向量
在这里插入图片描述
在这里插入图片描述
例2 使用RNN Module
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

改变数据

在这里插入图片描述
训练结果如下:
在这里插入图片描述

Embedding

associate:v.联系;联合;联想;交往;表示同意;(尤指)混在一起;表明支持;
one-hot表示的缺点:
1、维度太高(字符级:字符集ASIIC 128维 单词级:几万维)
2、过于稀疏
3、硬编码的,这个词向量并不是学习出来的
在这里插入图片描述
Embedding层是将高维的稀疏的样本向量映射到低维的稠密的空间中,这就是降维
在这里插入图片描述
嵌入层降维的方式:输入一个索引,通过查表来找到对应的向量,找的方法是通过将lookup表与一个one-hot向量进行想乘,然后得出最后的嵌入向量
在这里插入图片描述

例12-3 使用embedding和线性层的RNN

有时候的输出的隐藏层h的维度与类别的维度o不一致,所以可以添加Linear Layer,将h的维度映射为o的维度
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面的batch_first = True只要知道有这种用法即可
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
参数配置:
在这里插入图片描述
输入和输出:
在这里插入图片描述

构造模型、损失函数、优化器

在这里插入图片描述

训练

在这里插入图片描述
出现ohlol比以前更早了,是因为使用了更厉害的模型,学习能力更强
在这里插入图片描述

练习1:LSTM

LSTM中的这些个门儿,实际上这么多次专业名词总会使人感觉到这个模型很难学习,实际不难,只需看公式即可
在这里插入图片描述
在这里插入图片描述

为什么有用?
因为提供了下面这样的路径,有利于梯度传播,有了记忆单元所以减少梯度消失
在这里插入图片描述
在这里插入图片描述
LSTM比RNN效果好得多,因为计算复杂,时间复杂度高

联系2:GRU

GRU是一个折中的方法,比LSTM的计算速度快在这里插入图片描述
在这里插入图片描述
以上学习RNN需要重视的是
1、了解序列数据的维度情况
2、循环过程用到的权重共享机制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/715160.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

赶紧转行大模型,预计风口就今年一年,明年市场就饱和了!不是开玩笑

恕我直言&#xff0c;就这几天&#xff0c;各大厂都在裁员&#xff0c;什么开发测试运维都裁&#xff0c;只有大模型是急招人。 你说你不知道大模型是什么&#xff1f;那可太对了&#xff0c;你不知道说明别人也不知道&#xff0c;就是要趁只有业内部分人知道的时候入局&#…

深度学习1 -- 开头

感觉用这玩意越来越多&#xff0c;所以想学学。不过没想好怎么学&#xff0c;也没有提纲&#xff0c;买了两本书&#xff0c;一本是深度学习入门&#xff0c;小日子写的。还有一本就是花书。还有就是回Gatech参加线上课程&#xff0c;提纲大概是这样的。 https://omscs.gatech…

生产中的 RAG:使你的生成式 AI 项目投入运营

作者&#xff1a;来自 Elastic Tim Brophy 检索增强生成 (RAG) 为组织提供了一个采用大型语言模型 (LLM) 的机会&#xff0c;即通过将生成式人工智能 (GenAI) 功能应用于其自己的专有数据。使用 RAG 可以降低固有风险&#xff0c;因为我们依赖受控数据集作为模型答案的基础&…

比利时海外媒体宣发,发稿促进媒体通稿发布新形势-大舍传媒

引言 随着全球化的推进&#xff0c;海外媒体的影响力也日益增强。在这一背景下&#xff0c;比利时海外媒体的宣发工作成为了媒体通稿发布的新形势。大舍传媒作为一家专注于宣传推广的公司&#xff0c;一直致力于与比利时博伊克邮报&#xff08;boicpost&#xff09;合作&#…

ModuleNotFoundError: No module named ‘distutils‘的解决办法

最近想试试odoo17&#xff0c;在windows环境下&#xff0c;想安装试验一下&#xff0c;结果老出现oduleNotFoundError: No module named ‘distutils‘错误。查了一下&#xff0c;以为是python版本导致的&#xff0c;结果试了很多版本如下&#xff1a; 试了几个&#xff0c;每个…

4-异常-log4j配置日志滚动覆盖出现日志丢失问题

4-异常-log4j配置日志打印滚动覆盖出现日志丢失问题(附源码分析) 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术文&…

浪潮信息内存故障预警技术再升级 服务器稳定性再获提升

浪潮信息近日对其内存故障智能预警修复技术进行了全面升级&#xff0c;再次取得技术突破。此次升级后&#xff0c;公司服务器的宕机率实现了80%锐降&#xff0c;再次彰显了浪潮信息在服务器技术领域的卓越能力。 浪潮信息全新升级服务器内存故障智能预警修复技术MUPR (Memory …

大数据开发流程解析

大数据开发是一个复杂且系统的过程&#xff0c;涉及需求分析、数据探查、指标管理、模型设计、ETL开发、数据验证、任务调度以及上线管理等多个阶段。本文将详细介绍每个阶段的内容&#xff0c;并提供相关示例和代码示例&#xff0c;帮助理解和实施大数据开发流程。 本文中的示…

学习记录:VS2019+OpenCV3.4.1实现SURF库函数的调用

最近在学习opencv的使用&#xff0c;在参照书籍《OpenCV3编程入门》实现SURF时遇到不少问题&#xff0c;下面做归纳总结。 错误 LNK2019 无法解析的外部符号 “public: static struct cv::Ptr __cdecl cv::xfeatures2d::SURF::create(double,int,int,bool,bool)” (?createSUR…

Java文件/文件夹的新增/删除/递归遍历

获取File对象 这里的字符串可以乱写&#xff0c;但是如果不存在后续的操作也会失败 // 获取抽象的File对象&#xff08;文件或者目录&#xff0c;不一定真实存在&#xff09;File file1 new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTes…

k8s上使用ConfigMap 和 Secret

使用ConfigMap 和 Secret 实验目标&#xff1a; 学习如何使用 ConfigMap 和 Secret 来管理应用的配置。 实验步骤&#xff1a; 创建一个 ConfigMap 存储应用配置。创建一个 Secret 存储敏感信息&#xff08;如数据库密码&#xff09;。在 Pod 中挂载 ConfigMap 和 Secret&am…

明日周刊-第13期

在这期间发生了很多的事&#xff0c;导致拖更了一周。接下去努力不断更&#xff0c;哈哈哈希望如此。配图是最近上映的一部电影《狗阵》的海报&#xff0c;看完之后感悟颇深&#xff0c;希望大家都能去电影院感受一下。 文章目录 一周热点资源分享言论歌曲推荐 一周热点 最近一…

一文带你了解OSCP 2024

OSCP简述 我们先说说&#xff0c;OSCP 是什么&#xff1f; OSCP &#xff08;Offensive Security Certified Professional&#xff09;是 Offensive Security &#xff08;该公司开发和维护着 KALI Linux&#xff0c;以下简称 Offsec&#xff09;推出的体系非常完善&#xff0…

Intel平台,13600KF+3060Ti,虚拟机安装macOS 14(2024年6月)

距离上次装macOS虚拟机已经有一段时间了&#xff0c;macOS系统现在大版本升级的速度也是越来越快了&#xff0c;由于Office只支持最新三个版本的macOS&#xff0c;所以现在保底也得安装macOS 12了&#xff0c;我这次是用macOS 14做实验&#xff0c;13和12的安装方式和macOS 14一…

【flink实战】flink-connector-mysql-cdc导致mysql连接器报类型转换错误

文章目录 一. 报错现象二. 方案二&#xff1a;重新编译打包flink-connector-cdc1. 排查脚本2. 重新编译打包flink-sql-connector-mysql-cdc-2.4.0.jar3. 测试flink环境 三. 方案一&#xff1a;改造flink连接器 一. 报错现象 flink sql任务是&#xff1a;mysql到hdfs的离线任务&…

关于学习Token、JWT、Cookie等验证授权方式的总结

目录 一、为什么Cookie无法防止CSRF攻击&#xff0c;而Token可以&#xff1f; 二、为什么无论采用Cookie-session的方式&#xff0c;还是Token&#xff08;JWT&#xff09;的方式&#xff0c;在一个浏览器里&#xff0c;同一个网站只能保证一个用户处于登录状态&#xff1f; …

讨论C++模板

讨论C模板 函数重载和泛型编程模板分类函数模板语法原理函数模板的实例化隐式实例化显示实例化 匹配原则 类模板语法类模板的实例化 C支持了函数重载&#xff0c;通过函数名相同&#xff0c;参数列表不同来构成函数重载&#xff0c;以达到方便程序员调用。但还是没有改变代码大…

Python基础教程(二十一):多线程

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

C++ 56 之 菱形继承

#include <iostream> #include <string> using namespace std;// 动物类: 虚基类 class Animal{ public:int m_age; };// 羊类 class Sheep : virtual public Animal{ // virtual虚继承 };// 驼类 class Tuo : virtual public Animal{ // virtual虚继承 指向同一块…

【计算机毕业设计】基于Springboot的车辆管理系统【源码+lw+部署文档】

包含论文源码的压缩包较大&#xff0c;请私信或者加我的绿色小软件获取 免责声明&#xff1a;资料部分来源于合法的互联网渠道收集和整理&#xff0c;部分自己学习积累成果&#xff0c;供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。 本人尊重原创作者…