将您的代码从 TensorFlow 1 迁移到 TensorFlow 2(一)

注:原文中有很多链接,无法在微信内容中一一展示,如需请点击“阅读原文”直达官网内容页(英文)。

在 Google Colab 中运行
https://colab.research.google.com/github/tensorflow/docs/blob/master/site/en/guide/migrate.ipynb
在 GitHub 上查看源代码
https://github.com/tensorflow/docs/blob/master/site/en/guide/migrate.ipynb

下载笔记本
https://storage.googleapis.com/tensorflow_docs/docs/site/en/guide/migrate.ipynb

重要说明:
这份文档适用于使用低级别 TensorFlow API 的用户。如果您正在使用高级别 API (tf.keras),可能无需或仅需对您的代码执行很少操作,便可以让代码完全兼容 TensorFlow 2.0。查看您的优化器默认学习速率。

优化器默认学习速率
https://tensorflow.google.cn/guide/migrate#keras_optimizer_lr

在 TensorFlow 2.0 中,1.X 的代码不经修改也许还可运行(除了 contrib):
Contrib
https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

但是,这样做无法让您利用到我们对 TensorFlow 2.0 做出的许多改进。这份指南可以帮助您升级代码,让代码更加简洁、性能更好、更容易维护。

自动转换脚本

