如何使用 Python 开发深度学习模型

PyTorch 的核心是一个数学库,允许您对基于图形的模型执行高效计算和自动微分。直接实现这一点具有挑战性,但值得庆幸的是,现代 PyTorch API 提供了类和习语,使您可以轻松开发一套深度学习模型。

推荐:将NSDT场景编辑器加入你的3D工具链

3D工具集:NSDT简石数字孪生

如何使用 Python 开发深度学习模型

PyTorch 的核心是一个数学库,允许您对基于图形的模型执行高效计算和自动微分。直接实现这一点具有挑战性,但值得庆幸的是,现代 PyTorch API 提供了类和习语,使您可以轻松开发一套深度学习模型。

在本教程中,您将了解在 PyTorch 中开发深度学习模型的分步指南。

完成本教程后,您将了解:

  • Torch 和 PyTorch 之间的区别以及如何安装和确认 PyTorch 是否正常工作。
  • PyTorch 模型的五步生命周期以及如何定义、拟合和评估模型。
  • 如何为回归、分类和预测建模任务开发 PyTorch 深度学习模型。

用我的书《Deep Learning with PyTorch》开始你的项目。它提供了带有工作代码自学教程
让我们开始吧。

PyTorch 教程 - 如何开发深度学习模型

PyTorch 教程概述

