写点什么

都在关心 TensorFlow 2.0,那我手里基于 1.x 构建的程序怎么办?

  • 2019-08-24
  • 本文字数:5762 字

    阅读完需:约 19 分钟

都在关心TensorFlow 2.0,那我手里基于1.x构建的程序怎么办?


自 2015 年开源以来,TensorFlow 凭借性能、易用、配套资源丰富,一举成为当今最炙手可热的 AI 框架之一,当前无数前沿技术、企业项目都基于它来开发。一开始,TensorFlow 的主要目的是为构建神经网络提供高性能 API。然而,借助于机器学习社区对它的兴趣以及时间上的优势,这个类库已经演变成了一个完整的机器学习生态系统。

然而最近几个月,TensorFlow 正在经历推出以来最大规模的变化。TensorFlow 2.0 已经推出 beta 版本,同 TensorFlow 1.x 版本相比,新版本带来了太多的改变,最大的问题在于不兼容很多 TensorFlow 1.x 版本的 API。这不禁让很多 TensorFlow 1.x 用户感到困惑和无从下手。一般来讲,他们大量的工作和成熟代码都是基于 TensorFlow 1.x 版本开发的。面对版本不能兼容的问题,该如何去做?

本文将跟大家分享作者在处理 TensorFlow 适配和版本选择问题方面的经验,希望对你有所帮助。内容节选自《深度学习之TensorFlow工程化项目实战》一书,文末有送书福利!

一、新项目的版本选择

虽然 TensorFlow 的 2.0 版本中有很多光鲜靓丽的新功能。但是 TensorFlow 1.x 目前比较稳定,建议读者使用 TensorFlow 1.x 版本开发实际项目,并跟进 2.x 版本所更新的技术。待 2.x 版本迭代到 2.3 以上,再考虑使用 2.x 版本开发实际项目。


同时开发新项目时,尽量使用动态图+tf.keras 接口进行。这样,在以后的移植过程中,可以减少很多不兼容的问题。


如果选择 1.x 版本进行开发,尽量使用 TensorFlow 1.13.1、1.14 版本为主。因为 TensorFlow 2.x 版本的代码是基于 TensorFlow 1.13.1 转化而来。TensorFlow 1.13.1 版本可以部分支持 TensorFlow 2.0 版本的代码。而 1.14 版本在 1.13 基础上又更新了一代,相对更为稳定。

二、TensorFlow 1.x 版本与 2.x 版本共存的解决方案

由于 TensorFlow 框架的 1.x 版本与 2.x 版本差异较大。在 1.x 版本上实现的项目,有些并不能直接运行在 2.x 版本上,而新开发的项目推荐使用 2.x 版本。这就需要解决 1.x 版本与 2.x 版本共存的问题。


如用 Anaconda 软件创建虚环境的方法,则可以在同一个主机上安装不同版本的 TensorFlow。

1. 查看 Python 虚环境及 Python 的版本

在装完 Anaconda 软件之后,默认会创建一个虚环境。该虚环境的名字是“base”,是当前系统的运行主环境。可以用“conda info --envs”命令进行查看。


(1)在 Linux 系统中查看所有的 Python 虚环境。


以 Linux 系统为例,查看所有的 Python 虚环境具体命令如下:


(base) root@user-NULL:~# conda info --envs
复制代码


该命令执行后,会显示如下内容:


# conda environments:#base                  *  /root/anaconda3
复制代码


在显示结果中可以看到,当前虚环境的名字是“base”,是 Anaconda 默认的 Python 环境。


(2)在 Linux 系统中查看当前 Python 的版本


可以通过“python --version”命令查看当前 Python 的版本。具体命令如下:


(base) root@user-NULL:~# python --version
复制代码


执行该命令后会显示如下内容:


Python 3.6.4 :: Anaconda, Inc.
复制代码


在显示结果中可以看到,当前 Python 的版本是 3.6.4。

2. 创建 Python 虚环境

创建 Python 虚环境的命令是“conda create”。在创建时,应指定好虚环境的名字和需要使用的版本。


