线性回归——小批量随机梯度下降算法

先贴代码

import torch
import numpy as np
import random


trainsetshape = (100, 2)
true_w = torch.tensor([[2.00], [-3.4]], dtype=torch.float64)
true_b = 4.2


def data_iter(features, labels, batch_size=10):
    num_examples = len(features)
    indices = list(range(num_examples))
    random.shuffle(indices)  # 样本的读取顺序是随机的
    for i in range(0, num_examples, batch_size):
        j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)])  # 最后一次可能不足一个batch
        yield features.index_select(0, j), labels.index_select(0, j)


def linreg(X, w, b):
    return torch.mm(X, w) + b
# X: n*2
# w: 2*1
# b: n*1


def squared_loss(y_hat, y):
    # 注意这里返回的是向量, 另外, pytorch里的MSELoss并没有除以 2
    return ((y_hat - y.view(y_hat.size())) ** 2) * 0.5


def sgd(params, lr, batch_size):
    for param in params:
        param.data -= lr * param.grad # 注意这里更改param时用的param.data


if __name__ == '__main__':
    # 生成数据
    features = torch.from_numpy(np.random.normal(0, 1, trainsetshape))
    labels = torch.mm(features, true_w) + true_b
    labels += torch.from_numpy(np.random.normal(0, 0.01, labels.shape))


    w = torch.tensor([[5],[5]], dtype=torch.float64)
    b = torch.tensor([5], dtype=torch.float64)

    w.requires_grad_(requires_grad=True)
    b.requires_grad_(requires_grad=True)

    lr = 0.03
    num_epochs = 15

    batch_size = 10

    for epoch in range(num_epochs):  # 训练模型一共需要num_epochs个迭代周期
        # 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。X
        # 和y分别是小批量样本的特征和标签
        for X, y in data_iter(features, labels, batch_size=10):
            l = squared_loss(linreg(X, w, b), y).sum()  # l是有关小批量X和y的损失
            l.backward()  # 小批量的损失对模型参数求梯度
            sgd([w, b], lr, batch_size)  # 使用小批量随机梯度下降迭代模型参数

            # 不要忘了梯度清零
            w.grad.data.zero_()
            b.grad.data.zero_()
        train_l = squared_loss(linreg(features, w, b), labels)
        print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))

    print(w)
    print(b)

代码分别:导入包、定义了一些常量、定义了一些函数、定义了代码主体

训练模型y = b + x1w1 + x2w2

小批量随机梯度下降算法:比如一个数据集有10w条数据,你同时做矩阵运算不太现实,所以就要批量处理。比如每次处理100条、一千条。


1 准备工作

# 生成数据
    features = torch.from_numpy(np.random.normal(0, 1, trainsetshape))
    labels = torch.mm(features, true_w) + true_b
    labels += torch.from_numpy(np.random.normal(0, 0.01, labels.shape))
np.random.normal(): 生成一个形状为trainsetshape的,服从0,1正态分布的矩阵
数据类型是 numpy,要转换成tensor,要用到 torch.from_numpy() 函数
torch.mm() 矩阵乘法

我们先自己生产100条数据,设w1 = 2, w2 = =3.4, bias = 4.2, 然后再加上随机扰动

2 初始化随机的w1,w2,b和其他参数

	w = torch.tensor([[5],[5]], dtype=torch.float64)
	b = torch.tensor([5], dtype=torch.float64)

    w.requires_grad_(requires_grad=True)
    b.requires_grad_(requires_grad=True)

	# learning rate
    lr = 0.03

	# 迭代次数
    num_epochs = 15
	
	#分块大小
    batch_size = 10

这里要讲一讲autograd
我们声明了w、b是要在以后求微分的requires_grad=True
那么之后所有用w、b运算出来的变量都会带有requires_grad=True
比如loss_function(b, w),中b和w作为线性回归中丧失函数的参数,是要以后迭代求微分来进行梯度下降的。

3 梯度下降

for epoch in range(num_epochs):  # 训练模型一共需要num_epochs个迭代周期
        # 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。
        # X和y分别是小批量样本的特征和标签
        for X, y in data_iter(features, labels, batch_size=10):
            l = squared_loss(linreg(X, w, b), y).sum()  # l是有关小批量X和y的损失
            l.backward()  # 小批量的损失对模型参数求梯度
            sgd([w, b], lr, batch_size)  # 使用小批量随机梯度下降迭代模型参数

            # 不要忘了梯度清零
            w.grad.data.zero_()
            b.grad.data.zero_()
        train_l = squared_loss(linreg(features, w, b), labels)
        print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))
 l = squared_loss(linreg(X, w, b), y).sum()
 l.backward()
  • linreg(X, w, b)为假设函数计算出来的值
  • y为label的实际值
  • squared_loss()为损失函数

在这里,autograd要求求梯度必须为一个1维的值,即shape必须为1x1
backward为求梯度,然后会反射会涉及的变量

发布了113 篇原创文章 · 获赞 6 · 访问量 7117

猜你喜欢

转载自blog.csdn.net/swallowblank/article/details/101698357