本教程的重点是使用 PyTorch API 执行常见的深度学习模型开发任务;我们不会深入研究深度学习的数学和理论。为此,我建议从这本优秀的书开始(https://amzn.to/2Y8JuBv)。

在python中学习深度学习的最好方法是实践。潜入。您可以稍后回头了解更多理论。

我将每个代码示例设计为使用最佳实践并独立使用,以便您可以将其直接复制并粘贴到项目中,并使其适应您的特定需求。这将使您领先一步,而不是仅从官方文档中找出 API。

这是一个大型教程,因此分为三个部分;它们是:

  1. 如何安装 PyTorch
  2. 什么是火炬和PyTorch?
  3. 如何安装 PyTorch
  4. 如何确认已安装 PyTorch
  5. PyTorch 深度学习模型生命周期
  6. 步骤 1:准备数据
  7. 步骤 2:定义模型
  8. 步骤 3:训练模型
  9. 步骤 4:评估模型
  10. 第 5 步:进行预测
  11. 如何开发 PyTorch 深度学习模型
  12. 如何开发用于二元分类的 MLP
  13. 如何开发用于多类分类的MLP
  14. 如何开发用于回归的 MLP
  15. 如何开发用于图像分类的CNN

你可以在Python中进行深度学习!

完成本教程。最多需要60分钟!

你不需要了解一切(至少现在不需要)。您的目标是端到端地运行本教程并获得结果。您不需要在第一次通过时了解所有内容。随时列出您的问题。大量使用 API 文档来了解您正在使用的所有函数。

你不需要先知道数学。数学是描述算法如何工作的紧凑方式,特别是线性代数、概率和微积分的工具。这些并不是您可以用来了解算法如何工作的唯一工具。您还可以使用代码并探索具有不同输入和输出的算法行为。了解数学不会告诉您选择哪种算法或如何最好地配置它。你只能通过精心控制的实验来发现这一点。

您不需要知道算法是如何工作的。了解限制以及如何配置深度学习算法非常重要。但是学习算法可以稍后进行。你需要在很长一段时间内慢慢建立这种算法知识。今天,首先要熟悉这个平台。

你不需要是Python程序员。如果你不熟悉 Python 语言,它的语法可能是直观的。就像其他语言一样,专注于函数调用(例如 function())和赋值(例如 a = “b”)。这将使您大部分时间。您是开发人员;您知道如何非常快速地掌握语言的基础知识。只需开始,稍后再深入了解详细信息。

您不需要成为深度学习专家。您可以稍后了解各种算法的优点和局限性,并且您可以阅读大量教程来复习深度学习项目的步骤。

1. 如何安装PyTorch

在本节中,您将了解 PyTorch 是什么,如何安装它以及如何确认它已正确安装。

1.1. 什么是火炬和 PyTorch?

PyTorch是由Facebook开发和维护的用于深度学习的开源Python库。

该项目始于2016年,并迅速成为开发人员和研究人员的流行框架。

Torch(Torch7)是一个用C语言编写的深度学习开源项目,通常通过Lua接口使用。它是PyTorch的前身项目,不再积极开发。PyTorch 在名称中包含“Torch”,用“Py”前缀确认之前的 Torch 库,表示新项目的 Python 重点。

PyTorch API 简单灵活,使其成为学者和研究人员开发新的深度学习模型和应用程序的最爱。广泛使用导致了特定应用程序(如文本、计算机视觉和音频数据)的许多扩展,并且可能预训练了可以直接使用的模型。因此,它可能是学术界最常用的图书馆。

与Keras等更简单的界面相比,PyTorch的灵活性是以易用性为代价的,特别是对于初学者而言。选择使用 PyTorch 而不是 Keras 放弃了一些易用性、稍微陡峭的学习曲线和更多的代码以获得更大的灵活性,也许还有一个更有活力的学术社区。

1.2. 如何安装 PyTorch

在安装 PyTorch 之前,请确保您已安装 Python,例如 Python 3.6 或更高版本。

如果你没有安装Python,你可以使用Anaconda安装它。本教程将向您展示如何:

  • 如何使用 Anaconda 为机器学习设置 Python 环境

有很多方法可以安装 PyTorch 开源深度学习库。

在工作站上安装 PyTorch 的最常见,也许也是最简单的方法是使用 pip。

例如,在命令行上,可以键入:

1
sudo pip install torch

也许深度学习最流行的应用是计算机视觉,PyTorch计算机视觉包被称为“torchvision”。

也强烈建议安装火炬视,可以按以下方式安装:

1
sudo pip install torchvision

如果您更喜欢使用更特定于您的平台或包管理器的安装方法,您可以在此处查看完整的安装说明列表:

  • PyTorch 安装指南

现在无需设置 GPU。

本教程中的所有示例都可以在现代 CPU 上运行良好。如果要为 GPU 配置 PyTorch,可以在完成本教程后执行此操作。不要分心!

1.3. 如何确认 PyTorch 已安装

安装 PyTorch 后,确认库已成功安装并且您可以开始使用它非常重要。

不要跳过此步骤。

如果 PyTorch 未正确安装或在此步骤中引发错误,则以后将无法运行这些示例。

创建一个名为 versions.py 的新文件,并将以下代码复制并粘贴到该文件中。

1
2
3
# check pytorch version
import torch
print(torch.__version__)

保存文件,然后打开命令行并将目录更改为保存文件的位置。

然后键入:

1
python versions.py

然后,您应该看到如下所示的输出:

1
1.3.1

这确认了 PyTorch 安装正确,并且我们都使用相同的版本。

这还向您展示了如何从命令行运行 Python 脚本。我建议以这种方式从命令行运行所有代码,而不是从笔记本或 IDE 运行。

2. PyTorch 深度学习模型生命周期

在本节中,您将了解深度学习模型的生命周期以及可用于定义模型的 PyTorch API。

模型有一个生命周期,这个非常简单的知识为数据集建模和理解 PyTorch API 提供了支柱。

生命周期中的五个步骤如下:

  • 1. 准备数据。
  • 2. 定义模型。
  • 3. 训练模型。
  • 4. 评估模型。
  • 5. 做出预测。

让我们依次仔细看看每个步骤。

注意:使用 PyTorch API 有很多方法可以实现这些步骤中的每一个,尽管我的目标是向您展示最简单、最常见或最惯用的方法。

如果您发现更好的方法,请在下面的评论中告诉我。

步骤 1:准备数据

第一步是加载和准备数据。

神经网络模型需要数值输入数据和数值输出数据。

可以使用标准 Python 库来加载和准备表格数据,如 CSV 文件。例如,Pandas可用于加载CSV文件,scikit-learn的工具可用于编码分类数据,例如类标签。

PyTorch 提供了数据集类,您可以扩展和自定义该以加载数据集。

例如,数据集对象的构造函数可以加载数据文件(例如 CSV 文件)。然后,可以重写可用于获取数据集长度(行数或样本数)的 __len__() 函数,以及用于按索引获取特定样本的 __getitem__() 函数。

加载数据集时,还可以执行任何所需的转换,例如缩放或编码。

下面提供了自定义数据集类的框架。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# dataset definition
class CSVDataset(Dataset):
    # load the dataset
    def __init__(self, path):
        # store the inputs and outputs
        self.X = ...
        self.y = ...
 
    # number of rows in the dataset
    def __len__(self):
        return len(self.X)
 
    # get a row at an index
    def __getitem__(self, idx):
        return [self.X[idx], self.y[idx]]

加载后,PyTorch 提供 DataLoader 类,用于在模型训练和评估期间导航数据集实例。

可以为训练数据集、测试数据集甚至验证数据集创建 DataLoader 实例。

random_split() 函数可用于将数据集拆分为训练集和测试集。拆分后,可以将数据集中的行选择提供给 DataLoader,以及批大小以及是否应在每个纪元对数据进行随机排序。

例如,我们可以通过传入数据集中的选定行样本来定义 DataLoader

1
2
3
4
5
6
7
8
...
# create the dataset
dataset = CSVDataset(...)
# select rows from the dataset
train, test = random_split(dataset, [[...], [...]])
# create a data loader for train and test sets
train_dl = DataLoader(train, batch_size=32, shuffle=True)
test_dl = DataLoader(test, batch_size=1024, shuffle=False)

定义后,可以枚举 DataLoader,每次迭代生成一批样本。

1
2
3
4
...
# train the model
for i, (inputs, targets) in enumerate(train_dl):
...

步骤 2:定义模型

下一步是定义模型。

在 PyTorch 中定义模型的习惯用法涉及定义一个扩展模块类的类。

类的构造函数定义了模型的层,forward() 函数是定义如何通过模型的已定义层转发传播输入的覆盖。

有许多层可用,例如线性用于全连接层,Conv2d 用于卷积层,MaxPool2d 用于池化层。

激活函数也可以定义为层,例如ReLU,Softmax和Sigmoid。

下面是一个具有一层的简单 MLP 模型的示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
# model definition
class MLP(Module):
    # define model elements
    def __init__(self, n_inputs):
        super(MLP, self).__init__()
        self.layer = Linear(n_inputs, 1)
        self.activation = Sigmoid()
 
    # forward propagate input
    def forward(self, X):
        X = self.layer(X)
        X = self.activation(X)
        return X

在构造函数中定义给定层后,也可以初始化给定层的权重。

常见的例子包括 Xavier 和 He 权重初始化方案。例如:

1
2
...
xavier_uniform_(self.layer.weight)

步骤 3:训练模型

训练过程要求您定义损失函数和优化算法。

常见的损失函数包括:

  • BCELoss:二元分类的二进制交叉熵损失。
  • 交叉熵损失:多类分类的分类交叉熵损失。
  • MSELoss:回归的均方损失。

有关损失函数的更多信息,请参阅教程:

  • 用于训练深度学习神经网络的损失和损失函数

随机梯度下降用于优化,标准算法由 SGD 类提供,尽管该算法的其他版本可用,例如 Adam。

1
2
3
# define the optimization
criterion = MSELoss()
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)