尝试执行文档中描述的这些变更之前,首先需运行此升级脚本 (https://tensorflow.google.cn/guide/upgrade)。
这是将您的代码升级到 TensorFlow 2.0 的第一步。但您的代码不会因此具有 2.0 的特点。您的代码仍然可以使用 tf.compat.v1 端点来访问占位符、会话、集合以及 1.x 版本的其他功能。

高层行为变更

如果您使用tf.compat.v1.disable_v2_behavior()让您的代码可以在 TensorFlow 2.0 中工作,那么您仍需要处理全局行为变更。重大变更有:

Eager execution,v1.enable_eager_execution():任何隐式使用 tf.Graph 的代码都会执行失败。确保将这个代码打包进 with tf.Graph().as_default() 上下文中。
资源变量,v1.enable_resource_variables():一些代码可能会依赖由 TF 参考变量启用的非确定性行为。对资源变量进行写入时,它会处于锁定状态,因此可以提供更直观的一致性保证。
在边缘情形中,启用资源变量可能会改变其中的行为。
启用资源变量可能会创建额外的副本以及有更高的内存使用情况。
可以通过将 use_resource=False 传递给 tf.Variable 构造器来禁用资源变量。
Tensor Shapes,v1.enable_v2_tensorshape():TF 2.0 可简化张量形状的行为。您可以使用 t.shape[0],而不需要使用 t.shape[0].value。这样的变更很小,因此最好立即加以修复。有关示例,请参阅 TensorShape。
Control flow,v1.enable_control_flow_v2():TF 2.0 中的控制流实施已得到简化,因此会有不同的图表征。如有任何问题,请提交错误报告。

提交错误报告
https://github.com/tensorflow/tensorflow/issues

让代码成为 2.0 原生代码

这份指南会逐步讲解将 TensorFlow 1.x 代码转换成 TensorFlow 2.0 代码的示例。这一变更让您的代码可以获得性能优化和简化的 API 调用的优势。

在以下各种情况下,模式为:

  1. 替换 v1.Session.run 调用
    每一个 v1.Session.run 调用都应该替换为一个 Python 函数。

feed_dict 和 v1.placeholder 成为函数参数;

fetches 成为函数的返回值;

在转换期间,即刻执行使用标准 Python 工具(如 pdb)让调试变得简单。

之后添加一个 tf.function 修饰器,这样可以更有效率地在图中运行。如需了解其工作原理的更多内容,请参阅 AutoGraph 指南 。
AutoGraph 指南
https://tensorflow.google.cn/guide/function

请注意:

与v1.Session.run不同,tf.function有固定的返回签名,并且总是返回所有的输出。如果这样会导致性能问题,建议创建两个单独的函数;

不需要进行tf.control_dependencies或类似的操作:tf.function 会像事先写好一样,按顺序运行。例如,tf.Variable 赋值和 tf.assert 就会自动执行。

  1. 使用 Python 对象来追踪变量和损失

在 TF 2.0 中,强烈建议不要使用基于名称的变量追踪。请使用 Python 对象来追踪变量。
请使用tf.Variable,而不要使用v1.get_variable。

每一个v1.variable_scope 应该转换为一个 Python 对象。通常是下列对象中的一个:

tf.keras.layers.Layer

tf.keras.Model

tf.Module

如果您需要聚合变量列表(如tf.Graph.get_collection(tf.GraphKeys.VARIABLES),请使用Layer和Model对象中的.variables和.trainable_variables属性。

这些 Layer 和 Model 类会实施多种其他属性,因此不需要全局集合。其 .losses 属性可以替代 tf.GraphKeys.LOSSES 集合。

请参阅 Keras 指南了解详情。

Keras 指南
https://tensorflow.google.cn/guide/keras

警告:
许多 tf.compat.v1 符号会以隐式方式使用全局集合。

  1. 升级您的训练循环
    使用适合您用例的最高级别 API。推荐使用 tf.keras.Model.fit 构建自己的训练循环。
    这些高级别函数负责管理许多自己编写训练循环时容易漏掉的低级别细节。例如,这些函数会自动收集正则化损失,并且当调用模型时设置 training=True 参数。

  2. 升级您的数据输入流水线
    使用 tf.data 数据集进行数据输入。这些对象高效、可表达,与 TensorFlow 有很好的集成。
    可以直接传递到 tf.keras.Model.fit 方法。

    model.fit(dataset, epochs=5)
    可以直接通过标准 Python 来遍历:

    for example_batch, label_batch in dataset:
    break

  3. 迁移 compat.v1 符号
    tf.compat.v1 模块含有完整的 TensorFlow 1.x API,且具有其原始的语义。
    如果此类转换安全,则 TF2 升级脚本会将符号转换成 2.0 版本中对应的符号,即脚本能够确认行为在 2.0 版本与 1.x 中完全等效(例如,脚本判断两者是同一个函数,因此将 v1.arg_max 重命名为 tf.argmax)。
    升级脚本运行结束后,会留下一段代码,其中很可能多次出现 compat.v1。建议逐行检查代码,手动将其转换成 2.0 版本中对应的符号(如果有对应的符号,则会在日志中提及)。

模型转换

  1. 设置

     from __future__ import absolute_import, 		division, print_function, unicode_literals
     import tensorflow as tf
    
     import tensorflow_datasets as tfds
    
  2. 低级别变量和运算符的执行
    低级别 API 使用方法示例包括:
    使用变量作用域控制重用
    使用 v1.get_variable 创建变量。
    以显式方式访问集合
    以隐式方式访问集合,方法如下:
    v1.global_variables
    v1.losses.get_regularization_loss
    使用 v1.placeholder 设置图输入
    使用 Session.run 执行图
    手动初始化变量
    2.1 转换前
    使用 TensorFlow 1.x 的代码中的这些模式如下所示。

     in_a = tf.placeholder(dtype=tf.float32, shape=(2))
     in_b = tf.placeholder(dtype=tf.float32, shape=(2))
    
     def forward(x):
     with tf.variable_scope("matmul", reuse=tf.AUTO_REUSE):
     	W = tf.get_variable("W", initializer=tf.ones(shape=(2,2)),
                     regularizer=tf.contrib.layers.l2_regularizer(0.04))
     	b = tf.get_variable("b", initializer=tf.zeros(shape=(2)))
     	return W * x + b
    
     out_a = forward(in_a)
     out_b = forward(in_b)
    
     reg_loss=tf.losses.get_regularization_loss(scope="matmul")
    
     with tf.Session() as sess:
     	sess.run(tf.global_variables_initializer())
     	outs = sess.run([out_a, out_b, reg_loss],
             feed_dict={in_a: [1, 0], in_b: [0, 1]})
    

2.2 转换后

在转换后的代码中:

变量都是本地 Python 对象
forward 函数仍然定义计算
Session.run 的调用转换成对 forward 的调用
如果出于性能方面的考虑,也可以添加可选的 tf.function 修饰器
可以手动计算正则化,无需参考任何全局集合

没有会话或占位符

W = tf.Variable(tf.ones(shape=(2,2)), name="W")
b = tf.Variable(tf.zeros(shape=(2)), name="b")

@tf.function
def forward(x):
 return W * x + b

out_a = forward([1,0])
print(out_a)
tf.Tensor(

[[1. 0.]
[1. 0.]], shape=(2, 2), dtype=float32)

out_b = forward([0,1])

regularizer = tf.keras.regularizers.l2(0.04)
reg_loss=regularizer(W)
  1. 基于 tf.layers 的模型
    v1.layers 模块用来包含需要依赖 v1.variable_scope 的层函数以定义和重用变量。
    3.1 转换前

     def model(x, training, scope='model'):
     with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
     	x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu,
       kernel_regularizer=tf.contrib.layers.l2_regularizer(0.04))
     	x = tf.layers.max_pooling2d(x, (2, 2), 1)
     	x = tf.layers.flatten(x)
     	x = tf.layers.dropout(x, 0.1, training=training)
     	x = tf.layers.dense(x, 64, activation=tf.nn.relu)
     	x = tf.layers.batch_normalization(x, training=training)
     	x = tf.layers.dense(x, 10)
     	return x
    
     train_out = model(train_data, training=True)
     test_out = model(test_data, training=False)
    

3.2 转换后

这一简单的层堆栈可整齐地置于 tf.keras.Sequential 中(如需了解更加复杂的模型,请参阅自定义层和模型,以及函数式 API)
这个模型可以追踪变量和正则化损失
这个转换过程为一对一进行,因为有从 v1.layers 到 tf.keras.layers 的直接映射

大部分参数保持不变。但要注意区别:
training 参数运行时,模型将其传递到每个层
原始 model 函数的第一个参数(输入 x)会消失。这是因为对象层会将构建模型和调用模型分开

另请注意:
如果您使用的是 tf.contrib 初始化器的正则化器,则相比其他正则化器,会有更多的参数变动
代码不再写入集合,v1.losses.get_regularization_loss 之类的函数不再返回这些值,因此很可能破坏您的训练循环

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.04),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10)
])

