深度学习2-线性回归表示
数据处理-模型训练-梯度下降回传
深度学习步骤
目标
利用预测的w0,b0,使用生成数据求出真实的w,b即得到函数y=wx+b
给定500条数据,有关颜值、财富、幽默、人品四个方面对于按恋爱次数的影响到底有多大?下列为真实的w和b,需要我们设计合适的线性模型来进行拟合真实的函数
- 实现了一个简单的线性回归模型,通过生成合成数据并使用梯度下降优化方法来训练模型参数。
- 它采用了批量训练和 MAE 损失函数,通过可视化来检查模型拟合效果。
生成数据500*4的用户数据
loss=y^-y
import torch #框架
import matplotlib.pyplot as plt #画图
import random #随机
def create_data(w,b,data_num):#用于生成数据 w对应四个特征
x = torch.normal(0,0.1,(data_num,len(w)))#长应为数据个数500行,宽应为w个数
y = torch.matmul(x,w)+b #矩阵乘法
#加噪声给y
noise = torch.normal(0,0.1,y.shape)
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)#画散点图 (x某列,Y,1点大小)
plt.show()
- 导入库
import torch # 导入 PyTorch,用于张量操作和机器学习
import matplotlib.pyplot as plt # 用于绘图
import random # 用于生成随机数
- 定义生成数据的函数
def create_data(w, b, data_num):
# w 对应四个特征
x = torch.normal(0, 0.1, (data_num, len(w))) # 生成均值为 0,方差为 0.1 的正态分布数据,形状为 (500, 4)
y = torch.matmul(x, w) + b # 线性关系:y = x*w + b
# 加入噪声
noise = torch.normal(0, 0.1, y.shape) # 生成同形状的噪声
y += noise
return x, y
torch.normal(0, 0.1, (data_num, len(w)))
:生成一个 500 行 4 列的正态分布张量,模拟 500 个样本,每个样本有 4 个特征。torch.matmul(x, w) + b
:对特征进行线性变换,生成真实的标签值。- 加入噪声,模拟真实数据中的误差。
- 设置参数
num = 500 # 样本数量
true_w = torch.tensor([8.1, 2, 2, 4]) # 真实权重(4 个特征)
true_b = torch.tensor(1.1) # 真实偏置
- 生成数据
X, Y = create_data(true_w, true_b, num)
X
形状为(500, 4)
,表示 500 个样本,每个样本有 4 个特征。Y
形状为(500,)
,表示 500 个标签。
- 绘制散点图
plt.scatter(X[:, 3], Y, 1) # 取第 4 个特征(索引 3)作为横坐标
plt.show()
X[:, 3]
取出第 4 个特征作为横坐标。Y
作为纵坐标。1
表示点的大小。
运行结果
- 散点图展示的是第 4 个特征与标签之间的关系。
- 如果线性关系明显,散点应该围绕在一条直线附近。
- 加入噪声后,散点会有一定的离散度,但仍然呈现线性趋势。
生成随机批数据
- 定义生成器函数
def datas_provider(data, label, batch_size):
length = len(label) # 获取标签的长度(即样本数量)
indexs = list(range(length)) # 创建索引列表 [0, 1, 2, ..., length-1]
random.shuffle(index) # 随机打乱索引,增加数据的随机性
for each in range(0, length, batch_size):
get_indexs = indexs[each: each + batch_size] # 切片获取当前批次的索引
get_data = data[get_indexs] # 根据索引取出对应的数据
get_label = label[get_indexs] # 根据索引取出对应的标签
yield get_data, get_label # 通过生成器返回数据和标签
range(0, length, batch_size)
:每次步长为batch_size
(16),生成批量的起始索引。get_indexs = indexs[each: each + batch_size]
:取出当前批次的样本索引。data[get_indexs]
:根据索引取出样本。yield
:生成器返回当前批次的数据和标签,供外部迭代使用。
- 设置一次性产生数据批量大小
batch_size = 16
- 调用生成器
for batch_x, batch_y in datas_provider(X, Y, batch_size):
print(batch_x.shape)
print(batch_y.shape)
break
batch_x
:一个批次的数据,形状为(16, 4)
,表示每批 16 个样本,每个样本有 4 个特征。batch_y
:一个批次的标签,形状为(16,)
。break
:只输出第一个批次。
输出示例
输出第一个批次的数据和标签形状:
torch.Size([16, 4])
torch.Size([16])
解释:
16
表示批次大小(16 个样本)。4
表示每个样本有 4 个特征。16
表示每批对应的 16 个标签。
定义梯度函数
所有参数都带有梯度,都会保存在里面,需清0
定义线性模型
def model(w, x, b):
return torch.matmul(x, w) + b
- 这个函数表示一个简单的线性模型。它根据输入
x
和权重w
计算预测值,并加上偏置b
。
定义 MAE 损失函数LOSS
def mae_loss(pred_y, y):
return torch.mean(torch.abs(pred_y - y)) # 计算预测值与真实值之间的绝对误差
#torch.sum(torch.abs(pred_y - y)/len(y))
- 这里使用 MAE (Mean Absolute Error) 损失函数来衡量模型的预测值和实际值之间的误差。该函数计算预测值和实际值的绝对差的平均值。
梯度下降法优化参数
def sgd(params, lr):
with torch.no_grad(): # 在不计算梯度的情况下更新参数
for param in params:
param -= lr * param.grad # 按照学习率更新参数
param.grad.zero_() # 清空已经计算的梯度
- 这里实现了一个 SGD (Stochastic Gradient Descent) 优化器,它根据计算的梯度更新参数。
lr
是学习率,表示每次更新的步长。param.grad.zero_()
用于在每次更新后清零梯度。
生成数据
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) # 生成数据
true_w
和true_b
是真实的权重和偏置。X
和Y
是生成的输入数据和目标数据。
查看数据的散点图
plt.scatter(X[:, 3], Y, s=1)
plt.title("Generated Data")
plt.show()
- 这部分代码绘制
X[:, 3]
和Y
之间的散点图。通过这个图可以查看生成的数据分布。
初始化模型参数
w = torch.normal(0, 0.01, true_w.shape, requires_grad=True) # 初始化权重
b = torch.tensor(0.01, requires_grad=True) # 初始化偏置
- 在训练开始前,初始化权重
w
和偏置b
,并允许计算梯度。
定义超参数
learning_rate = 0.03
batch_size = 16
epochs = 50
- 这里定义了超参数:学习率
learning_rate
,批次大小batch_size
和训练的轮数epochs
。
训练过程
for epoch in range(epochs):
total_loss = 0
for batch_x, batch_y in data_provider(X, Y, batch_size):
pred_y = model(w, batch_x, b) # 使用当前参数进行预测
loss = mae_loss(pred_y, batch_y) # 计算损失
loss.backward() # 反向传播,计算梯度
sgd([w, b], learning_rate) # 使用SGD优化器更新参数
total_loss += loss.item() # 累加损失
avg_loss = total_loss / (num / batch_size) # 计算平均损失
print(f"Epoch {epoch + 1:03d}, Loss: {avg_loss:.6f}")
- 在训练循环中,使用批次数据进行预测、计算损失、反向传播以及更新参数。每个 epoch 输出一次平均损失。
输出结果
print(f"\n真实的参数值:w = {true_w.numpy()}, b = {true_b:.2f}")
print(f"预测的参数值:w = {w.detach().numpy()}, b = {b.detach().numpy():.2f}")
- 训练结束后,打印真实的参数值和预测的参数值。
可视化结果
idx = 1
plt.plot(X[:, idx].detach().numpy(), X[:, idx].detach().numpy() * w[idx].detach().numpy() + b.detach().numpy(),
color='red', label='Fitted line')
plt.scatter(X[:, idx].detach().numpy(), Y.detach().numpy(), s=1, label='Data points')
plt.title("Fitting Result")
plt.legend()
plt.show()
基于预测的参数w0,b0经训练得到的拟合直线拟合真实数据
全部代码
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
noise = torch.normal(0, 0.1, y.shape) # 加入噪声
y += noise
return x, y
# 批数据生成器
def data_provider(data, label, batch_size):
length = len(label)
indices = list(range(length))
random.shuffle(indices)
for i in range(0, length, batch_size):
batch_indices = indices[i: i + batch_size]
yield data[batch_indices], label[batch_indices]
# 定义线性模型
def model(w, x, b):
return torch.matmul(x, w) + b
# 定义 MAE 损失函数
def mae_loss(pred_y, y):
return torch.mean(torch.abs(pred_y - y))
# SGD优化器(梯度下降法更新参数)
def sgd(params, lr):
with torch.no_grad():
for param in params:
param -= lr * param.grad
param.grad.zero_()
# 生成数据
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, s=1)
plt.title("Generated Data")
plt.show()
# 初始化模型参数
w = torch.normal(0, 0.01, true_w.shape, requires_grad=True)
b = torch.tensor(0.01, requires_grad=True)
# 定义超参数
learning_rate = 0.03
batch_size = 16
epochs = 50
# 训练过程
for epoch in range(epochs):
total_loss = 0
for batch_x, batch_y in data_provider(X, Y, batch_size):
pred_y = model(w, batch_x, b)
loss = mae_loss(pred_y, batch_y)
loss.backward() # 反向传播
sgd([w, b], learning_rate)
total_loss += loss.item()
avg_loss = total_loss / (num / batch_size)
print(f"Epoch {epoch + 1:03d}, Loss: {avg_loss:.6f}")
# 输出结果
print(f"\n真实的参数值:w = {true_w.numpy()}, b = {true_b:.2f}")
print(f"预测的参数值:w = {w.detach().numpy()}, b = {b.detach().numpy():.2f}")
# 结果可视化
idx = 1
plt.plot(X[:, idx].detach().numpy(), X[:, idx].detach().numpy() * w[idx].detach().numpy() + b.detach().numpy(),
color='red', label='Fitted line')
plt.scatter(X[:, idx].detach().numpy(), Y.detach().numpy(), s=1, label='Data points')
plt.title("Fitting Result")
plt.legend()
plt.show()