训练模型涉及枚举训练数据集的数据加载程序

首先,训练周期数需要一个循环。然后,小批量需要一个内部循环,用于随机梯度下降。

1
2
3
4
5
6
...
# enumerate epochs
for epoch in range(100):
    # enumerate mini batches
    for i, (inputs, targets) in enumerate(train_dl):
     ...

模型的每次更新都涉及相同的常规模式,包括:

  • 清除最后一个误差梯度。
  • 输入通过模型的正向传递。
  • 计算模型输出的损失。
  • 通过模型反向传播误差。
  • 更新模型以减少损失。

例如:

1
2
3
4
5
6
7
8
9
10
11
...
# clear the gradients
optimizer.zero_grad()
# compute the model output
yhat = model(inputs)
# calculate loss
loss = criterion(yhat, targets)
# credit assignment
loss.backward()
# update model weights
optimizer.step()

步骤 4:评估模型

模型拟合后,可以在测试数据集上对其进行评估。

这可以通过使用测试数据集的 DataLoader 并收集测试集的预测,然后将预测与测试集的预期值进行比较并计算性能指标来实现。

1
2
3
4
5
...
for i, (inputs, targets) in enumerate(test_dl):
    # evaluate the model on the test set
    yhat = model(inputs)
    ...

第 5 步:进行预测