(1)在 Linux 系统中创建 Python 虚环境。


下面以在 Linux 系统中创建一个 Python 版本为 3.6.4 的虚环境为例(在 Windows 系统中,创建方法完全一致)。具体命令如下:


 (base) root@user-NULL:~# conda create --name tf2 python=3.6.4
复制代码


该命令创建一个名为“tf2”的 Python 虚环境。具体步骤如下:


①    在创建过程中会提示是否安装对应软件包,如下图所示。输入“Y”,则下载及安装软件包。



② 安装完软件包后,系统将会自动进行其他配置。如果出现如下图所示的界面,则表示创建 Python 虚拟环境成功。



在上图中显示了使用虚拟环境的命令:


conda activate tf2              #将虚拟环境tf2作为当前的Python环境conda deactivate                #使用默认的Python环境
复制代码


提示:

在 Windows 中,激活和取消激活虚拟环境的命令如下:

activate tf2
deactivate


(2)检查 Python 虚环境是否创建成功。


再次输入“conda info --envs”命令,查看所有的 Python 虚环境。具体命令如下:


(base) root@user-NULL:~# conda info –envs
复制代码


该命令执行后,会显示如下内容:


# conda environments:#base                  *  /root/anaconda3tf2                      /root/anaconda3/envs/tf2
复制代码


可以看到,虚环境中多了一个“tf2”,表示创建成功。


(3)删除 Python 虚环境。


如果想删除已经创建的虚环境,则可以使用“conda remove”命令。具体命令如下:


(base) root@user-NULL:~# conda remove --name tf2 --all
复制代码


该命令执行后没有任何显示。可以再次通过“conda info --envs”命令查看 Python 虚环境是否被删除。

3. 在 Python 虚环境中安装 TensorFlow

激活新创建的虚拟环境“tf2”,然后按照《深度学习之 TensorFlow 工程化项目实战》一书 2.3 节中介绍的方法安装 TensorFlow。具体命令如下:


(base) root@user-NULL:~# conda activate tf2                 # 激活tf2虚拟环境(tf2) root@user-NULL:~# pip install tf-nightly-2.0-preview  # 安装TensorFlow 2.0版
复制代码

三、2.x 版本对于静态图的影响

“静态图”是 TensorFlow 1.x 版本中张量流的主要运行方式。其运行机制是将“定义”与“运行”相分离。相当于:先用程序搭建起一个结构(即在内存中构建一个图),让数据(张量流)按照图中的结构顺序进行计算,最终运行出结果。


虽然在 TensorFlow 2.x 版本中默认的是动态图,但是也可以使用静态图。


在 TensorFlow 2.x 版本中,使用静态图的步骤与在 TensorFlow 1.x 版本中使用静态图的步骤完全一致。但是,由于静态图不是 TensorFlow 2.x 版本中的默认工作模式,所以在使用时还需要注意两点:


  1. 在代码的最开始处,用 tf.compat.v1.disable_v2_behavior 函数关闭动态图模式。

  2. 将 TensorFlow 1.x 版本中的静态图接口,替换成 tf.compat.v1 模块下的对应接口。


例如:


  • 将函数 tf.placeholder 替换成函数 tf.compat.v1.placeholder。

  • 将函数 tf.session 替换成函数 tf.compat.v1.session。

四、将 1.x 的动态图代码升级到 2.x 版本

在 TensorFlow 2.x 版本中,已经将动态图设为了默认的工作模式。使用动态图时,直接编写代码即可。


TensorFlow 1.x 中的 tf.enable_eager_execution 函数在 TensorFlow 2.x 版本中已经被删除,另外在 TensorFlow 2.x 版本中还提供了关闭动态图与启用动态图的两个函数。


  • 关闭动态图函数:tf.compat.v1.disable_v2_behavior。

  • 启用动态图函数:tf.compat.v1.enable_v2_behavior。

五、2.x 版本中的反向传播

在 1.x 版本中动态图的反向传播函数有多个:tf.GradientTape、tfe.implicit_gradients、tfe.implicit_value_and_gradients,可以根据实际的需要来灵活选择,使用起来非常灵活。(具体区别和实例演示可以参考《深度学习之 TensorFlow 工程化项目实战》一书)


