TensorFlow 2.x教程(一):为什么要升级的2.X

Posted by lili on September 14, 2020

本系列教程讲解TensorFlow 2.x的用法,希望帮助更多还在使用TensorFlow 1.x的读者尽快把知识”升级”到最新的2.x。本文是第一篇,主要介绍目前的深度学习框架竞争格局以及作为用户应该怎么选择。

时至今日,深度学习框架竞争的总体格局已经非常明显——TensorFlow和PyTorch两强占据了主要的市场,而其它框架已经没有太多机会了。TensorFlow借助较早开源的先发优势以及构建于其上的生态系统和开发者依然占据头把交椅的位置。但是PyTorch借助开发调试简单的优势逐渐追了上来,学术界是其重要领地。这对于TensorFlow来说非常致命,因为大部分创新都来源于学术界。如果某个SOTA的论文使用了PyTorch实现并且开源,那么工业界的应用开发者必然会慢慢使用PyTorch,因为他们不会也没有能力用TensorFlow从零开始实现它。

TensorFlow 1.x为了运行效率(而不是开发效率),让用户直接操作计算图。用Python编写的代码只是一种定义计算图的语言,最终的代码还是在C++的执行引擎上运行,这和早期Caffe等用配置文件来定义神经网络结果并无本质区别(当然python是通用语言,比叫配置文件的表达能力会强大很多)。这样的后果就是开发效率极低,出现错误极难调试。这其实也可以用编程语言来对比,比如C/C++运行效率要比Python高很多,但是开发效率却要低很多。在早期,机器比人值钱,因此大家追求运行效率。但是进入二十一世纪,计算资源已经无处不在而且价格也越来越低,开发效率就变得更加重要,这也是C/C++这类语言衰落的重要原因。

TensorFlow广受诟病的一点就是api过于混乱,比如最简单的2维卷积就要tf.nn.conv2d和tf.layers.conv2d(包括后来的tf.keras.layers.conv2d),而且这些api还不统一,比如tf.layers.dropout用的参数是dropout rate,而tf.nn.dropout用的是keep rate,这让人无所适从。

另外由于没有明确的高层(High-Level)API,Estimator、tflearn和tf.layers(其实这只是”中层”API)互相竞争,再加上外部的Keras,整个TensorFlow的高层API也异常混乱,在加上由于计算图带来的全局命名问题——变量的创建是散落各处并且没有Python变量与之对应,在使用get_variable和各种variable_scope,以及各种隐式的约定——可训练的变量会放到key为TRAINABLE_VARIABLES的集合(Collection)里。这一切都让TensorFlow的使用变得异常复杂,甚至为了解决namespace的问题还搞出了tf-slim。

因为这些中高层API并不成熟,所以每次版本更新都变动很大,这也导致代码的兼容性很差,很多老版本开发的代码就无法在新版本中使用,这也让很多用户转向了更加稳定的PyTorch。

为了解决所有这些问题,TensorFlow 2.x把计算图和Session等底层细节隐藏起来,默认通过eager execution的方式隐式构建计算图,简化了开发和方便了调试,同时为了保证效率,通过tf.function把Python代码直接翻译成TensorFlow的Operation。由于使用了Python的变量来跟踪计算图的变量,get_variable和variable_scope也把扫进了垃圾堆,这大大简化了开发和调试。

由于Keras被收购,基本上确定了它官方高层的API的地位(目前还有极少数Keras不能实现的功能因此保留了Estimator,但是可以先用Keras构建模型然后转成Estimator,所以在未来Estimator迟早要被丢弃)。同时TensorFlow 2.x对遗留的api进行了清理,让其变得更加清爽。

这一切都让TensorFlow变得更加好用,但是唯一的问题就是很多人已经习惯了TensorFlow 1.x的用法(不习惯的也早切换到别的框架去了),怎么尽快升级我们的知识跟上最新的版本就变得非常重要,本系列教程就是作者自己在”升级”知识过程中的笔记,希望对读者有帮助。