作者 | Wabaf Kumar
来源 | Medium
编辑 | 代码医生团队
Facebook刚刚发布了PyTorch v1.3,其中包含了一些最期待的功能。最具吸引力的三个是:
将简要介绍所有这些内容,并将链接到其他一些重要功能。
命名张量
PyTorch v1.3最终添加了对命名张量的支持,该功能使用户可以使用显式关联的名称访问张量尺寸,而无需记住尺寸编号。例如,到目前为止,在与计算机视觉相关的任务中,必须记住批处理的一般结构,如下所示-[N,C,H,W]。其中N是批处理大小,C是通道数,H和W分别是图像的高度和宽度。在对该批处理执行操作时,必须跟踪这种结构,但是现在只能使用维度名称,而无需跟踪其索引。此外,这些命名的表示形式可以提供增强的运行时错误检查。将在本文中进一步讨论它们。
import torch
batch = torch.zeros(64, 3, 100, 100, names=('N', 'C', 'H', 'W'))
print(batch.names)
创建命名张量
batch.namesbatch按顺序在张量上打印每个维的名称。
按名称对齐
使用align_as()或align_to()按名称将张量尺寸与指定顺序对齐。
在计算机视觉模型中,批次的表示通常需要在[N,C,H,W](用于模型的正向和反向传递)和[N,H,W,C](用于绘制和保存图像)之间改变。到现在为止,必须像在直觉上相反地完成此操作,batch.permute([0, 2, 3, 1])但是现在可以通过使用align_as()or align_to()运算符以更简单的方式来完成。
import torch
batch = torch.zeros(64, 3, 100, 100, names=('N', 'C', 'H', 'W'))
print(batch.shape) #torch.Size([64, 3, 100, 100])
batch = batch.align_to('N', 'H', 'W', 'C')
print(batch.shape) #torch.Size([64, 100, 100, 3])
对于大量维,普通置换运算符甚至需要交换所有维的位置,也需要所有维的明确列表。但是,在命名张量的情况下,维的排列或重新排序可以通过以下更简单的方式完成:
#####################
# Before PyTorch v1.3
#####################
import torch
batch = torch.zeros(2, 3, 2, 2, 2, 2, 2, 2, 2, 2)
print(batch.shape)
batch = batch.permute([0, 2, 1, 3, 4, 5, 6, 7, 8, 9])
print(batch.shape)
#####################
# After PyTorch v1.3
#####################
import torch
alphas = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
batch = torch.zeros(2, 3, 2, 2, 2, 2, 2, 2, 2, 2, names=alphas)
print(batch.shape)
batch = batch.align_to('a', 'c', 'b', ...)
print(batch.shape)
检查命名
除了使张量更直观之外,命名张量还提供其他错误检查。当运算符应用于命名张量时(对于二进制运算符,任何一个或两个命名张量)将隐式检查某些维名称在运行时是否匹配。这为错误提供了额外的安全性。在下面的示例中显示:
import torch
# The following will produce no error as the dimensions match
batch1= torch.zeros(64, 3, 100, 100, names=('N', 'C', 'H', 'W'))
batch2 = torch.zeros(64, 3, 100, 100, names=('N', 'C', 'H', 'W'))
batch3 = batch1 + batch2
# The following will produce an error as the dimensions don't match
batch1= torch.zeros(64, 3, 100, 100, names=('N', 'C', 'H', 'W'))
batch2 = torch.zeros(64, 3, 100, 100, names=('N', 'C', 'W', 'H'))
batch3 = batch1 + batch2
在上面的示例中,如果不是用于命名张量,batch1并且batch2可以被添加而没有任何错误,因为height = width =100。但是,batch2高度和宽度尺寸已互换,将其添加到该对象batch1可能不是预期的操作。多亏命名张量,此逻辑错误将通过名称检查(“ N”,“ C”,“ H”,“ W”)和(“ N”,“ C”,“ W”,“ H”)来捕获不一样。
名称何时匹配?
这些规则与numpy或PyTorch中尺寸的广播规则非常相似。引用官方的PyTorch文档:
如果两个名称相等(字符串相等),或者至少一个为,则两个名称匹配None。从本质上讲,没有一个是特殊的“通配符”名称。”
在下面的示例中展示了这一点:
import torch
batch1= torch.zeros(64, 3, 100, 100, names=('N', 'C', 'H', 'W'))
batch2 = torch.zeros(64, 3, 100, 100, names=('N', 'C', 'H', 'W'))
batch3 = torch.zeros(64, 3, 100, 100)
batch4 = torch.zeros(64, 3, 100, 100)
batch5 = torch.zeros(64, 3, 100, 100, names=('N', 'C', 'W', 'H'))
#Name tuple strings are equal so name matches
res1 = batch1 + batch2
#Name of one of the inputs (batch3) is None so matches
res2 = batch1 + batch3
#Name of both the inputs are None so matches
res2 = batch3 + batch4
#Name tuple strings are not equal so no name match and error
res3 = batch1 + batch5
名称传播
在对张量执行运算后,无需再次输入尺寸名称,它们将自动传播。PyTorch利用了两个运营商- match和unify 为名称的传播。
unify(A, B)确定哪个名称A并将B其传播到输出。如果两个名称匹配,则返回两个名称中更具体的一个。如果名称不匹配,则错误。
下面的示例展示了名称传播:
import torch
# Unary operator on named tensors
t = torch.randn(4, 2, names=('N', 'C'))
t = t.abs()
t.names #output: ('N', 'C')
import torch
# Binary operator on named tensors
t1 = torch.randn(4, names=('X'))
t2 = torch.randn(4)
t3 = t1 * t2
t3.names #output: ('X',)
局限性
在撰写本文时,命名的张量功能处于实验模式,可能会发生许多变化。但是,命名张量当前最大的限制之一是它们无法完全支持Autograd引擎。尽管命名张量的梯度计算完全相同,但autograd引擎完全忽略了该名称,并忽略了其提供的其他安全性。
量化
PyTorch 1.3现在支持张量量化。Tensorflow已经支持了这一点,并且在PyTorch中已经等待了很多。量化是一个相当简单但精心设计的概念。在这里,将通过回答三个问题(什么,为什么和如何)来简要概述它们。
什么是量化?
量化是一种以低精度格式执行操作或将高精度数据格式转换为低精度数据格式的技术。例如,通过将32位浮点格式视为8位定点格式来完成此操作。如果有兴趣,可以阅读定点和浮点算法及其相关的复杂性,以更好地理解量化的需求。
为什么要 量化?
进行研究和创建神经网络模型的全部目的是部署它们并使之对公众有利。虽然模型训练的需求仅与研究人员和机器学习从业人员的数量成比例地增长,但对模式推理的需求却与消费者的数量成比例地增长。为了允许更多更好地访问最终用户,部署用于推理的模型的表示需要比训练时的表示更为紧凑。要记住的另一件事是,反向传播需要模型权重和偏差的高精度表示。但是,在推论过程中,模型更加健壮,不需要高精度表示。从而,可以将32位浮点表示中大小为113.9MB的模型量化为int8,大小为76.8MB。
https://pytorch.org/tutorials/advanced/dynamic_quantization_tutorial.html#test-dynamic-quantization
如何在PyTorch v1.3中使用量化?
引用官方PyTorch文档:
与典型的FP32型号相比,PyTorch支持INT8量化,从而可将模型尺寸减少4倍,并将内存带宽要求减少4倍。与FP32计算相比,对INT8计算的硬件支持通常快2到4倍。
为了进行量化,PyTorch引入了三种新的数据类型,如下所示:
PyTorch现在为模型提供了三种量化方法:
需要注意的另一件事是PyTorch从一开始就支持量化。这意味着,还可以使用以下方程式(非常直观)和代码对张量进行量化:
此等式用于量化张量的int表示,可以使用 t.int_repr()
import torch
t = torch.tensor([1.111111111])
t_q = torch.quantize_per_tensor(t, 0.1, 10, torch.quint8)
#output: tensor([21], dtype=torch.uint8)
print(t_q.int_repr())
#output: tensor([1.1000], size=(1,), dtype=torch.quint8, quantization_scheme=torch.per_tensor_affine, scale=0.1, zero_point=10)
print(t_q)
这是量化张量上所有受支持的操作的列表。
行动支持
允许量化的自然目的是在性能至关重要的手机(和其他设备)上交付PyTorch模型。已经为Android和iOS实现了端到端PyTorch API。这将对减少推理延迟和用户隐私产生重大影响。但是,PyTorch移动设备目前处于试验阶段,它存在一些局限性。例如,当前版本仅支持正向传播(推断),不支持向后操作。
可以在PyTorch官方网站上访问iOS和Android的hello world教程。
https://pytorch.org/mobile/ios/
https://pytorch.org/mobile/android/
更多更新
除了这三个主要更新之外,PyTorch v1.3还实现了其他一些更改和错误修复。可以在官方PyTorch Github存储库上查看所有更改的列表。其中一些功能是:
https://github.com/pytorch/pytorch/releases
此外,如果要将代码从先前版本的PyTorch移植到PyTorch v1.3,则需要注意可能会导致错误或意外行为的功能。其中一些功能是(我直接引用了前面提到的发行说明中的这些更改):
https://github.com/pytorch/pytorch/releases