Pytorch|用Tensor和Variable实现线性回归

Tensor

import torch as t
%matplotlib inline
from matplotlib import pyplot as plt
from IPython import display

batch_size是“一批”的大小,每处理完一批之后都会更新一次参数。如果batch_size=1,则为随机梯度下降法;1<batch_size<样本数则为小批量梯度下降;batch_size=样本数则为批量梯度下降。
这里batch_size=8=样本数,但为什么书上还是说这是随机梯度下降呢?
这个函数产生了训练集,共8个样本,每个样本的input就是一个实数,output也是一个实数,所以x是一个1*8的向量。

t.manual_seed(1000)
def get_fake_data(batch_size=8):
    '''产生随机数据:y=x*2+3 加上了一些噪声'''
    x=t.rand(batch_size,1)*20   #rand:0,1均匀分布
    y=x*2+(1+t.randn(batch_size,1))*3
    return x,y
#随机初始化参数
w=t.rand(1,1)
b=t.zeros(1,1)
lr=0.001 #学习率
for ii in range(20000):
    x,y=get_fake_data()
    
    #forward:计算loss
    y_pred=x.mm(w)+b.expand_as(y)
    loss=0.5*(y_pred-y)**2  #均方误差
    loss=loss.sum()
    
    #backward:手动计算梯度
    dloss=1
    dy_pred=dloss*(y_pred-y)
    
    dw=x.t().mm(dy_pred)
    db=dy_pred.sum()
    
    #更新参数
    w.sub_(lr*dw)
    b.sub_(lr*db)
    
    if ii%1000 == 0:
        #画图
        display.clear_output(wait=True)
        x=t.arange(0,20).view(-1,1)
        y=x.float().mm(w)+b.expand_as(x)
        plt.plot(x.numpy(),y.numpy()) #predicted
        
        x2,y2=get_fake_data(batch_size=20)
        plt.scatter(x2.numpy(),y2.numpy()) #true data
        
        plt.xlim(0,20)
        plt.ylim(0,41)
        plt.show()
        plt.pause(0.5)
print(w,b)

t.arange(0,20)产生的是整型numpy,为了变成浮点型,用x.float()之外,也可以把x写作t.arange(0.,20.)
plt.scatter的输入必须是numpy,所以这里用了tensor.numpy()函数;后面用Variable实现的时候也是一样(绘图时x和y都是tensor而不是Variable)。
最后的输出是这样的:
在这里插入图片描述tensor([[2.1143]]) tensor([[3.0964]])
最后的输出是1*1的tensor,所以如果把w和b进行维度压缩的话,或许可以输出实数。

print(w.data.squeeze(0),b.data.squeeze(0))
print(w.data.squeeze(),b.data.squeeze())

结果:

tensor([1.9685]) tensor([3.1115])
tensor(1.9685) tensor(3.1115)

可见1维和0维(或许可以这么说吗)的tensor有中括号和小括号的区别。
不过书上的写法是print(w.squeeze()[0],b.sqeeze()[0]),我很不明白,而且也会报错。

Variable

import torch as t
from torch.autograd import Variable as V
%matplotlib inline
from matplotlib import pyplot as plt
from IPython import display
t.manual_seed(1000)
def get_fake_data(batch_size=8):
    x=t.rand(batch_size,1)*20
    y=x*2+(1+t.randn(batch_size,1))*3
    return x,y
w=V(t.rand(1,1),requires_grad=True)
b=V(t.zeros(1,1),requires_grad=True)
lr=0.001

for ii in range (8000):
    x,y=get_fake_data()
    x,y=V(x),V(y)
    y_pred=x.mm(w)+b.expand_as(y)
    loss=0.5*(y_pred-y)**2
    loss=loss.sum()
    
    loss.backward()
    
    w.data.sub_(lr*w.grad.data)
    b.data.sub_(lr*b.grad.data)
    
    w.grad.data.zero_()
    b.grad.data.zero_()
    
    
    if ii%1000 == 0:
        display.clear_output(wait=True)
        x=t.arange(0,20).view(-1,1)
        y=x.float().mm(w.data)+b.data.expand_as(x)
        plt.plot(x.numpy(),y.numpy())
        
        x2,y2=get_fake_data(batch_size=20)
        plt.scatter(x2.numpy(),y2.numpy())
        
        plt.xlim(0,20)
        plt.ylim(0,41)
        plt.show()
        plt.pause(0.5)
        
print(w.data.squeeze(),b.data.squeeze())

输出如下:
在这里插入图片描述

tensor(1.9373) tensor(3.0661)

这里用get_fake_data得到训练集后的第一步就是把它们转换成Variable,在更新参数、梯度清零、压缩维度时用Variable.data转换成Tensor。
前向传播和绘制拟合曲线是都用了y=wx+b,但是前向传播时x,w,b都是Variable,绘制拟合曲线时x,w,b都是Tensor。

y_pred=x.mm(w)+b.expand_as(y)  #前向传播
y=x.float().mm(w.data)+b.data.expand_as(x)  #绘制拟合曲线

是不是只要同一个式子变量数据类型符合一致就可以了呢?
其实把绘制曲线部分全部用Variable写也可以的,就像这样:

    if ii%1000 == 0:
        display.clear_output(wait=True)
        x=V(t.arange(0,20).view(-1,1))
        y=x.float().mm(w)+b.expand_as(x)
        plt.plot(x.data.numpy(),y.data.numpy())

要注意只有Tensor.numpy()而没有Variable.numpy()。
不过前向传播好像改了改会报错,但是谁会做这么没有美感的改动呢。

for ii in range (8000):
    x,y=get_fake_data()
    x,y=V(x),V(y)
    y_pred=V(x.data.mm(w.data)+b.data.expand_as(y.data))
    loss=0.5*(y_pred-y)**2
    loss=loss.sum()

报错:

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

另:每次都要手动清零,是因为pytorch的梯度默认叠加。如果不清零的话,w和b就会变成nan,输出如下:
在这里插入图片描述

tensor(nan) tensor(nan)
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值