但在 2.x 中,只保留了 tf.GradientTape 函数用于计算梯度。tfe.implicit_gradients 与 tfe.implicit_value_and_gradients 函数在 TensorFlow 2.x 中将不再被支持。

六、2.x 版本对于估算器的影响

TensorFlow 2.x 版本可以完全兼容 TensorFlow 1.x 版本的估算器框架代码。用估算器框架开发模型代码,不需要考虑版本移植的问题。

七、用工具进行代码的版本升级——适用于原生的 API 代码

如果手里的 1.x 代码只使用了原生的 API,那么可以直接使用 TensorFlow 2.x 版本中提供的工具对 TensorFlow 1.x 版本的代码进行升级。


TensorFlow 2.x 版本提供了一个升级 TensorFlow 1.x 版本代码的工具——tf_upgrade_v2,该工具可以非常方便地将 TensorFlow 1.x 版本中编写的代码移植到 TensorFlow 2.x 中。具体命令如下:


tf_upgrade_v2 --infile "1.x的代码文件"  -outfile "2.x的代码文件"
复制代码


该命令主要做的是名字匹配,实现了在 TensorFlow 2.x 版本中,将 TensorFlow 1.x 版本中的部分函数名字进行调整,部分例子如下:


  • 将函数 tf.random_uniform 改成了 tf.random.uniform。

  • 将函数 tf.random_crop 改成了 tf.image.random_crop。

  • 将函数 tf.random_shuffle 改成了 tf.random.shuffle。

  • 将函数 tf.read_file 改成了 tf.io.read_file。


tf_upgrade_v2 工具支持单文件转换和多文件批量转换两种方式。

1. 对单个代码文件进行转换

在命令行里输入 tf_upgrade_v2 命令,用“–infile”参数来指定输入文件,用“–outfile”参数来指定输出文件。具体命令如下:


tf_upgrade_v2 --infile foo_v1.py  --outfile foo_v2.py
复制代码


该命令可以将 TensorFlow 1.x 版本中编写的代码文件 foo_v1.py 转成可以支持 TensorFlow 2.x 版本的代码 foo_v2.py。

2. 批量转化多个代码文件

在命令行里输入 tf_upgrade_v2 命令,用“-intree”参数来指定输入文件路径,用“-outtree”参数来指定输出文件路径。具体命令如下:


tf_upgrade_v2 -intree foo_v1  -outtree foo_v2
复制代码


该命令可以将目录为 foo_v1 下的所有代码文件转成支持 TensorFlow 2.x 版本的代码文件,并保存到目录 foo_v2 中。

八、2.x 版本对于 TF-Hub、T2T 等库的影响

非常庆幸的是,TF-Hub、T2T 等库可以同时支持 TensorFlow 的 1.x 与 2.x 版本。

1.TF-Hub 库

TF-Hub 库是 TensorFlow 中专门用于预训练模型的库,其中包含很多在大型数据集上训练好的模型。如需在较小的数据集上实现识别任务,则可以通过微调这些预训练模型来实现。另外,它还能够提升原有模型在具体场景中的泛化能力,加快训练的速度。


在 GitHub 网站上有 TF-Hub 库的源码链接,其中包含了众多详细的说明文档。地址如下:


https://github.com/tensorflow/hub

2.T2T

Tensor2Tensor(T2T)是谷歌开源的一个模块化深度学习框架,其中包含当前各个领域中最先进的模型,以及训练模型时常用到的数据集。


如想了解更多关于 T2T 的细节,可以在以下链接中查看 T2T 框架的源码及教程:


https://github.com/tensorflow/tensor2tensor

九、2.x 版本对于 tf.layers 接口的影响

用 tf.layers 接口开发模型代码需要考虑版本移植的问题。在 TensorFlow 2.x 版本中,所有 tf.layers 接口都需要被换作 tf.compat.v1.layers。


