b站课程链接课时自己找一下
卷积神经网络
循环神经网络
输入数据类型
先找到单词的索引
embed一般是下载好的,存储每个词的特征,这里例子举例是随机的,实际上是由官方编制,下载word2vec或者GloVe,到本地使用
通过索引,查找到对应单词的词向量
注意:这种官网的embed是不能直接算梯度进行优化的
说明:
上述存在的问题
解决办法
减少参数数量
保存语境信息
比如“不喜欢”,不能只看到了“喜欢”没看到“不”
需要一个语境单元,来贯穿整个网络,保存整个语境信息
consistent memory
hth_{t}ht,记忆单元,会不断根据输入,循环更新自身,而不是像CNN一直往前冲[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LoOCU8cf-1674398676089)(/Users/xuan/Library/Application Support/typora-user-images/image-20230120173037729.png)]
上述的模型非常合理
至于最后选择输出的话,可以选择最后的hth_{t}ht,或者中间的hth_{t}ht,或者做一个融合,非常自由
这里E就是error
h0一般是[0,0…0]
这里表示方式有所不同
WRW_{R}WR就是WhhW_{hh}Whh
WIW_{I}WI就是WxhW_{xh}Wxh
回顾:
X[总共多少个词,总共几句,特征数]
某一时刻的输入XtX_{t}Xt,是每句话输入一个单词,这里就是[3,100]
这里用20维的memory来表示,每一步的memory更新是这样的,所以初始的memory设置应该是[batch_size,20]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5NGZd8o1-1674398676094)(/Users/xuan/Library/Application Support/typora-user-images/image-20230120203200543.png)]
这里是把数据一步喂到位,而不是前面分解的,比如对于X[5,3,100](3句话,每句五个词,每个词100维度表示),是自动在时间上进行五次展开的。输入的是X,不是一步步的XtX_{t}Xt
hth_{t}ht的参数是,第一个是几层,第二个是batch_size,第三个是h_dim。
out
对于X[5,3,100],h[1,3,10]来说
h是最后一个时刻的,维度是[1,3,20]
out是所有时刻的,维度是[10,3,20]
两层的话,out还是跟以前一样,代表是最后一层的,而h则是两层都有,二者是不同方向的,一个横着一个竖的
前面是一次全部喂进去,这个是手动一次一次喂,相当于没有循环的步骤,没有在时间上展开
通过前一段波形,能很好的预测下一段的曲线形状
因为很简单,所以batch设置为1,假设总长为50个点,那X就是[50,1,1]
import torch
import numpy as np
num_time_steps = 1
start = np.random.randint(3,size=1)[0]
time_steps = np.linspace(start, start+10, num_time_steps)
data = np.sin(time_steps)
data = data.reshape(num_time_steps, 1)
x = torch.tensor(data[:-1]).float().view(1, num_time_steps-1,1)
y = torch.tensor(data[1:]).float().view(1, num_time_steps-1,1)
随机初始化start,不然会记住
x,y比如说,这里x是0~48之间的曲线,y就是要预测的1~49的曲线。当然也可以通过0~40的点去预测10~50的点
网络结构
class Net(nn.Module):def __init__(self):super().__init__()self.rnn = nn.RNN(input_size=input_size,hidden_size=hidden_size,num_layers=1,batch_first=True, # 让输入X是[b,seq,f]的结构)for p in self.rnn.parameters():nn.init.normal_(p,mean=0.0,std = 0.001)self.linear = nn.Linear(hidden_size, output_size) #output_size为1def forward(self,x,hidden_prev):out, hidden_prev = self.rnn(x,hidden_prev) # hidden_prev就是htout = out.view(-1,hidden_size) # 将[1,seq,h]reshape为[seq,h]out = self.linear(out) # 线性层 [seq,h]->[seq,1]out = out.unsqueeze(dim=0) # [seq,1]->[1,seq,1]方便和真实值算msereturn out, hidden_prev
import torch
import numpy as np
import torch.nn as nn
import matplotlib.pyplot as plt
num_time_steps = 50 # 点的数量
input_size = 1
hidden_size = 16 # memory的维度
output_size = 1
lr = 0.01# 训练过程
model = Net()
criterion = nn.MSELoss()optimizer = torch.optim.Adam(model.parameters(), lr)hidden_prev = torch.zeros(1,1,hidden_size) # h0 是[b,1,10] 这里batch设为1
for iter in range(6000):start = np.random.randint(3, size=1)[0]time_steps = np.linspace(start, start + 10, num_time_steps)data = np.sin(time_steps)data = data.reshape(num_time_steps, 1)x = torch.tensor(data[:-1]).float().view(1, num_time_steps - 1, 1)y = torch.tensor(data[1:]).float().view(1, num_time_steps - 1, 1)output, hidden_prev = model(x,hidden_prev)hidden_prev = hidden_prev.detach()loss = criterion(output,y)model.zero_grad()loss.backward()optimizer.step()if iter % 100 == 0:print(f"Iteration:{iter} loss:{loss.item()}")# 预测代码,给定一个点。后面会一个一个将预测值作为输入值,一个一个预测
prediction = []
input = x[:,0,:]
for _ in range(x.shape[1]):input = input.view(1,1,1)pred, hidden_prev = model(input,hidden_prev)input = predprediction.append(pred.detach().numpy().ravel()[0])x = x.data.numpy().ravel()
y = y.data.numpy()
plt.scatter(time_steps[:-1], x.ravel(), s=90)
plt.plot(time_steps[:-1], x.ravel())plt.scatter(time_steps[1:], prediction)
plt.show()
因为LSTM中,ht充当了输出的角色,中间流通的memory用C表示(C经过一定筛选才作为h输出),所以C和H的size是一样的
所以这里输入每个size,跟RNN是一样的,上面的代表x的特征维,第二个是h/c的维度,第三个是有几层
forward函数里,其余都跟RNN的一样,就是把h变为了h和c
例子
3句话,每句10个单词
只有一层,所以这里第一个参数不写