文章目录
前言
深度学习项目之预测项目
一、导入库函数
import torch
import matplotlib.pyplot as plt # 画图的 深度学习和张量运算的强大工具
import random #生成随机数据
二、定义生成数据的函数
def create_data(w, b, data_num): #生成数据
定义一个函数名为:create_data的函数,其中:
w : 通常为权重(weigh)用于线性模型中的系数
b : 表示偏置(bias)用于线性模型中的截距。
data_num : 表示要生成的数据样本数量。
然后要书写函数内容如下:
def create_data(w, b, data_num):
x = torch.normal(0, 1, (data_num, len(w)) #使用torch.normal从正态分布中生成一个数据
y = torch.matmul(x, w) + b
noise = torc.normal(0, 0.01, y.shape)
y += noise
return x, y
使用torch.normal从正态分布中生成一个数据
0:均值(mean)为0
1:标准差(std)为1
(data_num,lem(w)):生成的张量形状为:(data_num,lem(w));
即生成data_num行,每行有lem(w)个数值
torch.matmul(x,w):执行矩阵 乘法,将输入数据x与权重w相乘+b:加上偏置值b,
noise作用:生成一个噪声张量,用于模拟数据中的随机噪声。
0:均值为0
0.01:标准差为0.01
y.shape:噪声的形状与y相同,可以确保对每个输出值添加噪声
作用:将生成的噪声加到原本计算好的y上
意义:这样生成的y不是严格的线性结果,而是有一定的随机性,更符合数据中常见的噪声数据
三、生成模型数据
num = 500
true_w = torch.tensor([8.1, 2, 2, 4])
true_b = torch.tensor(1.1)
用torch.tensor函数创建一个张量,内容为【8.1,2,2,4】用于数据生成或模型训练中作为参考值
用torch.tensor函数创建一个标准张量数值为1.1,用于线性表示的截距,即当所有输入特征值为0时,输出截距
X, Y = create_data(true_w, true_b, num)
调用之前定义的creat_data函数,传入数据true_w, true_b, num
利用creat_data函数给定的权重和截距生成一组数据
x:生成输入的数据张量生成其形状为 (500, 4)(500 行,每行 4 个特征)。
y:根据线性关系y = x*ture_w+ture_b计算得到目标值,并加入少量噪声,使得数据更符合真实情况。
plt.scatter(X[:, 3], Y, 1)
plt.show()
使用 Matplotlib 的 scatter 函数绘制散点图。
x[:,3]:从输入数据x中取出所有样本的第四列(因为样本的列是从0开始的,所有x[:,3]表示所有样本的第四个特征
y:作为每个样本的特征值,作为图的纵坐标
四、定义数据提供器函数
def data_provider(data, label, batchsize):
# 每次访问这个函数,就能提供一批数据
函数名为data_provider;
data:表示输入的数据(例如特征矩阵)。
lable:对应的数据标签或目标值(例如回归或分类问题中的真实值)。
batchsize:每个批次的样本数量,也可表示为步长
length = len(label)
计算lable的长度得到样本总数
indices = list(range(length))
random.shuffle(indices)
通过length的长度生成一个0到length-1长度的线性表,并通过使用 random.shuffle 对索引列表 indices 进行原地随机打乱。
for each in range(0, length, batchsize):
从0到length遍历数据索引,以batchsize为步长
get_indices = indices[each:each+batchsize]
根据当前起始位置each,从打乱的indices列表中切片出当前批次的索引,范围为[each:each+batchsize]
get_data = data[get_indices]
get_label = lable[get_indices]
get_data = data[get_indices]:利用前面的获取的索引,从数据data中选取对应的样本
get_label = lable[get_indices]:从标签lable中选取对应的标签
yield get_data,get_label
batchsize = 16#步长为16
yield为有存档点的return,意味着函数在执行到 yield 时会保存当前状态,下一次迭代时从此处继续执行。
五、定义模型函数
def fun(x, w, b):
pred_y = torch.matmul(x, w) + b
return pred_y
定义一个函数名为fun的函数,传入数据张量x,以及权重w,再加上偏置值b
torch.matmul(x, w)表示对数据和权重进行矩阵乘法运算,再加上偏置值b,即为标准的y=x*w+b的线性运算
六、定义 MAE(平均绝对误差)损失函数
def meaLoss(pred_y, y):
return torch.sum(abs(pred_y - y)) / len(y)
定义一个函数名为maeLoss的函数,用于计算模型损失
pre_y:为模型预测的输出
y:实际的标签和预测值
abs (pre_y - y):计算真实值与模拟值之间的绝对误差,绝对误差表示两个值之间的距离,没有正负区别
abs(pre_y - y) / len(y):将绝对误差除以样本数量,目的是为了对误差求平均,得到平均绝对误差(MAE)。
torch.sum(…):对所有经过除法处理后的误差求和,从而计算出总的平均绝对误差。
七、定义随机梯度下降(SGD)优化器函数
def sgrad(paras, lr): # 参数和学习率 随机梯度下降,更新参数
with torch.no_grad(): #属于这句代码的部分,不计算梯度
for para in paras:
para -= para.grad * lr # 不能写成 para = para - para.grad * lr
para.grad.zero_() # 使用过的梯度 归0
参数paras:一个可迭代参数,包含了所有需要更新的参数
参数lr:学习率,用于控制更新步长
with torch.no_grad():开启一个上下文管理器告诉PyTorch代码块内不需要记录梯度信息,避免在更新参数时,影响自动求导机制,从而节省内存和计算开销
para -= para.grad * lr:对当前参数进行原地更新
para.grad 是参数对应的梯度。用梯度乘以学习率得到参数更新后的步长
注:不能写成para = para - para.grad * lr因为这样创建一个新的参数para,导致原来的参数引用丢失,从而影响模型参数的更新。
zero():是Pytorch中的in-place操作,用于将梯度张量的所有元素置为 0。
八、开始训练
epochs = 50 #训练的次数
for epoch in range(epochs):
每次循环作为一次完整的训练轮次(epoch),在每个轮次中会遍历所有数据
data_loss = 0
在每个轮次(epoch)开始前会先清零累计损失,以便后续将每个批次的损失累加起来。
for batch_x, batch_y in data_provider(X, Y, batchsize):
调用data_provider(x, y, batchsize):生成器,每次迭代返回一批数据。每次循环batch_x为当前批次输入数据,batch_y为当前真实标签
pred_y = fun(batch_x, w_0, b_0)
调用函数fun来计算当前批次的预测值,fun实现了线性模型:计算公式为
pred_y= batch_x*w_0
loss = meaLoss(pred_y, batch_y)
使用定义的函数maeLoss计算平均绝对误差
loss.backward()
Pytorch会通过计算图计算w_0,b_0对loss的梯度,并将梯度存储在对应的参数.grad()中
sgrad([w_0, b_0], lr)
data_loss += loss
参数 [w_0, b_0] 是一个列表,包含需要更新的参数。lr为学习率,用于控制每次参数更新的步长。
在sgd函数中会在不记录梯度的上下文中,利用当前梯度对参数进行 in-place 更新,并将梯度清
零,为下次迭代作准备
idx = 0
plt.plot(X[:, idx].detach().numpy(), X[:, idx].detach().numpy() * w_0[idx].detach().numpy() + b_0.detach().numpy())
plt.scatter(X[:, idx], Y, 1)
plt.show()
绘制拟合结果图
九、代码总结
import torch
import matplotlib.pyplot as plt # 画图的
import random
def create_data(w, b, data_num): # 生成数据
x = torch.normal(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
num = 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)
plt.scatter(X[:, 3], Y, 1)
plt.show()
def data_provider(data, label, batchsize): # 每次访问这个函数,就能提供一批数据
length = len(label)
indices = list(range(length)) # 0-500的列表存入list
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 # 有存档点的return
batchsize = 16
# for batch_x, batch_y in data_provider(X, Y, batchsize):
# print(batch_x, batch_y)
def fun(x, w, b):
pred_y = torch.matmul(x, w) + b
return pred_y
def meaLoss(pred_y, y):
return torch.sum(abs(pred_y - y)) / len(y)
def sgrad(paras, lr): # 参数和学习率 随机梯度下降,更新参数
with torch.no_grad(): #属于这句代码的部分,不计算梯度
for para in paras:
para -= para.grad * lr # 不能写成 para = para - para.grad * lr
para.grad.zero_() # 使用过的梯度 归0
lr = 0.03
w_0 = torch.normal(0, 0.01, true_w.shape, requires_grad=True) # 这个w需要计算梯度
b_0 = torch.tensor(0.01, requires_grad=True)
print(w_0, b_0)
epochs = 50 #训练的次数
for epoch in range(epochs):
data_loss = 0
for batch_x, batch_y in data_provider(X, Y, batchsize):
pred_y = fun(batch_x, w_0, b_0)
loss = meaLoss(pred_y, batch_y)
loss.backward()
sgrad([w_0, b_0], lr)
data_loss += loss
print("epoch %03d: loss: %.6f"%(epoch, data_loss))
print("真实的函数值是", true_w, true_b)
print("训练得到的参数值是", w_0, b_0)
idx = 0
plt.plot(X[:, idx].detach().numpy(), X[:, idx].detach().numpy() * w_0[idx].detach().numpy() + b_0.detach().numpy())
plt.scatter(X[:, idx], Y, 1)
plt.show()
总结


444

被折叠的 条评论
为什么被折叠?



