PyTorch 深度学习(GPT 重译)(一)(1)https://developer.aliyun.com/article/1485198
2.1.5 运行!
在深度学习领域,对新数据运行经过训练的模型的过程称为推断。为了进行推断,我们需要将网络设置为eval
模式:
# In[11]: resnet.eval() # Out[11]: ResNet( (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False) (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace) (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False) (layer1): Sequential( (0): Bottleneck( ... ) ) (avgpool): AvgPool2d(kernel_size=7, stride=1, padding=0) (fc): Linear(in_features=2048, out_features=1000, bias=True) )
如果我们忘记这样做,一些预训练模型,如批量归一化和丢弃,将不会产生有意义的答案,这仅仅是因为它们内部的工作方式。现在eval
已经设置好,我们准备进行推断:
# In[12]: out = resnet(batch_t) out # Out[12]: tensor([[ -3.4803, -1.6618, -2.4515, -3.2662, -3.2466, -1.3611, -2.0465, -2.5112, -1.3043, -2.8900, -1.6862, -1.3055, ... 2.8674, -3.7442, 1.5085, -3.2500, -2.4894, -0.3354, 0.1286, -1.1355, 3.3969, 4.4584]])
一个涉及 4450 万参数的惊人操作集刚刚发生,产生了一个包含 1,000 个分数的向量,每个分数对应一个 ImageNet 类别。这没花多少时间,是吧?
现在我们需要找出获得最高分数的类别的标签。这将告诉我们模型在图像中看到了什么。如果标签与人类描述图像的方式相匹配,那太棒了!这意味着一切正常。如果不匹配,那么要么在训练过程中出了问题,要么图像与模型期望的差异太大,模型无法正确处理,或者存在其他类似问题。
要查看预测标签列表,我们将加载一个文本文件,列出标签的顺序与网络在训练期间呈现给网络的顺序相同,然后我们将挑选出网络产生的最高分数的索引处的标签。几乎所有用于图像识别的模型的输出形式与我们即将处理的形式类似。
让我们加载包含 ImageNet 数据集类别的 1,000 个标签的文件:
# In[13]: with open('../data/p1ch2/imagenet_classes.txt') as f: labels = [line.strip() for line in f.readlines()]
在这一点上,我们需要确定out
张量中对应最高分数的索引。我们可以使用 PyTorch 中的max
函数来做到这一点,该函数输出张量中的最大值以及发生最大值的索引:
# In[14]: _, index = torch.max(out, 1)
现在我们可以使用索引来访问标签。这里,index
不是一个普通的 Python 数字,而是一个单元素、一维张量(具体来说,tensor([207])
),所以我们需要获取实际的数值以用作索引进入我们的labels
列表,使用index[0]
。我们还使用torch.nn.functional.softmax
(mng.bz/BYnq
) 来将我们的输出归一化到范围[0, 1],并除以总和。这给了我们大致类似于模型对其预测的信心。在这种情况下,模型有 96%的把握知道它正在看的是一只金毛寻回犬:
# In[15]: percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100 labels[index[0]], percentage[index[0]].item() # Out[15]: ('golden retriever', 96.29334259033203)
哦哦,谁是个好孩子?
由于模型生成了分数,我们还可以找出第二、第三等等最好的是什么。为此,我们可以使用sort
函数,它可以将值按升序或降序排序,并在原始数组中提供排序后值的索引:
# In[16]: _, indices = torch.sort(out, descending=True) [(labels[idx], percentage[idx].item()) for idx in indices[0][:5]] # Out[16]: [('golden retriever', 96.29334259033203), ('Labrador retriever', 2.80812406539917), ('cocker spaniel, English cocker spaniel, cocker', 0.28267428278923035), ('redbone', 0.2086310237646103), ('tennis ball', 0.11621569097042084)]
我们看到前四个是狗(红骨是一种品种;谁知道?),之后事情开始变得有趣起来。第五个答案“网球”可能是因为有足够多的狗旁边有网球的图片,以至于模型基本上在说:“我有 0.1%的机会完全误解了什么是网球。”这是人类和神经网络在看待世界的根本差异的一个很好的例子,以及奇怪、微妙的偏见如何很容易潜入我们的数据中。
玩耍的时候到了!我们可以继续用随机图像询问我们的网络,看看它会得出什么结果。网络的成功程度很大程度上取决于主题在训练集中是否得到很好的代表。如果我们呈现一个包含训练集之外主题的图像,网络很可能会以相当高的信心给出错误答案。实验和了解模型对未见数据的反应是很有用的。
我们刚刚运行了一个在 2015 年赢得图像分类比赛的网络。它学会了从狗的例子中识别我们的狗,以及许多其他真实世界的主题。现在我们将看看不同的架构如何实现其他类型的任务,从图像生成开始。
2.2 一个假装到成功的预训练模型
让我们假设一下,我们是职业罪犯,想要开始销售著名艺术家的“失落”画作的赝品。我们是罪犯,不是画家,所以当我们绘制我们的假雷姆布兰特和毕加索时,很快就会显而易见它们是业余的模仿品而不是真品。即使我们花了很多时间练习,直到我们也无法分辨出画作是假的,试图在当地艺术拍卖行兜售也会立即被赶出去。更糟糕的是,被告知“这显然是假的;滚出去”,并不能帮助我们改进!我们将不得不随机尝试很多事情,评估哪些需要稍微长一点时间才能识别为赝品,并在未来的尝试中强调这些特征,这将花费太长时间。
相反,我们需要找到一个道德标准有问题的艺术史学家来检查我们的作品,并告诉我们究竟是什么让他们发现这幅画不真实。有了这个反馈,我们可以以明确、有针对性的方式改进我们的作品,直到我们的可疑学者再也无法将我们的画作与真品区分开来。
很快,我们的“波提切利”将在卢浮宫展出,他们的百元钞票将进入我们的口袋。我们会变得富有!
尽管这种情景有点荒谬,但其基础技术是可靠的,并且很可能会对未来几年数字数据的真实性产生深远影响。整个“照片证据”的概念很可能会变得完全可疑,因为制作令人信服但虚假的图像和视频将变得非常容易。唯一的关键因素是数据。让我们看看这个过程是如何运作的。
2.2.1 GAN 游戏
在深度学习的背景下,我们刚刚描述的被称为GAN 游戏,其中两个网络,一个充当画家,另一个充当艺术史学家,竞争着互相愚弄,创造和检测伪造品。GAN 代表生成对抗网络,其中生成表示正在创建某物(在本例中是假的杰作),对抗表示两个网络正在竞争愚弄对方,而网络显而易见。这些网络是最近深度学习研究的最原创的成果之一。
请记住,我们的总体目标是生成一类图像的合成示例,这些示例无法被识别为伪造品。当与合法示例混合在一起时,一个熟练的检查员会很难确定哪些是真实的,哪些是我们的伪造品。
生成器网络在我们的场景中扮演画家的角色,负责从任意输入开始生成逼真的图像。鉴别器网络是无情的艺术检查员,需要判断给定的图像是由生成器制作还是属于真实图像集。这种双网络设计对于大多数深度学习架构来说是非典型的,但是,当用于实现 GAN 游戏时,可以产生令人难以置信的结果。
图 2.5 GAN 游戏的概念
图 2.5 展示了大致的情况。生成器的最终目标是欺骗鉴别器,混淆真实和虚假图像。鉴别器的最终目标是发现自己被欺骗,但它也帮助生成器找出生成图像中的可识别错误。在开始阶段,生成器产生混乱的三眼怪物,看起来一点也不像伦勃朗的肖像画。鉴别器很容易区分混乱的混乱图像和真实的绘画作品。随着训练的进行,信息从鉴别器返回,生成器利用这些信息进行改进。训练结束时,生成器能够产生令人信服的伪造品,鉴别器不再能分辨哪个是真实的。
请注意,“鉴别器获胜”或“生成器获胜”不应被字面意义上解释–两者之间没有明确的比赛。然而,两个网络都是基于另一个网络的结果进行训练的,这推动了每个网络参数的优化。
这种技术已经被证明能够导致生成器从仅有噪音和一个条件信号(比如,对于人脸:年轻、女性、戴眼镜)生成逼真图像,换句话说,一个训练良好的生成器学会了一个可信的模型,即使被人类检查也看起来很真实。
2.2.2 CycleGAN
这个概念的一个有趣演变是 CycleGAN。CycleGAN 可以将一个域的图像转换为另一个域的图像(反之亦然),而无需我们在训练集中明确提供匹配对。
在图 2.6 中,我们有一个 CycleGAN 工作流程,用于将一匹马的照片转换为斑马,反之亦然。请注意,有两个独立的生成器网络,以及两个不同的鉴别器。
图 2.6 一个 CycleGAN 训练到可以愚弄两个鉴别器网络的程度
如图所示,第一个生成器学会生成符合目标分布(在这种情况下是斑马)的图像,从属于不同分布(马)的图像开始,以便鉴别器无法判断从马照片生成的图像是否真的是斑马的真实图片。同时–这就是缩写中Cycle前缀的含义–生成的假斑马被发送到另一个生成器,沿着另一条路(在我们的情况下是从斑马到马),由另一个鉴别器进行判断。创建这样一个循环显著稳定了训练过程,解决了 GAN 的一个最初问题。
有趣的是,在这一点上,我们不需要匹配的马/斑马对作为地面真相(祝你好运,让它们匹配姿势!)。从一组不相关的马图片和斑马照片开始对生成器进行训练就足够了,超越了纯粹监督的设置。这个模型的影响甚至超出了这个范围:生成器学会了如何有选择性地改变场景中物体的外观,而不需要关于什么是什么的监督。没有信号表明鬃毛是鬃毛,腿是腿,但它们被转换成与另一种动物的解剖学相一致的东西。
2.2.3 将马变成斑马的网络
我们现在可以玩这个模型。CycleGAN 网络已经在从 ImageNet 数据集中提取的(不相关的)马图片和斑马图片数据集上进行了训练。网络学会了将一张或多张马的图片转换成斑马,尽可能保持其余部分的图像不变。虽然人类在过去几千年里并没有为将马变成斑马的工具而屏住呼吸,但这个任务展示了这些架构模拟复杂现实世界过程的能力,远程监督。虽然它们有局限性,但有迹象表明,在不久的将来,我们将无法在实时视频中区分真实和虚假,这打开了一个我们将立即关闭的潘多拉魔盒。
玩一个预训练的 CycleGAN 将给我们一个机会,更近距离地看一看网络–在这种情况下是一个生成器–是如何实现的。我们将使用我们的老朋友 ResNet。我们将在屏幕外定义一个ResNetGenerator
类。代码在 3_cyclegan.ipynb 文件的第一个单元格中,但实现目前并不相关,而且在我们获得更多 PyTorch 经验之前,它太复杂了。现在,我们专注于它能做什么,而不是它是如何做到的。让我们用默认参数实例化这个类(code/p1ch2/3_cyclegan.ipynb):
# In[2]: netG = ResNetGenerator()
netG
模型已经创建,但它包含随机权重。我们之前提到过,我们将运行一个在 horse2zebra 数据集上预训练的生成器模型,该数据集的训练集包含 1068 张马和 1335 张斑马的图片。数据集可以在mng.bz/8pKP
找到。模型的权重已保存在.pth 文件中,这只是模型张量参数的pickle
文件。我们可以使用模型的load_state_dict
方法将它们加载到ResNetGenerator
中:
# In[3]: model_path = '../data/p1ch2/horse2zebra_0.4.0.pth' model_data = torch.load(model_path) netG.load_state_dict(model_data)
此时,netG
已经获得了在训练过程中获得的所有知识。请注意,这与我们在第 2.1.3 节中从torchvision
中加载resnet101
时发生的情况完全相同;但torchvision.resnet101
函数将加载过程隐藏了起来。
让我们将网络设置为eval
模式,就像我们为resnet101
所做的那样:
# In[4]: netG.eval() # Out[4]: ResNetGenerator( (model): Sequential( ... ) )
像之前打印模型一样,我们可以欣赏到它实际上相当简洁,考虑到它的功能。它接收一幅图像,通过查看像素识别出一匹或多匹马,并单独修改这些像素的值,使得输出看起来像一匹可信的斑马。我们在打印输出中(或者源代码中)不会认出任何类似斑马的东西:那是因为里面没有任何类似斑马的东西。这个网络是一个脚手架–关键在于权重。
我们准备加载一张随机的马的图像,看看我们的生成器会产生什么。首先,我们需要导入PIL
和torchvision
:
# In[5]: from PIL import Image from torchvision import transforms
然后我们定义一些输入转换,以确保数据以正确的形状和大小进入网络:
# In[6]: preprocess = transforms.Compose([transforms.Resize(256), transforms.ToTensor()])
让我们打开一个马文件(见图 2.7):
图 2.7 一个骑马的人。马似乎不太乐意。
# In[7]: img = Image.open("../data/p1ch2/horse.jpg") img
好吧,有个家伙骑在马上。(看图片的话,可能不会持续太久。)不管怎样,让我们通过预处理并将其转换为正确形状的变量:
# In[8]: img_t = preprocess(img) batch_t = torch.unsqueeze(img_t, 0)
我们现在不必担心细节。重要的是我们要保持距离跟随。此时,batch_t
可以被发送到我们的模型:
# In[9]: batch_out = netG(batch_t)
batch_out
现在是生成器的输出,我们可以将其转换回图像:
# In[10]: out_t = (batch_out.data.squeeze() + 1.0) / 2.0 out_img = transforms.ToPILImage()(out_t) # out_img.save('../data/p1ch2/zebra.jpg') out_img # Out[10]: <PIL.Image.Image image mode=RGB size=316x256 at 0x23B24634F98>
哦,天啊。谁像那样骑斑马呢?结果图像(图 2.8)并不完美,但请考虑到网络发现有人(某种程度上)骑在马上有点不寻常。需要重申的是,学习过程并没有经过直接监督,人类没有勾勒出成千上万匹马或手动 Photoshop 成千上万条斑马条纹。生成器已经学会生成一幅图像,可以愚弄鉴别器,让它认为那是一匹斑马,而图像并没有什么奇怪之处(显然鉴别器从未去过竞技场)。
图 2.8 一个骑斑马的人。斑马似乎不太乐意。
许多其他有趣的生成器是使用对抗训练或其他方法开发的。其中一些能够创建出可信的不存在个体的人脸;其他一些可以将草图转换为看起来真实的虚构景观图片。生成模型也被用于产生听起来真实的音频、可信的文本和令人愉悦的音乐。这些模型很可能将成为未来支持创造过程的工具的基础。
说真的,这种工作的影响难以言表。像我们刚刚下载的这种工具只会变得更加高质量和更加普遍。特别是换脸技术已经引起了相当多的媒体关注。搜索“deep fakes”会出现大量示例内容¹(尽管我们必须指出有相当数量的不适宜工作场所的内容被标记为这样;就像互联网上的一切一样,要小心点击)。
到目前为止,我们有机会玩弄一个能看到图像的模型和一个能生成新图像的模型。我们将以一个涉及另一个基本要素的模型结束我们的旅程:自然语言。
2.3 描述场景的预训练网络
为了亲身体验涉及自然语言的模型,我们将使用一个由 Ruotian Luo 慷慨提供的预训练图像字幕模型。这是 Andrej Karpathy 的 NeuralTalk2 模型的一个实现。当呈现一幅自然图像时,这种模型会生成一个用英语描述场景的字幕,如图 2.9 所示。该模型是在大量图像数据集上训练的,配有一对句子描述:例如,“一只虎斑猫斜靠在木桌上,一只爪子放在激光鼠标上,另一只放在黑色笔记本电脑上。”³
图 2.9 字幕模型的概念
这个字幕模型有两个连接的部分。模型的第一部分是一个网络,学习生成场景的“描述性”数值表示(Tabby 猫,激光鼠标,爪子),然后将这些数值描述作为第二部分的输入。第二部分是一个循环神经网络,通过将这些数值描述组合在一起生成连贯的句子。模型的两个部分一起在图像-字幕对上进行训练。
模型的后半部分被称为循环,因为它在后续的前向传递中生成其输出(单词),其中每个前向传递的输入包括前一个前向传递的输出。这使得下一个单词依赖于先前生成的单词,这是我们在处理句子或一般序列时所期望的。
2.3.1 神经对话 2
神经对话 2 模型可以在github.com/deep-learning-with-pytorch/ImageCaptioning.pytorch
找到。我们可以将一组图像放在data
目录中,并运行以下脚本:
python eval.py --model ./data/FC/fc-model.pth--infos_path ./data/FC/fc-infos.pkl --image_folder ./data
让我们尝试使用我们的 horse.jpg 图像。它说:“一个人骑着马在海滩上。”非常合适。
现在,就只是为了好玩,让我们看看我们的 CycleGAN 是否也能愚弄这个神经对话 2 模型。让我们在数据文件夹中添加 zebra.jpg 图像并重新运行模型:“一群斑马站在田野上。”嗯,它正确地识别了动物,但它在图像中看到了不止一只斑马。显然,这不是网络曾经见过斑马的姿势,也没有见过斑马上有骑手(带有一些虚假的斑马图案)。此外,斑马很可能是以群体形式出现在训练数据集中,因此我们可能需要调查一些偏见。字幕网络也没有描述骑手。同样,这可能是同样的原因:网络在训练数据集中没有看到骑手骑在斑马上。无论如何,这是一个令人印象深刻的壮举:我们生成了一张带有不可能情景的假图像,而字幕网络足够灵活,能够正确地捕捉主题。
我们想强调的是,像这样的东西,在深度学习出现之前是极其难以实现的,现在可以用不到一千行代码,使用一个不知道关于马或斑马的通用架构,以及一组图像和它们的描述(在这种情况下是 MS COCO 数据集)来获得。没有硬编码的标准或语法–一切,包括句子,都是从数据中的模式中产生的。
在这种情况下,网络架构在某种程度上比我们之前看到的更复杂,因为它包括两个网络。其中一个是循环的,但是它是由 PyTorch 提供的相同构建块构建的。
在撰写本文时,这样的模型更多地存在于应用研究或新颖项目中,而不是具有明确定义的具体用途。尽管结果令人鼓舞,但还不足以使用…至少现在还不足够。随着时间的推移(和额外的训练数据),我们应该期望这类模型能够向视觉受损的人描述世界,从视频中转录场景,以及执行其他类似的任务。
2.4 Torch Hub
从深度学习的早期就开始发布预训练模型,但直到 PyTorch 1.0,没有办法确保用户可以获得统一的接口来获取它们。TorchVision 是一个良好的接口示例,正如我们在本章前面看到的那样;但其他作者,正如我们在 CycleGAN 和神经对话 2 中看到的那样,选择了不同的设计。
PyTorch 1.0 引入了 Torch Hub,这是一个机制,通过该机制,作者可以在 GitHub 上发布一个模型,带有或不带有预训练权重,并通过 PyTorch 理解的接口公开它。这使得从第三方加载预训练模型就像加载 TorchVision 模型一样简单。
作者通过 Torch Hub 机制发布模型所需的全部工作就是在 GitHub 存储库的根目录中放置一个名为 hubconf.py 的文件。该文件具有非常简单的结构:
dependencies = ['torch', 'math'] # ❶ def some_entry_fn(*args, **kwargs): # ❷ model = build_some_model(*args, **kwargs) return model def another_entry_fn(*args, **kwargs): model = build_another_model(*args, **kwargs) return model
❶ 代码依赖的可选模块列表
❷ 一个或多个要向用户公开作为存储库入口点的函数。这些函数应根据参数初始化模型并返回它们
在我们寻找有趣的预训练模型的过程中,现在我们可以搜索包含 hubconf.py 的 GitHub 存储库,我们会立即知道可以使用 torch.hub 模块加载它们。让我们看看实际操作是如何进行的。为此,我们将回到 TorchVision,因为它提供了一个清晰的示例,展示了如何与 Torch Hub 交互。
让我们访问github.com/pytorch/vision
,注意其中包含一个 hubconf.py 文件。很好,检查通过。首先要做的事情是查看该文件,看看存储库的入口点–我们稍后需要指定它们。在 TorchVision 的情况下,有两个:resnet18
和resnet50
。我们已经知道这些是做什么的:它们分别返回一个 18 层和一个 50 层的 ResNet 模型。我们还看到入口点函数包括一个pretrained
关键字参数。如果为True
,返回的模型将使用从 ImageNet 学习到的权重进行初始化,就像我们在本章前面看到的那样。
现在我们知道存储库、入口点和一个有趣的关键字参数。这就是我们加载模型所需的全部内容,使用 torch.hub,甚至无需克隆存储库。没错,PyTorch 会为我们处理:
import torch from torch import hub resnet18_model = hub.load('pytorch/vision:master', # ❶ 'resnet18', # ❷ pretrained=True) # ❸
❶ GitHub 存储库的名称和分支
❷ 入口点函数的名称
❸ 关键字参数
这将下载 pytorch/vision 存储库的主分支的快照,以及权重,到本地目录(默认为我们主目录中的.torch/hub),并运行resnet18
入口点函数,返回实例化的模型。根据环境的不同,Python 可能会抱怨缺少模块,比如PIL
。Torch Hub 不会安装缺少的依赖项,但会向我们报告,以便我们采取行动。
此时,我们可以使用适当的参数调用返回的模型,在其上运行前向传递,就像我们之前做的那样。好处在于,现在通过这种机制发布的每个模型都将以相同的方式对我们可用,远远超出视觉领域。
请注意,入口点应该返回模型;但严格来说,它们并不一定要这样做。例如,我们可以有一个用于转换输入的入口点,另一个用于将输出概率转换为文本标签。或者我们可以有一个仅包含模型的入口点,另一个包含模型以及预处理和后处理步骤。通过保持这些选项开放,PyTorch 开发人员为社区提供了足够的标准化和很大的灵活性。我们将看到从这个机会中会出现什么样的模式。
在撰写本文时,Torch Hub 还很新,只有少数模型是以这种方式发布的。我们可以通过谷歌搜索“github.com hubconf.py”来找到它们。希望在未来列表会增长,因为更多作者通过这个渠道分享他们的模型。
2.5 结论
希望这是一个有趣的章节。我们花了一些时间玩弄用 PyTorch 创建的模型,这些模型经过优化,可以执行特定任务。事实上,我们中更有进取心的人已经可以将其中一个模型放在 Web 服务器后面,并开始一项业务,与原始作者分享利润!一旦我们了解了这些模型是如何构建的,我们还将能够利用在这里获得的知识下载一个预训练模型,并快速对稍有不同的任务进行微调。
我们还将看到如何使用相同的构建块构建处理不同问题和不同类型数据的模型。PyTorch 做得特别好的一件事是以基本工具集的形式提供这些构建块–从 API 的角度来看,PyTorch 并不是一个非常庞大的库,特别是与其他深度学习框架相比。
本书不专注于完整地介绍 PyTorch API 或审查深度学习架构;相反,我们将建立对这些构建块的实践知识。这样,您将能够在坚实的基础上消化优秀的在线文档和存储库。
从下一章开始,我们将踏上一段旅程,使我们能够从头开始教授计算机技能,使用 PyTorch。我们还将了解,从预训练网络开始,并在新数据上进行微调,而不是从头开始,是解决问题的有效方法,特别是当我们拥有的数据点并不是特别多时。这是预训练网络是深度学习从业者必备的重要工具的另一个原因。是时候了解第一个基本构建块了:张量。
2.6 练习
- 将金毛猎犬的图像输入到马到斑马模型中。
- 你需要对图像进行哪些处理?
- 输出是什么样的?
- 在 GitHub 上搜索提供 hubconf.py 文件的项目。
- 返回了多少个存储库?
- 找一个带有 hubconf.py 的看起来有趣的项目。你能从文档中理解项目的目的吗?
- 收藏这个项目,在完成本书后回来。你能理解实现吗?
2.7 总结
- 预训练网络是已经在数据集上训练过的模型。这样的网络通常在加载网络参数后可以立即产生有用的结果。
- 通过了解如何使用预训练模型,我们可以将神经网络集成到项目中,而无需设计或训练它。
- AlexNet 和 ResNet 是两个深度卷积网络,在它们发布的年份为图像识别设立了新的基准。
- 生成对抗网络(GANs)有两部分–生成器和判别器–它们共同工作以产生与真实物品无法区分的输出。
- CycleGAN 使用一种支持在两种不同类别的图像之间进行转换的架构。
- NeuralTalk2 使用混合模型架构来消耗图像并生成图像的文本描述。
- Torch Hub 是一种标准化的方式,可以从具有适当的 hubconf.py 文件的任何项目中加载模型和权重。
¹Vox 文章“乔丹·皮尔模拟奥巴马公益广告是对假新闻的双刃警告”中描述了一个相关例子,作者是阿贾·罗曼诺;mng.bz/dxBz (警告:粗俗语言
.
² 我们在github.com/deep-learning-with-pytorch/ImageCaptioning .pytorch
上维护代码的克隆。
³Andrej Karpathy 和 Li Fei-Fei,“用于生成图像描述的深度视觉语义对齐”,cs.stanford.edu/people/karpathy/cvpr2015.pdf
.
⁴ 联系出版商了解特许经营机会!
三、始于张量
本章涵盖
- 理解张量,PyTorch 中的基本数据结构
- 张量的索引和操作
- 与 NumPy 多维数组的互操作
- 将计算迁移到 GPU 以提高速度
在上一章中,我们参观了深度学习所能实现的许多应用。它们无一例外地包括将某种形式的数据(如图像或文本)转换为另一种形式的数据(如标签、数字或更多图像或文本)。从这个角度来看,深度学习实际上是构建一个能够将数据从一种表示转换为另一种表示的系统。这种转换是通过从一系列示例中提取所需映射的共同点来驱动的。例如,系统可能注意到狗的一般形状和金毛寻回犬的典型颜色。通过结合这两个图像属性,系统可以正确地将具有特定形状和颜色的图像映射到金毛寻回犬标签,而不是黑色实验室(或者一只黄褐色的公猫)。最终的系统可以处理数量相似的输入并为这些输入产生有意义的输出。
这个过程始于将我们的输入转换为浮点数。我们将在第四章中涵盖将图像像素转换为数字的过程,正如我们在图 3.1 的第一步中所看到的那样(以及许多其他类型的数据)。但在我们开始之前,在本章中,我们将学习如何通过张量在 PyTorch 中处理所有浮点数。
3.1 世界是由浮点数构成的
由于浮点数是网络处理信息的方式,我们需要一种方法将我们想要处理的现有世界数据编码为网络可以理解的内容,然后将输出解码回我们可以理解并用于我们目的的内容。
图 3.1 一个深度神经网络学习如何将输入表示转换为输出表示。(注意:神经元和输出的数量不是按比例缩放的。)
深度神经网络通常通过阶段性地学习从一种数据形式到另一种数据形式的转换来进行学习,这意味着每个阶段之间部分转换的数据可以被视为一系列中间表示。对于图像识别,早期的表示可以是边缘检测或某些纹理,如毛皮。更深层次的表示可以捕捉更复杂的结构,如耳朵、鼻子或眼睛。
一般来说,这种中间表示是描述输入并以对描述输入如何映射到神经网络输出至关重要的方式捕捉数据结构的一组浮点数。这种描述是针对手头的任务具体的,并且是从相关示例中学习的。这些浮点数集合及其操作是现代人工智能的核心–我们将在本书中看到几个这样的例子。
需要记住这些中间表示(如图 3.1 的第二步所示)是将输入与前一层神经元的权重相结合的结果。每个中间表示对应于其前面的输入是独一无二的。
在我们开始将数据转换为浮点输入的过程之前,我们必须首先对 PyTorch 如何处理和存储数据–作为输入、中间表示和输出有一个扎实的理解。本章将专门讨论这一点。
为此,PyTorch 引入了一种基本数据结构:张量。我们在第二章中已经遇到了张量,当我们对预训练网络进行推断时。对于那些来自数学、物理或工程领域的人来说,张量这个术语通常与空间、参考系统和它们之间的变换捆绑在一起。在深度学习的背景下,张量是将向量和矩阵推广到任意维数的概念,正如我们在图 3.2 中所看到的。同一概念的另一个名称是多维数组。张量的维数与用于引用张量内标量值的索引数量相一致。
图 3.2 张量是 PyTorch 中表示数据的基本构件。
PyTorch 并不是唯一处理多维数组的库。NumPy 是迄今为止最流行的多维数组库,以至于现在可以说它已经成为数据科学的通用语言。PyTorch 与 NumPy 具有无缝互操作性,这带来了与 Python 中其他科学库的一流集成,如 SciPy (www.scipy.org)、Scikit-learn (scikit-learn.org
)和 Pandas (pandas.pydata.org
)。
与 NumPy 数组相比,PyTorch 张量具有一些超能力,比如能够在图形处理单元(GPU)上执行非常快速的操作,将操作分布在多个设备或机器上,并跟踪创建它们的计算图。这些都是在实现现代深度学习库时的重要特性。
我们将通过介绍 PyTorch 张量来开始本章,涵盖基础知识,以便为本书其余部分的工作做好准备。首先,我们将学习如何使用 PyTorch 张量库来操作张量。这包括数据在内存中的存储方式,如何在常数时间内对任意大的张量执行某些操作,以及前面提到的 NumPy 互操作性和 GPU 加速。如果我们希望张量成为编程工具箱中的首选工具,那么理解张量的能力和 API 是很重要的。在下一章中,我们将把这些知识应用到实践中,并学习如何以一种能够利用神经网络进行学习的方式表示多种不同类型的数据。
PyTorch 深度学习(GPT 重译)(一)(3)https://developer.aliyun.com/article/1485200