Softmax回归的从零实现

感谢!
我也是遇到了这个问题,找不到解决方法,翻了好久评论终于在你这找到了答案!
我也挺好奇为什么其他的同学没有遇到类似的问题 :joy:

Run with Jupyter notebook or add “d2l.plt.show()”

2 Likes


这里执行第二段代码报
UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at .[./learn_/Dive_into_deep_learning/d2l-zh/pytorch/chapter_linear-networks/torch/csrc/utils/tensor_numpy.cpp:180).)
这个错,不过好像不影响运行其他代码,有什么办法修复吗?

cross_entropy只是计算loss,真更新还是靠updater,相当于前面章节的train方法,updater里面就是一个sgd,最后训练好的模型的参数就是W和b了。

def cross_entropy(y_hat, y):
return - torch.log(y_hat[range(len(y_hat)), y])

cross_entropy(y_hat, y)

这里的交叉熵损失函数定义为什么没有y_hat本身与LOG相乘?就是直接使用LOG函数了。

我发现这里每个epoch只训练了一个batchsize的数据,对吗?这好像我以前对于“每个epoch要遍历全体数据集一遍”的认知,并且下载的fashion-mnist数据都是一些无法打开的文件,它们是怎么被读入的?

每个epoch只训练了一个batchsize的数据

不是的,你看Dataloader部分的定义

fashion-mnist数据都是一些无法打开的文件

从名称看应该都是字节数据,直接读取的byte

已经把dataloader里面的num_workers设置成0了,但是还是报错,如何解决?

这个if的两个选择是选择训练的时候使用内置还是自定义的优化器,都是在训练阶段;只有在验证或测试阶段需要with torch.no_grad()

问题5 不就是 word2vec 训练过程遇到的问题么,word2vec 采用了两种训练优化方法:Hierarchical softmax 和 Negative Sampling

Accumulator这个类的add函数设计不好,非常2容易让人产生歧义,metric.add(1,2);让人以为是1和2相加,而实际上是self.data[0] = self.data[0] +1;self.data[1] = self.data[1] +1

应该是内置的loss_function 求的的是均值loss, 这里虽然optim使用的是内置的,但是求l所用的损失函数是自定义的,函数结果没有除以batch,所以先对l求均值

可能现在回复你已经过时了,不过 按我的理解,sum和mean其实主要影响了“梯度的大小”,反向传播时,依据损失求梯度,如果是sum,则梯度会比mean大n倍,那么在学习率不变的情况下,步子会迈得很长,体现到图形上就是正确率提升不了。所以需要缩小学习率。

如有不对还望指正。

    if isinstance(updater, torch.optim.Optimizer):
        # 使用PyTorch内置的优化器和损失函数
        updater.zero_grad()
        l.mean().backward()
        updater.step()
    else:
        # 使用定制的优化器和损失函数
        l.sum().backward()
        updater(X.shape[0])

请问下为什么使用定制的优化器的时候,就不需要清零梯度呢?

为什么torch内置 反向求导要mean().backward() ?

if isinstance(updater, torch.optim.Optimizer):
# 使用PyTorch内置的优化器和损失函数
updater.zero_grad()
l.mean().backward()
updater.step()
else:
# 使用定制的优化器和损失函数
l.sum().backward()
updater(X.shape[0])
metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())

因为 Pytorch 内置的 backward 会累加梯度,也就是每一个 batch算参数的梯度都会默认累加
所以要清0
自己写的优化器 不会累加梯度,所以不用清零

参数已经保留 在 W 和 b中了,这些参数都是训练后的参数

you should use english version

问题在于W和b没有定义,需要在net()里面定义W和b,并进行初始化

以下是chatgpt给我的答案。l.mean().backward()和l.sum().backward()的区别在于它们计算梯度的方式。l.mean().backward()计算的是平均损失对权重的梯度,而l.sum().backward()计算的是总损失对权重的梯度。

在实践中,这两种方式通常会得到相似的结果,因为它们都是在尝试最小化损失。然而,使用l.mean().backward()可能会使得梯度的大小更稳定,因为它不会因为批量大小的变化而变化。这可能会使得训练过程更稳定,特别是在批量大小可能变化的情况下。

另一方面,使用l.sum().backward()可能会使得梯度的大小更大,这可能会导致训练过程更快,但也可能导致训练过程更不稳定。

总的来说,哪种方式更好取决于你的具体情况。如果你的批量大小是固定的,那么你可能会发现l.sum().backward()和l.mean().backward()在实践中没有太大的区别。如果你的批量大小可能变化,那么你可能会发现l.mean().backward()在实践中更稳定