Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
apachecn-dl-zh
提交
ba688b35
A
apachecn-dl-zh
项目概览
OpenDocCN
/
apachecn-dl-zh
12 个月 前同步成功
通知
298
Star
83
Fork
35
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
apachecn-dl-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ba688b35
编写于
1月 16, 2021
作者:
W
wizardforcel
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
2021-01-16 18:15:35
上级
6291f709
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
18 addition
and
18 deletion
+18
-18
new/pt-dl-handson/3.md
new/pt-dl-handson/3.md
+6
-6
new/pt-dl-handson/4.md
new/pt-dl-handson/4.md
+9
-9
new/pt-dl-handson/8.md
new/pt-dl-handson/8.md
+3
-3
未找到文件。
new/pt-dl-handson/3.md
浏览文件 @
ba688b35
...
@@ -16,7 +16,7 @@ PyTorch 最初是由 Facebook 实习生作为研究框架开始的,现已发
...
@@ -16,7 +16,7 @@ PyTorch 最初是由 Facebook 实习生作为研究框架开始的,现已发
## 构思和计划
## 构思和计划
通常,在组织中,产品团队会向工程团队显示问题陈述,希望知道他们是否可以解决。 这是构想阶段的开始。 在学术界,这可能是决策阶段,在此阶段,候选人必须为其论文找到问题。 在构思阶段,工程师们集思广益并找到了可能解决问题的理论方法。 除了将问题陈述转换为理论解决方案外,构想阶段还包括确定数据类型以及应使用哪些数据集来构建
**概念证明**
(
**POC
[ **
最低可行产品
**(**
MVP
**)的
**
)。 在这个阶段,团队通过分析问题陈述的行为,现有的可用实现,可用的预先训练的模型等来决定采用哪种框架。
通常,在组织中,产品团队会向工程团队显示问题陈述,希望知道他们是否可以解决。 这是构想阶段的开始。 在学术界,这可能是决策阶段,在此阶段,候选人必须为其论文找到问题。 在构思阶段,工程师们集思广益并找到了可能解决问题的理论方法。 除了将问题陈述转换为理论解决方案外,构想阶段还包括确定数据类型以及应使用哪些数据集来构建
**概念证明**
(
**POC
**
)或
**最低可行产品**
(
**MVP
**
)。 在这个阶段,团队通过分析问题陈述的行为,现有的可用实现,可用的预先训练的模型等来决定采用哪种框架。
这个阶段在行业中很常见,我有成千上万个示例,其中计划周密的构思阶段帮助团队按时推出了可靠的产品,而计划外的构思阶段破坏了整个产品的创建。
这个阶段在行业中很常见,我有成千上万个示例,其中计划周密的构思阶段帮助团队按时推出了可靠的产品,而计划外的构思阶段破坏了整个产品的创建。
...
@@ -30,7 +30,7 @@ PyTorch 最初是由 Facebook 实习生作为研究框架开始的,现已发
...
@@ -30,7 +30,7 @@ PyTorch 最初是由 Facebook 实习生作为研究框架开始的,现已发
不同类型的深度学习问题需要不同类型的数据集,并且每种类型的可能需要不同类型的预处理,具体取决于我们使用的神经网络架构。 这是深度学习管道构建中的核心问题之一。
不同类型的深度学习问题需要不同类型的数据集,并且每种类型的可能需要不同类型的预处理,具体取决于我们使用的神经网络架构。 这是深度学习管道构建中的核心问题之一。
尽管社区已经免费提供了用于不同任务的数据集,但是编写预处理脚本几乎总是很痛苦。 PyTorch 通过提供抽象类来编写自定义数据集和数据加载器来解决此问题。 这里给出的示例是一个简单的
`dataset`
类,用于加载我们在第 2 章,
*一个简单神经网络*
中使用的
`fizzbuzz`
数据集,但是将其扩展为可以处理任何类型的数据集 非常简单。 PyTorch 的官方文档使用类似的方法对图像数据集进行预处理,然后再将其传递给复杂的
**卷积神经网络**
(
**CNN**
)架构。
尽管社区已经免费提供了用于不同任务的数据集,但是编写预处理脚本几乎总是很痛苦。 PyTorch 通过提供抽象类来编写自定义数据集和数据加载器来解决此问题。 这里给出的示例是一个简单的
`dataset`
类,用于加载我们在第 2 章,
“一个简单神经网络”
中使用的
`fizzbuzz`
数据集,但是将其扩展为可以处理任何类型的数据集 非常简单。 PyTorch 的官方文档使用类似的方法对图像数据集进行预处理,然后再将其传递给复杂的
**卷积神经网络**
(
**CNN**
)架构。
PyTorch 中的
`dataset`
类是高级抽象,可处理数据加载程序几乎需要的所有内容。 用户定义的自定义
`dataset`
类需要覆盖父类的
`__len__`
函数和
`__getitem__`
函数,其中数据加载程序正在使用
`__len__`
来确定数据集的长度,而
`__getitem__`
数据加载器正在使用该物品来获取物品。
`__getitem__`
函数希望用户将索引作为参数传递,并获取驻留在该索引上的项目:
PyTorch 中的
`dataset`
类是高级抽象,可处理数据加载程序几乎需要的所有内容。 用户定义的自定义
`dataset`
类需要覆盖父类的
`__len__`
函数和
`__getitem__`
函数,其中数据加载程序正在使用
`__len__`
来确定数据集的长度,而
`__getitem__`
数据加载器正在使用该物品来获取物品。
`__getitem__`
函数希望用户将索引作为参数传递,并获取驻留在该索引上的项目:
...
@@ -198,7 +198,7 @@ transform = transforms.Compose(
...
@@ -198,7 +198,7 @@ transform = transforms.Compose(
)
)
```
```
前面的示例显示了
`transforms.Compose`
如何将
`ToTensor`
和
`Normalize`
组合在一起以组成单个管道。
`ToTensor`
将三通道输入 RGB 图像转换为尺寸为
*通道×宽度×高度*
的三维张量。 这是 PyTorch 中视觉网络期望的尺寸顺序。
前面的示例显示了
`transforms.Compose`
如何将
`ToTensor`
和
`Normalize`
组合在一起以组成单个管道。
`ToTensor`
将三通道输入 RGB 图像转换为尺寸为
`通道×宽度×高度`
的三维张量。 这是 PyTorch 中视觉网络期望的尺寸顺序。
`ToTensor`
还将每个通道的像素值从 0 到 255 转换为 0.0 到 1.0 的范围。
`Transforms.Normalize`
是具有均值和标准差的简单归一化。 因此,
`Compose`
循环遍历所有转换,并使用先前转换的结果调用转换。 以下是从源代码复制的
`torchvision`
转换撰写的
`__call__`
函数:
`ToTensor`
还将每个通道的像素值从 0 到 255 转换为 0.0 到 1.0 的范围。
`Transforms.Normalize`
是具有均值和标准差的简单归一化。 因此,
`Compose`
循环遍历所有转换,并使用先前转换的结果调用转换。 以下是从源代码复制的
`torchvision`
转换撰写的
`__call__`
函数:
...
@@ -308,9 +308,9 @@ print(next(iter(test_iter)))
...
@@ -308,9 +308,9 @@ print(next(iter(test_iter)))
`sort_key`
使用我们传递的
`lambda`
函数对数据集进行排序。 在某些情况下,对数据集进行排序会有所帮助,而在大多数情况下,随机性会帮助网络学习一般情况。
`Iterator`
足够聪明,可以使用通过参数传递的批量大小来批量输入数据集,但是它并不止于此。 它可以动态地将所有序列填充到每批最长序列的长度。
`Iterator`
的输出(如
`print`
语句所示)为
`TEXT`
数据,其大小为
`16x99`
,其中
`99`
是我们为测试数据集传递的批量大小,而 16 是该数据集的长度。 该特定批量中最长的序列。
`sort_key`
使用我们传递的
`lambda`
函数对数据集进行排序。 在某些情况下,对数据集进行排序会有所帮助,而在大多数情况下,随机性会帮助网络学习一般情况。
`Iterator`
足够聪明,可以使用通过参数传递的批量大小来批量输入数据集,但是它并不止于此。 它可以动态地将所有序列填充到每批最长序列的长度。
`Iterator`
的输出(如
`print`
语句所示)为
`TEXT`
数据,其大小为
`16x99`
,其中
`99`
是我们为测试数据集传递的批量大小,而 16 是该数据集的长度。 该特定批量中最长的序列。
如果
`Iterator`
类需要更巧妙地处理事情怎么办? 如果数据集用于语言建模,并且我们需要一个数据集来进行
**
在整个时间**
(
**BPTT**
)中的反向传播
,那该怎么办?
`torchtext`
也为这些模块抽象了模块,这些模块继承自我们刚刚使用的
`Iterator`
类。
`BucketIterator`
模块将序列进行更智能的分组,以便将具有相同长度的序列归为一组,并且此减少了将噪声引入数据集的不必要填充的长度。
`BucketIterator`
还可以在每个时期对批量进行混洗,并在数据集中保持足够的随机性,从而使网络无法从数据集中的顺序中学习,这实际上并没有在教授任何现实世界的信息。
如果
`Iterator`
类需要更巧妙地处理事情怎么办? 如果数据集用于语言建模,并且我们需要一个数据集来进行
**
时间上的反向传播**
(
**BPTT**
)
,那该怎么办?
`torchtext`
也为这些模块抽象了模块,这些模块继承自我们刚刚使用的
`Iterator`
类。
`BucketIterator`
模块将序列进行更智能的分组,以便将具有相同长度的序列归为一组,并且此减少了将噪声引入数据集的不必要填充的长度。
`BucketIterator`
还可以在每个时期对批量进行混洗,并在数据集中保持足够的随机性,从而使网络无法从数据集中的顺序中学习,这实际上并没有在教授任何现实世界的信息。
`BPTTIterator`
是从
`Iterator`
类继承的另一个模块,可帮助语言建模数据集,并且需要为
`t`
的每个输入从
*t + 1*
获取标签。
`t`
是时间。
`BPTTIterator`
接受输入数据的连续流和输出数据的连续流(在翻译网络的情况下,输入流和输出流可以不同,在语言建模网络的情况下,输入流和输出流可以相同)进行转换 它遵循前面描述的时间序列规则的迭代器。
`BPTTIterator`
是从
`Iterator`
类继承的另一个模块,可帮助语言建模数据集,并且需要为
`t`
的每个输入从
`t + 1`
获取标签。
`t`
是时间。
`BPTTIterator`
接受输入数据的连续流和输出数据的连续流(在翻译网络的情况下,输入流和输出流可以不同,在语言建模网络的情况下,输入流和输出流可以相同)进行转换 它遵循前面描述的时间序列规则的迭代器。
`torchtext`
还保存了开箱即用的数据集。 下面是一个示例,说明访问数据集的可用版本有多么容易:
`torchtext`
还保存了开箱即用的数据集。 下面是一个示例,说明访问数据集的可用版本有多么容易:
...
@@ -476,7 +476,7 @@ Ignite 是一种神经网络训练工具,可将某些样板代码抽象出来
...
@@ -476,7 +476,7 @@ Ignite 是一种神经网络训练工具,可将某些样板代码抽象出来
#### 引擎
#### 引擎
`Engine`
接受一个训练器函数,该函数实质上是用于训练神经网络算法的典型循环。 它包括循环遍历,循环遍历,将现有梯度值归零,使用批量调用模型,计算损失以及更新梯度。 以下示例显示了这一点,该示例取自第 2 章和
*简单神经网络*
:
`Engine`
接受一个训练器函数,该函数实质上是用于训练神经网络算法的典型循环。 它包括循环遍历,循环遍历,将现有梯度值归零,使用批量调用模型,计算损失以及更新梯度。 以下示例显示了这一点,该示例取自第 2 章和
“简单神经网络”
:
```
py
```
py
for
epoch
in
range
(
epochs
):
for
epoch
in
range
(
epochs
):
...
...
new/pt-dl-handson/4.md
浏览文件 @
ba688b35
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
CNN 是具有数十年历史的机器学习算法,直到 Geoffrey Hinton 和他的实验室提出 AlexNet 时,才证明其功能强大。 从那时起,CNN 经历了多次迭代。 现在,我们在 CNN 之上构建了一些不同的架构,这些架构为世界各地的所有计算机视觉实现提供了动力。
CNN 是具有数十年历史的机器学习算法,直到 Geoffrey Hinton 和他的实验室提出 AlexNet 时,才证明其功能强大。 从那时起,CNN 经历了多次迭代。 现在,我们在 CNN 之上构建了一些不同的架构,这些架构为世界各地的所有计算机视觉实现提供了动力。
CNN 是一种基本上由小型网络组成的网络架构,几乎类似于第 2 章,
*简单神经网络*
中引入的简单前馈网络,但用于解决图像作为输入的问题。 CNN 由神经元组成,这些神经元具有非线性,权重参数,偏差并吐出一个损耗值,基于该值,可以使用反向传播对整个网络进行重新排列。
CNN 是一种基本上由小型网络组成的网络架构,几乎类似于第 2 章,
“简单神经网络”
中引入的简单前馈网络,但用于解决图像作为输入的问题。 CNN 由神经元组成,这些神经元具有非线性,权重参数,偏差并吐出一个损耗值,基于该值,可以使用反向传播对整个网络进行重新排列。
如果这听起来像简单的全连接网络,那么 CNN 为何特别适合处理图像? CNN 让开发人员做出适用于图像的某些假设,例如像素值的空间关系。
如果这听起来像简单的全连接网络,那么 CNN 为何特别适合处理图像? CNN 让开发人员做出适用于图像的某些假设,例如像素值的空间关系。
...
@@ -24,7 +24,7 @@ CNN 由几个三维内核组成,它们像滑动窗口一样在输入张量中
...
@@ -24,7 +24,7 @@ CNN 由几个三维内核组成,它们像滑动窗口一样在输入张量中
图 4.1:不同的层显示不同的信息
图 4.1:不同的层显示不同的信息
来源:
*可视化和理解卷积网络*
,Matthew D. Zeiler 和 Rob Fergus
来源:
《可视化和理解卷积网络》
,Matthew D. Zeiler 和 Rob Fergus
由于使用了相同的内核来覆盖整个图像,因此我们正在重用内核参数,从而减少了参数数量。
由于使用了相同的内核来覆盖整个图像,因此我们正在重用内核参数,从而减少了参数数量。
...
@@ -62,7 +62,7 @@ PyTorch 为计算机视觉提供了几个便捷功能,其中包括卷积层和
...
@@ -62,7 +62,7 @@ PyTorch 为计算机视觉提供了几个便捷功能,其中包括卷积层和
我们正在开发 CNN 以执行简单的分类任务。 使用简单 CNN 的想法是为了了解 CNN 的工作原理。 弄清基础知识后,我们将转到高级网络设计,在其中使用高级 PyTorch 函数,该函数与该应用程序具有相同的功能,但效率更高。
我们正在开发 CNN 以执行简单的分类任务。 使用简单 CNN 的想法是为了了解 CNN 的工作原理。 弄清基础知识后,我们将转到高级网络设计,在其中使用高级 PyTorch 函数,该函数与该应用程序具有相同的功能,但效率更高。
我们将使用 CIFAR10 作为输入数据集,它由 10 类 60,000 张 32x32 彩色图像组成,每类 6,000 张图像。
`torchvision`
具有更高级别的功能,可下载和处理数据集。 如我们在第 3 章,
*深度学习工作流*
中看到的示例一样,我们下载数据集,然后使用转换对其进行转换,并将其包装在
`get_data()`
函数下。
我们将使用 CIFAR10 作为输入数据集,它由 10 类 60,000 张 32x32 彩色图像组成,每类 6,000 张图像。
`torchvision`
具有更高级别的功能,可下载和处理数据集。 如我们在第 3 章,
“深度学习工作流”
中看到的示例一样,我们下载数据集,然后使用转换对其进行转换,并将其包装在
`get_data()`
函数下。
```
py
```
py
def
get_data
():
def
get_data
():
...
@@ -91,7 +91,7 @@ def normalize(image, mean, std):
...
@@ -91,7 +91,7 @@ def normalize(image, mean, std):
image
[
channel
]
=
(
image
[
channel
]
-
mean
[
channel
])
/
std
[
channel
]
image
[
channel
]
=
(
image
[
channel
]
-
mean
[
channel
])
/
std
[
channel
]
```
```
`get_data()`
返回经过测试的可迭代迭代器和火车装载器。 现在数据已经准备好了,我们需要像建立
*FizB
*
*u
z*
网络时那样,设置模型,损失函数和优化器。
`get_data()`
返回经过测试的可迭代迭代器和火车装载器。 现在数据已经准备好了,我们需要像建立
*FizB
uz
z*
网络时那样,设置模型,损失函数和优化器。
##### 型号
##### 型号
...
@@ -150,7 +150,7 @@ class Conv(nn.Module):
...
@@ -150,7 +150,7 @@ class Conv(nn.Module):
图 4.3b
图 4.3b
我们通过将内核锚定在图像的左上像素开始卷积,如图
*图 4.3b*
所示。 现在,我们将图像中的每个像素值与相应的内核值相乘,然后将所有像素值相加,得到一个值。 但是我们有一个要处理的问题。 内核的顶行和左列将乘以什么? 为此,我们介绍了填充。
我们通过将内核锚定在图像的左上像素开始卷积,如图
“图 4.3b”
所示。 现在,我们将图像中的每个像素值与相应的内核值相乘,然后将所有像素值相加,得到一个值。 但是我们有一个要处理的问题。 内核的顶行和左列将乘以什么? 为此,我们介绍了填充。
我们在输入张量的外侧添加行和列,其值为零,以便内核中的所有值在输入图像中都有一个对应的值要配对。 我们从乘法中得到的单个值和加法运算是我们对该实例进行的卷积运算的输出。
我们在输入张量的外侧添加行和列,其值为零,以便内核中的所有值在输入图像中都有一个对应的值要配对。 我们从乘法中得到的单个值和加法运算是我们对该实例进行的卷积运算的输出。
...
@@ -183,9 +183,9 @@ Variable containing:
...
@@ -183,9 +183,9 @@ Variable containing:
```
```
如您所知,如果我们使用大小为
1 x 1 x
*深度*
的内核,则通过对整个图像进行卷积,将获得与输入相同大小的输出。 在 CNN 中,如果我们想减小输出的大小而与内核的大小无关,我们将使用一个不错的技巧通过跨步来对输出的大小进行下采样。 “图 4.4”显示了步幅减小对输出大小的影响。 以下公式可用于计算输出的大小以及内核的大小,填充宽度和步幅。
如您所知,如果我们使用大小为
`1 x 1 x 深度`
的内核,则通过对整个图像进行卷积,将获得与输入相同大小的输出。 在 CNN 中,如果我们想减小输出的大小而与内核的大小无关,我们将使用一个不错的技巧通过跨步来对输出的大小进行下采样。 “图 4.4”显示了步幅减小对输出大小的影响。 以下公式可用于计算输出的大小以及内核的大小,填充宽度和步幅。
*W =(WF + 2P)/ S + 1*
,其中
`W`
是输入大小,
`F`
是内核大小,
`S`
跨步应用
`P`
填充。
`W = (WF + 2P) / S + 1`
,其中
`W`
是输入大小,
`F`
是内核大小,
`S`
跨步应用
`P`
填充。
![
Model
](
img/B09475_04_05.jpg
)
![
Model
](
img/B09475_04_05.jpg
)
...
@@ -336,7 +336,7 @@ LinkNet 由一个初始块,一个最终块,一个带有四个卷积模块的
...
@@ -336,7 +336,7 @@ LinkNet 由一个初始块,一个最终块,一个带有四个卷积模块的
##### 注意
##### 注意
有关反卷积的更多信息,请参见论文
*深度学习卷积算法指南*
[5]或 GitHub 存储库[6]。
有关反卷积的更多信息,请参见论文
《深度学习卷积算法指南》
[5]或 GitHub 存储库[6]。
![
Deconvolution
](
img/B09475_04_12.jpg
)
![
Deconvolution
](
img/B09475_04_12.jpg
)
...
@@ -392,7 +392,7 @@ LinkNet 中的所有卷积都紧随其后的是批量规范化和 ReLU 层,但
...
@@ -392,7 +392,7 @@ LinkNet 中的所有卷积都紧随其后的是批量规范化和 ReLU 层,但
ε值将添加到平方根内的分母中以保持数值稳定性,而动量因子决定应从上一层获得多少动量以加快操作速度。
ε值将添加到平方根内的分母中以保持数值稳定性,而动量因子决定应从上一层获得多少动量以加快操作速度。
`__init__`
检查是否需要激活并创建层。 这是
`torch.nn.Sequential`
有用的地方。 将三个不同的层(卷积,批量规范化和 ReLU)定义为单个
`ConvBlock`
层的明显方法是为所有三个层创建 Python 属性,并将第一层的输出传递给第二层,然后将该输出传递给第三层 in。但是使用
`nn.Sequential`
,我们可以将它们链接在一起并创建一个 Python 属性。 这样做的缺点是,随着网络的增长,您将为所有小模块提供额外的
`Sequential`
包装器,这将使解释网络图变得困难。 存储库中的可用代码(带有
`nn.Sequential`
包装器)将生成类似
*的图形,如图 4.10a*
一样,而没有使用
`Sequential`
包装器构建的层将生成类似
*的图形,如图 4.10b 所示。*
。
`__init__`
检查是否需要激活并创建层。 这是
`torch.nn.Sequential`
有用的地方。 将三个不同的层(卷积,批量规范化和 ReLU)定义为单个
`ConvBlock`
层的明显方法是为所有三个层创建 Python 属性,并将第一层的输出传递给第二层,然后将该输出传递给第三层 in。但是使用
`nn.Sequential`
,我们可以将它们链接在一起并创建一个 Python 属性。 这样做的缺点是,随着网络的增长,您将为所有小模块提供额外的
`Sequential`
包装器,这将使解释网络图变得困难。 存储库中的可用代码(带有
`nn.Sequential`
包装器)将生成类似
“图 4.10a”的图形,而没有使用
`Sequential`
包装器构建的层将生成类似“图 4.10b”的图形
。
```
py
```
py
class
ConvBlockWithoutSequential
(
nn
.
Module
):
class
ConvBlockWithoutSequential
(
nn
.
Module
):
...
...
new/pt-dl-handson/8.md
浏览文件 @
ba688b35
...
@@ -12,7 +12,7 @@ ONNX 很棒,并且每个人都喜欢它,但是 ONNX 的主要缺点之一是
...
@@ -12,7 +12,7 @@ ONNX 很棒,并且每个人都喜欢它,但是 ONNX 的主要缺点之一是
接下来是 TorchScript 的引入,它可以将本机 Python 模型转换为可以在高性能 Universe 中加载的序列化形式,例如 C ++线程。 PyTorch 的后端 LibTorch 可以读取 TorchScript,这使 PyTorch 高效。 有了它,开发人员可以对模型进行原型设计,甚至可以使用 Python 本身对其进行训练。 训练后,可以将模型转换为到
**中间表示**
(
**IR**
)。 目前,仅开发了 C ++后端,因此可以将 IR 作为 C ++对象加载,然后可以从 PyTorch 的 C ++ API 中读取。 TorchScript 甚至可以在 Python 程序中转换控制流,这在生产支持的情况下使其优于 ONNX 方法。 TorchScript 本身是 Python 语言中可能的操作的子集,因此不允许任何 Python 操作用 TorchScript 编写。 官方文档本身提供了非常详细的说明,并讨论了可能的情况和不可能的情况,以及许多示例[1]。
接下来是 TorchScript 的引入,它可以将本机 Python 模型转换为可以在高性能 Universe 中加载的序列化形式,例如 C ++线程。 PyTorch 的后端 LibTorch 可以读取 TorchScript,这使 PyTorch 高效。 有了它,开发人员可以对模型进行原型设计,甚至可以使用 Python 本身对其进行训练。 训练后,可以将模型转换为到
**中间表示**
(
**IR**
)。 目前,仅开发了 C ++后端,因此可以将 IR 作为 C ++对象加载,然后可以从 PyTorch 的 C ++ API 中读取。 TorchScript 甚至可以在 Python 程序中转换控制流,这在生产支持的情况下使其优于 ONNX 方法。 TorchScript 本身是 Python 语言中可能的操作的子集,因此不允许任何 Python 操作用 TorchScript 编写。 官方文档本身提供了非常详细的说明,并讨论了可能的情况和不可能的情况,以及许多示例[1]。
在本章中,我们将从使用 Flask(流行的 Python Web 框架)提供普通的 Python PyTorch 模型开始。 这样的设置通常就足够了,特别是如果您要设置示例 Web 应用程序或满足您个人需求或类似用例的东西。 然后,我们将探索 ONNX 并将 PyTorch 模型转换为 MXNet,然后可以使用 MXNet 模型服务器提供服务。 从那里,我们将转到 TorchScript,这是 PyTorch 街区的新孩子。 使用 TorchScript,我们将制作 C ++可执行文件,然后可以在 LibTorch 的帮助下从 C ++执行该可执行文件。 然后,可以从稳定,高性能的 C ++服务器甚至使用 cgo 的 Go 服务器提供高效的 C ++可执行文件。 对于所有份量,我们将使用在第 2 章,
*简单神经网络*
中构建的 fizzbuzz 网络。
在本章中,我们将从使用 Flask(流行的 Python Web 框架)提供普通的 Python PyTorch 模型开始。 这样的设置通常就足够了,特别是如果您要设置示例 Web 应用程序或满足您个人需求或类似用例的东西。 然后,我们将探索 ONNX 并将 PyTorch 模型转换为 MXNet,然后可以使用 MXNet 模型服务器提供服务。 从那里,我们将转到 TorchScript,这是 PyTorch 街区的新孩子。 使用 TorchScript,我们将制作 C ++可执行文件,然后可以在 LibTorch 的帮助下从 C ++执行该可执行文件。 然后,可以从稳定,高性能的 C ++服务器甚至使用 cgo 的 Go 服务器提供高效的 C ++可执行文件。 对于所有份量,我们将使用在第 2 章,
“简单神经网络”
中构建的 fizzbuzz 网络。
## 与烧瓶一起食用
## 与烧瓶一起食用
...
@@ -72,7 +72,7 @@ flask run
...
@@ -72,7 +72,7 @@ flask run
```
```
我们已经建立了简单的 Flask 应用程序。 现在,将 fizzbuzz 模型引入我们的应用程序。 以下代码片段显示了与第 2 章和
*简单神经网络*
相同的模型,供您参考。 该模型将从路由器功能中调用。 我们已经在第 2 章和“一个简单的神经网络”中对模型进行了训练,因此,我们将在这里加载训练后的模型,而不是再次对其进行训练:
我们已经建立了简单的 Flask 应用程序。 现在,将 fizzbuzz 模型引入我们的应用程序。 以下代码片段显示了与第 2 章和
“简单神经网络”
相同的模型,供您参考。 该模型将从路由器功能中调用。 我们已经在第 2 章和“一个简单的神经网络”中对模型进行了训练,因此,我们将在这里加载训练后的模型,而不是再次对其进行训练:
```
py
```
py
import
torch.nn
as
nn
import
torch.nn
as
nn
...
@@ -154,7 +154,7 @@ Flask 为我们提供了`request`实用程序,它是一个全局变量,但
...
@@ -154,7 +154,7 @@ Flask 为我们提供了`request`实用程序,它是一个全局变量,但
在 HTTP
`POST`
请求中,我们传递了输入数字为
`14`
的 JSON 对象,我们的服务器返回了下一个数字
`FizBuz`
。 所有这些魔术都发生在我们的
`app.py`
调用的
`controller.run()`
方法中。 现在,让我们看看该函数在做什么。
在 HTTP
`POST`
请求中,我们传递了输入数字为
`14`
的 JSON 对象,我们的服务器返回了下一个数字
`FizBuz`
。 所有这些魔术都发生在我们的
`app.py`
调用的
`controller.run()`
方法中。 现在,让我们看看该函数在做什么。
接下来是使用
`run()`
方法的
`controller`
文件。 在这里,我们将输入数字转换为 10 位二进制数(请记住,这是我们作为输入传递给第 2 章,
*简单神经网络*
的 fizzbuzz 网络)的函数 火炬张量。 然后将二进制张量传递给我们模型的正向函数,以得到具有预测的 1 x 4 张量。
接下来是使用
`run()`
方法的
`controller`
文件。 在这里,我们将输入数字转换为 10 位二进制数(请记住,这是我们作为输入传递给第 2 章,
“简单神经网络”
的 fizzbuzz 网络)的函数 火炬张量。 然后将二进制张量传递给我们模型的正向函数,以得到具有预测的 1 x 4 张量。
通过从加载了保存的
`.pth`
文件的模型文件中调用
`FizBuz`
类来创建我们的模型。 我们使用 Torch 的
`load_state_dict`
方法将参数加载到初始化的模型中。 之后,我们将模型转换为
`eval()`
模式,这将模型设置为评估模式(它在评估模式下关闭了 batchnorm 丢弃层)。 模型的输出是运行
`max`
并确定哪个索引具有最大值,然后将其转换为可读输出的概率分布。
通过从加载了保存的
`.pth`
文件的模型文件中调用
`FizBuz`
类来创建我们的模型。 我们使用 Torch 的
`load_state_dict`
方法将参数加载到初始化的模型中。 之后,我们将模型转换为
`eval()`
模式,这将模型设置为评估模式(它在评估模式下关闭了 batchnorm 丢弃层)。 模型的输出是运行
`max`
并确定哪个索引具有最大值,然后将其转换为可读输出的概率分布。
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录