另外,在 TensorFlow 2.x 版本中,tf.layers 模块更多用于 tf.keras 接口的底层实现。如果是开发新项目,则建议直接使用 tf.keras 接口;如果要重构已有的项目,也建议使用 tf.keras 接口进行替换。

十、2.x 版本的新特性——自动图

在 2.x 版本中,加入了很多新特性,自动图是最为实用的特性之一。


在 TensorFlow 1.x 版本中,要开发基于张量控制流的程序,必须使用 tf.conf、tf. while_loop 之类的专用函数。这增加了开发的复杂度。


在 TensorFlow 2.x 版本中,可以通过自动图(AutoGraph)功能,将普通的 Python 控制流语句转成基于张量的运算图,大大简化了开发工作。


在 TensorFlow 2.x 版本中,可以用 tf.function 装饰器修饰 Python 函数,将其自动转化成张量运算图。示例代码如下:


import tensorflow as tf           #导入TensorFlow2.0@tf.functiondef autograph(input_data):    #用自动图修饰的函数    if tf.reduce_mean(input_data) > 0:      return input_data           #返回是整数类型    else:      return input_data // 2      #返回整数类型a =autograph(tf.constant([-6, 4]))b =autograph(tf.constant([6, -4]))print(a.numpy(),b.numpy())        #在TensorFlow 2.x上运行,输出:[-3  2] [ 6 -4]
复制代码


从上面代码的输出结果中可以看到,程序运行了控制流“tf.reduce_mean(input_data) > 0”语句的两个分支。这表明被装饰器 tf.function 修饰的函数具有张量图的控制流功能。


在使用自动图功能时,如果在被修饰的函数中有多个返回分支,则必须确保所有的分支都返回相同类型的张量,否则会报错。


TensorFlow 2.x 版本还有更多新特性,比如 TensorFLow.js、TF-Lite、模型保存和恢复的新 API 等都可以使 AI 的开发和应用变得更加快捷、方便。具体可以参考《深度学习之 TensorFlow 工程化项目实战》一书的介绍和实例演示。

十一、将代码升级到 TensorFlow 2.x 版本的经验总结

下面将升级代码到 TensorFlow 2.x 版本的方法汇总起来,有如下几点。

1. 最快速转化的方法

在代码中没有使用 contrib 模块的情况下,可以在代码最前端加上如下两句,直接实现代码升级。


import tensorflow.compat.v1 as tftf.disable_v2_behavior()
复制代码


这种方法只是保证代码在 TensorFlow 2.x 版本上能够运行,并不能发挥 TensorFlow 的最大性能。

2. 使用工具进行转化的方法

在代码中没有使用 contrib 模块的情况下,用 tf_upgrade_v2 工具可以快速实现代码升级。当然 tf_upgrade_v2 工具并不是万能的,它只能实现基本的 API 升级。一般在转化完成之后还需要手动二次修改。

3. 将静态图改成动态图的方法

静态图可以看作程序的运行框架,可以将输入输出部分原样套用在函数的调用框架中。具体步骤如下:


(1)将会话(session)转化成函数。


(2)将注入机制中的占位符(tf.placeholder)和字典(feed_dict)转化成函数的输入参数。


(3)将会话运行(session.run)后的结果转化成函数的返回值。


在实现过程中,可以通过自动图功能,用简单的函数逻辑替换静态图的运算结构。

4. 将共享变量转成 Python 对象的命名空间

在定义权重参数时,用 tf.Variable 函数替换 tf.get_variable 函数。每个变量的命名空间(variable_scope)用类对象空间进行替换,即将网络封装成类的形式来搭建模型。


在封装类的过程中,可以继承 tf.keras 接口(如:tf.keras.layers.Layer、tf.keras.Model),也可以继承更底层的接口(如 tf.Module、tf.layers.Layer)。


在对模型进行参数更新时,可以使用实例化类对象的 variables 和 trainable_variables 属性来控制参数。

5. 升级 TF-slim 接口开发的程序

