量化机器学习系列分享(八)Pytorch代码的基本框架
由bq2qbou2创建,最终由bq2qbou2 被浏览 140 用户
1. Pytorch介绍
1.1 Pytorch包介绍
Python中的Pytorch包,是使用最多的,用来构建神经网络模型的工具,它的特点包括:
- 可以灵活地搭建任何类型的神经网络模型
- 支持使用GPU运算
- 有一套通用的代码框架
Pytorch包在BigQuant平台是有预装的,因此在AIStudio中直接调用即可
import torch
1.2 Pytorch中的数据结构:Tensor
在Pytorch中,数据格式一般不使用Pandas的DataFrame或Numpy的Array,而是Pytorch包中自带的Tensor
在Pytorch中,通常要把数据从Pandas / Numpy的形式转为Tensor,再把数据输入Pytorch的模型中
- Tensor的形式其实和Numpy比较类似,展示出来也是也是矩阵的形式
- Tensor支持高性能计算和GPU加速计算
https://bigquant.com/codeshare/d194f932-6db4-43bf-bc9f-45dc35c992a3
2. Pytorch中的数据
Pytorch中关于数据的工具有两个
- Dataset:数据集
- DataLoader:数据加载器
在Pytorch的框架中,数据由Dataset传入DataLoader,再由DataLoader传入神经网络模型
2.1 Dataset
Pytorch中的Dataset类是用于表示数据集的抽象类
- 允许用户自定义如何加载数据
- 并提供一个统一的接口供模型训练使用
2.1.1 TensorDataset
对于比较工整的结构数据,例如表格或者矩阵
- 我们可以直接把数据转换为Tensor
- 再定义一个针对此Tensor的TensorDataset
https://bigquant.com/codeshare/d82a08d5-3048-4aca-ab80-5fece6fd2033
2.1.2 自定义Dataset
在Pytorch中,我们还可以自定义Dataset,这种情景常用于不工整的非结构化数据,例如图片、文字等
自定义Dataset,本质上是定义一个类,它会继承Dataset类,并且要自定义三个重要方法:
- 初始化方法:init:当中要定义好数据的来源,例如:
- 传统的表格数据:表格从csv读进来存为pandas的dataframe
- 图片数据:所有图片存在一个文件夹中,读进来存为一个列表的图片
- 文字数据:所有文字存在一个文件中,读进来存为一个列表的字符串
- 获取长度方法:len:当中要定义数据集的长度是如何决定的,例如:
- 传统的表格数据:一共有多少行数据
- 图片数据:一共有多少张图片
- 文字数据:一共有多少段文字
- 获取数据方法:getitem:当中要定义一条数据是如何获取的,例如:
- 传统的表格数据:一行数据,转为Tensor
- 图片数据:一张图片,转为Tensor
- 文字数据:一段文字,转为Tensor
https://bigquant.com/codeshare/70e8cf88-95c1-4c6d-9d2b-2e4f564fdcd2
2.2 DataLoader
DataLoader是Pytorch中的数据加载器
- DataLoader支持按批次加载数据
- 因为大部分深度学习模型的数据量都非常大,一次性把所有数据都加载到模型中是不现实的
- 因此,我们需要按批次把数据
- DataLoader支持随机加载数据
- 把数据打乱后再输入到模型中
- 这样做可以避免数据顺序对于模型参数学习的影响
DataLoader基本不需要自定义,我们直接建一个DataLoader对象,并且强调以下参数:
- dataset:要加载的数据集
- batch_size:每个批次中的样本数量
- shuffle:是否在每个epoch开始时打乱数据顺序,默认为False
- num_workers:用于数据加载的子进程数量
DataLoader是一个可遍历的对象,我们在模型训练是遍历DataLoader,做到按批次加载数据
\
3. 神经网络模型的建立
在Pytorch中,建立一个神经网络模型,也是要自定义一个类来实现,这个类要继承自torch.nn.Module类,当中要自定义两个重要的方法:
- 初始化方法:通常是用来准备模型中需要使用的计算单元,基本都来自于torch.nn中
- 前向计算方法:定义模型中的前向计算逻辑
3.1 前馈神经网络
以下是一个Pytorch中搭建的前馈神经网络的模型
- 输入层:节点数未知,当做参数传进去
- 第一层:节点数256,激活函数ReLU,随机丢弃10%
- 第二层:节点数128,激活函数ReLU,随机丢弃10%
- 输出层:节点数1
import torch
import torch.nn as nn
class DNN(nn.Module):
def __init__(self, input_dim):
super(DNN, self).__init__()
self.fc1 = nn.Linear(input_dim, 256)
self.fc2 = nn.Linear(256, 128)
self.fc3 = nn.Linear(128, 1)
self.dropout = nn.Dropout(0.1)
self.relu = nn.ReLU()
def forward(self, data):
# 第一层
out = self.fc1(data)
out = self.relu(out) # 激活函数层
out = self.dropout(out) # dropout层
# 第二层
out = self.fc2(out)
out = self.relu(out)
out = self.dropout(out)
# 输出层
out = self.fc3(out)
return out
3.2 卷积神经网络
以下是一个Pytorch中搭建的一维卷积神经网络的模型
输入层到第一层:输入通道等于特征数,输出通道等于16
- 卷积运算:3X1的卷积核,步长为1,补齐1圈0
- 池化运算:2X1的最大池化,步长为2,
第一层到第二层:输入通道等于16,输出通道等于32
- 卷积运算:3X1的卷积核,步长为1,补齐1圈0
- 池化运算:2X1的最大池化:步长为2
第二层的输出展开为一个一维向量后,拼接一个前馈神经网络
import torch
import torch.nn as nn
class CNN1D(nn.Module):
def __init__(self, input_size):
super(CNN1D, self).__init__()
self.conv1 = nn.Conv1d(in_channels=input_size, out_channels=16, kernel_size=3, stride=1, padding=1)
self.conv2 = nn.Conv1d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1)
self.relu = nn.ReLU()
self.maxpool = nn.MaxPool1d(kernel_size=2, stride=2)
self.dropout = nn.Dropout(0.1)
self.fc1 = nn.Linear(32 * (input_size // 4), 64)
self.fc2 = nn.Linear(64, 1)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.dropout(x)
x = self.conv2(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.dropout(x)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
3.3 循环神经网络
以下是一个Pytorch中搭建的循环神经网络的模型
- input_size:数据端的维度
- hidden_size:状态端的维度
- num_layers:RNN的层数
import torch
import torch.nn as nn
class RNN(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size):
super(SimpleRNN, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.rnn = nn.RNN(input_size, hidden_size, num_layers)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
# 初始化隐藏状态
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
# 前向传播 RNN
out, _ = self.rnn(x, h0)
# 只取最后一个时间步的输出
out = self.fc(out[:, -1, :])
return out
在Pytoch中建立一个LSTM模型,只需将RNN节点换成LSTM节点即可
import torch
import torch.nn as nn
class SimpleLSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size):
super(SimpleLSTM, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.lstm = nn.LSTM(input_size, hidden_size, num_layers)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
# 初始化隐藏状态和细胞状态
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
# 前向传播 LSTM
_, (hn, cn) = self.lstm(x, (h0, c0))
# 只取最后一个时间步的隐藏状态传入全连接层
out = self.fc(hn[-1])
return out
\
4. 神经网络模型的训练
4.1 损失函数
在Pytorch中,损失函数也是在torch.nn类中调取,常见的损失函数包括:
- nn.CrossEntropyLoss: 分类问题的交叉熵
- nn.MSELoss: 回归问题的均方误差
- nn.L1Loss: 回归问题的L1损失
4.2 优化器
优化器就是之前我们在优化方法那一章讲到的,使用什么样的优化方法
优化器需要在torch.optim中调用,并且要传入模型参数,常见的有:
- SGD: 随机梯度下降优化器
- Adagrad: 自适应梯度优化器
- Adam: 自适应矩估计优化器
4.3 神经网络的训练框架
在Pytorch中,神经网络的训练,基本上是用两层循环来实现的:
- 外层循环:训练的次数
- 内层循环:使用DataLoader按批次加载数据
在内层循环中,我们要做以下事情
- 前向计算得出输出
- 输出与标签之间求出损失
- 损失指导优化器更新参数
在计算的时候,我们可以使用GPU加速,在使用GPU加速的时候,我们要将三个东西放入GPU:
- 数据
- 模型
- 优化器
在训练结束后,我们还可以直接把预测数据传入训练好的模型中,完成预测
- 如果模型放入了GPU,那么预测数据也要传入GPU
- 预测数据如果数据量比较小,就不需要用到DataLoader和Dataset
以下我们通过一个完整的Pytorch代码框架,来理解一下使用Pytorch进行训练的过程
https://bigquant.com/codeshare/ea4fddb8-3094-45f8-8d2f-59f9dae2cc24
\