线性回归的简洁实现

https://zh.d2l.ai/chapter_linear-networks/linear-regression-concise.html

1 Like

练习1的问题应该改成“如果我们用nn.MSELoss(reduction=‘sum’)替换 ,nn.MSELoss()”为了使代码的行为相同,需要怎么更改学习速率?为什么?
答:应该把学习率除以batch_size,因为默认参数是’mean’,换成’sum’需要除以批量数,一般会采用默认,因为这样学习率可以跟batch_size解耦(老师直播讲了~~

32 Likes

我测试了几次简洁实现和从零开始的代码,为什么基本上都是从零开始的损失更小呢?大部分从零开始的损失都是0.000050左右,而简洁实现大部分是0.000100左右

2 Likes

net[0].weight.grad是不是可以用来得到梯度?

3 Likes

Hi @dongming, 一般我们先call .backward() 再call .grad。详见https://zh-v2.d2l.ai/chapter_preliminaries/autograd.html

2 Likes

我也是得到同样结果,epoch相同的情况下从零开始更优,请您有找到什么比较好的解释吗?

1 Like

关于练习1,以下两种方式理论上等价,为何loss function取mean显著由于取sum的方式?

loss function reduction= ‘mean’ , lr=0.03:
epoch 1, loss 0.000361
epoch 2, loss 0.000095
epoch 3, loss 0.000095
w的估计误差: tensor([-0.0002, -0.0002])
b的估计误差: tensor([8.6784e-05])

loss function reduction = ‘sum’, lr =0.03/batch_size=0.003
epoch 1, loss 0.176310
epoch 2, loss 0.091707
epoch 3, loss 0.092358
w的估计误差: tensor([0.0007, 0.0012])
b的估计误差: tensor([0.0005])

3 Likes

mean意味着所有样本损失的平均值,即loss会除以样本数,sum没有除这个样本数,所以会放大1000倍(这里样本数为1000)

1 Like

1.我刚才试验了几遍,由于按batch_size=10抽样本进行训练并计算损失,所以sum方式时应该用lr/10来弥补,即在optim中除10来替代loss fuction中除10,这个思路应该是没有问题的。
2.按mini batch方式训练,样本数并不为1000, 若用lr除1000得到的结果更离谱

2 Likes

num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X) ,y)
trainer.zero_grad()
l.backward()
trainer.step()
l = loss(net(features), labels)
print(f’epoch {epoch + 1}, loss {l:f}’)
在线性回归的简洁实现中
每个epoch结尾处的计算loss并打印没有with torch.no_grad():(目的是将其移除计算图)
但是手动实现中却有,为什么它是如何保证每个epoch结束处的计算损失不会被计算入梯度

同样疑问,感觉这里是需要使用的no_grad去移除计算图再去计算的

小白表示还是有疑问,一次10个样本,理论上学习率除以10就可以了呀

net.parameter() or net[0].weight.requires_grad is set to True by default; while in sgd function, it declares: with torch.no_grad():.

loss function is executed out of the loop for gradient update backwardly. I don’t think it needs come with “torch.no_grad()”.

1 Like
num_epochs = 3
for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X) ,y)
        trainer.zero_grad()
        l.backward()
        trainer.step()
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l:f}')

这段代码中的trainer.zero_grad()应该要放在 l = loss(net(X) ,y)前面吧?

为什么要放到前面,trainer.zero_grad()是清除上一轮所有结点的梯度值,和本轮的前向传播没有关系啊,我觉得没问题

1 Like

请问在反向传播中

l.backward()

为什么不和上一讲一样对非标量进行累加后再反向传播?
谢谢!

我认为训练中的’l’和每个epoch结尾的’l’应该不是一个变量,(每次计算loss都是重新生成一个新的’l’?),所以应该不影响梯度计算

第3题:print(net[0].weight.grad)

5 Likes

可以去查看一下简洁实现版本的SGD源代码:

@torch.no_grad()
    def step(self, closure=None):
        """Performs a single optimization step.

        Arguments:
            closure (callable, optional): A closure that reevaluates the model
                and returns the loss.
        """
        loss = None
        if closure is not None:
            with torch.enable_grad():
                loss = closure()
......

有torch.no_grad()的

3 Likes

是不是在trainer.zero_grad()里实现的