Pytorch 基础
+ ++
大多数机器学习工作流:
+-
+
- 处理数据 +
- 创建模型 +
- 优化模型参数 +
- 保存训练后模型 +
通过 Pytorch 基础部分的内容,读者可以完整的走完一整个MachineLearning的工作流,若读者对其中某个环节不理解或感兴趣,针对这些工作流中的每一个环节都有相关的扩展阅读链接。
+我们将使用 FashionMNIST 数据集训练一个神经网络,该神经网络预测输入图像是否属于一下类别之一:T恤/上衣、裤子、套头衫、连衣裙、外套、凉鞋、成山、运动鞋、包包、靴子。(是个多分类任务)
+快速入门
++https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html
+
本节会快速走完一个机器学习多分类的Demo,以此快速了解流程中必要的基本ML相关API。
+处理数据
Pytorch 中有两个用于处理数据的子库 torch.utils.data.DataLoader
和 torch.utils.data.Dataset.Dataset
。顾名思义,Dataset
存储样本及其相应的标签,并将 DataLoader
可迭代对象包装在 Dataset
中。
1 | import torch |
通过上面的引用(import),我们可以发现:Pytorch 中有非常多的子库,这些子库专注于某一特定的领域,例如: TorchText, TorchVision, 和 TorchAudio, 这些所有子库中都包含相应的数据集。
+本次教程中我们使用 TorchVision
数据集。
该 torchvision,.datasets
模块包含 Dataset
来自现实世界中的视觉图像数据,最经典的有:CIFAT,COCO(full list here)
本次教程中我们使用 FashionMNIST
数据集。每个 TorchVison
下的 Dataset
都包含两个参数:transform
和 target_transform
分别用来修改样本与打标签。
1 | # 从公开数据集中读取训练数据 |
至此为止,通过上面的工作,我们将 Dataset
作为参数传递给了 DataLoader
。同时封装了相关数据集作为一个可迭代的对象,支持自动批处理、采样、洗牌(shuffling)、和多进程的数据加载。
+
下一步中,我们定义 batch_size = 64
,即 dataloader
可迭代中的每个元素都将返回一批含有64个特征的标签。
1 | batch_size = 64 |
输出:
+1 | Shape of X [N, C, H, W]: torch.Size([64, 1, 28, 28]) |
++关于 loading data in PyTorch 的详细说明
+
+
构建模型
为了在 Pytorch 中定义神经网络,我们创建一个继承自 nn.Module 的类。
+我们通过 __init__
函数定义神经网络的层,并指明数据如何通过 forward
函数进入神经网络层。
++在设备允许的情况下,推荐使用GPU来加速神经网络的运算操作。
+
代码实现:
+1 | # 获取用于训练的设备(cpu/gpu/mps) |
打印结果:
+1 | Using cpu device |
在 PyTorch 中构建神经网络
++这一部分是对‘构建模型’部分的一点补充说明,也是 PyTorch 官网教程中的扩展阅读部分
+
神经网络是由多个对数据进行操作的层/模型组合而成的。torch.nn 命名空间几乎已经提供了构建一个神经网络所需要用到的所有模块。
+所有模块都在 PyTorch 下的子块 nn.Module 中提供。
+基于这样的结构化嵌套模块,整个神经网络可以自由的进行构建和管理复杂的架构。
+在上面的代码块中,我们通过 NeuralNetwork
函数定义了一个神经网络模型 model
。
为了使用该模型,我们将输入数据传递给它。这个操作将执行 forward
操作和一些后台操作。
请记住:不要直接使用 model.forward()
!
+
通过输入操作调用模型,最后将返回一个二维张量,其中 dim = 0 对应于每个类别的 10 个原始预测输出,dim = 1 对应与每个输出的单个值。
+我们可以通过 nn.Softmax
模块实例传递对结果预测的概率来进行最终预测概率的判断。
1 | X = torch.rand(1, 28, 28, device = device) |
打印结果:
+1 | Predicted class: tensor([7], device = 'cuda:0') |
模型层 Model Layers
分解 FashionMNIST
模型中的各层。为了说明这一点,我们通过获取一个包含 3 张大小为 28*28 的小批量图像样本,看看当数据传递到网络时会发生什么。
1 | input_image = torch.rand(3, 28, 28) |
打印输出:
+1 | torch.Size([3, 28, 28]) |
nn.Flatten
初始化 nn.Flatten 层,将每个2D 28*28 图像转换成包含 784 个像素值的连续数组(保持小批量尺寸(dim = 0))
+1 | flatten = nn.Flatten() |
打印输出:
+1 | torch.Size([3, 784]) |
nn.Linear
线性层模块通过输入的权重w和偏差值b进行线性变换。
+1 | layer1 = nn.Linear(in_features = 28*28, out_features = 20) |
打印输出:
+1 | torch.Size([3, 20]) |
nn.ReLU
非线性激活函数可以在模型的输入输出之间创建复杂的映射关系。激活函数通过引入非线性的变换帮助神经网络学习各种现象。
+在实例模型中,我们在线性层之间使用ReLU激活函数。但还有其他激活函数可以在模型的线性层中间作为激活函数使用,详情参考:激活函数-wiki
+1 | print(f"Before ReLU: {hidden1}\n\n") |
打印输出:
+1 | Before ReLU: tensor([[ 0.4158, -0.0130, -0.1144, 0.3960, 0.1476, -0.0690, -0.0269, 0.2690, |
nn.Sequential
nn.Sequential是一个有序的模块容器。数据按照定义好的方式顺序的通过当前模块。
您可以使用顺序容器来组合一个“快捷网络” ,例如:seq_modules
.
1 | seq_modules = nn.Sequential( |
nn.Softmax
Softmax激活函数通常用在最后一个线性层,用来返回对数区间介于 [-infty, infty] 中的原始值,这些值最终被传递给 nn.Softmax
模块。
Softmax 激活函数将对应输出区间范围缩放在 [0, 1] 之间,表示模型对每个类别的预测概率。其中,dim
中所有参数指示值求和应该为 1 。
1 | softmax = nn.Softmax(dim = 1) |
模型的参数
神经网络往往非常的复杂,在整个网络的构建过程中,如果可以便捷的将每个部分表示出来,对于训练过程中的优化和修改相对的权重与偏差等都会有非常大的帮助。
+子类化 nn.Module
模块可以帮助我们解决这个问题,该模块会自动跟踪模型对象中定义的所有字段,并使用模型的 parameters()
函数或 named_parameters()
函数方法访问所有参数。
在本次示例中,我们遍历每个参数,并预览它们的所有数值参数。
+1 | print(f"Model structure: {model}\n\n") |
打印输出结果:
+1 | Model structure: NeuralNetwork( |