在第十节课 多层感知机 的代码实现部分,做的小实验,介绍了对FashionMNIST
(衣物)数据集进行十分类的神经网络实现效果,主要展示的是训练的Loss以及准确度的训练批次图,10个epoch
期间遇到问题如下:
AttributeError: module ‘d2l.torch‘ has no attribute ‘train_ch3‘
⚠️注意:本章节用到的train_ch3,可能在后续新的版本将不复存在,如果你想按照老师的视频实现的效果,应该使用下面的命令安装旧的版本
pip install d2l==0.17.5 --user
Softmax函数,输入是一个二维张量
def softmax(X):
X_exp = torch.exp(X) # 1. 求指数
partition = X_exp.sum(1, keepdim=True) # 2. 求和
return X_exp / partition # keepdim to boardcast 3. 输出指数归一化矩阵
这个函数在自定义的网络中net( X )调用
def net(X):
# -1 means convert the dimension atomatically
# the input shape X (256, 1, 28, 28) --> (28*28, 256)
return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)
最后,写一个epoch迭代
⚠️:这里面没有写梯度更新的函数,直接调用torch中的自动求道实现,也就是下文代码中的updater.step()
。
for X, y in train_iter:
y_hat = net(X) # 将batch传入进去
l = loss(y_hat, y) # 计算loss值
if isinstance(updater, torch.optim.Optimizer):
updater.zero_grad()
l.backward() # 求梯度
updater.step() # 根据梯度更新权重参数矩阵W
metric.add(
float(l) * len(y), accuracy(y_hat, y),
y.size().numel())
else:
l.sum().backward()
updater(X.shape[0])
metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
手动实现的Softmax训练效果
⚠️:nn.CrossEntropyLoss()会在输出的时候自动应用Softmax进行求Loss(公式如下图所示)
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))
loss = nn.CrossEntropyLoss() # 损失函数 内嵌了Softmax函数
trainer = torch.optim.SGD(net.parameters(), lr=0.1) # 梯度下降优化器选择
内置Softmax实现10分类的回归效果
可以看到,调用torch内部实现的Softmax函数经过优化之后,相比手写的Softmax函数,迭代的过程更加稳定(抖动更小)
W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_grad=True))
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_grad=True))
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))
# function ReLU
def relu(X):
a = torch.zeros_like(X)
return torch.max(X, a)
# model
def net(X):
X = X.reshape((-1, num_inputs)) # 行数自动调整(batch_size),列数规定
H = relu(X @ W1 + b1)
return (H @ W2 + b2)
loss = nn.CrossEntropyLoss() # 隐式实现 Softmax
❓:有个疑惑,实现起来没有老师在视频里面展示的那种效果按照视频中的代码运行还是没有看到有loss曲线
后来改了一下损失函数loss = nn.CrossEntropyLoss(reduction='none')
才看到部分loss曲线(如上图),但是还是出不来视频中老师的效果
总的来说,在同样的训练轮次下,MLP实现的效果跟前面用单层的Softmax实现,效果差了
根据上述的结果,猜测是否是因为模型参数增加了,所以需要更多的训练轮次呢?🤨
于是我们将训练轮次由原来的10轮上升为30轮
结果如下:
增大训练轮次后,loss确实减少了,取得了比原来好的效果!
视频中李沐老师有提及,如果将==权重矩阵初始化为0(而不是上述代码使用正态分布)==会怎么样,于是我将原来的训练轮次改回了10,然后将权重改为初始化为0的效果
# test:全部设成0
# 全部设置成rendn
W1 = nn.Parameter(torch.zeros(num_inputs, num_hiddens, requires_grad=True))
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.zeros(num_hiddens, num_outputs, requires_grad=True))
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))
实验结果如下:
可以看到,图中不再显示原来的3条曲线了不是因为bug,而是因为训练的loss太大了!
上面也显示的最终训练Loss=2.3027
updater = torch.optim.AdamW(params, lr=lr)
这个优化效果确实显著!
记得加loss = nn.CrossEntropyLoss(reduction='none')
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10))
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
试验结果如下
效果应该是这几个实验中最好的了(不知道是不是有torch中计算优化的缘故)😊
用了Adam反而效果不那么好?
如果有同学🧑🎓能够有更好的训练结果(或者能复现李沐老师视频里面的结果的话),欢迎在下面评论区讨论,谢谢啦!
各位看官,都看到这里了,麻烦动动手指头给博主来个点赞8,您的支持作者最大的创作动力哟!
才疏学浅,若有纰漏,恳请斧正
本文章仅用于各位作为学习交流之用,不作任何商业用途,若涉及版权问题请速与作者联系,望悉知