目录
一、手动构建模型
1、概念
2、模型构建
0.相关库函数
1.构建数据集
2.加载数据集
3.初始化参数
4.线性回归
5.损失函数
6.优化器
7.训练数据集
8.预测数据
9.调用
二、官方模型定义组件
1、模型组件
0.库函数
1.损失函数组件
2.线性回归模型组件
3.优化器方法
2、数据加载器
1.构建数据类
2.数据加载器
3、数据集加载案例
1.加载Excel数据集
2.加载图片数据集
3.加载官方数据集
4、数据增强
一、手动构建模型
1、概念
模型训练中的三个基础概念:
名词 | 定义 |
---|---|
Epoch | 使用训练集的全部数据对模型进行一次完整训练,被称为“一代训练” |
Batch | 使用训练集中的一小部分样本对模型权重进行一次反向传播的参数更新,这一小部分样本被称为“一批数据” |
Iteration | 使用一个Batch数据对模型进行一次参数更新的过程,被称为“一次训练” |
2、模型构建
0.相关库函数
import math
import torch
import random
from sklearn.datasets import make_regression
1.构建数据集
def build_data():# 噪声设置noise = random.randint(1,5)# 样本数量sample = 500# 真实偏置bias = 0.5# 划分数据集 coef=True 表示希望函数返回生成数据的真实系数 coef即为真实系数x,y,coef = make_regression(n_samples=sample,n_feature=4,coef=True,noise=noise,bias=bias,random_state=666)# 数据转换为张量x = torch.tensor(x,dtype=torch.float32)y = torch.tensor(y,dtype=torch.float32)coef = torch.tensor(coef, dtype=torch.float32)return x,y,coef,bias
2.加载数据集
将数据集转换为迭代器,以便在训练过程中进行批量处理。
def load_data(x,y):# 配置参数# 单批次数量batch_size = 16# 样本总数量n_samples = x.shape[0] # len(x)# 单轮训练的次数&向上取整n_batches = math.ceil(n_samples/batch_size)# 数据索引indices = list(range(n_samples))# 打乱索引random.shuffle(indices)# 循环从单批次中取出数据for i in range(0,n_batches):# 取出每批次对应的范围 同时做防越界处理 数量start = i*batch_sizeend = min((i+1)*batch_size, n_samples)index = indices[start:end]# 返回对应数据yield x[index],y[index]
3.初始化参数
随机初始化权重w和设置偏置b。
def initialize(n_feature):# 根据特征数量设置权重# 随机数种子torch.manual_seed(666)# 随机化权重 正态分布w = torch.randn(n_features,require_grad=True,dtype=torch.float32)# 手动设置偏置b = torch.tensor(0.0,require_grad=True,dtype=torch.float32)return w,b
4.线性回归
设置模型函数,即进行”前向传播“。
def regressor(x,w,b):return torch.matmul(x,w) + b # x@w + b
5.损失函数
设置为均分误差形式,即反向传播的对象。
def Loss(y_pred,y_true):# 均方误差return torch.mean((y_pred - y_true)**2)
6.优化器
用在梯度更新,向梯度下降的方向更新。
def optim_step(w,b,dw,db,lr):w.data = w.data - lr*dw.datab.data = b.data - lr*db.datareturn w,b
7.训练数据集
def train():# 生成数据x,y,coef,bias = build_data()# 初始化参数w,b = initialize(n_features=x.shape[1])# 训练参数lr = 0.01 # 学习率epoch = 50 # 训练次数# 训练数据for i in range(epoch):total_loss = 0 # 误差总和count = 0 # 训练次数计数# 每个批次中的数据for batch_x,batch_y_true in load_data(x,y):# 预测数据batch_y_pred = regressor(batch_x,w,b)# 计算损失函数loss = MSE(batch_y_pred,batch_y_true) # 因为是均方误差 所以不需要讲究顺序total_loss += losscount += 1# 梯度清零if w.grad is not None:w.data.zero_()if b.grad is not None:b.data.zero_()# 反向传播 计算梯度loss.backward()# 梯度更新 得出预测权重和偏置w,b = optim_step(w,b,w.grad,b.grad,lr)print(f'epoch:{i},loss:{total_loss/count}')return w.data,b,coef,bias
8.预测数据
def detect(x,w,b):return torch.matmul(x.type(torch.float32),w) + b # tensor相乘加上偏置
9.调用
if __name__ == "__main__":w,b,coef,bias = train()print(f'真实系数:{coef},真实偏置:{bias}')print(f'预测系数:{w},预测偏置:{b}')# 根据手动添加的特征预测结果 这里添加了两个y_pred = detect(torch.tensor([[4,5,6,6],[7,8,8,9]]),w,b)print(f'y_pred:{y_pred}')
二、官方模型定义组件
1、模型组件
0.库函数
import torch
import torch.nn as nn
import torch.optim as optim
1.损失函数组件
def test01():"""损失函数组件"""y_true = torch.tensor([1,2,3,4,5,6],dtype=torch.float32)y_pred = torch.tensor([2,3,4,5,6,7],dtype=torch.float32)# 均分误差工具loss = nn.MSELoss()e = loss(y_true,y_pred)print(e)
2.线性回归模型组件
def test02():"""线性回归模型组件"""model = nn.Linear(4,1) # w1x1+w2x2+w3x3+w4x4+b=y 隐式操作:w1 w2 w3 w4已经初始化# x = torch.tensor([[1,2,3,4]],dtype=torch.float32)# y = model(x)print(model.parameters())x1 = torch.tensor([[1,2,3,4],[1,2,3,4],[1,2,3,4]],dtype=torch.float32)y1 = model(x1)# print(y)print(y1)
3.优化器方法
def test03():"""优化器方法"""# 梯度更新# 01 构造数据集input_x = torch.randint(1,10,(400,5)).type(torch.float32)target = torch.randint(1,10,(400,1)).type(torch.float32)# 02 线性层模型model = nn.Linear(5,1)# 03 优化器对象sgd = optim.SGD(model.parameters(),lr=0.01) # 将模型参数w传入优化器# 04 预测y_pred = model(input_x)# 05 损失函数loss_fn = nn.MSELoss()loss = loss_fn(y_pred,target) # 均方误差# print(loss)# 06 梯度清零sgd.zero_grad() # 相当于 w.grad.zero_()# 07 反向传播loss.backward() # 1 损失函数对参数的导数 2 求梯度# 08 梯度更新sgd.step()# 09 访问更新后的wprint(model.weight)
2、数据加载器
1.构建数据类
在 PyTorch 中,构建自定义数据加载类通常需要继承 torch.utils.data.Dataset 并实现以下几个方法:
1、__init__ 方法 用于初始化数据集对象:通常在这里加载数据,或者定义如何从存储中获取数据的路径和方法。
def __init__(self,data,target):self.data = dataself.target = target
2、__len__ 方法 返回样本数量:需要实现,以便 Dataloader加载器能够知道数据集的大小。
def __len__(self):return len(self.data)
3、__getitem__ 方法 根据索引返回样本:将从数据集中提取一个样本,并可能对样本进行预处理或变换。如果需要进行更多的预处理或数据变换,可以在该方法中添加额外的逻辑。
def __getitem__(self,index):return self.data[index],self.target[index]
2.数据加载器
在训练或者验证的时候,需要用到数据加载器批量的加载样本。
和构建数据整合:
import torch
import torch.nn as nn
from torch.utils.data import Dataset,DataLoaderclass CustomDataSet(Dataset):def __init__(self,data,target):self.data = dataself.target = targetdef __getitem__(self,index):return self.data[index],self.target[index]def __len__(self):return len(self.data)if __name__ == '__main__':# data = CustomDataSet() -> __init__# len(data) -> __len__# data[0] -> __getitem__x = torch.randn(100,3)y = torch.randn(100,1)# 数据集data = CustomDataSet(x,y)count = len(data)print(count)print(data[0])"""数据加载器"""data_loader = DataLoader(data,batch_size=16,shuffle=True) # 小批次设置为16 shuffle=True打乱顺序for x,y in data_loader:print(x.shape,y.shape)
3、数据集加载案例
1.加载Excel数据集
import torch
import pandas as pd
from torch.utils.data import Dataset,DataLoaderclass my_excel_dataset(Dataset):def __init__(self,path):"""读取excel文件, 提取特征值保存在data中, 标签值保存在target中"""data_pd = pd.read_excel(path)# 数据处理:删除NAN的列data_pd.dropna(axis=1,how='all')# 将数据转换为DataFramedata_pd = pd.DataFrame(data_pd)# 删除原有的表头,并重命名列名为英文data_pd.columns = ["zubie","student_id","name","self_work","expression","ppt","answer","present","defense","comments",]data_pd = data_pd.drop(["zubie", "student_id", "name", "self_work", "comments"],axis=1)# print(data_pd.head())# 转换为tensorself.data = torch.tensor(data_pd.iloc[:,:-1].to_numpy(),dtype=torch.float32)self.target = torch.tensor(data_pd.iloc[:,-1].to_numpy(),dtype=torch.float32)def __len__(self):return len(self.data)def __getitem__(self,index):return self.data[index],self.target[index]if __name__ == '__main__':data = my_excel_dataset('./data/21级大数据答辩成绩表.xlsx')data_loader = DataLoader(data,batch_size=4,shuffle=True)for x,y in data_loader:print(x,y)
2.加载图片数据集
os模块相关API:
import os"""
os模块的API
"""
def test01():"""遍历当前目录"""for root, dirs, files in os.walk("./data"):# root:当前目录路径 dirs:当前路径下所有子目录 files:当前路径下所有非目录子文件print(root, dirs, files,'666')def test02():"""查看文件"""path = os.path.join("./data", "1.png")# 拼接路径 path = "./data"+"/"+"1.png"print(path)def test03():"""获取文件名"""_,str = os.path.split("./data/animal/cat")print(str)def test04():"""enumrate 生成枚举下标"""x=["20","hello","9999"]for i in range(len(x)):print(i,x[i])x=["20","hello","9999"]for i,el in enumerate(x):print(i,el)
案例:
import os
import cv2
import torch
from torch.utils.data import Dataset,DataLoaderclass my_image_dataset(Dataset):def __init__(self,path):self.path = pathself.classname=[]self.data = []self.label = []# 遍历文件夹for root,dirs,files in os.walk(path):if root == path:# 通过读取文件目录创建分类名self.classname = dirs# print(dirs)# returnelse:for file in files:# 单个文件的完整路径file_path = os.path.join(root,file)self.data.append(file_path)# 该文件对应的类别class_id = self.classname.index(os.path.split(root)[1])self.label.append(class_id)def __len__(self):return len(self.data)def __getitem__(self,index):img_path = self.data[index] # xlabel = self.label[index] # yimg = cv2.imread(img_path)img = cv2.resize(img,(300,300))img = torch.from_numpy(img)# HWC to CHWimg = img.permute(2,0,1) # 维度转换return img, labelif __name__ == '__main__':data = my_image_dataset('./data/animal')# print(data[120])print(len(data))print(data.classname)train_loader = DataLoader(data, batch_size=32, shuffle=True)for x,y in train_loader:print(x) # [32,3,300,300] 单批次32张图片;3通道;300*300大小print(y) # [32] 32个标签# test04()
3.加载官方数据集
在 PyTorch 中官方提供了一些经典的数据集,如 CIFAR-10、MNIST、ImageNet 等,可以直接使用这些数据集进行训练和测试。
注意,该案例下需要联网下载官方数据集。官方地址:Datasets — Torchvision 0.20 documentation
from torchvision import datasets,transforms
from torch.utils.data import DataLoaderdef test01():transform = transforms.Compose([transforms.ToTensor()])data = datasets.MNIST(root='./data',train=True,download=True,transform=transform)for x,y in DataLoader(data,batch_size=4,shuffle=True):print(x.shape,y.shape)if __name__ == '__main__':test01()
4、数据增强
数据增强是提高模型泛化能力(鲁棒性)的一种有效方法,尤其在图像分类、目标检测等任务中。数据增强可以模拟更多的训练样本,从而减少过拟合风险。数据增强通过torchvision.transforms模块来实现。
具体参考官方文档:Illustration of transforms — Torchvision 0.20 documentation