环境,基于anaconda(允许不同版本python环境存在与pc上)pycharm专业版,pytorch(计算梯度),英伟达显卡。
调用模块:
import torch
import matplotlib.pyplot as plt # 画图
import random
创建数据模块
首先需要用一组w(权重)和b(偏差)创建x,y,使用一个函数creat_data用于创建数据,其中w和b的数据类型是张量tensor,data_num表示传入数据的组数(相当于矩阵的行数),len(w)是w的个数。(data_num,len(w))为想要生成的数据集的shape
torch.normal(均值,标准差,可选的输出张量(形状))函数通过从给定输入均值和标准差的离散正态分布中抽取随机数返回一个张量。利用该函数创建数据x.
根据公式创建y
最后返回x和y
def create_data(w,b, data_num):# w权重,偏差b,data_num是数据的组数 作用创建x,y
x = torch.normal(0, 1, (data_num,len(w)))#0为方差,1为均值,(data_num,len(w))为形状
y = torch.matmul(x, w) + b #matmul矩阵相乘
noise = torch.normal(0,0.01,y.shape) #生成与y同型的噪声
y += noise
return x,y
创建真实值
使用现有的一组数据w和b生成对应的x与y。使用上述数据创建模块创建即可。
num = 500#生成500组数据
true_w = torch.tensor([8.1, 2, 2, 4])#真实值转为张量
true_b = torch.tensor(1.1)
X, Y = create_data(true_w,true_b, num)
提供数据以供计算loss值
其中,这里为减少loss的计算量,选m个张量计算一次loss,m为1个batchsize.最后将计算的每一组loss代入公式得到loss。为计算loss值,编写一个函数,可以在每次访问时选取一个batchsize的X与Y的张量值用于计算一次loss。
函数data_provider,将数据顺序打乱,然后分批输出。
注:先将数据的排列顺序打乱再取数据,使用random.shuffle()打乱张量下标
def data_provider(data, label, batchsize): #每次访问,就提供一笔数据 data为数据 ,label为标签,选batchsize大小的一组值计算其loss
length = len(label)
indices = list(range(length))
random.shuffle(indices)
for each in range(0, length, batchsize):
get_indices = indices[each: each + batchsize]#取一个
get_data = data[get_indices]
get_label = label[get_indices]
yield get_data, get_label#每次选出一个batchsize的数据
计算y的预测值和损失(loss)值
def fun(x, w, b):
pred_y = torch.matmul(x,w) + b
return pred_y
def maeloss(pred_y, y):
loss = torch.sum(abs(pred_y - y)) / len(y)
梯度下降优化器
定义函数回传(回传不计算梯度)回传一次梯度需归零,防止累积
def sgd(paras, lr):#lr为学习率用于调控步长
with torch.no_grad:#不计算梯度
for para in paras:
para -= para.grad*lr
para.grad_zero #把梯度归零
训练
参数初始化,取一个初始的w0,b0供训练使用,规定训练轮数epochs。
一轮训练流程:
-
初始化loss值,取一个batchsize的数据
-
用初始w0,b0,和取得的x计算预测值
-
用真实值y和预测值计算loss值
-
对损失值计算梯度,使用backward()函数进行梯度回传,计算梯度。
-
sgd优化器优化梯度(梯度下降)
-
记录这一轮的loss供参考
lr = 0.001##学习率,超参数
w_0 = torch.normal(0,0.01,true_w.shape,requires_grad=True)#计算梯度
b_0 = torch.tensor(0.01,requires_grad=True)
epochs = 50#训练的轮数
for epoch in range(epochs): #训练开始
data_loss = 0#初始化
for batch_x, batch_y in data_provider(X,Y,batchsize):
pred = fun(batch_x, w_0, b_0)##
loss = maeloss(pred, batch_y)
loss.backward()#将梯度回传
sgd([w_0, b_0], lr)#优化
data_loss += loss#记录这一轮的loss
print("epoch %3d: loss: %.6f"%(epoch,data_loss))
一次线性模型训练过程模拟大致完成。