train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 1))
train_out = model(train_data, training=True)
print(train_out)
tf.Tensor([[0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]], shape=(1, 10), dtype=float32)
test_out = model(test_data, training=False)
print(test_out)

tf.Tensor(
[[0.08641145 0.07439621 0.08764433 0.08413846 0.13945633 0.10146178
0.08674773 0.10674053 0.13481253 0.09819068]], shape=(1, 10), dtype=float32)

#Here are all the trainable variables.
len(model.trainable_variables)

8

#Here is the regularization loss.
model.losses

[]
4. 混合变量和 v1.layers
现有代码经常将低级别 TF 1.x 的变量和运算与高级别的 v1.layers 混合。

4.1 转换前

def model(x, training, scope='model'):
  with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
    W = tf.get_variable(
      "W", dtype=tf.float32,
      initializer=tf.ones(shape=x.shape),
      regularizer=tf.contrib.layers.l2_regularizer(0.04),
      trainable=True)
    if training:
      x = x + W
    else:
      x = x + W * 0.5
    x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu)
    x = tf.layers.max_pooling2d(x, (2, 2), 1)
    x = tf.layers.flatten(x)
    return x

train_out = model(train_data, training=True)
test_out = model(test_data, training=False)

4.2 转换后

如要转换这个代码,请遵循之前示例中的层到层的映射模式。

v1.variable_scope 实际上是其自身的层。因此将其重写为 tf.keras.layers.Layer。请参阅此指南以了解详情。
指南
https://tensorflow.google.cn/guide/keras/custom_layers_and_models

通用模式是:
在__init__ 中收集层参数
在 build 中构建变量
在 call 中执行计算,然后返回结果

v1.variable_scope 本质上是其自身的层。因此将其重写为 tf.keras.layers.Layer。请参阅此指南以了解详情。

指南
https://tensorflow.google.cn/guide/keras/custom_layers_and_models

#Create a custom layer for part of the model
class CustomLayer(tf.keras.layers.Layer):
  def __init__(self, *args, **kwargs):
    super(CustomLayer, self).__init__(*args, **kwargs)

  def build(self, input_shape):
    self.w = self.add_weight(
        shape=input_shape[1:],
        dtype=tf.float32,
        initializer=tf.keras.initializers.ones(),
        regularizer=tf.keras.regularizers.l2(0.02),
        trainable=True)

  # Call method will sometimes get used in graph mode,
  # training will get turned into a tensor
  @tf.function
  def call(self, inputs, training=None):
    if training:
      return inputs + self.w
    else:
      return inputs + self.w * 0.5
