Effective TensorFlow 2.0高效开发指南

前段时间tf发布了2.0版本,今天略读了一番,发现新特性确实可以在开发中节省很多时间。阅读的同时,顺便将开发指南翻译了一点,如有错误欢迎指正。
effective tensorflow 2.0
为使tensorflow用户更高效,tensorflow 2.0中进行了多出更改。tensorflow 2.0删除了篇冗余api,使api更加一致(统一rnns, 统一优化器),并通过eager execution更好地与python集成。
许多rfcs已经解释了tensorflow 2.0带来的变化。本指南介绍了tensorflow 2.0应该怎么进行开发。这假设您已对tensorflow 1.x有一定了解。
a brief summary of major changes
api cleanup
许多api在tf 2.0中进行了移动或删除。一些主要的变化包括删除tf.app,tf.flags,使tf.logging支持现在开源的absl-py,重新生成项目的tf.contribe,通过清理tf.*中那些较少使用的命名空间,例如tf.math。一些api已替换为自己的2.0版本-tf.summary,tf.keras.metrics, 和tf.keras.optimizers。最快升级应用这些重命名带来的变化可使用v2升级脚本。
eager execution
tensorflow 1.x要求用户通过tf.*api手动的将抽象语法树(图)拼接在一起。然后它要求用户通过一组输入、输出张量传递给session.run()从而手动编译调用这个图。tensorflow 2.0 eager execution可以像python那样执行,在2.0中,graph 和 session会像实现细节一样。
值得注意的是tf.control_dependencies()不再需要了,因为所有代码都是行顺序执行的(用tf.function声明)。
no more globals
tensorflow 1.x严重依赖隐式全局命名空间。当你调用tf.variable(),它会被放入默认图中,即使你忘了指向它的python变量,它也会被保留在那里。然后你可以恢复它,但前提是你得知道它创建时的名称。如果你无法控制变量的创建,这很难做到。其结果是,各种各样的机制,试图帮助用户再次找到他们的变量,以及为框架找到用户创建的变量:variable scopes, global collections。例如tf.get_global_step(),tf.global_variables_initializer(),还有优化器隐式计算所有可训练变量的梯度等等。tensorflow 2.0消除了这些机制(variable 2.0 rfc)默认支持的机制:跟踪你的变量!如果你忘记了一个tf.variable,它就会当作垃圾被回收。
functions, not sessions
session.run()几乎可以像函数一样调用:指定输入和被调用的函数,你可以得到一组输出。在tensorflow 2.0中,您可以使用python函数tf.function()来标记它以进行jit编译,以便tensorflow将其作为单个图运行(function 2.0 rfc)。这种机制允许tensorflow 2.0获得图模型所有的好处:
性能:函数可以被优化(node pruning, kernel fusion, etc.)
可移植性:该功能可以被导出/重新导入(savedmodel 2.0 rfc),允许用户重用和共享模块化tensorflow功能。
# tensorflow 1.x
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# tensorflow 2.0
outputs = f(input)
凭借穿插python 和tensorflow代码的能力,我们希望用户能够充分利用python的表现力。除了在没有python解释器的情况下执行tensorflow,如mobile, c++, 和 js。为了帮助用户避免在添加时重写代码@tf.function, autograph会将python构造的一个子集转换为他们的tensorflow等价物:
for/while -> tf.while_loop (支持break 和 continue)
if->tf.cond
for _ in dataset -> dataset.reduce
autograph支持控制流的任意嵌套,这使得可以有较好性能并且简洁地实现许多复杂的ml程序,如序列模型,强化学习,自定义训练循环等。
recommendations for idiomatic tensorflow 2.0
refactor your code into smaller functions
tensorflow 1.x中常见使用模式是“kitchen sink”策略,其中所有可能的计算的联合被预先布置,然后选择被评估的张量,通过session.run()运行。在tensorflow 2.0中,用户应该将代码重构为较小的函数,这些函数根据需要被调用。通常,没有必要用tf.function去装饰那些比较小的函数;仅用tf.function去装饰高等级的计算,例如,训练的一个步骤,或模型的前向传递。
use keras layers and models to manage variables
keras模型和图层提供了方便variables和 trainable_variables属性,它以递归方式收集所有因变量。这使得在本地管理变量非常容易。
对比:
def dense(x, w, b):
return tf.nn.sigmoid(tf.matmul(x, w)+ b)
@tf.function
def multilayer_perceptron(x, w0, b0, w1, b1, w2, b2 ...):
x = dense(x, w0, b0)
x = dense(x, w1, b1)
x = dense(x, w2, b2)
...
# 你仍然需要管理w_i和b_i,它们的形状远离代码定义。
keras版本:
# 可以调用每个图层,其签名等效于 linear(x)
layers =[tf.keras.layers.dense(hidden_size, activation=tf.nn.sigmoid)for _ in range(n)]
perceptron = tf.keras.sequential(layers)
# layers[3].trainable_variables => returns [w3, b3]
# perceptron.trainable_variables => returns [w0, b0, ...]
keras layers/models继承自tf.train.checkpointable并集成了@tf.function,这使得直接从keras对象导出savedmodels或checkpoint成为可能。您不一定要使用keras的.fitapi来利用这些集成。
这是一个迁移学习的例子,演示了keras如何轻松收集相关变量的子集。假设你正在训练一个带有共享主干的多头模型:
trunk = tf.keras.sequential([...])
head1 = tf.keras.sequential([...])
head2 = tf.keras.sequential([...])
path1 = tf.keras.sequential([trunk, head1])
path2 = tf.keras.sequential([trunk, head2])
# train on primary dataset
for x, y in main_dataset:
with tf.gradienttape()as tape:
prediction = path1(x)
loss = loss_fn_head1(prediction, y)
# simultaneously optimize trunk and head1 weights.
gradients = tape.gradients(loss, path1.trainable_variables)
optimizer.apply_gradients(gradients, path1.trainable_variables)
# fine-tune second head, reusing the trunk
for x, y in small_dataset:
with tf.gradienttape()as tape:
prediction = path2(x)
loss = loss_fn_head2(prediction, y)
# only optimize head2 weights, not trunk weights
gradients = tape.gradients(loss, head2.trainable_variables)
optimizer.apply_gradients(gradients, head2.trainable_variables)
# you can publish just the trunk computation for other people to reuse.
tf.saved_model.save(trunk, output_path)
combine tf.data.datasets and @tf.function
在内存中迭代拟合训练数据时,可以随意使用常规的python迭代。或者,tf.data.dataset是从硬盘读取训练数据流的最好方法。datasets是可迭代的(不是迭代器),它可以像在eager模式下的其他python迭代一样工作。您可以通过用tf.function()包装代码来充分利用数据集异步预取/流功能,这将使用autograph等效的图操作替换python的迭代。
@tf.function
def train(model, dataset, optimizer):
for x, y in dataset:
with tf.gradienttape()as tape:
prediction = model(x)
loss = loss_fn(prediction, y)
gradients = tape.gradients(loss, model.trainable_variables)
optimizer.apply_gradients(gradients, model.trainable_variables)
如果您使用keras .fit()api,则无需担心数据集迭代。
model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)
take advantage of autograph with python control flow
autograph提供了一种将依赖于数据的控制流转换为等效图形模式的方法,如tf.cond和tf.while_loop。
数据相关控制流出现的一个常见位置是序列模型。tf.keras.layers.rnn包装了一个rnn cell,允许您既可以静态也可以动态的循环展开。为了演示,您可以重新实现动态展开,如下所示:
classdynamicrnn(tf.keras.model):
def __init__(self, rnn_cell):
super(dynamicrnn,self).__init__(self)
self.cell = rnn_cell
def call(self, input_data):
# [batch, time, features] -> [time, batch, features]
input_data = tf.transpose(input_data,[1,0,2])
outputs = tf.tensorarray(tf.float32, input_data.shape[0])
state =self.cell.zero_state(input_data.shape[1], dtype=tf.float32)
for i in tf.range(input_data.shape[0]):
output, state =self.cell(input_data[i], state)
outputs = outputs.write(i, output)
return tf.transpose(outputs.stack(),[1,0,2]), state
有关autograph功能的更详细概述,请参阅指南
use tf.metrics to aggregate data and tf.summary to log it
要记录摘要,请使用tf.summary.(scalar|histogram|...)上下文管理器将其重定向到编写器。(如果省略上下文管理器,则不会发生任何事情。)与tf 1.x不同,摘要直接发送给编写器; 没有单独的“合并”操作,也没有单独的add_summary()调用,这意味着step必须在调用点提供该值。
summary_writer = tf.summary.create_file_writer('/tmp/summaries')
with summary_writer.as_default():
tf.summary.scalar('loss',0.1, step=42)
要在将数据记录为摘要之前聚合数据,请使用 tf.metrics。metrics是有状态的;它们积累值并在您调用 .result()时返回结果。清除积累值,请使用 .reset_states()。
def train(model, optimizer, dataset, log_freq=10):
avg_loss = tf.keras.metrics.mean(name='loss', dtype=tf.float32)
for images, labels in dataset:
loss = train_step(model, optimizer, images, labels)
avg_loss.update_state(loss)
if tf.equal(optimizer.iterations % log_freq,0):
tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations)
avg_loss.reset_states()
def test(model, test_x, test_y, step_num):
loss = loss_fn(model(test_x), test_y)
tf.summary.scalar('loss', loss, step=step_num)
train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train')
test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test')
with train_summary_writer.as_default():
train(model, optimizer, dataset)
with test_summary_writer.as_default():
test(model, test_x, test_y, optimizer.iterations)
通过将tensorboard指向摘要日志目录来可视化生成的摘要:tensorboard --logdir /tmp/summaries。

松下FZ-55为社区医疗服务提供移动解决方案
关于科研级全项目土壤肥料养分检测仪
通用处理器的历史和发展 通用处理器是否可行?
物联网的远程低功耗通信问题及如何安全地实现它
聊聊MyBatis自定义缓存的原理和使用
Effective TensorFlow 2.0高效开发指南
热敏电阻转4-20mA,NTC温度变送器/模块
5G时代来临对于互联网的影响
4498元vivoXplay6预约12月6日正式开始,先来看看开箱图吧!
COMPUTEX人工智能和机器人新品频发,AI时代落地还有多远?
Stratus与微软Azure物联网云平台达成合作,可实现快速启动物联网项目
微导纳米签3.86亿大单 向亿晶光电销售TOPCon电池设备
SpaceX 公司买下两座深水石油钻井平台 为“星际飞船”火箭提供支持
夜视的原理是什么
Android O首个开发者预览版仅三周 华为已在华为Mate9上开始内测
摩托车、电动车灯带爆闪方案 降压恒流AP2400
采用ROHM独有的自适应导通时间控制,隔离型电源的瞬态响应速度大幅提升
3D视觉将是人工智能“开眼看世界”的提供者
ipv6协议有什么特点
Wi-Fi信号的频段和信道的区别是什么