拟合模型可用于对新数据进行预测。

例如,您可能有单个图像或一行数据,并且想要进行预测。

这需要您将数据包装在 PyTorch 张量数据结构中。

张量只是用于保存数据的 NumPy 数组的 PyTorch 版本。它还允许您在模型图中执行自动微分任务,例如在训练模型时调用 back()。

预测也将是一个张量,尽管您可以通过将张量与自动微分图分离并调用 NumPy 函数来检索 NumPy 数组。

1
2
3
4
5
6
7
...
# convert row to data
row = Variable(Tensor([row]).float())
# make prediction
yhat = model(row)
# retrieve numpy array
yhat = yhat.detach().numpy()

现在我们已经熟悉了 PyTorch API 的高级和模型生命周期,让我们看看如何从头开始开发一些标准的深度学习模型。

3. 如何开发 PyTorch 深度学习模型

在本节中,您将了解如何使用标准深度学习模型(包括多层感知器 (MLP) 和卷积神经网络 (CNN))进行开发、评估和预测。

多层感知器模型(简称MLP)是一种标准的全连接神经网络模型。

它由节点层组成,其中每个节点连接到前一层的所有输出,每个节点的输出连接到下一层节点的所有输入。

MLP 是具有一个或多个完全连接层的模型。此模型适用于表格数据,即在表或电子表格中查找的数据,每个变量一列,每个变量一行。您可能想使用 MLP 探索三个预测建模问题;它们是二元分类、多类分类和回归。

让我们在真实数据集上为每种情况拟合一个模型。

注意:本节中的模型有效,但未优化。看看你是否可以提高他们的表现。在下面的评论中发布您的发现。

3.1. 如何开发用于二元分类的 MLP

我们将使用电离层二进制(两类)分类数据集来演示用于二进制分类的 MLP。

该数据集涉及预测大气中是否存在给定雷达回波的结构。

The dataset will be downloaded automatically using Pandas, but you can learn more about it here.

  • Ionosphere Dataset (csv).
  • Ionosphere Dataset Description.

我们将使用 LabelEncoder 将字符串标签编码为整数值 0 和 1。该模型将拟合 67% 的数据,其余 33% 将用于评估,使用 train_test_split() 函数进行拆分。

最好将“relu”激活与“He Uniform”权重初始化一起使用。这种组合对于克服训练深度神经网络模型时梯度消失的问题大有帮助。有关 ReLU 的更多信息,请参阅教程:

  • 整流线性单元 (ReLU) 的温和介绍

该模型预测类 1 的概率并使用 sigmoid 激活函数。该模型使用随机梯度下降进行优化,并试图最小化二进制交叉熵损失。

下面列出了完整的示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# pytorch mlp for binary classification
from numpy import vstack
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from torch.utils.data import random_split
from torch import Tensor
from torch.nn import Linear
from torch.nn import ReLU
from torch.nn import Sigmoid
from torch.nn import Module
from torch.optim import SGD
from torch.nn import BCELoss
from torch.nn.init import kaiming_uniform_
from torch.nn.init import xavier_uniform_
 
# dataset definition
class CSVDataset(Dataset):
    # load the dataset
    def __init__(self, path):
        # load the csv file as a dataframe
        df = read_csv(path, header=None)
        # store the inputs and outputs
        self.X = df.values[:, :-1]
        self.y = df.values[:, -1]
        # ensure input data is floats
        self.X = self.X.astype('float32')
        # label encode target and ensure the values are floats
        self.y = LabelEncoder().fit_transform(self.y)
        self.y = self.y.astype('float32')
        self.y = self.y.reshape((len(self.y), 1))
 
    # number of rows in the dataset
    def __len__(self):
        return len(self.X)
 
    # get a row at an index
    def __getitem__(self, idx):
        return [self.X[idx], self.y[idx]]
 
    # get indexes for train and test rows
    def get_splits(self, n_test=0.33):
        # determine sizes
        test_size = round(n_test * len(self.X))
        train_size = len(self.X) - test_size
        # calculate the split
        return random_split(self, [train_size, test_size])
 
