pytorch模型训练demo代码
在PyTorch中,模型训练通常涉及几个关键步骤:定义模型、定义损失函数、选择优化器、准备数据加载器、编写训练循环。以下是一个简单的PyTorch模型训练演示代码,该代码实现了一个用于手写数字识别(使用MNIST数据集)的简单神经网络。
首先,确保你已经安装了PyTorch和torchvision(用于加载MNIST数据集)。
import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader # 定义模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(28*28, 500) # 输入层到隐藏层 self.relu = nn.ReLU() self.fc2 = nn.Linear(500, 10) # 隐藏层到输出层 def forward(self, x): x = x.view(-1, 28*28) # 展平图像 x = self.relu(self.fc1(x)) x = self.fc2(x) return x # 准备数据 transform = transforms.Compose([ transforms.ToTensor(), # 转换为Tensor transforms.Normalize((0.5,), (0.5,)) # 归一化 ]) train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True) train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True) # 实例化模型、损失函数和优化器 model = Net() criterion = nn.CrossEntropyLoss() # 多分类交叉熵损失 optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) # 训练模型 num_epochs = 5 for epoch in range(num_epochs): for i, (images, labels) in enumerate(train_loader): # 前向传播 outputs = model(images) loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() # 清零梯度 loss.backward() # 反向传播 optimizer.step() # 更新参数 if (i+1) % 100 == 0: print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss: {loss.item():.4f}') print('Finished Training')
在这个例子中,我们定义了一个简单的全连接神经网络
Net
,它包含两个全连接层和一个ReLU激活函数。我们使用MNIST数据集进行训练,该数据集包含了手写数字的图像。我们使用了交叉熵损失函数和SGD优化器。在训练循环中,我们遍历数据加载器中的每个批次,对每个批次执行前向传播以计算损失,然后执行反向传播以计算梯度,并使用优化器更新模型的参数。每处理100个批次,我们就打印当前的损失值,以便监控训练过程。
dataset & dataloader
dataset3个必要函数:__init__、__getitem__、__len__
__getitem__的调用时机是遍历dataloader时,遍历dataloader时,返回的属性是在__getitem__方法中return的值
执行代码可以看到__getitem__的调用时机;
改变num_workers还可以看到确实是多线程在搬运数据
import os
from torch.utils.data import Dataset, DataLoader
class MyDataset(Dataset):
def __init__(self):
print('init my dataset')
self.imgs = os.listdir('../YOLO5/datasets/coco128/images/train2017')
def __getitem__(self, idx):
print('get item')
return self.imgs[idx]
def __len__(self):
return len(self.imgs)
if __name__ == '__main__':
my_dataset = MyDataset()
print('create my_dataloader')
my_dataloader = DataLoader(dataset=my_dataset, batch_size=8, shuffle=True, num_workers=0, drop_last=True)
for idx, data in enumerate(my_dataloader):
print(idx, data)
下面我们以yolov5的代码来看下这个dataset和dataloader的实际应用,可以看到getitem中返回了这些值,然后遍历pbar也就是dataloader时,获取了imgs, targets, paths这些属性;
还有一点需要注意,使用enumerate时,会同时返回index
def __getitem__(self, index):
#此处省略1万行代码
return torch.from_numpy(img), labels_out, self.im_files[index], shapes
pbar = enumerate(train_loader)
LOGGER.info(("\n" + "%11s" * 7) % ("Epoch", "GPU_mem", "box_loss", "obj_loss", "cls_loss", "Instances", "Size"))
if RANK in {-1, 0}:
pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar
optimizer.zero_grad()
for i, (imgs, targets, paths, _) in pbar: # batch -------------------------------------------------------------
callbacks.run("on_train_batch_start")
网络架构可视化工具
可视化项目:
https://github.com/lutzroeder/netron?tab=readme-ov-file
推荐使用onnx格式,模型更加精细
深度学习的原理
深度学习的原理主要基于人工神经网络(Artificial Neural Networks, ANNs)的复杂结构,特别是多层感知机(Multi-Layer Perceptrons, MLPs)和卷积神经网络(Convolutional Neural Networks, CNNs)、循环神经网络(Recurrent Neural Networks, RNNs)等高级变种。这些网络通过模仿人脑神经元之间的连接和通信方式,来学习数据的表示(representation)和模式(patterns)。以下是深度学习原理的几个关键方面:
人工神经网络基础:
- 神经元(Neurons):神经网络的基本单元,模拟生物神经元。每个神经元接收来自其他神经元的输入信号,加权求和(包括偏置项),然后通过激活函数(如Sigmoid、ReLU等)处理,产生输出信号。
- 层(Layers):多个神经元排列成层,输入层接收原始数据,隐藏层处理数据,输出层产生最终结果。
- 权重(Weights)和偏置(Biases):神经元之间的连接强度由权重表示,偏置项用于调整激活函数的输入。
前向传播(Forward Propagation):
在训练过程中,输入数据通过神经网络逐层向前传播,直到输出层产生预测结果。这一过程中,网络的权重和偏置保持不变。损失函数(Loss Function):
用于量化预测结果与真实结果之间的差异。常见的损失函数包括均方误差(MSE)、交叉熵损失等。反向传播(Backpropagation):
根据损失函数的梯度,通过链式法则逐层反向传播,更新每一层神经元的权重和偏置,以最小化损失函数。这是通过梯度下降(或其变种如Adam、RMSprop等)算法实现的。优化算法:
用于更新网络参数的算法,旨在找到使损失函数最小化的参数值。梯度下降是最常用的优化算法之一,但现代深度学习框架通常提供多种优化器供选择。过拟合与正则化:
当模型在训练数据上表现良好但在未见过的数据上表现不佳时,称为过拟合。为了缓解过拟合,可以使用正则化技术(如L1/L2正则化、Dropout等)来减少模型的复杂度。激活函数:
激活函数引入非线性因素,使得神经网络能够学习和表示复杂的非线性关系。不同的激活函数适用于不同的任务和数据。卷积神经网络(CNNs):
特别适用于处理图像数据,通过卷积层、池化层等结构自动提取图像特征。循环神经网络(RNNs)及其变体(如LSTM、GRU):
特别适用于处理序列数据(如文本、时间序列),能够捕捉数据中的时序依赖关系。深度学习的成功在很大程度上归功于这些组件的巧妙组合和大规模数据的可用性,以及计算能力的显著提高。通过这些技术,深度学习模型能够在许多复杂任务上达到甚至超越人类水平的性能。
卷积网络的多层结构的作用
todo 一直说"从低层次的边缘、颜色、纹理等特征,到中层次的简单形状、模式,再到高层次的复杂结构和语义信息",这个如何可视化?之前有大佬进行过可视化,在哪里找?
CNN(卷积神经网络)之所以需要多层结构,主要是基于以下几个原因:
1. 特征抽象与组合
- 逐层特征提取:CNN通过多层卷积操作,逐层提取图像中的特征。从低层次的边缘、颜色、纹理等特征,到中层次的简单形状、模式,再到高层次的复杂结构和语义信息,这一过程是逐步进行的。每一层都在前一层的基础上进一步抽象和组合特征,从而构建出更加复杂和具有区分度的特征表示。
- 组合不同层次的特征:多层结构使得CNN能够组合不同层次的特征,从而实现对输入数据的全面理解和建模。这种组合能力对于处理复杂的图像数据尤为重要,因为图像中的信息往往分布在不同的尺度和层次上。
2. 提高模型表达能力
- 增加非线性:每一层卷积后通常会接入非线性激活函数(如ReLU),这增加了模型的非线性表达能力。多层非线性变换能够拟合更加复杂的函数关系,使得模型能够学习到输入数据中的复杂模式。
- 避免信息丢失:通过多层卷积和池化操作,虽然会在一定程度上降低特征图的分辨率,但多层结构能够保留更多的信息,避免在单一层次上进行过度降维而导致的信息丢失。
3. 扩大感受野
- 感受野的累积:在CNN中,感受野是指卷积核在输入图像上能够看到的区域大小。随着卷积层的增加,每一层神经元的感受野会逐渐增大,从而能够捕捉到更加全局和抽象的特征。这种感受野的累积效应是CNN能够处理复杂图像任务的关键因素之一。
4. 适应不同尺度的特征
- 多尺度特征提取:通过不同大小和步长的卷积核,CNN能够在不同尺度上提取特征。多层结构使得CNN能够同时处理多个尺度的特征,从而更加全面地理解输入数据。
5. 提高模型鲁棒性
- 特征冗余:多层结构使得CNN能够学习到多种特征表示,这些特征表示之间存在冗余和互补关系。当某些特征受到噪声或遮挡等影响时,其他特征仍然能够提供有效的信息支持,从而提高模型的鲁棒性。
综上所述,CNN之所以需要多层结构,主要是为了逐层提取和组合图像中的特征、提高模型的表达能力、扩大感受野、适应不同尺度的特征以及提高模型的鲁棒性。这些优势使得CNN在图像识别、目标检测、语义分割等任务中取得了显著的成果。
深度学习卷积层的作用
深度学习中的卷积层(Convolutional Layer)是卷积神经网络(Convolutional Neural Networks, CNNs)的核心组成部分,它们对输入数据执行卷积操作,这一操作在图像处理和计算机视觉任务中尤为关键。卷积层的主要作用可以概括为以下几点:
特征提取:卷积层通过一组可学习的滤波器(也称为卷积核或权重)对输入数据进行滑动窗口式的点积运算,从而提取出输入数据的局部特征。这些特征可以是边缘、角点、纹理等,它们对于后续的图像识别或分类任务至关重要。
减少参数数量:由于卷积层中的每个神经元都与前一层的一个局部区域相连接(即局部连接性),并且这个连接权重(即卷积核)在输入数据的不同位置是共享的(即权重共享),因此可以显著减少模型需要学习的参数数量,从而降低模型的复杂度,提高训练效率,并减少过拟合的风险。
平移不变性:由于卷积层中的权重共享特性,网络对于输入数据中的平移变换(即图像中的物体位置变化)具有一定的不变性。这意味着,无论图像中的物体出现在哪个位置,网络都能有效地识别出它。
降维和池化:虽然卷积层本身并不直接进行降维操作,但它通常与池化层(Pooling Layer)结合使用。池化层通过对卷积层的输出进行下采样(如最大池化、平均池化等),可以进一步减少数据的空间大小(即降维),并提取出更重要的特征,同时增加模型对输入数据中的小变形(如旋转、缩放等)的鲁棒性。
学习层次化特征:通过堆叠多个卷积层,网络能够学习到从简单到复杂的层次化特征表示。浅层的卷积层通常学习到的是边缘、线条等低级特征,而深层的卷积层则能够学习到更高级、更抽象的特征,这些特征对于完成复杂的图像识别或分类任务至关重要。
综上所述,卷积层在深度学习中,特别是在处理图像数据时,发挥着至关重要的作用。它们通过特征提取、减少参数数量、实现平移不变性、降维和池化以及学习层次化特征等方式,为后续的图像识别、分类、检测等任务提供了强有力的支持。
编码解码
深度学习中的编码解码(Encoder-Decoder)结构是一种广泛应用于图像处理、自然语言处理(NLP)等领域的网络架构。这种结构有效地结合了特征提取(编码)和结果生成(解码)两个过程,以下是对该结构的详细解析:
一、编码器(Encoder)
定义与功能:
- 编码器负责从输入数据中提取有用的特征信息。这些特征信息通常是输入数据中不同对象或区域的抽象表示,有助于后续的处理或生成任务。
结构与操作:
- 编码器通常由一系列的网络层组成,如卷积层(Convolutional Layers)、池化层(Pooling Layers