pytorch_机器学习高维线性拟合权重衰减demo复现_tensor的view函数

本文作者在实现线性回归的权重衰减demo时遇到问题,发现由于初始化一维tensor并转换为二维操作影响了梯度计算。通过debug发现`view`操作改变了`is_leaf`属性,导致w的grad为None。博主分享了解决方案及训练集过拟合现象。
摘要由CSDN通过智能技术生成

今天的第二篇博客。

在复现下一个高维线性拟合demo的时候又双叒叕遇到了一个问题。

好家伙,我再次好家伙。

先上代码再详说,这次是一个从零开始实现权重衰减的demo:

import torch
import numpy as np
import d2lzh_pytorch.util as util
import torch.utils.data as Data

# 1.生成特征
# y=0.05+∑0.01*xi+随机噪声
n_train=20 # 20个训练数据
n_test=100 # 100个测试数据
n_input_features=200 # 每个数据有200维
true_w=torch.ones(n_input_features) * 0.01
true_b=0.05

features=torch.randn(n_train+n_test,n_input_features)
labels=torch.mm(features,true_w.view(-1,1))+ true_b
labels += torch.tensor(np.random.normal(0,0.01,labels.size()),dtype=torch.float32)

train_features=features[:n_train]
train_labels=labels[:n_train]
test_features=features[n_train:]
test_labels=labels[n_train:]

# 2.生成训练数据集
batch_size=1
dataset=Data.TensorDataset(train_features,train_labels)
train_iter=Data.DataLoader(dataset,batch_size,shuffle=True)

# 3.初始化权重偏差参数
def init_param():
    w=torch.randn(n_input_features,requires_grad=True)
    b=torch.zeros(1,requires_grad=True)
    return w,b

# 4.定义l2惩罚项
def l2_penalty(w):
    return (w**2).sum()/2

# 5.定义模型
lr=0.003
num_epochs=100
loss=util.squared_loss # 返回一个列向量
net=util.linreg
w,b=init_param()

lamda=0
w=w.view(-1,1) # w是一维的tensor,无法进行torch.mm

for _ in range(num_epochs):
    train_loss,test_loss=[],[]
    for x,y in train_iter:
        y_hat=net(x,w,b)
        l=loss(y_hat,y)+lamda * l2_penalty(w)
        l=l.sum()

        if w.grad is not None: # 否则一上来就清零会报错
            w.grad.data.zero_()
            b.grad.data.zero_()

        l.backward()

        util.sgd([w,b],lr,batch_size) # 更新参数

    train_l=loss(net(train_features,w,b),train_labels).mean().item()
    train_loss.append(train_l)
    test_l=loss(net(test_features,w,b),test_labels).mean().item()
    test_loss.append(test_l)
print('final epoch:train_loss: ',train_loss[-1],'test_loss:',test_loss[-1])
print('L2 norm of w:', w.norm().item())

其中一些函数sgd,loss_square啥的都在d2lzh_pytorch.util这个python文件中,具体如下:

#定义损失函数
def squared_loss(y,y_hat):
    return (y_hat-y.view(y_hat.size()))**2

#定义优化算法 随机小批量下降
def sgd(params,lr,batch_size):
    for param in params:
        param.data -= lr*param.grad/batch_size

出现的问题如下:
在这里插入图片描述
就是说w的grad是None。

我这明明把w的requires_grad设为True了,怎么backward()后就成None了呢???

又是好一番debug,终于找到原因了,就是这个罪恶的红框:
在这里插入图片描述

因为我在初始化w的时候,创建的是个一维tensor,但是net要进行矩阵相乘的运算,所以需要将w转化为二维,我就单独写了一句。就是这句话出问题了,在使用backward()求梯度的时候,只有requires_grad为true以及is_leaf为true的tensor,才会被计算梯度,即grad属性才会被赋予值。

view改变了is_leaf属性,所以在进行梯度计算时,梯度并不会积累到w的grad中,后面进行参数更新的时候,w的grad是None,自然会报错了。我写了一个测试,本来is_leaf是True的tensor在view之后就变成false了
在这里插入图片描述
慢慢来吧。

-----------------------------补一个结果截图----------------------------
在这里插入图片描述

120个数据中只有20个用于训练,可见训练集上的损失很小,但是测试集上的损失很大,出现了过拟合现象。

参考链接:python中backward是什么意思_pytorch的梯度计算以及backward方法详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值