custom_layer = CustomLayer()
print(custom_layer([1]).numpy())
print(custom_layer([1], training=True).numpy())

[1.5]
[2.]

train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 1))
#Build the model including the custom layer
model = tf.keras.Sequential([
    CustomLayer(input_shape=(28, 28, 1)),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
])

train_out = model(train_data, training=True)
test_out = model(test_data, training=False)

请注意下列事项:
子类 Keras 模型和层需要在 v1 图(自动控制依赖项)中以即刻模式运。
将call()打包进tf.function()来获得自动图和自动控制依赖项。
不要忘记接受一个 call 的 training 参数。
有时是 tf.Tensor。
有时是 Python 布尔值。
使用 self.add_weight() 在构造函数或 Model.build 中创建模型变量。
在 Model.build 中,您可以访问输入形状,因此可以创建具有匹配形状的权重。
用 tf.keras.layers.Layer.add_weight 后,Keras 可以追踪变量和正则化损失。
不要在您的对象中保留 tf.Tensors。
否则可能会在 tf.function 或即刻上下文中创建,导致产生这些行为不一样的张量。
使用 tf.Variable 获得状态,而这些变量在两种上下文中可以一直使用
tf.Tensors 只适用于中间值。

  1. Slim 和 contrib.layers 注意事项
    很大一部分旧的 TensorFlow 1.x 代码使用 Slim 代码库,可使用 TensorFlow 1.x 将其打包成tf.contrib.layers。作为contrib的模块,在 TensorFlow 2.0 中将不再可用,即使在tf.compat.v1中亦如此。将使用 Slim 的代码转换到 TF 2.0 比转换使用v1.layers的代码库涉及的因素更多。事实上,最好先将您的 Slim 代码转换到v1.layers,然后再转换到 Keras。

移除 arg_scopes,所有参数均需要为显式;
如要使用,请将normalizer_fn和activation_fn分离至其自己的层中;
可分离的卷积层映射至一个或多个不同的 Keras 层(深度、逐点和可分离 Keras 层);
Slim 与 v1.layers 有不同的参数名和默认值;
一些参数有不同的尺度;
如果您使用 Slim 预训练模型,可以尝试来自 tf.keras.applications 的 Keras 预训练模型或从原始 Slim 代码导出的 TF Hub TF2 SavedModel。

Slim
https://ai.googleblog.com/2016/08/tf-slim-high-level-library-to-define.html
一些 tf.contrib 层没有移至核心 TensorFlow,相反移至 TF add-ons 组件包中。
TF add-ons 组件包
https://github.com/tensorflow/addons

训练

有许多方法可以将数据喂给 tf.keras 模型。这些方法可以将 Python 生成器和 Numpy 数组作为输入接收。

推荐使用 tf.data 软件包将数据喂给模型,其中包含操作数据的高性能类集合。

如果您使用的仍然是 tf.queue,则现在仅支持将这些当作数据结构,而不能作为输入流水线。

  1. 使用数据集
    TensorFlow Datasets 软件包 (tfds) 包含将预定义数据集加载成 tf.data.Dataset 对象的实用程序。
    TensorFlow Datasets
    https://tensorflow.google.cn/datasets

tfds
https://tensorflow.google.cn/datasets/api_docs/python/tfds

例如,使用 tfds 加载 MNIST 数据集:

datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)
mnist_train, mnist_test = datasets['train'], datasets['test']

Downloading and preparing dataset mnist (11.06 MiB) to /home/kbuilder/tensorflow_datasets/mnist/1.0.0…

WARNING:absl:Dataset mnist is hosted on GCS. It will automatically be downloaded to your
local data directory. If you’d instead prefer to read directly from our public
GCS bucket (recommended if you’re running on GCP), you can instead set
data_dir=gs://tfds-data/datasets.

