对线性层的复用 Dense网络:稠密网络,有很多线性层对输入数据进行空间上的变换,又叫DNN 输入x1,x2…xn是数据样本的不同特征 Dense连接就是指全连接 比如预测天天气,就需要知道之前几天的数据,每一天的数据都包含若个特征,需要若干天的数据作为输入
假设现在取前3天,每一天有3个特征 第一种方法:把x1,x2,x3拼成有9个维度的长向量,然后去训练最后一天是否有雨 用全连接稠密网络进行预测,如果输入序列很长,而且每一个序列维度很高的话,对网络训练有很大挑战,因为稠密网络(全连接网络)实际上权重是最多的。对于卷积层:比如输入通道是128个,输出通道是64个,如果用55的卷积。权重数就是 2564188=204800,卷积层的输入输出只与通道数和卷积核的大小有关,全连接层和变换之后的数据大小有关 ,比如3阶张量经过一系列的卷积变换还剩下4096个元素,4096我们很少直接降成1维或者10维,而是先降成1024维,40961024=4194304,所以相比起来,卷积层的权重并不多,而全连接层的权重较多 。在网络的全部参数中,全连接层是占大头的 为什么卷积神经网络的权重比较少呢? 因为使用了权重共享的概念,做卷积时,整个图像的卷积核是共享的,并不是图像上的每一个像素要和下一层的featureMap建立连接,权重数量就少 处理视频的时候,每一帧就少一张图像,我们需要把一组图像做成一个集合,如果用全连接网络的话,使用到的权重的数量就是一个天文数字,难以处理 RNN专门用来处理带有序列模式的数据,也使用权重共享减少需要训练的权重的数量 我们把x1,x2,x3,xn看成是一个序列,不仅考虑x1,x2之间的连接关系,还考虑x1,x2的时间上的先后顺序 x2依赖于x1,x3依赖于x2,下一天的天气状况部分依赖于前一天的天气状况,RNN主要处理这种具有序列连接的 天气,股市,金融,自然语言处理都是序列数据 RNN Cell本质是一个线性层(linear),把一个维度映射到另一个维度(比如把输入的3维向量xt变成输出5维向量ht) 这个线性层与普通的线性层的区别是这个线性层是共享的 展开就是下图(其中所有的RNN cell是同一个线性层,因为是展开的嘛),h0是先验值,没有就设置成0向量 具体的计算过程:
输入xt先做线性变换,h t-1也是,xt的维度是input_size,h t-1的维度是hidden_size,输出ht的维度是hidden_size,我们需要先把xt的维度变成hidden_size,所以Wih应该是一个 hidden_sizeinput_size的矩阵,Wihxt得到一个 hidden_size1的矩阵(就是维度为hidden_size的向量),bih是偏置。输入权重矩阵Whh是一个hidden_sizehidden_size的矩阵。 whhHt-1+bhh和WihXt+bih都是维度为hidden_size的向量,两个向量相加,就把信息融合起来了,融合之后用tanh做激活,循环神经网络的激活函数用的是tanh,因为tanh的取值在-1到+1之间,算出结果得到隐藏层输出ht
把RNN Cell以循环的方式把序列(x1,x2,…)一个一个送进去,然后依次算出隐藏层(h1,h2…)的过程,每一次算出来的h会作为下一个RNN Cell的输入,这就叫循环神经网络
①自己构建Cell 需要设定输入的值input_size,和隐层的值hidden_size,就能确定权重W的维度和偏置b的维度
cell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size) hidden = cell(input, hidden)#实例化Cell之后,我们需要给定当前的输入input以及当前的hidden,所以需要用循环来处理比如
h1=Cell(x1,h0)batchSize表示批量 seqLen=3表示每一个样本都有x1,x2,x3这些特征 inputSize=4表示每一个特征都是4维的 hoddenSize=2表示每一个隐藏层是2维
𝒊𝒏𝒑𝒖𝒕. 𝑠ℎ𝑎𝑝𝑒 = (𝒃𝒂𝒕𝒄𝒉𝑺𝒊𝒛𝒆,𝒊𝒏𝒑𝒖𝒕𝑺𝒊𝒛𝒆) 𝑜𝑢𝑡𝑝𝑢𝑡. 𝑠ℎ𝑎𝑝𝑒 =(𝑏𝑎𝑡𝑐ℎ𝑆𝑖𝑧𝑒, ℎ𝑖𝑑𝑑𝑒𝑛𝑆𝑖𝑧)#h0需要满足这个条件The sequence can be warped in one Tensor with shape:
𝑑𝑎𝑡𝑎𝑠𝑒𝑡. 𝑠ℎ𝑎𝑝𝑒 = (𝒔𝒆𝒒𝑳𝒆𝒏, 𝒃𝒂𝒕𝒄𝒉𝑺𝒊𝒛𝒆,𝒊𝒏𝒑𝒖𝒕𝑺𝒊𝒛)代码展示
import torch batch_size=1 seq_len=3 input_size=4 hidden_size=2 Cell=torch.nn.RNNCell(input_size=input_size,hidden_size=hidden_size)#初始化,构建RNNCell dataset=torch.randn(seq_len,batch_size,input_size)#设置dataset的维度 hidden=torch.zeros(batch_size,hidden_size)#隐层的维度:batch_size*hidden_size,先把h0置为0向量 for idx,input in enumerate(dataset): print('='*20,idx,'='*20) print('Input size:',input.shape) hidden=Cell(input,hidden) print('Outputs size:',hidden.shape) print(hidden)结果:
==================== 0 ==================== Input size: torch.Size([1, 4]) Outputs size: torch.Size([1, 2]) tensor([[0.8677, 0.8320]], grad_fn=<TanhBackward>) ==================== 1 ==================== Input size: torch.Size([1, 4]) Outputs size: torch.Size([1, 2]) tensor([[-0.9137, -0.5884]], grad_fn=<TanhBackward>) ==================== 2 ==================== Input size: torch.Size([1, 4]) Outputs size: torch.Size([1, 2]) tensor([[0.9840, 0.9235]], grad_fn=<TanhBackward>)②直接使用RNN
cell = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size, num_layers=num_layers)#num_layers:RNN的层数#num_layers:RNN的层数,如果RNN有多层,每一层都会有输出
out, hidden = cell(inputs, hidden)inputs:所有的x,x1,x2,x3,xn 用RNN不用自己写循环,它自动循环,所以输入的时候要把所有的序列都送进去,然后给定h0,然后我们就会得到所有的隐层输出以及最后一层的输出 当RNN有多层,同样颜色的RNNCell是同一个,所以下图是有3个线性层(一个RNNCell是一个线性层)
代码
import torch batch_size=1 seq_len=3 input_size=4 hidden_size=2 num_layers=1 cell=torch.nn.RNN(input_size=input_size,hidden_size=hidden_size,num_layers=num_layers) #构造RNN时指明输入维度,隐层维度以及RNN的层数 inputs=torch.randn(seq_len,batch_size,input_size) hidden=torch.zeros(num_layers,batch_size,hidden_size) out,hidden=cell(inputs,hidden) print('Output size:',out.shape) print('Output:',out) print('Hidden size:',hidden.shape) print('Hidden',hidden)结果
Output size: torch.Size([3, 1, 2]) Output: tensor([[[-0.9123, 0.9218]], [[ 0.9394, -0.2471]], [[-0.9064, 0.5193]]], grad_fn=<StackBackward>) Hidden size: torch.Size([1, 1, 2]) Hidden tensor([[[-0.9064, 0.5193]]], grad_fn=<StackBackward>)如果初始化RNN时,把batch_first设置成了TRUE,那么inputs的参数batch_size和seq_len需要调换一下位置
①把字符转成向量 inputsize=4,因为输入有4个字符(e h l o) 这相当于一个多分类问题,输出就是一个4维的向量,每一维代表是某一个字符的概率,接交叉熵就能输出概率了 代码
import torch input_size=4 hidden_size=4 batch_size=1 idx2char=['e','h','l','o'] x_data=[1,2,2,2,3] y_data=[3,1,2,3,2] one_hot_lookup=[[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]] #查询字典 x_one_hot=[one_hot_lookup[x] for x in x_data]#独热向量 inputs=torch.Tensor(x_one_hot).view(-1,batch_size,input_size)#取出来one_hot_lookup中的一行向量 labels=torch.LongTensor(y_data).view(-1,1) #构建模型 class Model(torch.nn.Module): def __init__(self,input_size,hidden_size,batch_size): super(Model,self).__init__() self.batch_size=batch_size self.input_size=input_size self.hidden_size=hidden_size self.rnncell=torch.nn.RNNCell(input_size=self.input_size,hidden_size=self.hidden_size) def forward(self,input,hidden): hidden=self.rnncell(input,hidden)#ht=cell(xt,ht-1) return hidden def init_hidden(self): return torch.zeros(self.batch_size,self.hidden_size) net=Model(input_size,hidden_size,batch_size) criterion=torch.nn.CrossEntropyLoss() optimizer=torch.optim.Adam(net.parameters(),lr=0.1) #训练 for epoch in range(15): loss=0 optimizer.zero_grad()#每一轮训练先把优化器的梯度清零 hidden=net.init_hidden() print('Predicted string:',end='') for input,label in zip(inputs,labels): hidden=net(input,hidden) loss+=criterion(hidden,label) _,idx=hidden.max(dim=1)#hidden现在是4维向量,用max找到最大的概率 print(idx2char[idx.item()],end='') loss.backward() # loss.backward(retain_graph=True) optimizer.step() print(',Epoch [%d/15] loss=%.4f' % (epoch+1,loss.item())