这篇博客早就想写了,因为这节课是我在疫情的假期里看的,还不错,准备一直看完。所有最近又复习了一遍。因为之前一直在学《动手学深度学习》PyTorch版,不过,我这个人真是懒,一直么学好,也断断续续。不过,我还是会把那本书接着学一遍,先看这个视频了,因为最近有可能用到。
本系列博客是根据哔哩哔哩上pytorch入门与实战这个视频课程写的(主要是代码),因为是小白,死磕课本有点费劲,学习《动手学深度学习》PyTorch版时就发现了。
哔哩哔哩上这系列课的网址:https://www.bilibili.com/video/BV12741177Cu?from=search&seid=17209581732555565064
实现的两层神经网络的模型: 注:为了简单实现,偏置项b不在网络中实现。
$ h = w_{1}*X + b_{1} $
$ a = max(0,h) $
$ y_{hat} = w_{2}*a + b_{2} $
以下代码是我为了记忆,自己直接敲的一遍,有错误请指出,谢谢了
下面使用numpy实现该神经网络:1 2 3 4 步,所有的网络基本都是这几步,其他的就是数据处理什么的
import numpy as np
N, D_in, H, D_out = 64, 1000, 100, 10
# 定义输入输出数据
x = np.random.randn(D_in, H)
y = np.random.randn(N, D_out)
# 权重随机初始化
w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)
learning_rate = 1e-6
for it in range(500): # 对网络训练500次
# 1 Forward pass,前向网络,也就是模型
h = x.dot(w1) # .dot()在numpy中是计算向量点积的函数
h_relu = np.maximum(h, 0) # .maximum()是采用的ReLU激活函数
y_pred = h_relu.dot(w2)
# 2 计算损失函数
loss = np.square(y_pred - y).sum() # 平方损失函数,.square()就是求平方,sum()求和
print(it, loss)
# 3 backward pass, 反向网络,也就是计算梯度。若是看代码费劲,可以先对上面提的神经网络模型公式进行求导,然后对应到Forward Pass中的定义即可。我的推导见附录一
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.T.dot(grad_y_pred)
grad_h_relu = grad_y_perd.dot(w2.T)
grad_h = grad_h_relu.copy()
grad_h[h<0] = 0
grad_w1 = x.T.dot(grad_h)
# 4 update weights of w1 and w2, 更新权重,也就是学习一个好的权重
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
PyTorch实现上述两层神经网络模型:附录二有numpy和PyTorch的封装的函数的小差别对比
import torch
N, D_in, H, D_out = 64, 1000, 100, 10
# 定义输入输出数据
x = torch.randn(D_in, H)
y = torch.randn(N, D_out)
# 权重随机初始化
w1 = torch.randn(D_in, H)
w2 = torch.randn(H, D_out)
learning_rate = 1e-6
for it in range(500): # 对网络训练500次
# 1 Forward pass,前向网络,也就是模型
h = x.mm(w1) # .mm()在torch中是计算向量点积的函数
h_relu = h.clamp(min=0) # .clamp()是采用的ReLU激活函数,是类似于range,一个min,一个max,夹在中间,大于max,就记为max,小于min,就记为min
y_pred = h_relu.mm(w2)
# 2 计算损失函数
loss = np.square(y_pred - y).sum() # 平方损失函数,.square()就是求平方,sum()求和
print(it, loss)
# 3 backward pass, 反向网络,也就是计算梯度。若是看代码费劲,可以先对上面提的神经网络模型公式进行求导,然后对应到Forward Pass中的定义即可。我的推导见附录一
grad_y_pred = (y_pred - y).pow(2)
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_perd.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h<0] = 0
grad_w1 = x.t().mm(grad_h)
# 4 update weights of w1 and w2, 更新权重,也就是学习一个好的权重
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
PyTorch简化版实现上述网络(torch.nn.Sequential()):(因为pytorch封装了好多方法和类,可以自动求梯度,不用自己实现)
import torch.nn as nn
N, D_in, H, D_out = 64, 1000, 100, 10
x = torch.randn(D_in, H)
y = torch.randn(N, D_out)
model = nn.Sequential(
nn.Linear(D_in, H, bias=False),
nn.ReLU(),
nn.Linear(H, D_out)
)
nn.init.normal_(model[0].weight) # 初始化一下权重,否则会模型效果会差。
nn.init.normal_(model[2].weight)
loss_fn = nn.MSELoss(reduction='sum')
learning_rate = 1e-6
for it in range(500):
y_pred = model(x) # 相当于model.forward(x),model会自动做前向传播
loss = loss_fn(y_pred, y)
print(it, loss)
loss.backward()
with torch.no_grad(): #加入这句,可以不记录计算图的历史,节省内存
for param in model.parameters(): # 遍历模型参数,优化
param -= learning_rate * param.grad
model.zero_grad() # 计算下次梯度前,清零梯度
PyTorch简化版实现上述网络(torch.nn.Module())
import torch.nn as nn
N, D_in, H, D_out = 64, 1000, 100, 10
x = torch.randn(D_in, H)
y = torch.randn(N, D_out)
class TwoLayerNet(nn.Module):
def __init__(self, D_in, H, D_out):
super(TwoLayerNet, self).__init__() # 必须这么写
self.linear1 = nn.Linear(D_in, H, bias=False)
self.linear2 = nn.Linear(H, D_out, bias=False)
def forward(self,x):
y_pred = self.linear2(self.linear1(x).clamp(min=0))
return y_pred
model = TwoLayreNet(D_in, H, D_out)
loss_fn = nn.MSELoss(reduction='sum')
learning_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) # 若使用SGD优化器,需要初始化weight,否则效果不好,玄学。。。
for it in range(500):
y_pred = model(x)
loss = loss_fn(y_pred,y)
print(it, loss)
# 三步操作:梯度清零,反向计算新梯度,一步优化(update parameter)
optimizer.zero_grad()
loss.backward()
optimizer.step()
上述torch.nn.Sequential和torch.nn.Modele,在我学习《动手学深度学习》时也介绍过,可以去我以前的博客看看,欢迎指点和探讨,我是小白,虽然我黑。
附录一:(字体有点low了)
附录二:(字体样子自动过滤)