HBox(children=(FloatProgress(value=0.0, description=‘Dl Completed…’, max=19.0, style=ProgressStyle(descripti…

Dataset mnist downloaded and prepared to /home/kbuilder/tensorflow_datasets/mnist/1.0.0. Subsequent calls will reuse this data.

然后准备用于训练的数据:

重新缩放每个图像;

将样本顺序随机排列;

收集图像和标签批次。

BUFFER_SIZE = 10 # Use a much larger value for real code.
BATCH_SIZE = 64
NUM_EPOCHS = 5


def scale(image, label):
  image = tf.cast(image, tf.float32)
  image /= 255

  return image, label

为了使样本简短,将数据集修剪为仅返回 5 个批次:

train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
test_data = mnist_test.map(scale).batch(BATCH_SIZE)

STEPS_PER_EPOCH = 5

train_data = train_data.take(STEPS_PER_EPOCH)
test_data = test_data.take(STEPS_PER_EPOCH)
image_batch, label_batch = next(iter(train_data))
  1. 使用 Keras 训练循环

如果您不需要对训练过程进行低级别的控制,推荐使用 Keras 内置的fit、evaluate和predict方法。无论以何种方式实施(顺序式、函数式或子类式),这些方法都能提供统一的界面用来训练模型。

这些方法的优点有:
接受 Numpy 数组、Python 生成器和tf.data.Datasets;
自动应用正则化和激活损失;
支持tf.distribute来进行多设备训练;
支持将任意可调用项作为损失和指标;
支持tf.keras.callbacks.TensorBoard之类的回调以及自定义回调;
性能出色,可自动使用 TensorFlow 图。

下面是使用 Dataset 训练模型的示例(如需了解工作原理详情,请参阅教程

(https://tensorflow.google.cn/tutorials))。

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.02),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10)
])

# Model is the full model w/o custom layers
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

model.fit(train_data, epochs=NUM_EPOCHS)
loss, acc = model.evaluate(test_data)

print("Loss {}, Accuracy {}".format(loss, acc))

Epoch 1/5
5/5 [] - 1s 135ms/step - loss: 1.5057 - accuracy: 0.5469
Epoch 2/5
5/5 [
] - 0s 25ms/step - loss: 0.5486 - accuracy: 0.8844
Epoch 3/5
5/5 [] - 0s 27ms/step - loss: 0.3718 - accuracy: 0.9375
Epoch 4/5
5/5 [
] - 0s 26ms/step - loss: 0.2631 - accuracy: 0.9656
Epoch 5/5
5/5 [==============================] - 0s 26ms/step - loss: 0.2045 - accuracy: 0.9875
5/Unknown - 0s 27ms/step - loss: 1.5769 - accuracy: 0.6562Loss 1.5769457340240478, Accuracy 0.65625

  1. 编写自己的循环
    如果 Keras 模型训练步骤对您而言有效,但您需要超过此步骤外的更多控制,可以考虑在自己的数据迭代循环中使用tf.keras.Model.train_on_batch方法。
    请谨记:很多对象可以作为tf.keras.callbacks.Callback实施。

这个方法不仅具备上文提及的方法的诸多优势,而且可以让用户控制外循环。

在训练期间,您也可以使用tf.keras.Model.test_on_batch或tf.keras.Model.evaluate来检查性能。

请注意:
train_on_batch 和 test_on_batch 默认返回单个批次的损失和指标。如果您传入 reset_metrics=False,则会返回累加指标,而且必须记住适当地重置指标累加器。同样请谨记像 AUC 一类的指标需要 reset_metrics=False 来对其准确计算。

为了继续训练上述模型:

# Model is the full model w/o custom layers
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

metrics_names = model.metrics_names

for epoch in range(NUM_EPOCHS):
  #Reset the metric accumulators
  model.reset_metrics()

  for image_batch, label_batch in train_data:
    result = model.train_on_batch(image_batch, label_batch)
    print("train: ",
          "{}: {:.3f}".format(metrics_names[0], result[0]),
          "{}: {:.3f}".format(metrics_names[1], result[1]))
  for image_batch, label_batch in test_data:
    result = model.test_on_batch(image_batch, label_batch,
                                 # return accumulated metrics
                                 reset_metrics=False)
  print("\neval: ",
        "{}: {:.3f}".format(metrics_names[0], result[0]),
        "{}: {:.3f}".format(metrics_names[1], result[1]))

train: loss: 0.128 accuracy: 1.000
train: loss: 0.213 accuracy: 1.000
train: loss: 0.174 accuracy: 0.969
train: loss: 0.220 accuracy: 0.984
train: loss: 0.351 accuracy: 0.906

eval: loss: 1.542 accuracy: 0.656
train: loss: 0.076 accuracy: 1.000
train: loss: 0.118 accuracy: 1.000
train: loss: 0.102 accuracy: 1.000
train: loss: 0.125 accuracy: 1.000
train: loss: 0.188 accuracy: 0.984

eval: loss: 1.546 accuracy: 0.663
train: loss: 0.067 accuracy: 1.000
train: loss: 0.080 accuracy: 1.000
train: loss: 0.087 accuracy: 1.000
train: loss: 0.077 accuracy: 1.000
train: loss: 0.132 accuracy: 0.984

eval: loss: 1.553 accuracy: 0.694
train: loss: 0.065 accuracy: 1.000
train: loss: 0.067 accuracy: 1.000
train: loss: 0.071 accuracy: 1.000
train: loss: 0.061 accuracy: 1.000
train: loss: 0.073 accuracy: 1.000

eval: loss: 1.516 accuracy: 0.762
train: loss: 0.058 accuracy: 1.000
train: loss: 0.061 accuracy: 1.000
train: loss: 0.055 accuracy: 1.000
train: loss: 0.056 accuracy: 1.000
train: loss: 0.054 accuracy: 1.000

eval: loss: 1.482 accuracy: 0.800
train: loss: 0.059 accuracy: 1.000
train: loss: 0.062 accuracy: 1.000
train: loss: 0.046 accuracy: 1.000
train: loss: 0.056 accuracy: 1.000
train: loss: 0.051 accuracy: 1.000

eval: loss: 1.451 accuracy: 0.822

  1. 自定义训练步骤
    您可以通过实施自己的训练循环来获得更多的灵活度和控制力。分为三个步骤:
    遍历 Python 生成器或tf.data.Dataset来获得一批样本。

使用tf.GradientTape来收集梯度。
使用tf.keras.optimizers中的一个将权重更新应用于模型变量。

请谨记:

总是在子类层和模型的 call 方法上加入 training 参数。
确保 training 参数设置准确时调用模型。
直到模型基于一批数据运行后,模型变量才会存在,具体视使用方法而定。
您需要手动处理模型正则化损失这类的对象。

与 v1 相比的简化如下:

无需运行变量初始化器。变量创建时已初始化。
无需添加手动控制依赖项。即使在 tf.function 中,操作也像在即刻模式中一样。

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.02),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10)
])

