1. 案例需求


1️⃣ 设置损失函数和优化器 :损失函数 指MSE、MAE等;优化器 是用来结合反向传播更新参数的 ,之前在自动微分中更新参数的代码是通过公式 w新 = w旧 - 学习率 * 梯度 或 w.data = w.data -0.01 * w.grad手动更新;但优化器中有一个名为step的函数,通过 优化器.step() 可在底层自动帮忙更新参数。
2️⃣ MSE代替平方损失函数、DataLoader代替数据加载器、SGD(随机梯度下降)代替优化器即梯度下降、Linear代替假设函数即 y=wx+b。
2. 需求
1️⃣ 导包:对于TensorDataset 包:python进阶中自己手动做过一个数据加载器(结论歌词):每批8条,5000多条歌词生成 np来做训练,之前是自己做的,分批训练是后面会做的多的;
2️⃣ 数据加载器(DataLoader)可分批获取数据 ,假设一个10000条数据,每批100条,可分成100批,每100条进行训练,即分批次训练。但张量无法直接转数据加载器,可通过 张量 转 张量数据集对象TensorDataSet 转 数据加载器 DataLoader,但当数据不是张量时,要先将数据转成张量 如numpy对象,即:numpy对象 - -> 张量Tensor - -> 张量数据集对象TensorDataSet - -> 数据加载器DataLoader;
nn 神经网络包,里面有大量的损失函数;
optim 优化器包,如 SGD随机梯度下降包;
make_regression 创建线性回归模型数据集包,后面不会用,因为后面的数据集都已有了,这次是自己造的,所以需要用一次;
matplotlib.pyplot 可视化包,做绘图、可视化的;

3. 代码
1. 定义函数,创建线性回归样本数据
def create_dataset():
1️⃣ 创建数据集对象:x, y, coef = make_regression(...) :n_samples=100100条样本,n_features=11个特征,noise=10噪声:噪声越大样本点越散,coef=True是否返回系数 默认为False,random_state=3 随机种子;print(type(x))打印 x,是一个ndarray类型即<class 'numpy.ndarray'>;想将 x封装成数据加载及,先从numpy 转成张量,在到数据集对象,再到数据加载器;
2️⃣ 把上述的数据 numpy转成张量 对象:x = torch.tensor(x,...),y = torch.tensor(y,...);coef 权重不需要转,后面用到 x特征,y目标值标签;打印结果:y = w( coef )x + b( bias );
2. 定义函数,表示模型训练
def train(x, y, coef):
数据集、数据加载器、模型、损失、优化器;
1️⃣ 创建数据集对象 ,将tensor--》数据集对象--》数据加载器:dataset=TensorDataset(x,y);
2️⃣ 创建数据加载器对象 ,参1:数据集对象,参2:批量大小,参数3:是否打乱数据(训练集打乱,测试集不打乱):dataloader=DataLoader(dataset,batch_size=16,shuffle=True)
3️⃣ 创建模型对象 ,参1:输入特征维度,参2:输出特征维度,model=nn.Linear(in_features=1, out_features=1);
4️⃣ 创建损失函数对象 ,criterion =nn.MSELoss();
5️⃣ 创建优化器对象 ,参1:模型参数,参2:学习率 optimizer=optim.SGD(model.parameters(),lr=0.01);
python
# 导入相关模块
import torch
from torch.utils.data import TensorDataset # 构造数据集对象
from torch.utils.data import DataLoader # 数据加载器
from torch import nn # nn模块中有平方损失函数和假设函数
from torch import optim # optim模块中有优化器函数
from sklearn.datasets import make_regression # 创建线性回归模型数据集
import matplotlib.pyplot as plt # 可视化
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 1.定义函数,创建线性回归样本数据
def create_dataset():
# 1.创建数据集对象
x, y, coef = make_regression(
n_samples=100, # 100条样本(100个样本点)
n_features=1, # 1个特征(1个特征点)
noise=10, # 噪声,噪声越大,样本点越散,噪声越小,样本点越集中
coef=True, # 是否返回系数,默认为False,返回值为None
bias=14.5, # 偏置
random_state=3 # 随机种子,随机种子相同,输出数据相同
)
print(type(x)) # <class 'numpy.ndarray'>
# 2.把上述的数据封装成 张量对象
x = torch.tensor(x, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32)
# 3.返回结果
return x, y, coef
# 2.定义函数,表示模型训练
def train(x, y, coef):
# 1.创建数据集对象,将tensor--》数据集对象--》数据加载器
dataset = TensorDataset(x, y)
# 2.创建数据加载器对象
# 参1:数据集对象,参2:批量大小,参数3:是否打乱数据(训练集打乱,测试集不打乱)
dataloader = DataLoader(dataset, batch_size=16, shuffle=True)
# 3.创建模型对象
# 参1:输入特征维度,参2:输出特征维度
model = nn.Linear(in_features=1, out_features=1)
# 4.创建损失函数对象
criterion = nn.MSELoss()
# 5.创建优化器对象
# 参1:模型参数,参2:学习率
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 6.具体的训练过程
# 6.1 定义变量,分别表示:训练轮数,每轮的(平均)损失值,训练总损失值,训练的样本数
epochs, loss_list, total_loss, total_sample = 100, [], 0.0, 0
# 6.2 开始训练,按轮训练
for epoch in range(epochs): # epochs的值:0, 1, 2,...,99
# 6.3 每轮是分批次训练的,所以从数据加载器中获取 批次数据
for train_x, train_y in dataloader: # 7批(16, 16, 16, 16, 16, 16, 4)
# 6.4 模型预测
y_pred = model(train_x)
# 6.5 计算(每轮的平均)损失值
loss = criterion(y_pred, train_y.reshape(-1, 1)) # -1自动计算
# 6.6 计算总损失 和样本(批次)数
total_loss += loss.item()
total_sample += 1
# 6.7 梯度清零 + 反向传播 + 梯度更新
optimizer.zero_grad() # 梯度清零
loss.backward() # 反向传播,计算梯度
optimizer.step() # 梯度更新
# 6.8 把本轮的平均损失值添加到列表中
loss_list.append(total_loss / total_sample)
print(f'第{epoch + 1}轮,平均损失值:{total_loss / total_sample}')
# 7.打印最终的训练结果
print(f'{epochs}轮的平均损失分别是:{loss_list}')
print(f'模型参数,权重:{model.weight}, 偏置:{model.bias}')
# 8.绘制损失曲线
# 参1:100轮,参2:每轮的平均损失值
plt.plot(range(epochs), loss_list)
plt.title('损失曲线变化图')
plt.grid() # 绘制网格图
plt.show()
# 9.绘制预测值和真实值之间的关系
# 9.1 绘制样本点分布情况
plt.scatter(x, y)
# 9.2 绘制训练模型的预测值
# x:100个样本点的特征
y_pred = torch.tensor(data=[v * model.weight + model.bias for v in x])
# 9.3 计算真实值
y_true = torch.tensor(data=[v * coef + 14.5 for v in x])
# 9.4 绘制预测值和真实值的折线图
plt.plot(x, y_pred, color='red', label='预测值')
plt.plot(x, y_true, color='green', label='真实值')
# 9.5 绘制图例,网格
plt.legend()
plt.grid()
# 9.6 显示图像
plt.show()
# 3.测试
if __name__ == '__main__':
# 3.1 创建数据集
x, y, coef = create_dataset()
print(f'x: {x}, y: {y}, coef: {coef}')
# 3.2 模型训练
train(x, y, coef)