PLUS会员

量化机器学习系列分享(八)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

\

{link}