optimizer = tf.keras.optimizers.Adam(0.001)
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

@tf.function
def train_step(inputs, labels):
  with tf.GradientTape() as tape:
    predictions = model(inputs, training=True)
    regularization_loss=tf.math.add_n(model.losses)
    pred_loss=loss_fn(labels, predictions)
    total_loss=pred_loss + regularization_loss

  gradients = tape.gradient(total_loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))

for epoch in range(NUM_EPOCHS):
  for inputs, labels in train_data:
    train_step(inputs, labels)
  print("Finished epoch", epoch)

Finished epoch 0
Finished epoch 1
Finished epoch 2
Finished epoch 3
Finished epoch 4
5. 新版指标和损失
在 TensorFlow 2.0 中,指标和损失是对象。两者都是即刻工作模式,且都位于tf.function中。
损失对象是可调用型,并且使用 (y_true, y_pred) 作为参数:

cce = tf.keras.losses.CategoricalCrossentropy(from_logits=True)
cce([[1, 0]], [[-1.0,3.0]]).numpy()

4.01815

指标对象有以下方法:
Metric.update_state() — 添加新的观察结果;
Metric.result() — 依据观察到的值,得到指标的当前结果;
Metric.reset_states() — 清除所有观察结果。

对象本身是可调用型。使用 update_state 后,调用会用新的观察结果更新状态,并返回指标的新结果。

您不需要手动初始化指标的变量,而且由于 TensorFlow 2.0 有自动控制依赖项,所以也不需要担心这两点。

下面的代码使用一个指标来跟踪自定义训练循环中观察到的平均损失。

# Create the metrics
loss_metric = tf.keras.metrics.Mean(name='train_loss')
accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')

