最新发布的飞桨开源深度学习框架1.7版本,带来多项重要更新。很是值得关注的是,飞桨“动态图”能力有了重大升级,不但编程体验极大提高,并且训练性能已媲美“静态图”,部署能力也有全面强化。php
下载安装命令
## CPU版本安装命令
pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle
## GPU版本安装命令
pip install -f https://paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu
有过深度学习框架编程体验的开发者都知道,目前主要有声明式和命令式两种编程范式,通常被称为静态图模式和动态图模式。相对于静态图模式,动态图类采用“define-by-run”的执行方式,写一行代码便可即时得到结果,在编程体验、调试便捷性等方面有绝佳的优点;而静态图采用先编译后执行的方式,事先定义好总体网络结构再执行,可以对全局编译优化,更有利于性能的提高,也有利于模型的保存和部署。python
飞桨做为源于产业实践的深度学习框架,并致力于让深度学习技术的创新与应用更简单,目前同时支持动态图和静态图,兼顾开发的灵活性和高性能。c++
飞桨开源深度学习框架自1.3版增长动态图功能,1.5版本发布动态图编程范式预览版,通过多个版本的持续完善,目前已经在易用性、运行效率、模型部署能力等方面有很大的加强。飞桨将持续强化编程开发灵活性易用性的同时,保持更强劲的性能优点和全面的部署能力,助力开发者快速实现AI想法、快速上线AI业务。git
下面咱们就来看看,本次飞桨在动态图方面带来哪些新升级:github
深度效率优化,媲美静态图的训练性能
训练性能表现对一个深度学习框架而言很是重要,尤为是在工业生产应用场景中。动态图模式在带来了编程体验提高的同时,也让不少人顾虑它的性能损失问题。飞桨在对动态图支持的实现上,特别考虑到执行效率的优化问题。在1.6版本中,对于不少任务模型,动态图的执行性能已经能和静态图模式相接近。在1.7版本中,进一步对Python与C++交互效率、C++端运行效率等方面作了深度优化,总体训练性能已和静态图图相媲美。即便对于RNN一类的动态图的性能短板任务,飞桨动态图也达到了极高的速度水平。编程
咱们能够看到,在P40环境下,基于LSTM实现的语言模型任务,当下的训练速度相比1.6版本有近三倍的提高。网络
下面来看一下,本次升级对应的关键技术点:数据结构
-
提高Python与 C++交互效率框架
咱们知道,为了保证运行效率,框架底层的运算逻辑都是使用C++实现的,而为了编程的便利性,框架的用户编程接口为Python。在动态图模式下,每个OP执行时,都须要进行一次Python与C++交互,即将Python端的对象传递给C++端,这相对于静态图模式是一种显著的额外开销。新版本中,优化了Python与C++交互的数据结构,传递的结构更加精简,大大提高了执行效率。dom
在1.6版本的实现中,动态图的VarBase对象包含在Variable对象当中的,python与c++交互处理的是Variable对象,可是在Python的底层,这种对象保护关系是经过map进行实现的,咱们获取或者修改包含的元素,性能都很是的差,在1.7中,咱们从新设计了动态图的VarBase对象,python与c++直接传递VarBase对象,节省map的查找和修改开销,从而提升性能。
-
优化C++端运行效率
动态图模式下,每一个OP执行时,均须要作一次数据构造,OP运行结束以后进行析构。因为Op中包含了复杂的map等结构,这种结构的构造和析构会都带来很大的开销,在1.7版本中,咱们经过框架的优化,移除了这种map的构造和析构。简化数据结构,下降构造开销,由此提高执行效率。
-
【提高运行效率】优化DataLoader,提高总体性能
DataLoader虽然不算是动态图核心功能,但倒是影响任务总体训练性能的重要因素。因为动态图执行模式下的差别性,对应的DataLoader的设计和实现须要有不一样于静态图模式的更多考量。动态图模式下若每一个op执行时,都申请python的全局锁(Global Interpreter Lock),会致使异步DataLoader中数据处理的线程效率受到很大影响,若是训练时每一个batch的数据量比较大,DataLoader的性能就不如静态图模式下那么高效。为此,飞桨新版本的动态图模式在原来的基础上引入了multi-processing进行数据处理,这种进程间的处理不受全局锁的影响,进而提高执行效率。在resnet,se_resnext等任务上,总体性能提高约30%。
-
优化反向计算策略,删除冗余Tensor空间,下降显存占用。
针对部分OP,在执行反向计算时不依赖正向Tensor值,只依赖Tensor shape的状况,引入策略,删除不须要的Tensor空间,只保留须要的Tensor shape信息,以下降显存占用。在Resnet等任务上,同一个硬件设备上,可以设置最大batch size 提高了20%左右。
强化部署能力,追求极佳产业应用实践
在工业界,深度学习模型的部署是技术落地很是关键的部分。动态图模式采用命令式执行,并使用python原生语法来构建网络的形式,带来灵活性和便利性的同时,对于模型在C++端的自动部署产生了巨大的挑战。由于动态图模式下,没有一个总体的静态的网络结构内部表达,须要将python语法自动映射到C++端。
飞桨在推出动态图编程模式的同时,周密考虑了对训练后部署的支持。针对网络中不包含依赖数据的控制流的模型, 咱们提供了基于TracedLayer的方案来将动态图模型转换为静态图的方案,完成自动部署的功能;对于网络中存在依赖数据的控制流模型,飞桨实现了基于python语法解析和重构的技术,能够将python的控制流解释为飞桨控制流op,总体映射为静态图图表达,这种方案将支持绝大部分任务完成推理部署功能,会在下个版本发布。
TracedLayer 使用方法以下:
import paddle.fluid as fluid from paddle.fluid.dygraph import Linear, to_variable, TracedLayer import numpy as np #自动一个Layer class ExampleLayer(fluid.dygraph.Layer): def __init__(self): super(ExampleLayer, self).__init__() self._fc = Linear(3, 10) # 包含一个Linear层 def forward(self, input): return self._fc(input) with fluid.dygraph.guard(): layer = ExampleLayer() in_np = np.random.random([2, 3]).astype('float32') # 须要一个fake的数据 in_var = to_variable(in_np) #调用trace方法 out_dygraph, static_layer = TracedLayer.trace(layer, inputs=[in_var]) # 内部使用Executor运行静态图模型 out_static_graph = static_layer([in_var]) print(len(out_static_graph)) # 1 print(out_static_graph[0].shape) # (2, 10) # 将静态图模型保存为预测模型 static_layer.save_inference_model(dirname='./saved_infer_model')
对于上述操做保存的文件,能够直接使用静态图的C++部署方案,进行部署上线。
提高易用性,追求极致编码体验
在追求框架极限性能和部署能力的同时,飞桨也一直持续优化框架的易用性,在编程接口和模块使用上不断的打磨,精益求精,努力让你们的使用成本最低。在1.7版本中经过优化反向自动剪枝策略,在提高执行效率的同时,对于没有反向的op输出,不用显式设置stop_gradient的属性;Layer的构造函数中移除了name_scope,减小参数的传递;并移除Layer中的 build_once接口,方便你们更方便的进行参数的初始化、模型预测等;增长了一系列容器,包含Sequencial,LayerList,ParameterList,更加方便Layer和参数的管理,并可以下降你们使用时出错的几率。关于新版本的功能优化接口升级的细节可查看官网。
咱们来看一个demo示例,针对上述一系列的改动,模型的代码会更加简洁。
# 1.6版本示例 class MyLayer(fluid.Layer): def __init__(self): ... # 在1.6中相似的Layer须要单独定义 self.conv2d1 = Conv2D("conv1", 3, 5) self.conv2d2 = Conv2D("conv2", 3, 5) self.conv2d3 = Conv2D("conv3":, 3, 5) self.layer_list = [TestLayer(shapes[i]) for i in range(10)] # 1.6中 列表中的Layer须要单独调用 add_sublayer, 增长使用成本 # 并且add_sublayer的第一个参数必须惟一,惟一出错 for i, layer in enumerate(self.layer_list): self.add_sublayer("layer_" + str(i), layer) def forward(self, x, y): # 使用的时候,须要单独调用 y = self.conv2d1(x) y = self.conv2d2(y) y = self.conv2d3(y) for layer in self.layer_list: x, y = layer(x, y) return x, y # 1.7版本示例 class MyLayer(fluid.Layer): def __init__(self): ... # 在1.7中,Layer能够统一放入Sequencial容器进行管理 # Sequencial中的Layer必须是单输入、单输出的 self.sequential = Sequential([ Conv2D(3, 3, 5), # Conv2D的构造再也不须要name_scope Conv2D(5, 3, 5), Conv2D(5, 3, 5)]) # 在1.7中,多个Layer能够经过LayerList统一管理,不在调度调用 add_sublayer # 因为这个Layer的输入和输出都是两个,不能放入Sequencial中 self.layer_list = fluid.dygraph.LayerList( [TestLayer(shapes[i]) for i in range(10)]) def forward(self, x, y): # Sequencial的对象在调用时,内部包含的Layer会依次执行,没必要单独调用 y = self.sequential(x) for layer in self.layer_list: x, y = layer(x, y) return x, y
目前动态图功能已趋于完善,接口也趋于稳定,在后续新版本会最大可能保持前向兼容,飞桨将持续为广大开发者提供灵活高效的产业级深度学习框架。
若是您加入官方QQ群,您将赶上大批志同道合的深度学习同窗。官方QQ群:703252161。
若是您想详细了解更多飞桨的相关内容,请参阅如下文档。
下载安装命令
## CPU版本安装命令
pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle
## GPU版本安装命令
pip install -f https://paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu
官网地址:
https://www.paddlepaddle.org.cn
飞桨PGL项目地址:
https://github.com/PaddlePaddle/PGL
飞桨开源框架项目地址:
GitHub: https://github.com/PaddlePaddle/Paddle
Gitee: https://gitee.com/paddlepaddle/Paddle
>> 访问 PaddlePaddle 官网,了解更多相关内容。