先贴代码
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为求梯度,然后会反射会涉及的变量