pytorch
完成线性回归分析
0.总结
Get to the points first. The article comes from LawsonAbs!
pytorch
中相关函数的使用- 线性回归、梯度下降的理解与计算
1.要求
- 使用随机生成的模拟数据去训练一个函数模型
- 数据集是点对,呈现的是一次线性函数关系
2.主要思路
这个案例带有 “验证” 的味道,即我们事先定义好一个函数模型,并根据这个模型随机生成一些数据,然后给这些数据集加点儿噪声,最后得到的数据集就是通常所说的训练集。根据训练集训练一个一维函数模型,并使用随机生成的数据测试模型的效果如何,最后用matplotlib
展现拟合效果。
- step1.事先定义一个函数,即我们的原始数据服从这个函数模型,然后在其中加点儿噪声就得到训练的数据集了;
- step2.【因为这里是一维函数模型,所以我们就设一次线性函数为这个问题的模型】令函数模型为
y=w*x+b
。并随机初始化w,b
的值; - step3.事先定义好学习率
lr = 0.001
; - step4.采用梯度下降的方法更新参数,这里没有调用
Autograd
中的方法,而是自己计算梯度并更新; - step5.每训练完一批数据之后,就开始进行一次模拟验证【对应
if ii % 10 == 0:
中的部分】
3.代码
from __future__ import print_function
import torch as t
import numpy as np
from matplotlib import pyplot as plt
from IPython import display
t.manual_seed(1000) # 设置随机数种子,保证任何机器运行都相同
def get_fake_data(batch_size=8):
# 从均匀分布[0,1) 中抽出8*1的数据,并放大20倍【这里的放大倍数是没有影响的】
x = t.rand(batch_size, 1) * 20;
# print(x) # 其类似一个8行1列的向量
# 添加随机噪声
# 这里的 1+t.randn(batch_size,1) 会在[8,1]这个tensor中每个位置都加1。举例如下:
"""
tensor([[-0.9596],
[ 0.3518],
[-0.4039],
[ 1.7584],
[-0.4145],
[ 0.8561],
[-0.4429],
[ 1.4079]])
tensor([[0.0404],
[1.3518],
[0.5961],
[2.7584],
[0.5855],
[1.8561],
[0.5571],
[2.4079]])
"""
y = x * 2 + (1 + t.randn(batch_size, 1)) * 3
return x, y
x, y = get_fake_data()
# 只不过是将tensor 转换为numpy
#plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())
# 随机初始化参数
w = t.rand(1, 1) # => w是个tensor
b = t.zeros(1, 1) # => b也是个tensor
lr = 0.001 # learning rate
'''01.这里的意思就是生成一个具有20000个数据对作为样本,然后用这20000个数据对去训练一个函数模型出来'''
for ii in range(20000):
x, y = get_fake_data() # 模拟出假的数据
# forward: 计算loss
#print(x.size()) # torch.Size([8, 1])
#print(w.size()) # torch.Size([1, 1])
y_pred = x.mm(w) + b.expand_as(y)
loss = 0.5 * (y_pred - y) ** 2 # 均方误差
loss = loss.sum() # Returns the sum of all elements in the input tensor
# backward: 手动计算梯度
dloss = 1 # dloss是什么?
dy_pred = dloss * (y_pred - y)
# print(x.size()) # torch.Size([8, 1])
# print(dy_pred.size()) # torch.Size([8, 1])
'''
01.dw = x.t().mm(dy_pred) 里为什么有个x.t()操作? 是什么意思?
02.mm函数计算的是两个tensor的乘积,但是如果要做矩阵乘积,显然是无法相乘的。
所以就需要转换【转置】。
这里的x.t()就是将x进行转置操作。
03.结合learning rate 调整参数
'''
dw = x.t().mm(dy_pred)
db = dy_pred.sum()
w.sub_(lr * dw)
b.sub_(lr * db)
# 每训练100次就查看训练的效果到底怎么样了
if ii % 10 == 0:
# 清空输出 Clear the output of the current cell receiving output
display.clear_output(wait=True)
x = t.arange(0, 20).view(-1, 1)
# print(x.dtype) # torch.int64 所以需要显式的调用.float()将其转换成float型
# 其根本原因在于t.arange(0,20)是根据默认1为步长来分配的,导致会出现int64
# print(w.dtype)
'''
01.这里再生成一批数据,就相当于测试集。让这个测试集去表示训练模型的具体效果如何
02.plot是画出直线,scatter是画出离散的点。这样就可以直观地看出拟合的效果了
03.为了图形更好看,所以设置了一下长度的限制。
04.为了不直接跳出图形界面,暂缓了0.5s
05.最后输出了w,b的两个参数值
'''
y = x.float().mm(w)+ b.expand_as(x)
plt.plot(x.numpy(), y.numpy()) # predicted
x2, y2 = get_fake_data(batch_size=20) # 这里生成的数据是20个
plt.scatter(x2.numpy(), y2.numpy()) # true data
plt.xlim(0, 20) # 设置x轴,y轴的最大值
plt.ylim(0, 41)
plt.show()
print("w=",w.item(), "b=",b.item())
上面这段代码在pycharm
中的执行结果就是:
- 屏幕上会弹出若干幅图形,这些图形由两部分构成:
(1)训练得到的函数模型
(2)真实数据(其实就是我们模拟生成的数据)的一个个参数点坐标 - 底部会打印出参数w,b的值。
和一部分的参数展示:
4.难点分析
tensor
【其实就是矩阵】间的相互运算pytorch
函数的学习
这里我都在文章中的代码中进行了详细的注释。- 梯度下降的理解与计算
4.1 看看到底是怎么运算?
我觉得新手最容易怀疑的问题就是:y=w*x+b
,这个乘与加的过程到底是什么样的?这里我就把数据拿出来,专门做个解释。
-
函数模型
y = x*w + b
-
数据
x = tensor([[ 8.8605],
[13.1534],
[ 8.5220],
[ 6.9218],
[13.6363],
[16.2603],
[ 4.5726],
[12.9265]])
w = tensor([[0.3915]])
我们手动相乘一下,就得到了如下的结果:
x*w = tensor([[3.46888575],
[5.1495561],
[]...
])
实际计算机运算得到的x*w
值如下:
tensor([[3.4685],
[5.1490],
[3.3360],
[2.7096],
[5.3380],
[6.3652],
[1.7900],
[5.0602]])
然后再加上b的值【这里是0矩阵】,最后就成了y_pred
的值【即y的预测值】。可以发现二者是相同的。【计算机应该不会算错的】
而此时生成的y的值为:
y = tensor([[24.2896],
[23.1069],
[21.5958],
[12.2041],
[35.8736],
[36.4838],
[14.5665],
[28.4940]])
可以看到他们的之间的loss
太大了,现在的问题就是调整这个w,b去减少loss。这是后话,不说了。
4.2 具体函数的使用
expand_as()
把一个tensor变成和函数括号内一样形状的tensor,用法与expand()
类似
具体实例:
>>> import torch as t
>>> x=t.rand(3,4)
>>> print(x.size())
torch.Size([3, 4])
>>> print(x)
tensor([[0.7740, 0.1354, 0.3477, 0.7286],
[0.3327, 0.4944, 0.3491, 0.1855],
[0.3790, 0.8667, 0.6716, 0.2647]])
>>> b=t.zeros(1,1)
>>> print(b)
tensor([[0.]])
>>> print(b.size())
torch.Size([1, 1])
>>> b=b.expand_as(a)
>>> print(b.size())
torch.Size([2, 3])
>>> print(b)
tensor([[0., 0., 0.],
[0., 0., 0.]])
- 平方运算【
**2
】
这里我们在loss函数中用到了平方运算。是将(y_pred-y)**2
,这里的y是一个tensor,相当于一个8行一列的数组,其平方运算就是直接将tensor的每位直接对应相乘,然后得到的结果。示例如下:
import torch as t
x=t.rand(8,1) * 10
print("x=",x)
y=x**2
print("y=(x**2)=",y)
当二维或者更加高维的tensor去验证也可以发现的确就是这样运算方法。