TensorFlow 2.x 版本将彻底抛弃 TF-slim 接口,所以升级 TF-slim 接口程序需要较大的工作量。官方网站给出的指导建议是:如果手动将 TF-slim 接口程序转化为 tf.layers 接口实现,则可以满足基本使用;如果想与 TensorFlow 2.x 版本结合得更加紧密,则可以再将其转化为 tf.keras 接口。


以上内容来自于《深度学习之TensorFlow工程化项目实战》一书,如果你想了解 TensorFlow 的更多使用技巧,或有关新旧版本的升级方法,或更多实例演示,请参考此书。


2019-08-24 08:0012031

评论

发布
暂无评论
发现更多内容

react源码中的生命周期和事件系统

flyzz177

React

用javascript分类刷leetcode3.动态规划(图文视频讲解)

js2030code

JavaScript LeetCode

跳板攻击中如何追踪定位攻击者主机(上)

郑州埃文科技

数据安全 网络攻击 跳板攻击

真希望你也明白runtime.Map和sync.Map

面向加薪学习

面试 并发 源码阅读 go语言 Map集合

卡塔尔世界杯出现了半自动越位识别技术、动作轨迹捕捉等黑科技。

汀丶人工智能

12月日更 12月月更 世界杯黑科技

Flink核心组件

穿过生命散发芬芳

flink 12月月更

超1800万累计观看,多次占据热榜前列……“无障碍字幕直播间”带来的远不止这些!

猿始人

GaussDB(DWS)运维 :遇到truncate执行慢,怎么办

华为云开发者联盟

数据库 后端 华为云 12 月 PK 榜

北京同仁堂两大名牌品种亮相帝都

联营汇聚

KCL - 让 Kubernetes 资源清单管理更容易

Peefy

编程 Serverless Kubernetes #开源 #DevOps

从React源码角度看useCallback,useMemo,useContext

flyzz177

React

云原生时代数据库运维体系演进

vivo互联网技术

数据库 运维 故障自愈

从React源码来学hooks是不是更香呢

flyzz177

React

react源码分析:babel如何解析jsx

flyzz177

React

JavaScript刷LeetCode心得

js2030code

JavaScript LeetCode

2022-12-12:有n个城市,城市从0到n-1进行编号。小美最初住在k号城市中 在接下来的m天里,小美每天会收到一个任务 她可以选择完成当天的任务或者放弃该任务 第i天的任务需要在ci号城市完成,

福大大架构师每日一题

算法 rust 福大大

【前端相关】服务端渲染和客户端渲染的比较

No8g攻城狮

CSS css3 前端 js 前端框架

2022年11月中国汽车智能网联月度观察

易观分析

汽车 智能网联

【IntelliJ IDEA】【SVN】SVN详细的介绍和Idea中如何使用SVN

No8g攻城狮

ide svn Git Submodule git fetch IDEA DeBug

易观分析潘玉宇:信贷全流程化监管将成行业发展重点,银行间联合风控程度将逐渐加深

易观分析

银行 普惠金融

带你实现react源码的核心功能

flyzz177

React

react源码分析:实现react时间分片

flyzz177

React

React 之 Context 的变迁与背后实现

冴羽

JavaScript 源码分析 前端 前端框架 React

架构实战营 2-6 钱包高可用实战随堂练习

西山薄凉

「架构实战营」

教你用JavaScript实现点击支付框

小院里的霍大侠

JavaScript 小白 编程开发 实战案例 初学者

开源依赖项管理指南

SEAL安全

12 月 PK 榜 依赖管理 传递依赖 开源依赖项

【其他】快出数量级的性能是怎样炼成的

No8g攻城狮

MySQL sql 数据库·

Verilog 时延与过程结构

芯动大师

Verilog语法 Verilog延时 Verilog过程结构

JDK自带命令优化

@下一站

代码优化 12月日更 12月月更 jvm优化 java程序优化

架构实战营 2-5 微信红包分析随堂测验

西山薄凉

「架构实战营」

前端工程师leetcode算法面试必备-简单的二叉树

js2030code

JavaScript LeetCode

都在关心TensorFlow 2.0,那我手里基于1.x构建的程序怎么办?_AI&大模型_李金洪_InfoQ精选文章