# model definition
class MLP(Module):
    # define model elements
    def __init__(self, n_inputs):
        super(MLP, self).__init__()
        # input to first hidden layer
        self.hidden1 = Linear(n_inputs, 10)
        kaiming_uniform_(self.hidden1.weight, nonlinearity='relu')
        self.act1 = ReLU()
        # second hidden layer
        self.hidden2 = Linear(10, 8)
        kaiming_uniform_(self.hidden2.weight, nonlinearity='relu')
        self.act2 = ReLU()
        # third hidden layer and output
        self.hidden3 = Linear(8, 1)
        xavier_uniform_(self.hidden3.weight)
        self.act3 = Sigmoid()
 
    # forward propagate input
    def forward(self, X):
        # input to first hidden layer
        X = self.hidden1(X)
        X = self.act1(X)
         # second hidden layer
        X = self.hidden2(X)
        X = self.act2(X)
        # third hidden layer and output
        X = self.hidden3(X)
        X = self.act3(X)
        return X
 
# prepare the dataset
def prepare_data(path):
    # load the dataset
    dataset = CSVDataset(path)
    # calculate split
    train, test = dataset.get_splits()
    # prepare data loaders
    train_dl = DataLoader(train, batch_size=32, shuffle=True)
    test_dl = DataLoader(test, batch_size=1024, shuffle=False)
    return train_dl, test_dl
 
# train the model
def train_model(train_dl, model):
    # define the optimization
    criterion = BCELoss()
    optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)
    # enumerate epochs
    for epoch in range(100):
        # enumerate mini batches
        for i, (inputs, targets) in enumerate(train_dl):
            # clear the gradients
            optimizer.zero_grad()
            # compute the model output
            yhat = model(inputs)
            # calculate loss
            loss = criterion(yhat, targets)
            # credit assignment
            loss.backward()
            # update model weights
            optimizer.step()
 
# evaluate the model
def evaluate_model(test_dl, model):
    predictions, actuals = list(), list()
    for i, (inputs, targets) in enumerate(test_dl):
        # evaluate the model on the test set
        yhat = model(inputs)
        # retrieve numpy array
        yhat = yhat.detach().numpy()
        actual = targets.numpy()
        actual = actual.reshape((len(actual), 1))
        # round to class values
        yhat = yhat.round()
        # store
        predictions.append(yhat)
        actuals.append(actual)
    predictions, actuals = vstack(predictions), vstack(actuals)
    # calculate accuracy
    acc = accuracy_score(actuals, predictions)
    return acc
 
# make a class prediction for one row of data
def predict(row, model):
    # convert row to data
    row = Tensor([row])
    # make prediction
    yhat = model(row)
    # retrieve numpy array
    yhat = yhat.detach().numpy()
    return yhat
 
# prepare the data
path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv'
train_dl, test_dl = prepare_data(path)
print(len(train_dl.dataset), len(test_dl.dataset))
# define the network
model = MLP(34)
# train the model
train_model(train_dl, model)
# evaluate the model
acc = evaluate_model(test_dl, model)
print('Accuracy: %.3f' % acc)
# make a single prediction (expect class=1)
row = [1,0,0.99539,-0.05889,0.85243,0.02306,0.83398,-0.37708,1,0.03760,0.85243,-0.17755,0.59755,-0.44945,0.60536,-0.38223,0.84356,-0.38542,0.58212,-0.32192,0.56971,-0.29674,0.36946,-0.47357,0.56811,-0.51171,0.41078,-0.46168,0.21266,-0.34090,0.42267,-0.54487,0.18641,-0.45300]
yhat = predict(row, model)
print('Predicted: %.3f (class=%d)' % (yhat, yhat.round()))

运行示例首先报告训练数据集和测试数据集的形状,然后拟合模型并在测试数据集上对其进行评估。最后,对单行数据进行预测。

注意:根据算法或评估过程的随机性质或数值精度的差异,您的结果可能会有所不同。请考虑运行几次示例并比较平均结果。

3D建模学习工作室 翻译整理,转载请注明出处!

NSDT场景编辑器 | NSDT 数字孪生 | GLTF在线编辑器 | 3D模型在线转换 | UnrealSynth虚幻合成数据生成器 | 3D模型自动纹理化工具
2023 power by nsdt©鄂ICP备2023000829号