干货|如何从TensorFlow转入PyTorch

Posted CUDATEK酷达智能

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货|如何从TensorFlow转入PyTorch相关的知识,希望对你有一定的参考价值。

CUDATEK是深度学习软硬件解决方案专家,提供GPU硬件解决方案;CUDA解决方案专家; 面向制造业,影视动漫娱乐硬件解决方案;专业计算金融GPU解决方案;IVA GPU软硬件解决方案。

当我第一次尝试学习 PyTorch 时,没几天就放弃了。和 TensorFlow 相比,我很难弄清 PyTorch 的核心要领。但是随后不久,PyTorch 发布了一个新版本,我决定重新来过。在第二次的学习中,我开始了解这个框架的易用性。在本文中,我会简要解释 PyTorch 的核心概念,为你转入这个框架提供一些必要的动力。其中包含了一些基础概念,以及先进的功能如学习速率调整、自定义层等等。

yTorch 的易用性如何?

Andrej Karpathy 是这样评价的

资源

 

首先要知道的是:PyTorch 的主目录和教程是分开的。而且因为开发和版本更新的速度过快,有时候两者之间并不匹配。所以你需要不时查看源代码:http://pytorch.org/tutorials/。

 

当然,目前网络上已有了一些 PyTorch 论坛,你可以在其中询问相关的问题,并很快得到回复:https://discuss.pytorch.org/。

 

把 PyTorch 当做 NumPy 用

 

让我们先看看 PyTorch 本身,其主要构件是张量——这和 NumPy 看起来差不多。这种性质使得 PyTorch 可支持大量相同的 API,所以有时候你可以把它用作是 NumPy 的替代品。PyTorch 的开发者们这么做的原因是希望这种框架可以完全获得 GPU 加速带来的便利,以便你可以快速进行数据预处理,或其他任何机器学习任务。将张量从 NumPy 转换至 PyTorch 非常容易,反之亦然。让我们看看如下代码:

干货|如何从TensorFlow转入PyTorch

从张量到变量

 

张量是 PyTorch 的一个完美组件,但是要想构建神经网络这还远远不够。反向传播怎么办?当然,我们可以手动实现它,但是真的需要这样做吗?幸好还有自动微分。为了支持这个功能,PyTorch 提供了变量,它是张量之上的封装。如此,我们可以构建自己的计算图,并自动计算梯度。每个变量实例都有两个属性:包含初始张量本身的.data,以及包含相应张量梯度的.grad

干货|如何从TensorFlow转入PyTorch

你也许注意到我们手动计算了自己的梯度,这样看起来很麻烦,我们能使用优化器吗?当然。

干货|如何从TensorFlow转入PyTorch

并不是所有的变量都可以自动更新。但是你应该可以从最后一段代码中看到重点:我们仍然需要在计算新梯度之前将它手动归零。这是 PyTorch 的核心理念之一。有时我们会不太明白为什么要这么做,但另一方面,这样可以让我们充分控制自己的梯度。

 

静态图 vs 动态图

 

PyTorch 和 TensorFlow 的另一个主要区别在于其不同的计算图表现形式。TensorFlow 使用静态图,这意味着我们是先定义,然后不断使用它。在 PyTorch 中,每次正向传播都会定义一个新计算图。在开始阶段,两者之间或许差别不是很大,但动态图会在你希望调试代码,或定义一些条件语句时显现出自己的优势。就像你可以使用自己最喜欢的 debugger 一样!

 

你可以比较一下 while 循环语句的下两种定义——第一个是 TensorFlow 中,第二个是 PyTorch 中:

干货|如何从TensorFlow转入PyTorch
干货|如何从TensorFlow转入PyTorch

看起来第二种方法比第一个简单多了,你觉得呢?

 

模型定义

 

现在我们看到,想在 PyTorch 中创建 if/else/while 复杂语句非常容易。不过让我们先回到常见模型中,PyTorch 提供了非常类似于 Keras 的、即开即用的层构造函数:

 

神经网络包(nn)定义了一系列的模块,它可以粗略地等价于神经网络的层。模块接收输入变量并计算输出变量,但也可以保存内部状态,例如包含可学习参数的变量。nn 包还定义了一组在训练神经网络时常用的损失函数。

干货|如何从TensorFlow转入PyTorch

如果你想要构建复杂的模型,我们可以将 nn.Module 类子类化。当然,这两种方式也可以互相结合。

干货|如何从TensorFlow转入PyTorch

在__init__方法中,我们需要定义之后需要使用的所有层。在正向方法中,我们需要提出如何使用已经定义的层的步骤。而在反向传播上,和往常一样,计算是自动进行的。

 

自定义层

 

如果我们想要定义一些非标准反向传播模型要怎么办?这里有一个例子——XNOR 网络:

干货|如何从TensorFlow转入PyTorch

在这里我们不会深入细节,如果你对它感兴趣,可以参考一下原始论文:

https://arxiv.org/abs/1603.05279

 

与我们问题相关的是反向传播需要权重必须介于-1 到 1 之间。在 PyTorch 中,这可以很容易实现:

干货|如何从TensorFlow转入PyTorch

