TF 1.0到2.0迁移

作者: AnuoF | 来源:发表于2019-04-11 20:33 被阅读0次

    TF 1.0到2.0迁移

    在TensorFlow 2.0中,仍然可以运行未经修改的1.x代码(contrib除外):

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

    但是,这并不能让您利用TensorFlow
    2.0中的许多改进。本指南将帮助您升级代码,使其更简单、更高效、更易于维护。

    自动转换脚本

    第一步是尝试运行升级脚本

    这将在将代码升级到TensorFlow
    2.0时执行初始步骤,但是它不能使您的代码适合TensorFlow
    2.0。您的代码仍可以使用tf.compat.v1端点来访问占位符、会话、集合和其他1.x样式的功能。

    使代码2.0原生化

    本指南将介绍将TensorFlow 1.x代码转换为TensorFlow
    2.0的几个示例。这些更改将使您的代码利用性能优化和简化的API调用。

    在每一种情况下,模式是:

    1. 替换tf.Session.run调用

    每个tf.Sessionrun调用都应该被Python函数替换:

    • feed_dict和tf.placeholder变成函数参数

    • fetches变成函数的返回值

    您可以使用标准Python工具(如pdb)逐步调试该函数。如果您对它的工作满意,可以添加一个tf.function装饰器,使其在图形模型下高效运行。有关其工作原理的更多信息,请参阅AutoGraph指南。

    2. 使用Python对象来跟踪变量和损失

    使用tf.Variable代替tf.get_variable。每个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指南

    3. 升级您的训练循环

    使用适用于您的用例的最高级API,最好是tf.keras.Model.fit建立自己的训练循环。

    如果您编写自己的训练循环,这些高级函数可以管理很多困难容易遗漏的低级细节。例如,它们会自动收集正则化损失,并在调用模型时设置training=True参数。

    4. 升级数据输入管道

    使用tf.data数据集进行数据输入,这些对象是高效的、富有表现力的,并且与张量流很好地集成。它们可以直接传递给tf.keras.Model.fit方法。

    model.fit(dataset, epochs=5)
    

    它们可以直接在标准Python上进行迭代:

    for example_batch, label_batch in dataset: break 
    

    转换模型

    1. 安装

    from __fucture__ import absolute_import, division, print_function 
    import tensorflow as tf \# pip install –q tensorflow==2.0.0-alpha0 
    import tensorflow_datasets as tfds
    

    2. 低阶变量和操作执行

    低级API使用的示例包括:

    • 使用变量范围来控制重用

    • 使用tf.get_variable创建变量

    • 明确地访问集合

    • 使用以下方式隐式访问集合:

    • tf.global_variables

    • tf.losses.get_regularization_loss

    • 使用tf.placeholder设置图形输入

    • 使用session.run执行图

    • 手动初始化变量

    转换前

    以下是使用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’, resuse=tf.AUTO_RESUE): 
            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 x \* train_data + b 
    
    out_a = model(in_a) 
    out_b = model(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]})
    

    转换后

    在转换后的代码中:

    • 变量是本地Python对象

    • 前向函数依然定义了计算

    • sess.run调用被替换为forward的调用

    • 可以添加可选的tf.function装饰器以提高性能

    • 正则化是手动计算的,不设计任何全局集合

    • 没有sessions和placeholders

      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) 
      
      out_b = forward([0, 1]) 
      regularizer = tf.keras.regularizers.l2(0.02) 
      reg_loss = regularizer(W)                                                                                   
      

    3. 基于tf.layers的模型

    tf.layers模块用于包含依赖于tf.variable_scope来定义和重用变量的层函数。

    转换前

    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, activation=tf.nn.softmax) 
            return x 
    
    train_out = model(train_data, training=True) 
    test_out = model(test_data, training=False)
    

    转换后

    • 简单的层堆栈可以整齐地放入tf.keras.Sequence中。(对于更复杂的模型,请参见自定义层和模型,以及函数API)

    • 模型跟踪变量和正则化损失

    • 转换是一对一的,因为它是从tf.layers到tf.keras.layers直接映射的。

    大多数参数保持不变,但注意区别:

    • 训练参数在运行时由模型传递给每个层

    • 原来模型函数的第一个参数(intput x)消失,这是因为层将构建模型与调用模型分开了。

    同时也要注意:

    • 如果你使用tf.contrib的初始化器的正则化器,那么它们的参数变化会比其他变量更多。

    • 代码不在写入集合,因此像tf.losses.get_regularization_loss这样的函数将不再返回这些值,这可能会破坏您的训练循环。

      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.lyaers.BatchNormalization(), 
          tf.keras.layers.Dense(10, activation=’softmax’) 
      ]) 
      
      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) 
      test_out = model(test_data, training= False) 
      print(test_out) # 这里是所有可训练的变量 
      print(len(model.trainable_variables) # 这里是正则化损失 print(model.losses) 
      

    4. 混合变量和tf.layers

    现存的代码通常将较低级别的TF 1.x变量和操作与较高级的tf.layers混合。

    转换前

    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)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
    

    转换后

    要转换此代码,请遵循将图层映射到图层的模式,如上例所示。

    一般模式是:

    • init中收集层参数

    • 在build中构建变量

    • 在call中执行计算并返回结果

    tf.variable_scope实际上是它自己的一层,因此将其重写为tf.keras.layers.Layer。有关信息信息请参阅指南

    # 创建自定义图层 
    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) # 调用方法有时会在图形模式下使用,训练会变成一个张量 
        
        @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()) 
    
    train_data = tf.ones(shape=(1, 28, 28, 1)) 
    test_data = tf.ones(shape=(1, 28, 18, 1)) # 构建包含自定义层的模型 
    
    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, trainging=False)                                                                                                                                                                                         
    

    需要注意以下几点:

    • 子类化的Keras模型和层需要在v1图(无自动控制依赖关系)和eager模型是运行

    • 将call()封装在tf.function()中以获取自动图和自动控制依赖项

    • 不要忘了调用时需要一个训练参数(tf.Tensor或Python布尔值)

    • 使用self.add_weight()在构造函数或def build()中创建模型变量

    • 在build中,您可以访问数据的形状,因此可以创建具有匹配形状的权重

    • 使用tf.keras.layers.Layser.add_weight可以让Keras跟踪变量和正则化损失

    • 不要将tf.Tensor保存在你的对象中

    • 它们可能在tf.function中或eager上下文中创建,并且这些张量的行为也不同

    • 使用tf.Variables作为状态,它们始终可用于两个上下文

    • tf.Tensors仅用于中间值

    5. 关于Slim和contrib.layers的说明

    大量较旧的TensorFlow 1.x代码使用Slim库,该库与TensorFlow
    1.x一起打包为tf.contrib.layers。
    作为contrib模块,即使在tf.compat.v1中,TensorFlow 2.0中也不再提供此模块。
    使用Slim将代码转换为TF 2.0比转换使用tf.layers的存储库更复杂。
    实际上,首先将Slim代码转换为tf.layers然后转换为Keras可能是有意义的。

    • 删除arg_scopes,所有args都需要显式

    • 如果您使用它们,请将normalizer_fn和activation_fn拆分为它们自己的图层

    • 可分离的转换层映射到一个或多个不同的Keras层(深度、点和可分离的Keras层)

    • Slim和tf.layers具有不同的arg名称和默认值

    • 有些args有不同的尺度

    • 如果您使用Slim预训练模型,请尝试使用tf.keras.applications或TFHub

    • 某些tf.contrib图层可能尚未移至核心TensorFlow,而是已移至TF附加组件包。

    训练

    有多种方式将数据馈送给tf.keras模型,可以是Python生成器和Numpy数据作为输入。

    将数据馈送给模型的推荐方法是使用tf.data包,其中包含一组用于处理数据的高性能类。

    如果您仍在使用tf.queue,则仅支持这些作为数据结构,而不是数据管道。

    1. 使用Datasets

    TensorFlow数据集包(tfds)包含用于将预定义数据集加载为tf.data.Dataset对象的使用程序。对于此示例,使用tfds加载MNIST数据集:

    datasets, ds_info = tfds.load(name=’mnist’, with_info=True, as_supervised=True) 
    mnist_train, mnist_test = datasets[‘train’], datasets[‘test’] 
    

    然后为训练准备数据:

    • 重新缩放每个图像

    • 打乱样本数据的顺序

    • 收集批量图像和标签

      BUFFER_SIZE = 10 # 实际代码中使用更大的值 
      BATCH_SIZE = 64 
      NUM_EPOCHS = 5 
      
      def scale(image, label): 
          image = tf.cast(image, tf.float32) 
          image /= 255 
          return image, label 
      
      train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE).take(5) 
      test_data = mnist_test.map(scale).batch(BATCH_SIZE).take(5) 
      STEPS_PER_EPOCH = 5 # 使示例保持简短,仅返回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)) 
      

    2. 使用Keras训练循环

    如果你不需要对训练过程进行低级别的控制,建议使用Keras内置的fit、evaluate和predict方法,这些方法提供了一个统一的接口来训练模型,而不管实现是什么(sequential、functional或子类化的)。

    这些方法的有点包括:

    • 它们接受Numpy数组、Python生成器和tf.data.Datasets

    • 它们自动应用正则化和激活损失

    • 它们支持用于多设备训练的tf.distribute

    • 它们支持任意的callables作为损失和指标

    • 它们支持回调,如tf.keras.callbacks.TensorBoard和自定义回调

    • 它们具有高性能,可自动使用TensorFlow图形

    以下是使用数据集训练模型的示例:

    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, activation=’softmax’) ]) 
    
    # 模型是没有自定义图层的完整模型 
    model.compile(optimizer=’adam’, loss=’spare_categorical_crossentropy’, 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 214ms/step - loss: 1.5402 - accuracy: 0.5063 Epoch 2/5 5/5 [==============================] - 0s 18ms/step - loss: 0.5344 - accuracy: 0.8875 Epoch 3/5 5/5 [==============================] - 0s 19ms/step - loss: 0.3505 - accuracy: 0.9406 Epoch 4/5 5/5 [==============================] - 0s 17ms/step - loss: 0.2635 - accuracy: 0.9781 Epoch 5/5 5/5 [==============================] - 0s 19ms/step - loss: 0.2163 - accuracy: 0.9750 5/Unknown - 0s 47ms/step - loss: 1.6750 - accuracy: 0.7781Loss 1.6750491619110108, Accuracy 0.778124988079071 |

    3. 编写你自己的训练循环

    如果Keras模型的训练步骤适合您,但您需要在该步骤之外进行更多的控制,请考虑在您自己的数据迭代循环中使用tf.keras.model.train_on_batch方法。

    记住:许多东西可以作为tf.keras.Callback的实现。

    此方法具有上一节中提到的方法的许多优点,但允许用户控制外循环。

    您还可以使用tf.keras.model.test_on_batch或tf.keras.Model.evaluate来检查训练期间的性能。

    继续训练上面的模型:

    # 模型是没有自定义图层的完整模型 
    model.compile(optimizer=’adam’, loss=’sparse_categorical_crossentropy’, metrics=[‘accuracy’]) 
    metrics_names = model.metrics_names 
    for epoch in range(NUM_EPOCHS): 
        # 重置指标 
        model.reset_metrics() 
    
    for image_batch, labels_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, reset_metrics=False) 
    print(“\\neval: “, “{}: {:.3f}”.format(metrics_names[0], result[0]), “{}: {:.3f}”.format(metrics_names[1], result[1]))                                                                                                                                                                                                                                                                                                                                                                        
    

    | train: loss: 0.279 accuracy: 0.938 train: loss: 0.270 accuracy: 0.953 train: loss: 0.282 accuracy: 0.922 train: loss: 0.181 accuracy: 0.984 train: loss: 0.226 accuracy: 0.984 eval: loss: 1.611 accuracy: 0.719 train: loss: 0.119 accuracy: 1.000 train: loss: 0.123 accuracy: 1.000 train: loss: 0.106 accuracy: 1.000 train: loss: 0.135 accuracy: 1.000 train: loss: 0.233 accuracy: 0.953 eval: loss: 1.610 accuracy: 0.784 train: loss: 0.095 accuracy: 1.000 train: loss: 0.097 accuracy: 1.000 train: loss: 0.106 accuracy: 1.000 train: loss: 0.165 accuracy: 0.953 train: loss: 0.165 accuracy: 0.969 eval: loss: 1.599 accuracy: 0.800 train: loss: 0.082 accuracy: 1.000 train: loss: 0.079 accuracy: 1.000 train: loss: 0.067 accuracy: 1.000 train: loss: 0.084 accuracy: 1.000 train: loss: 0.130 accuracy: 0.984 eval: loss: 1.571 accuracy: 0.797 train: loss: 0.069 accuracy: 1.000 train: loss: 0.067 accuracy: 1.000 train: loss: 0.054 accuracy: 1.000 train: loss: 0.061 accuracy: 1.000 train: loss: 0.121 accuracy: 0.984 eval: loss: 1.535 accuracy: 0.819 |

    4. 自定义训练步骤

    如果您需要更多的灵活性和控制,可以通过实现自己的训练循环来实现,有三个步骤:

    1. 迭代Python生成器或tf.data.Dataset以获取样本数据;

    2. 使用tf.GradientTape收集渐变;

    3. 使用tf.keras.optimizer将权重更新应用于模型。

    记住:

    • 始终在子类层和模型的调用方法中包含一个训练参数。

    • 确保在正确设置训练参数的情况下调用模型。

    • 根据使用情况,在对一批数据运行模型之前,模型变量可能不存在。

    • 您需要手动处理模型的正则化损失等事情

    请注意相对于v1的简化:

    • 不需要运行变量初始化器,变量在创建时初始化。

    • 不需要添加手动控制依赖项,即使在tf.function中,操作也像在eager模式下一样。

    • 上面的模型:

      model = tf.keras.Sequential([ 
          tf.keras.layers.Conv2D(32, 3, activation=’relu’, kernel_regularizer=tf.keras.regularizer.l2(0.02), 
          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, activation=’softmax’) ]) 
      
      optimizer = tf.keras.optimizers.Adam(0.001) 
      loss_fn = tf.keras.losses.SparseCategoricalCrossentropy() 
      
      @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中,metrics是对象,Metrics对象在eager和tf.functions中运行,一个metrics具有以下方法:

    • update_state() – 添加新的观察结果

    • result() – 给定观察值,获取metrics的当前结果

    • reset_states() – 清除所有观察值

    对象本身是可调用的,与update_state一样,调用新观察更新状态,并返回metrics的新结果。

    你不需要手动初始化metrics的变量,而且因为TensorFlow
    2.0具有自动控制依赖项,所以您也不需要担心这些。

    下面的代码使用metrics来跟踪自定义训练循环中观察到的平均损失:

    # 创建metrics 
    loss_metric = tf.keras.metrics.Mean(name=’train_loss’) 
    accuracy_metrics = 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)) 
    
        # 更新metrics 
        loss_metrics.update_state(total_loss) 
        accuracy_metrics.update_state(labels, predictions) 
    
    for epoch in range(NUM_EPOCHS):
        # 重置metrics 
        loss_metric.reset_states() 
        accuracy_metric.reset_states() 
        for inputs, labels in train_data: 
            train_step(inputs, labels) 
    
        # 获取metric结果 
        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.214 accuracy: 0.984 Epoch: 1 loss: 0.170 accuracy: 0.991 Epoch: 2 loss: 0.142 accuracy: 0.994 Epoch: 3 loss: 0.122 accuracy: 1.000 Epoch: 4 loss: 0.114 accuracy: 0.997 |

    保存和加载

    1. Checkpoint兼容性

    TensorFlow 2.0使用基于对象的检查点。

    如果小心的话,仍然可以加载旧式的基于名称的检查点,代码转换过程可能会导致变量名的更改,但是有一些变通的方法。

    最简单的方法是将新模型的名称与检查点的名称对齐:

    • 变量仍然都有你可以设置的名称参数。

    • Keras模型还采用名称参数,并将其设置为变量的前缀。

    • tf.name_scope函数可用于设置变量名称前缀,这与tf.variable_scope非常不同,它只影响名称,不跟踪变量和重用。

    如果这不适合您的用例,请尝试使用tf.compat.v1.train.init_from_checkpoint函数,它需要一个assignment_map参数,该参数指定从旧名称到新名称的映射。

    2. 保存的模型兼容性

    对于保存的模型没有明显的兼容性问题:

    • TensorFlow 1.x saved_models在TensorFlow 2.0中工作。

    • 如果支持所有操作,TensorFlow 2.0 saved_models甚至可以在TensorFlow
      1.x中加载工作。

    Estimators

    1. 使用Estimators进行训练

    TensorFlow 2.0支持Estimators,使用Estimators时,可以使用TensorFlow
    1.x中的input_fn()、tf.extimatro.TrainSpec和tf.estimator.EvalSpec。

    以下是使用input_fn和train以及evaluate的示例:

    # 定义一个estimator的input_fn 
    def input_fn(): 
        datasets, ds_info = tfds.load(name’mnish’, with_info=True, as_supervised=True) 
        mnish_train, mnist_test = datasets[‘train’], datasets[‘test’] 
    
        BUFFER_SIZE = 10000 
        BATCH_SIZE = 64 
        
        def scale(image, labels): 
            image = tf.cast(image, tf.float32) 
            image /= 255 
            return image, labels[…, tf.newaxis] 
        
        train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
        return train_data.repeat() 
    
    # 定义 train & eval specs 
    train_spec = tf.estimator.TrainSpec(input_fn=input_fn, max_steps=STEPS_PER_EPOCH * NUM_EPOCHS) 
    eval_spec = tf.estimator.EvalSpec(input_fn=input_fn, steps=STEPS_PER_EPOCH) 
    

    2. 使用Keras模型定义

    在TensorFlow2.0中如何构建estimators存在一些差异。我们建议您使用Keras定义模型,然后使用tf.keras.model_to_estimator将您的模型转换为estimator。下面的代码展示了如何在创建和训练estimator时使用这个功能。

    def make_model(): 
        rerurn tf.keras.Sequential([ tf.keras.layers.Conv2D(32, 3, activation=’relu’, kernel_regularizer=tf.keras.regularizers.l2(0.02), inut_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, activation=’softmax’) ]) 
    
    model = make_model() 
    model.compile(optimizer=’adam’, loss=’sparse_categorical_crossentropy’, metrics=[‘accuracy’]) 
    estimator = tf.keras.estimator.model_to_estimator(keras_model = model) 
    tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
    

    | W0307 18:10:32.629323 140330712794880 estimator.py:1799] Using temporary folder as model directory: /tmp/tmp8dhzipj4 W0307 18:10:33.441684 140330712794880 deprecation.py:323] From /usr/local/lib/python3.5/dist-packages/tensorflow/python/training/training_util.py:238: Variable.initialized_value (from tensorflow.python.ops.variables) is deprecated and will be removed in a future version. Instructions for updating: Use Variable.read_value. Variables in 2.X are initialized automatically both in eager and graph (inside tf.defun) contexts. W0307 18:10:36.949727 140330712794880 deprecation.py:323] From /usr/local/lib/python3.5/dist-packages/tensorflow/python/ops/metrics_impl.py:363: to_float (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version. Instructions for updating: Use `tf.cast` instead. W0307 18:10:37.080184 140330712794880 deprecation.py:323] From /usr/local/lib/python3.5/dist-packages/tensorflow/python/training/saver.py:1276: checkpoint_exists (from tensorflow.python.training.checkpoint_management) is deprecated and will be removed in a future version. Instructions for updating: Use standard file APIs to check for files with this prefix. ({'accuracy': 0.65, 'global_step': 25, 'loss': 1.6268775}, []) |

    3. 使用自定义model_fn

    如果您需要维护现有的自定义estimator
    model_fn,则可以将model_fn转换为使用Keras模型。

    但是出于兼容性原因,自定义model_fn仍将以1.x样式的图形模式运行,这意味着没有eager
    execution,也没有自动控制依赖。

    在自定义model_fn中使用Keras模型类似于在自定义训练循环中使用它:

    • 根据mode参数适当设置训练阶段

    • 将模型的trainable_variables显示传递给优化器

    但相对于自定义循环,存在重要差异:

    • 使用tf.keras.Model.get_losses_for提取损失,而不是使用model.losses

    • 使用tf.keras.Model.get_updates_for提取模型的更新

    以下代码从自定义model_fn创建estimator,说明所有这些问题:

    def my_model_fn(features, labels, mode): 
        model = make_model() 
        optimizer = tf.compat.v1.train.AdamOptimizer() 
        loss_fn = tf.keras.losses.SparseCategoricalCrossentropy() 
    
        training = (model == tf.estimator.ModeKeys.TRAIN) 
        predictions = model(features, training=training) 
    
        reg_loss = model.get_losses_for(None) + model.get_losses_for(features) 
        total_loss = loss_fn(labels, predictions) + tf.math.add_n(reg_losses) 
    
        accuracy = tf.campat.v1.metrics.accuracy(labels=labels, 
        predictions=tf.math.argmax(predictions, axis=1), name=’acc_op’) 
    
        update_ops = model.get_updates_for(None) + model.get_updates_for(features) 
        
        with tf.control_dependencies(update_ops): 
            train_op = optimizer.minimize( total_loss, var_list=model.trainable_variables, global_step=tf.compat.v1.train.get_or_create_global_step())
    
        return tf.estimator.EstimatorSpec( mode=mode, predictions=predictions, loss=total_loss, train_op=train_op, eval_metric_ops={‘accuracy’:accuracy}) 
    
    # 创建Estimator & Train 
    estimator = tf.estimator.Estimator(model_fn=my_model_fn) 
    tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec) 
    

    | W0307 18:10:38.249397 140330712794880 estimator.py:1799] Using temporary folder as model directory: /tmp/tmpj7quc09l W0307 18:10:39.147113 140330712794880 deprecation.py:506] From /usr/local/lib/python3.5/dist-packages/tensorflow/python/training/slot_creator.py:187: calling Zeros._init_ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version. Instructions for updating: Call initializer instance with the dtype argument instead of passing it to the constructor ({'accuracy': 0.51875, 'global_step': 25, 'loss': 1.619755}, []) |

    TensorShape

    这个类别简化为int代替tf.compat.v1.Demension对象,所以没有必要调用.value()来获取int。

    仍可从tf.TensorShape.dims访问单个tf.compat.v1.Dimension对象。以下演示了TensorFlow
    1.x和TensorFlow 2.0之间的区别:

    明所有这些问题:

    # 创建一个shape并选择一个索引 
    i = 0 shape = tf.TensorShape([16, None, 256]) 
    print(shape) 
    
    value = shape[i].value  # TF 1.x 
    value = shape[i] # TF 2.0 
    
    # TF 1.x 
    for dim in shape: 
        value = dim.value 
        print(value) 
    
    # TF 2.0 
        for value in shape: 
        print(value) 
    
    # TF 1.x 
    dim = shape[i] 
    dim.assert_is_compatiable_with(other_dim) 
    
    # TF 2.0 
    other_dim = 16 
    Dimension = tf.compat.v1.Dimension 
    if shape.rank is None: 
        dim = Dimension(None) 
    else: dim = shape.dims[i] 
        dim.is_compatible_with(other_dim) 
    
    shape = tf.TensorShape(None) 
    if shape: 
        dim = shape.dims[i] 
        dim.is_compatible_with(other_dim) 
    

    如果已知等级,则tf.TensorShape的布尔值为True,否则为False。

    print(bool(tf.TensorShape([]))) # 标量 Scalar 
    print(bool(tf.TensorShape([0]))) # 0长度的向量 vector 
    print(bool(tf.TensorShape[1]))) # 1长度的向量 vector 
    print(bool(tf.TensorShape[None]))) # 未知长度的向量 
    print(bool(tf.TensorShape([1, 10, 100]))) # 3D tensor 
    print(bool(tf.TensorShape([None, None, None]))) # 3D tensor with no known dimensions 
    print() 
    print(bool(tf.TensorShape(None)))) # 未知等级的张量 
    

    | True True True True True True False |

    其他行为改变

    您可能会遇到TensorFlow 2.0中的一些其他行为变化。

    ResourceVariables

    TensorFlow
    2.0默认创建爱女ResourceVariables,而不是RefVariables。ResourceVariables被锁定用于写入,因此提供更直观的一致性保证。

    • 这可能会改变边缘情况下的行为

    • 这可能偶尔会创建额外的副本,可能会有更高的内存使用量

    • 可以通过将use_resource=False传递给tf.Variable构造函数来禁用此功能

    Control Flow

    控制流op实现得到了简化,因此在TensorFlow 2.0中生成了不同的图。

    结论

    回顾一下本节内容:

    • 运行更新脚本

    • 删除contrib

    • 将模型切换为面向对象的样式(Keras)

    • 尽可能使用tf.keras或tf.estimator训练和评估循环

    • 否则,请使用自定义循环,但请未必避免会话和集合

    将代码转换为TensorFlow 2.0需要一些工作,但会有以下改变:

    • 更少的代码行

    • 提高清晰度和简洁性

    • 调试更简单

    相关文章

      网友评论

        本文标题:TF 1.0到2.0迁移

        本文链接:https://www.haomeiwen.com/subject/mebxwqtx.html