为使TensorFLow用户更高效,TensorFlow 2.0中进行了多出更改。TensorFlow 2.0删除了篇冗余API,使API更加一致(统一RNNs, 统一优化器),并经过Eager execution更好地与Python集成。html
许多RFCs已经解释了TensorFlow 2.0带来的变化。本指南介绍了TensorFlow 2.0应该怎么进行开发。这假设您已对TensorFlow 1.x有必定了解。node
许多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升级脚本。python
TensorFlow 1.x要求用户经过tf.*
API手动的将抽象语法树(图)拼接在一块儿。而后它要求用户经过一组输入、输出张量传递给session.run()
从而手动编译调用这个图。TensorFlow 2.0 Eager execution能够像Python那样执行,在2.0中,graph 和 session会像实现细节同样。git
值得注意的是tf.control_dependencies()
再也不须要了,由于全部代码都是行顺序执行的(用tf.function
声明)。github
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
,它就会看成垃圾被回收。api
session.run()
几乎能够像函数同样调用:指定输入和被调用的函数,你能够获得一组输出。在TensorFlow 2.0中,您可使用Python函数tf.function()
来标记它以进行JIT编译,以便TensorFlow将其做为单个图运行(Function 2.0 RFC)。这种机制容许TensorFlow 2.0得到图模型全部的好处:session
# 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等价物:app
for
/while
-> tf.while_loop
(支持break 和 continue)if
->tf.cond
for _ in dataset
-> dataset.reduce
AutoGraph支持控制流的任意嵌套,这使得能够有较好性能而且简洁地实现许多复杂的ML程序,如序列模型,强化学习,自定义训练循环等。框架
TensorFlow 1.x中常见使用模式是“kitchen sink”策略,其中全部可能的计算的联合被预先布置,而后选择被评估的张量,经过session.run()
运行。在TensorFlow 2.0中,用户应该将代码重构为较小的函数,这些函数根据须要被调用。一般,没有必要用tf.function
去装饰那些比较小的函数;仅用tf.function
去装饰高等级的计算,例如,训练的一个步骤,或模型的前向传递。异步
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的.fit
API来利用这些集成。
这是一个迁移学习的例子,演示了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)
在内存中迭代拟合训练数据时,能够随意使用常规的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)
AutoGraph提供了一种将依赖于数据的控制流转换为等效图形模式的方法,如tf.cond
和tf.while_loop
。
数据相关控制流出现的一个常见位置是序列模型。tf.keras.layers.RNN
包装了一个RNN cell,容许您既能够静态也能够动态的循环展开。为了演示,您能够从新实现动态展开,以下所示:
class DynamicRNN(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功能的更详细概述,请参阅指南
要记录摘要,请使用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
。