【动手学深度学习】线性回归+基础优化算法

  1. 线性回归模型

  1. 基础优化算法——梯度下降

  • 梯度是上升最快的方向,负梯度是下降最快的方向

  1. 代码实现

先在之前安装好的pytorch中安装d2l,在Anaconda Prompt中先activate pytorch,再执行pip install -U d21安装d21包

conda activate pytorch
pip install -U d2l

在Pycharm上面编程,想要看到图像需要加上d2l.plt.show(),pycharm不支持%matplotlib inline ,删去

import random #用于随机化生成的数据
import torch #框架
from d2l import torch as d2l #我们引入的包
def synthetic_data(w ,b ,num_examples):
    'y = wX+ b+ 噪音项'
    X = torch.normal(mean=0,std=1,size=(num_examples,len(w))) #构造x,从标准正态分布N~(0,1),提取一个num_examplesxW的矩阵
    y = torch.matmul(X,w) +b          #matul函数作矩阵乘法
    y+=torch.normal(mean=0,std=0.01,size=(y.shape))  #加入噪音项
    return X,y.reshape((-1,1))

true_w = torch.tensor([1,3.8])
true_b = 4.2
features,labels = synthetic_data(w = true_w,b=true_b,num_examples=1000)
# 我们将数据可视化,以查看数据是否生成正确
d2l.set_figsize((4,4 ))
d2l.plt.scatter(x=features[:, 1].numpy(),y=labels.numpy(),s=1,c='r') # s → 散点的面积
d2l.plt.show()

运行结果:

手动实现线性回归完整代码如下:

import random #用于随机化生成的数据
import torch #框架
from d2l import torch as d2l #我们引入的包
def synthetic_data(w ,b ,num_examples):#生成数据的函数
    'y = wX+ b+ 噪音项'
    X = torch.normal(mean=0,std=1,size=(num_examples,len(w))) # 生成一个(样本数,特征数)
    y = torch.matmul(X,w) +b#matmul矩阵乘法
    y+=torch.normal(mean=0,std=0.01,size=(y.shape))
    return X,y.reshape((-1,1))#变成nX1维,固定列为1列,不知道多少行,即一个列向量

true_w = torch.tensor([1,3.8])#torch.Tensor()使用List创建,含小数代表数据类型为浮点数
true_b = 4.2
features,labels = synthetic_data(w = true_w,b=true_b,num_examples=1000)#调函数生成数据
# 我们将数据可视化,以查看数据是否生成正确
d2l.set_figsize((4,4 ))
d2l.plt.scatter(x=features[:, 1].numpy(),y=labels.numpy(),s=1,c='r') # s → 散点的面积
d2l.plt.show()


#读取数据  调用框架中现有的API来读取数据
def data_iter(batch_size , features , labels):#labels存着实际真实值y
    num_examples = len(features) # len(features)  -》1000 返回的是 行的数量
    indexes = list(range(num_examples))
    #shuffle my Data
    random.shuffle(indexes)
    for i in range(0, num_examples, batch_size):#range(0, 30, 5) 步长为 5,此处步长为batch_size
        batch_indexes = torch.tensor(
           indexes[i: min(i + batch_size, num_examples)])#min为了不越界
        yield features[batch_indexes],labels[batch_indexes]#yield:return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
next(data_iter(10,features,labels)) # 只取第一次的数据 表明我的data迭代器没有任何问题,接下来就可以设置一个梯度下降了


#定义模型
def linerRegression(X,w,b):
    '''定义线性回归'''
    return torch.matmul(X,w)+b
def squared_loss(y_hat,y):
    '''均方误差'''
    return (y_hat-y.reshape(y_hat.shape))**2/2
def sgd(params,lr,batch_size):
    '''随机批量梯度下降'''
    with torch.no_grad():#类似try...finally,torch.no_grad即更新的时候不参与梯度计算
        for param in params:
            param -= lr*param.grad / batch_size
            param.grad.zero_()


#初始化模型参数
w = torch.normal(mean=0,std=1,size=(2,1),requires_grad=True)
b = torch.tensor(4.2,requires_grad=True)

lr = 0.03
num_epochs = 3
batch_size = 10
net = linerRegression#函数实例化?
loss = squared_loss

for epoch in range(num_epochs):
    for X,y in data_iter(batch_size=batch_size,features=features,labels=labels):#读取数据
        l = loss(y_hat=net(X=X,w=w,b=b),y=y)  # 一个样本的均方误差
        l.sum().backward() # loss function求和算梯度
        sgd([w, b], lr, batch_size)  # 使用参数的梯度更新参数,使用sgd对w和b进行更新
    with torch.no_grad():#在使用pytorch时,并不是所有的操作都需要进行计算图的生成,只是想要网络结果的话就不需要后向传播 ,如果你想通过网络输出的结果去进一步优化网络的话 就需要后向传播了。
        train_l = loss(net(features, w, b), labels)
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

运行结果如下:

epoch 1, loss 0.020302
epoch 2, loss 0.000120
epoch 3, loss 0.000047

简洁版利用库函数实现线性回归完整代码如下:

import torch
import torch.nn#nn是神经网络的缩写,里面有很多定义好的层
import numpy as np
from torch.utils import data
from d2l import torch as d2l
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
# 用两个问号查询函数相关信息 发现这个函数是来自我们本地的函数
# 我们将数据可视化,以查看数据是否生成正确
d2l.set_figsize((4,4 ))
d2l.plt.scatter(x=features[:, 1].numpy(),y=labels.numpy(),s=1,c='r') # s → 散点的面积
d2l.plt.show()

#读取数据并且分割成批量大小返回
def load_array(data_arrays,batch_size,is_train=True):
    '''构造一个Python的迭代器类似于我们之前的data_iter+'''
    dataset = data.TensorDataset(*data_arrays)  # (1)创建数据集,或者说封装数据集,可以传入多个参数
    return data.DataLoader(dataset=dataset,batch_size=batch_size,shuffle=is_train)#shuffle=is_train需要随机打乱

batch_size = 10
data_iter = load_array((features, labels), batch_size) # 传入(features,labels)
next(iter(data_iter))#转为python的iter,通过next得到一个x、y
#定义模型
net = torch.nn.Sequential(torch.nn.Linear(2, 1))# Sequential是个容器,功能是把layer按顺序放在一起
# 在PyTorch中,全连接层在Linear类中定义。值得注意的是,我们将两个参数传递到nn.Linear中。
#第一个指定输入特征形状,即2,第二个指定输出特征形状,输出特征形状为单个标量,因此为1。

#定义损失函数
loss = torch.nn.MSELoss()# 均方误差是MSE
#定义优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.03)

#算法实现
num_epochs = 3 # 迭代的次数

for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X) ,y) # 我们之前定义的在optim模块中的MSEloss()算法
        trainer.zero_grad() # 每次调用SGD之后都要清空 ,因为我们进行的是小批量梯度下降
        l.backward() # 在前面我们进行了前向传播,现在进行反向传播更新我们的参数
        trainer.step()#子模型更新
    l = loss(net(features), labels) # 完成一次迭代之后查看我们的损失函数的值
    print(f'epoch {epoch + 1}, loss {l:f}')

运行结果如下:

epoch 1, loss 0.000208
epoch 2, loss 0.000097
epoch 3, loss 0.000097

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值