@tf.function
def train_step(inputs, labels):
  with tf.GradientTape() as tape:
    predictions = model(inputs, training=True)
    regularization_loss=tf.math.add_n(model.losses)
    pred_loss=loss_fn(labels, predictions)
    total_loss=pred_loss + regularization_loss

  gradients = tape.gradient(total_loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  # Update the metrics
  loss_metric.update_state(total_loss)
  accuracy_metric.update_state(labels, predictions)


for epoch in range(NUM_EPOCHS):
  # Reset the metrics
  loss_metric.reset_states()
  accuracy_metric.reset_states()

  for inputs, labels in train_data:
    train_step(inputs, labels)
  # Get the metric results
  mean_loss=loss_metric.result()
  mean_accuracy = accuracy_metric.result()

  print('Epoch: ', epoch)
  print('  loss:     {:.3f}'.format(mean_loss))
  print('  accuracy: {:.3f}'.format(mean_accuracy))

Epoch: 0
loss: 0.173
accuracy: 0.997
Epoch: 1
loss: 0.138
accuracy: 1.000
Epoch: 2
loss: 0.117
accuracy: 1.000
Epoch: 3
loss: 0.099
accuracy: 1.000
Epoch: 4
loss: 0.093
accuracy: 0.997

  1. Keras 优化器
    v1.train中的优化器(如v1.train.AdamOptimizer和v1.train.GradientDescentOptimizer)可以在tf.keras.optimizers中找到对应项。
    将 v1.train 转换到 keras.optimizers

转换优化器时,请注意以下几点:

升级优化器可能会使旧的检查点不兼容。
现在,所有的 ε (epsilons) 默认值为 1e-7 而不是 1e-8(大多数情况下可以忽略不计)。
v1.train.GradientDescentOptimizer 可以用 tf.keras.optimizers.SGD 直接替代。
可以通过使用 momentum 参数:tf.keras.optimizers.SGD(…, momentum=…) 将 v1.train.MomentumOptimizer 直接替换成 SGD 优化器。
v1.train.AdamOptimizer能够经过转换来使用tf.keras.optimizers.Adam。beta1和beta2参数已重命名为beta_1和beta_2。
v1.train.RMSPropOptimizer 可以转换为 tf.keras.optimizers.RMSprop。decay 参数已重命名为 rho。
v1.train.AdadeltaOptimizer 可以直接转换为 tf.keras.optimizers.Adadelta。
tf.train.AdagradOptimizer 可以直接转换为 tf.keras.optimizers.Adagrad。
tf.train.FtrlOptimizer 可以直接转换为 tf.keras.optimizers.Ftrl。accum_name 和 linear_name 参数已移除。
tf.contrib.AdamaxOptimizer 和 tf.contrib.NadamOptimizer 可以直接转换为 tf.keras.optimizers.Adamax 和 tf.keras.optimizers.Nadam。beta1 和 beta2 参数已重命名为 beta_1 和 beta_2。

一些 tf.keras.optimizers 的全新默认值 (https://tensorflow.google.cn/api_docs/python/tf/keras/optimizers)。
警告:
如果您发现模型的收敛行为发生变化,请检查默认学习速率。

optimizers.SGD、optimizers.Adam 或 optimizers.RMSprop 没有做任何变更。

以下几个优化器的默认学习速率已变更:

optimizers.Adagrad 从 0.01 变更到 0.001
optimizers.Adadelta 从 1.0 变更到 0.001
optimizers.Adamax 从 0.002 变更到 0.001
optimizers.Nadam 从 0.002 变更到 0.001

  1. TensorBoard

TensorFlow 2.0 包含 tf.summary API 的重大更新,该 API 用于写入摘要数据以在 TensorBoard 中进行可视化。有使用 TF 2.0 API 编写的多份教程可为您提供全新 tf.summary 的总体介绍。其中包含一份 TensorBoard TF2.0 迁移指南。

多份教程
https://tensorflow.google.cn/tensorboard/r2/get_started

TensorBoard TF2.0 迁移指南
https://tensorflow.google.cn/tensorboard/r2/migrate_tf2
原文链接
https://tensorflow.google.cn/guide/migrate#premade_estimators
将您的代码从 TensorFlow 1 迁移到 TensorFlow 2(一)_第1张图片
关注公众号渣渣渣辉,回复手册获取更多.

如果帮到了你,就请收藏评论加点赞,多谢支持。

原文来自微信公众号,侵删。

你可能感兴趣的:(将您的代码从 TensorFlow 1 迁移到 TensorFlow 2(一))