PyTorch 深度学习实战 |用 TensorFlow 训练神经网络

Posted TiAmo zhang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyTorch 深度学习实战 |用 TensorFlow 训练神经网络相关的知识,希望对你有一定的参考价值。

为了更好地理解神经网络如何解决现实世界中的问题,同时也为了熟悉 TensorFlow 的 API,本篇我们将会做一个有关如何训练神经网络的练习,并以此为例,训练一个类似的神经网络。

我们即将看到的神经网络,是一个预训练好的用于对手写体数字(整数)图像进行识别的神经网络,它使用了 MNIST 数据集(http://yann.lecun.com/exdb/mnist/),这是一个经常被用于研究模式识别任务的经典的数据集。

01、MNIST 数据集

Modifiled National Institute of Standards and Technology(MNIST)数据集包含 6 万张图像的训练集和 1 万张图像的测试集。每个图像是一个手写体的数字。来自美国政府所提供数据的 MNIST 数据集,最初是用来测试计算机系统识别手写字体方法的。如果计算机能成功识别手写体,这将对提高邮政服务和税收系统以及政府服务的效率,具有重大意义。在当前的研究中,也有一些不同的、更新的数据集(如 CIFAR 数据集)。但是,用 MNIST 数据集来理解神经网络的工作原理仍然是非常有用的,因为使用它,已知模型可达到很高的精确度和效率。

▍CIFAR 数据集是一个机器学习数据集,包含不同类别的图像。与 MNIST 数据集不同的是,CIFAR 数据集包含许多不同领域的类,比如动物、活动和对象。CIFAR 数据集可在https://www.cs.toronto.edu/~kriz/cifar.html下载。

▍摘自 MNIST 数据集的训练集图像。每个图像是一个单独的 20×20 像素的手写数字图像,原始数据集可以在 http://yann.lecun.com/exdb/mnist/找到

02、用 TensorFlow 训练神经网络

现在,让我们用 MNIST 数据集训练一个神经网络,并识别新的数字。

在这个手写体识别的问题上,我们用一个特殊的神经网络——“卷积神经网络”——来解决。我们的神经网络包含三个隐藏层:两个全连接层和一个卷积层。卷积层被以下基于 Python 语言的 TensorFlow 代码段所定义,详见代码段 1。

W = tf.Variable(
      tf.truncated_normal([5, 5, size_in, size_out],
     stddev=0.1),
    name="Weights")
B = tf.Variable(tf.constant(0.1, shape=[size_out]),
    name="Biases")

convolution = tf.nn.conv2d(input, W, strides=[1, 1, 1, 1],
padding="SAME")
activation = tf.nn.relu(convolution + B)

tf.nn.max_pool(
activation,
ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1],

在神经网络训练期间,只需执行一次代码段。

变量 W 和 B 代表权重(weights)和偏差(biases)。这些变量是在隐藏层节点中使用的,用于在数据通过神经网络时,更改神经网络对数据的解释。神经网络中还包含其他变量,但是现在暂时不用考虑这些。

全连接层被以下 Python 代码段所定义,详见代码段 2。

W = tf.Variable(
      tf.truncated_normal([size_in, size_out], stddev=0.1),
     name="Weights")
B = tf.Variable(tf.constant(0.1, shape=[size_out]),
     name="Biases")
     activation = tf.matmul(input, W) + B

这里依然有 TensorFlow 的两个变量:权重 W 和偏移量 B。可注意到,这些变量的初始化非常简单:权重 W 被初始化为随机值,这个初始化是被来自标准差(standard deviation)为 0.1 的被剪枝的高斯分布(使用 size_in 和 size_out 进行剪枝)来完成的;而偏移量 B 则被初始化为常数 0.1。这两个值会随着每次运行而被更改。该代码片段被执行了两次,产生两个全连接层——其中的一个将数据传递给另一个。

这 11 行 Python 代码代表了一个完整的神经网络。我们将使用 Keras 来对每个组件的模型架构进行详细讨论。现在,重点是了解神经网络在每次运行时每个层中的 W 和 B 的值是如何改变的,以及这些代码段如何形成不同的神经层。这 11 行的代码也是几十年神经网络研究成果的积累。

让我们来开始训练这个网络,并且来评估它再 MNIST 手写体数据集中的表现如何。

03、训练神经网络

按照以下步骤来搭建该练习的相关环境:

1.打开两个终端实例(instance)。

2.分别进入到 chapter_4/activity_2[1]目录。

3.在这两个 instance 中,确保您的 Python 3 虚拟环境处于激活状态,并确认已经安装 requirements.txt 中所列举的所有安装包。

4.在其中一个 instance 中,使用如下命令启动 TensorBoard:

$ tensorboard--logdir=mnist_example/

5.在另一个 instance 中,从相应路径下,运行 mnist.py 脚本。

6.打开服务。打开浏览器,在 TensorBoard 提供的 URL(及端口)中,打开页面。

在运行脚本 mnist.py 的终端中,您将看到一个进度条,其中包含了模型在不同时期的训练情况。打开浏览器页面时,您将看到一些图表,点击读取 Accuracy(准确率)的那个,放大它,让页面刷新(或者点击 refresh 按钮刷新)。随着训练次数的增加,您会看到随着迭代次数的增加,这个模型的准确率会越来越高。

这可以解释神经网络在训练过程中能够很早达到高准确度的能力。

我们可以看到,在大约第 200 个 epochs(或迭代步数 steps)时,神经网络的准确率超过了 90%。也就是说,网络可以正确地预测测试集中 90%的手写数字。在训练到第 2000 步的时候,该网络的准确率不断提高,在这一阶段结束时达到了 97%的准确率。

现在让我们来测试一下这个网络在对于从未使用过的数据表现如何。我们使用 Shafeen Tejani 创建的开源网络应用程序来测试一下这个神经网络是否能够正确识别出我们自己写的手写数字。

04、用未见数据测试神经网络的性能

在浏览器中访问http://mnist-demo.herokuapp.com/,然后我们可以在指定的白色方格中画一个 0 到 9 之间的数字(如下图所示)。

▍可以手绘数字并可测试神经网络准确性的 Web 应用程序

▍上述应用程序: https://github.com/ShafeenTejani/mnist-demo .

在该应用程序中,您可以看到两个神经网络的实验结果。我们训练的那个神经网络(称为卷积神经网络 CNN)位于左侧。看看它能否识别您手写的数字?试着在指定区域的边缘画出数字。例如,试着把数字 1 画在那个区域的右边,如下图所示。

▍两个神经网络都很难估计区域边缘的值

▍在本例中,我们看到数字 1 绘制在绘图区域的右侧。这个绘在边缘的数字,两个网络都没识别出来它应该是 1。

MNIST 数据集中不包含写在边缘的数字图像。由于没有包含处于区域边缘的训练数据,因此这两个神经网络都无法正确识别边缘处的数字。如果我们把手写数字写到更靠近指定区域的中心,那么这两个神经网络的识别效果能够得到一定的改善,这说明神经网络的性能依赖于训练数据。如果用于训练的数据与用于测试的数据差异很大,那么神经网络很可能会出现令人失望的结果。

05、实例:探索一个训练好的神经网络

下面将探索刚才在练习中训练的神经网络。我们还会通过改变超参数来训练一些其他的神经网络。那么就让我们从练习中训练的神经网络开始吧。

让我们用 TensorBoard 打开神经网络,来了解神经网络的组成。

打开终端,chapter_4/activity_2 目录下,执行以下指令

$ tensorboard --logdir=mnist_examle/

启动 TensorBoard(如下图所示):

▍启动 TensorBoard 实例后的终端显示

现在,在浏览器中打开 TensorBoard 提供的 URL。您应该能够看到 TensorBoard 标量页面。

通过 TensorBoard 命令提供的 URL,打开对应的页面,可以看到如下图所示的 TensorBoard 界面:

▍TensorBoard 登录页面

现在让我们来深入了解这个已经训练好的神经网络,看看它是如何工作的。

在 TensorBoard 页面上,点击 Scalars 页,将 Accuracy 图放大。然后把 Smoothing 进度条移动到 0.9。

准确率图(accuracy graph)衡量了神经网络对测试集标签的预测准确率。起初,神经网络对于数据的预测几乎全部错误。这是因为我们只是用随机值初始化了神经网络的权值和偏差,所以其预测尝试只是大致的猜测。然后,神经网络在第二次运行时,会更新其神经层的权重(weights)和偏差(biases);神经网络将继续通过改变其权重和偏差来使每个节点能更好地预测数据,而对于那些对预测造成损失的节点,则会通过惩罚项[1]逐渐减少其对神经网络的影响(最终达到 0)。通过这种方式来一步一步地降低损失,提升神经网络的准确率。正如您所看到的,这是一种非常有效的技术,可以迅速产生非常好的预测结果。

现在,让我们把注意力集中在准确率(Accuracy)的图上,来看看这个算法是如何在 1000 步(epoches)之后达到很高的准确率(>95%)的。在 1000 步到 2000 步之间,又会发生什么呢?

如果我们继续用更多的训练步数(epochs)来训练,神经网络的预测会变得更精确吗?当训练步数在 1000 到 2000 之间时,神经网络的准确率会继续提高,但提高的幅度在下降。如果用更多的训练步数(epochs)进行训练,神经网络的精准度可能还会略有改善,但在目前的网络架构下,它不会达到 100%的准确率。

该脚本是谷歌官方脚本的修改版本,它是为了展示 TensorFlow 的工作方式。我们将脚本划分为易于理解的函数,并添加了许多注释来帮助您的学习。您可以通过修改以下变量来运行该脚本:

LEARNING_RATE=0.0001EPOCHS=2000

现在,您可以通过修改这些变量的值来运行该脚本。例如,尝试将学习率(learning rate)修改为 0.1,将步数(epochs)修改为 100。您觉得神经网络的效果如何?

▍在神经网络中还有许多其他参数可以修改。现在,尝试修改网络的训练次数(epochs)和学习速度(learning rate)。您将会注意到,这两种改动都能极大地影响神经网络的输出。通过改变这两个参数,观察是否可以用当前的体系结构来更快地训练这个神经网络。

可使用 TensorBoard 来(可视化)验证一下训练的神经网络。可将初始值乘以 10,将这些参数再修改几次,直到注意到神经网络性能有提升时为止。这种对神经网络进行调优并找到提升精度的过程,与当今工业应用中用于改进现有神经网络模型的过程是类似的。

Pytorch100例 | 用深度学习处理分类问题实战教程


PyTorchTensorFlow库是用于深度学习的两个最常用的 Python 库。PyTorch 是 Facebook 开发的,而 TensorFlow 是 Google 的项目。在本文中,你将看到如何使用 PyTorch 库来解决分类问题。
分类问题属于机器学习问题的范畴,其中给定一组特征,任务是预测离散值。预测肿瘤是否癌变,或者学生是否可能通过考试,是分类问题的一些常见示例。
在本文中,我们将根据银行客户的某些特征,预测客户是否有可能在 6 个月后离开银行。客户离开的现象也称为客户流失。因此,我们的任务是根据各种客户特征来预测客户流失。
在你继续之前,假定你对 Python 编程语言具有中级水平,并且你已经安装了 PyTorch 库。此外,了解了基本机器学习概念的知识可能会对理解本文有所帮助。如果你尚未安装 PyTorch,则可以使用以下 pip 命令进行安装:

$ pip install pytorch

数据集

我们将在本文中使用的数据集可通过此Kaggle 链接免费获得,也可以添加我微信获取。让我们将所需的库和数据集导入我们的 Python 应用程序:

import torch
import torch.nn as nn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

我们可以使用第三方库的read_csv()方法pandas导入包含我们数据集的 CSV 文件。

dataset = pd.read_csv(r'E:Datasets\\customer_data.csv')

让我们打印数据集的形状:

dataset.shape

输出:

(10000, 14)

输出显示数据集有 10,000 条记录和 14 列。
我们可以使用.head()方法打印数据集的前五行。

dataset.head()

输出:

你可以在我们的数据集中看到 14 列。我们的任务是基于前 13 列预测第 14 列的值,即Exited。需要注意的是,前 13 列的值是在Exited获取该列的值之前 6 个月记录的,因为任务是预测自记录客户信息起 6 个月后的客户流失。

探索性数据分析

让我们对我们的数据集执行一些探索性数据分析。我们将首先预测 6 个月后实际离开银行的客户的比例,并使用饼图进行可视化。
让我们首先增加图表的默认绘图大小:

fig_size = plt.rcParams["figure.figsize"]
fig_size[0] = 10
fig_size[1] = 8
plt.rcParams["figure.figsize"] = fig_size

以下脚本绘制Exited列的饼图。

dataset.Exited.value_counts().plot(kind='pie', autopct='%1.0f%%', colors=['skyblue', 'orange'], explode=(0.05, 0.05))

输出:

输出显示,在我们的数据集中,20% 的客户离开了银行。这里1代表客户离开银行的情况,0代表客户没有离开银行的情况。
让我们绘制数据集中所有地理位置的客户数量:

sns.countplot(x='Geography', data=dataset)

输出:

输出显示,几乎一半的客户属于法国,而属于西班牙和德国的客户比例各为 25%。
现在让我们绘制每个独特地理位置的客户数量以及客户流失信息。我们可以使用seaborn库中的countplot()函数来做到这一点。

sns.countplot(x='Exited', hue='Geography', data=dataset)

输出:

输出显示,尽管法国客户的总数是西班牙和德国客户的两倍,但法国和德国客户离开银行的客户比例相同。同样,德国和西班牙客户的总体数量相同,但德国客户离开银行的数量是西班牙客户的两倍,这表明德国客户更有可能在 6 个月后离开银行。

数据预处理

在我们训练我们的 PyTorch 模型之前,我们需要预处理我们的数据。如果查看数据集,你会看到它有两种类型的列:数值列和分类列。数字列包含数字信息。CreditScoreBalanceAge等。类似地,GeographyGender是分类列,因为它们包含分类信息,例如客户的位置和性别。有一些列可以被视为数字列和分类列。例如,该HasCrCard列的值可以是 1 或 0。但是,那HasCrCard列包含有关客户是否拥有信用卡的信息。建议将既可被视为分类又可被视为数值的列视为分类。
让我们再次打印数据集中的所有列,并找出哪些列可以被视为数字列,哪些列应该被视为分类列。数据框的columns属性打印所有列名:

dataset.columns

输出:

Index(['RowNumber', 'CustomerId', 'Surname', 'CreditScore', 'Geography',
       'Gender', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'HasCrCard',
       'IsActiveMember', 'EstimatedSalary', 'Exited'],
      dtype='object')

在我们数据集中的列中,我们不会使用RowNumberCustomerIdSurname列,因为这些列的值是完全随机的并且与我们需要预测的目标无关。例如,客户的姓氏对客户是否会离开银行没有影响。在其余列中,GeographyGenderHasCrCardIsActiveMember列可以视为分类列。让我们创建这些列的列表:

categorical_columns = ['Geography', 'Gender', 'HasCrCard', 'IsActiveMember']

Exited列外的所有剩余列都可以视为数字列。

numerical_columns = ['CreditScore', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'EstimatedSalary']

最后,输出(Exited列)存储在outputs变量中。

outputs = ['Exited']

我们已经创建了分类、数字和输出的列表。但是,目前分类列的类型不是分类的。你可以使用以下脚本检查数据集中所有列的类型:

dataset.dtypes

输出:

RowNumber            int64
CustomerId           int64
Surname             object
CreditScore          int64
Geography           object
Gender              object
Age                  int64
Tenure               int64
Balance            float64
NumOfProducts        int64
HasCrCard            int64
IsActiveMember       int64
EstimatedSalary    float64
Exited               int64
dtype: object

你可以看到GeographyGender列的类型为object,HasCrCard 和IsActive 列的类型为int64,我们需要将分类列的类型转换为category,我们可以使用函数来做到这一点,如下所示:

for category in categorical_columns:
    dataset[category] = dataset[category].astype('category')

现在,如果您再次绘制数据集中列的类型,您应该会看到以下结果:

dataset.dtypes

输出

RowNumber             int64
CustomerId            int64
Surname              object
CreditScore           int64
Geography          category
Gender             category
Age                   int64
Tenure                int64
Balance             float64
NumOfProducts         int64
HasCrCard          category
IsActiveMember     category
EstimatedSalary     float64
Exited                int64
dtype: object

现在让我们看看Geography列中的所有类别:

dataset['Geography'].cat.categories

输出:

Index(['France', 'Germany', 'Spain'], dtype='object')

当你将列的数据类型更改为类别时,列中的每个类别都会分配一个唯一代码。例如,让我们绘制该Geography列的前五行并打印前五行的代码值:

dataset['Geography'].head()

输出:

0    France
1     Spain
2    France
3    France
4     Spain
Name: Geography, dtype: category
Categories (3, object): [France, Germany, Spain]

以下脚本绘制Geography列前五行中值的编号:

dataset['Geography'].head().cat.codes

输出:

0    0
1    2
2    0
3    0
4    2
dtype: int8

输出显示法国已编码为 0,西班牙已编码为 2。
由于我们将使用 PyTorch 进行模型训练,因此我们需要将分类列和数值列转换为张量。让我们首先将分类列转换为张量。在 PyTorch 中,可以通过 numpy 数组创建张量。我们首先将四个分类列中的数据转换为 numpy 数组,然后水平堆叠所有列,如以下脚本所示:

geo = dataset['Geography'].cat.codes.values
gen = dataset['Gender'].cat.codes.values
hcc = dataset['HasCrCard'].cat.codes.values
iam = dataset['IsActiveMember'].cat.codes.values

categorical_data = np.stack([geo, gen, hcc, iam], 1)

categorical_data[:10]

上面的脚本打印分类列中水平堆叠的前十条记录。输出如下:
输出:

array([[0, 0, 1, 1],
       [2, 0, 0, 1],
       [0, 0, 1, 0],
       [0, 0, 0, 0],
       [2, 0, 1, 1],
       [2, 1, 1, 0],
       [0, 1, 1, 1],
       [1, 0, 1, 0],
       [0, 1, 0, 1],
       [0, 1, 1, 1]], dtype=int8)

现在要从前面提到的 numpy 数组创建一个张量,你可以简单地将数组传递给模块的torch类的tensor模块。对于分类列,数据类型应为torch.int64.

categorical_data = torch.tensor(categorical_data, dtype=torch.int64)
categorical_data[:10]

输出:

tensor([[0, 0, 1, 1],
        [2, 0, 0, 1],
        [0, 0, 1, 0],
        [0, 0, 0, 0],
        [2, 0, 1, 1],
        [2, 1, 1, 0],
        [0, 1, 1, 1],
        [1, 0, 1, 0],
        [0, 1, 0, 1],
        [0, 1, 1, 1]])

在输出中,你可以看到分类数据的 numpy 数组现已转换为tensor对象。以同样的方式,我们可以将数值列转换为张量:

numerical_data = np.stack([dataset[col].values for col in numerical_columns], 1)
numerical_data = torch.tensor(numerical_data, dtype=torch.float)
numerical_data[:5]

输出:

tensor([[6.1900e+02, 4.2000e+01, 2.0000e+00, 0.0000e+00, 1.0000e+00, 1.0135e+05],
        [6.0800e+02, 4.1000e+01, 1.0000e+00, 8.3808e+04, 1.0000e+00, 1.1254e+05],
        [5.0200e+02, 4.2000e+01, 8.0000e+00, 1.5966e+05, 3.0000e+00, 1.1393e+05],
        [6.9900e+02, 3.9000e+01, 1.0000e+00, 0.0000e+00, 2.0000e+00, 9.3827e+04],
        [8.5000e+02, 4.3000e+01, 2.0000e+00, 1.2551e+05, 1.0000e+00, 7.9084e+04]])

在输出中,你可以看到前五行包含我们数据集中六个数字列的值。
最后一步是将输出的 numpy 数组转换为tensor对象。

outputs = torch.tensor(dataset[outputs].values).flatten()
outputs[:5]

输出:

tensor([1, 0, 1, 0, 0])

现在让我们绘制分类数据、数值数据和相应输出的形状:

print(categorical_data.shape)
print(numerical_data.shape)
print(outputs.shape)

输出:

torch.Size([10000, 4])
torch.Size([10000, 6])
torch.Size([10000])

在我们训练模型之前有一个非常重要的步骤。我们将分类列转换为数字列(类别数字化),其中唯一值由整数表示。例如,在Geography列中,我们看到法国用 0 表示,德国用 1 表示。我们可以使用这些值来训练我们的模型。但是,更好的方法是以 N 维向量的形式表示分类列中的值,而不是整数。向量能够捕获更多信息,并能以更合适的方式找到不同分类值之间的关系。因此,我们将以 N 维向量的形式表示分类列中的值。这个过程称为嵌入。
我们需要为所有分类列定义嵌入大小(向量维度)。关于维数没有硬性规定。定义列的嵌入大小的一个好的经验法则是将列中唯一值的数量除以 2(但不超过 50)。例如,对于该Geography列,唯一值的数量为 3。该Geography列的相应嵌入大小将为 3/2 = 1.5 = 2(四舍五入)。
以下脚本创建一个元组,其中包含唯一值的数量和所有分类列的维度大小:

categorical_column_sizes = [len(dataset[column].cat.categories) for column in categorical_columns]
categorical_embedding_sizes = [(col_size, min(50, (col_size+1)//2)) for col_size in categorical_column_sizes]
print(categorical_embedding_sizes)

输出:

[(3, 2), (2, 1), (2, 1), (2, 1)]

对于有监督的深度学习模型,例如我们在本文中开发的模型,需要使用训练数据进行训练,并在测试数据集上评估模型性能。因此,我们需要将我们的数据集划分为训练集和测试集,如下面的脚本所示:

total_records = 10000
test_records  = int(total_records * .2)

categorical_train_data = categorical_data[:total_records-test_records]
categorical_test_data = categorical_data[total_records-test_records:total_records]
numerical_train_data = numerical_data[:total_records-test_records]
numerical_test_data  = numerical_data[total_records-test_records:total_records]
train_outputs = outputs[:total_records-test_records]
test_outputs  = outputs[total_records-test_records:total_records]

我们的数据集中有 10,000 条记录,其中 80% 的记录,即 8000 条记录,将用于训练模型,而其余 20% 的记录将用于评估我们模型的性能。请注意,在上面的脚本中,分类和数值数据以及输出已分为训练集和测试集。
为了验证我们是否正确地将数据划分为训练集和测试集,让我们打印训练和测试记录的长度:

print(len(categorical_train_data))
print(len(numerical_train_data))
print(len(train_outputs))

print(len(categorical_test_data))
print(len(numerical_test_data))
print(len(test_outputs))

输出:

8000
8000
8000
2000
2000
2000

创建预测模型

我们已将数据分为训练集和测试集,现在是时候定义我们的训练模型了。为此,我们可以定义一个名为Model的类,它将用于训练模型。

class Model(nn.Module):

    def __init__(self, embedding_size, num_numerical_cols, output_size, layers, p=0.4):
        super().__init__()
        self.all_embeddings = nn.ModuleList([nn.Embedding(ni, nf) for ni, nf in embedding_size])
        self.embedding_dropout = nn.Dropout(p)
        self.batch_norm_num = nn.BatchNorm1d(num_numerical_cols)

        all_layers = []
        num_categorical_cols = sum((nf for ni, nf in embedding_size))
        input_size = num_categorical_cols + num_numerical_cols

        for i in layers:
            all_layers.append(nn.Linear(input_size, i))
            all_layers.append(nn.ReLU(inplace=True))
            all_layers.append(nn.BatchNorm1d(i))
            all_layers.append(nn.Dropout(p))
            input_size = i

        all_layers.append(nn.Linear(layers[-1], output_size))

        self.layers = nn.Sequential(*all_layers)

    def forward(self, x_categorical, x_numerical):
        embeddings = []
        for i,e in enumerate(self.all_embeddings):
            embeddings.append(e(x_categorical[:,i]))
        x = torch.cat(embeddings, 1)
        x = self.embedding_dropout(x)

        x_numerical = self.batch_norm_num(x_numerical)
        x = torch.cat([x, x_numerical], 1)
        x = self.layers(x)
        return x

如果你以前从未使用过 PyTorch,上面的代码可能看起来会有些难度,我尽力为你分解。
在第一行中,我们声明了一个Model继承自Module的类。在类的构造函数(__init__()方法)中传递以下参数:

  1. embedding_size:包含分类列的嵌入大小(embedding size)
  2. num_numerical_cols:存储数字列的总数
  3. output_size:输出层的大小或可能输出的数量。
  4. layers:包含所有层的神经元数量的列表。
  5. p:Dropout值,默认值为0.5

在构造函数内部,初始化了一些变量。首先,该all_embeddings变量包含所有分类列的ModuleList对象列表。embedding_dropout存储所有层的丢失值。最后,batch_norm_num存储所有数字列的BatchNorm1d对象列表。
接下来,为了找到输入层的大小,将分类列数和数字列数相加并存储在input_size变量中。之后,for循环迭代并将相应的层添加到all_layers列表中。添加的层是:

  • Linear:用于计算输入和权重矩阵之间的点积
  • ReLu:用作激活函数
  • BatchNorm1d: 用于对数值列应用批量归一化
  • Dropout:用于避免过拟合

for循环后,输出层将附加到层列表。由于我们希望神经网络中的所有层按顺序执行,因此将层列表传递给nn.Sequential类。
接下来,在该forward方法中,分类列和数字列都作为输入传递。分类列的嵌入发生在以下几行中。

embeddings = []
for i, e in enumerate(self.all_embeddings):
    embeddings.append(e(x_categorical[:,i]))
x = torch.cat(embeddings, 1)
x = self.embedding_dropout(x)

数字列的批量归一化应用以下脚本:

x_numerical = self.batch_norm_num(x_numerical)

最后,嵌入的分类列x和数字列x_numerical连接在一起并传递给 sequential layers

训练模型

要训练模型,首先我们必须创建一个Model(我们在上一节中定义的类的对象)。

model = Model(categorical_embedding_sizes, numerical_data.shape[1], 2, [200,100,50], p=0.4)

你可以看到我们传递了分类列的嵌入大小、数字列的数量、输出大小(在我们的例子中为 2)和隐藏层中的神经元。你可以看到我们有三个隐藏层,分别有 200、100 和 50 个神经元。如果需要,你可以选择任何其他尺寸。
让我们打印我们的模型,看看它的外观:

print(model)

输出:

Model(
  (all_embeddings): ModuleList(
    (0): Embedding(3, 2)
    (1): Embedding(2, 1)
    (2): Embedding(2, 1)
    (3): Embedding(2, 1)
  )
  (embedding_dropout): Dropout(p=0.4)
  (batch_norm_num): BatchNorm1d(6, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (layers): Sequential(
    (0): Linear(in_features=11, out_features=200, bias=True)
    (1): ReLU(inplace)
    (2): Batch

以上是关于PyTorch 深度学习实战 |用 TensorFlow 训练神经网络的主要内容,如果未能解决你的问题,请参考以下文章

Pytorch100例 | 用深度学习处理分类问题实战教程

PyTorch 深度学习实战 |用 TensorFlow 训练神经网络

Pytorch 入门与实战----pytorch入门

对比学习:《深度学习之Pytorch》《PyTorch深度学习实战》+代码

深度学习-PyTorch框架实战系列

深度学习理论与实战PyTorch实现