正如你所见,我们应该只定义两种方法:一个为正向传播,一个为反向传播。如果我们需要从正向通道访问一些变量,我们可以将它们存储在 ctx 变量中。注意:在此前的 API 正向/反向传播不是静态的,我们存储变量需要以 self.save_for_backward(input) 的形式,并以 input, _ = self.saved_tensors 的方式接入。

 

在 CUDA 上训练模型

 

我们曾经讨论过传递一个张量到 CUDA 上。但如果希望传递整个模型,我们可以通过调用.cuda() 来完成,并将每个输入变量传递到.cuda() 中。在所有计算后,我们需要用返回.cpu() 的方法来获得结果。

 

同时,PyTorch 也支持在源代码中直接分配设备:

干货|如何从TensorFlow转入PyTorch

因为有些时候我们想在 CPU 和 GPU 中运行相同的模型,而无需改动代码,我们会需要一种封装:

干货|如何从TensorFlow转入PyTorch

权重初始化

 

在 TesnorFlow 中权重初始化主要是在张量声明中进行的。PyTorch 则提供了另一种方法:首先声明张量,随后在下一步里改变张量的权重。权重可以用调用 torch.nn.init 包中的多种方法初始化为直接访问张量的属性。这个决定或许并不直接了当,但当你希望初始化具有某些相同初始化类型的层时,它就会变得有用。

干货|如何从TensorFlow转入PyTorch

反向排除子图

 

有时,当你希望保留模型中的某些层或者为生产环境做准备的时候,禁用某些层的自动梯度机制非常有用。在这种思路下,PyTorch 设计了两个 flag:requires_grad 和 volatile。第一个可以禁用当前层的梯度,但子节点仍然可以计算。第二个可以禁用自动梯度,同时效果沿用至所有子节点。

干货|如何从TensorFlow转入PyTorch

训练过程

 

当然,PyTorch 还有一些其他卖点。例如你可以设定学习速率,让它以特定规则进行变化。或者你可以通过简单的训练标记允许/禁止批规范层和 dropout。如果你想要做的话,让 CPU 和 GPU 的随机算子不同也是可以的。

干货|如何从TensorFlow转入PyTorch

同时,你也可以添加模型信息,或存储/加载一小段代码。如果你的模型是由 OrderedDict 或基于类的模型字符串,它的表示会包含层名。

干货|如何从TensorFlow转入PyTorch

根据 PyTorch 文档,用 state_dict() 的方式存储文档更好。

 

记录

 

训练过程的记录是一个非常重要的部分。不幸的是,PyTorch 目前还没有像 Tensorboard 这样的东西。所以你只能使用普通文本记录 Python 了,你也可以试试一些第三方库:

logger:https://github.com/oval-group/logger


Crayon:https://github.com/torrvision/crayon


tensorboard_logger:

https://github.com/TeamHG-Memex/tensorboard_logger


tensorboard-pytorch:

https://github.com/lanpa/tensorboard-pytorch


Visdom:

https://github.com/facebookresearch/visdom

掌控数据

你可能会记得 TensorFlow 中的数据加载器,甚至想要实现它的一些功能。对于我来说,我花了四个小时来掌握其中所有管道的执行原理。

干货|如何从TensorFlow转入PyTorch

首先,我想在这里添加一些代码,但我认为上图足以解释它的基础理念了。


PyTorch 开发者不希望重新发明轮子,他们只是想要借鉴多重处理。为了构建自己的数据加载器,你可以从 torch.utils.data.Dataset 继承类,并更改一些方法:

干货|如何从TensorFlow转入PyTorch

有两件事你需要事先知道:

 

1. PyTorch 的图维度和 TensorFlow 的不同。前者的是 [Batch_size × channels × height × width] 的形式。但如果你没有通过预处理步骤 torchvision.transforms.ToTensor() 进行交互,则可以进行转换。在 transforms 包中还有很多有用小工具。

 

2. 你很可能会使用固定内存的 GPU,对此,你只需要对 cuda() 调用额外的标志 async = True,并从标记为 pin_memory = True 的 DataLoader 中获取固定批次。

 

最终架构

 

现在我们了解了模型、优化器和很多其他细节。是时候来个总结了:

干货|如何从TensorFlow转入PyTorch

这里有一段用于解读的伪代码:

干货|如何从TensorFlow转入PyTorch

结论

 

希望本文可以让你了解 PyTorch 的如下特点:

· 

它可以用来代替 Numpy

它的原型设计非常快

调试和使用条件流非常简单

有很多方便且开箱即用的工具

· 

 

PyTorch 是一个正在快速发展的框架,背靠一个富有活力的社区。现在是尝试 PyTorch 的好时机。

业务咨询与购买:karena@cudatek.com



上海酷达计算机科技有限公司

TEL 021-54181199




以上是关于干货|如何从TensorFlow转入PyTorch的主要内容,如果未能解决你的问题,请参考以下文章

干货|Pytorch还是Tensorflow?英伟达工程师帮你总结了

干货丨新手必读,PyTorch与TensorFlow的全方位对比

手把手教你由TensorFlow上手PyTorch(附代码)

干货|PyTorch和TensorFlow哪家强:九项对比读懂各自长项短板

干货|如何为TensorFlow和PyTorch自动选择空闲GPU,解决抢卡争端

如何从TensorFlow迁移到PyTorch