ใช้โมเดล TF1.x ในเวิร์กโฟลว์ TF2

ดูบน TensorFlow.org ทำงานใน Google Colab ดูบน GitHub ดาวน์โหลดโน๊ตบุ๊ค

คู่มือนี้ให้ภาพรวมและตัวอย่าง โค้ดชิมของรหัสโมเดล ที่คุณสามารถใช้เพื่อใช้โมเดล TF1.x ที่มีอยู่ในเวิร์กโฟลว์ TF2 เช่น การดำเนินการอย่างกระตือรือร้น tf.function และกลยุทธ์การแจกจ่ายโดยมีการเปลี่ยนแปลงเล็กน้อยในโค้ดการสร้างแบบจำลองของคุณ

ขอบเขตการใช้งาน

แผ่นชิมที่อธิบายในคู่มือนี้ออกแบบมาสำหรับรุ่น TF1.x ที่ต้องพึ่งพา:

  1. tf.compat.v1.get_variable และ tf.compat.v1.variable_scope เพื่อควบคุมการสร้างตัวแปรและการนำกลับมาใช้ใหม่ และ
  2. API ที่ใช้การรวบรวมกราฟ เช่น tf.compat.v1.global_variables() , tf.compat.v1.trainable_variables , tf.compat.v1.losses.get_regularization_losses() และ tf.compat.v1.get_collection() เพื่อติดตาม ของน้ำหนักและการสูญเสียการทำให้เป็นมาตรฐาน

ซึ่งรวมถึงโมเดลส่วนใหญ่ที่สร้างขึ้นบน tf.compat.v1.layer , tf.contrib.layers API และ TensorFlow-Slim

แผ่นชิม ไม่ จำเป็นสำหรับรุ่น TF1.x ต่อไปนี้:

  1. โมเดล Keras แบบสแตนด์อโลนที่ติดตามน้ำหนักที่ฝึกได้และการสูญเสียการทำให้เป็นมาตรฐานผ่าน model.trainable_weights และ model.losses ตามลำดับ
  2. tf.Module ที่ติดตามน้ำหนักที่ฝึกได้ทั้งหมดผ่านทาง module.trainable_variables และสร้างเฉพาะน้ำหนักหากยังไม่ได้สร้าง

โมเดลเหล่านี้มีแนวโน้มที่จะทำงานใน TF2 ด้วยการดำเนินการที่กระตือรือร้นและ tf.function ที่พร้อมใช้งานทันที

ติดตั้ง

นำเข้า TensorFlow และการพึ่งพาอื่น ๆ

pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is available only in
# Tensorflow 2.8

pip install -q tf-nightly
import tensorflow as tf
import tensorflow.compat.v1 as v1
import sys
import numpy as np

from contextlib import contextmanager

track_tf1_style_variables มัณฑนากร

คีย์ชิมที่อธิบายในคู่มือนี้คือ tf.compat.v1.keras.utils.track_tf1_style_variables ซึ่งเป็นมัณฑนากรที่คุณใช้ภายในเมธอดที่เป็นของ tf.keras.layers.Layer และ tf.Module เพื่อติดตามตุ้มน้ำหนักแบบ TF1.x และ จับการสูญเสียการทำให้เป็นมาตรฐาน

การตกแต่งเมธอดการโทรของ tf.keras.layers.Layer หรือ tf.Module ด้วย tf.compat.v1.keras.utils.track_tf1_style_variables อนุญาตให้สร้างตัวแปรและนำกลับมาใช้ใหม่ผ่าน tf.compat.v1.get_variable (และตามส่วนขยาย tf.compat.v1.layers ) เพื่อให้ทำงานอย่างถูกต้องภายในเมธอดที่ตกแต่ง แทนที่จะสร้างตัวแปรใหม่ทุกครั้งที่เรียก นอกจากนี้ยังจะทำให้เลเยอร์หรือโมดูลติดตามน้ำหนักที่สร้างหรือเข้าถึงโดยปริยายผ่าน get_variable ภายในวิธีที่ตกแต่ง

นอกเหนือจากการติดตามตุ้มน้ำหนักด้วยตนเองภายใต้ layer.variable มาตรฐาน / module.variable /etc คุณสมบัติ ถ้าวิธีการเป็นของ tf.keras.layers.Layer การสูญเสียการทำให้เป็นมาตรฐานใด ๆ ที่ระบุผ่านอาร์กิวเมนต์ตัวกำหนด get_variable หรือ tf.compat.v1.layers จะถูกติดตามโดยเลเยอร์ภายใต้คุณสมบัติ layer.losses มาตรฐาน

กลไกการติดตามนี้เปิดใช้งานการใช้คลาสขนาดใหญ่ของรหัสส่งต่อโมเดลรูปแบบ TF1.x ภายในเลเยอร์ Keras หรือ tf.Module ใน TF2 แม้จะเปิดใช้งานพฤติกรรม TF2

ตัวอย่างการใช้งาน

ตัวอย่างการใช้งานด้านล่างแสดงให้เห็นแบบจำลองชิมเมอร์ที่ใช้ในการตกแต่ง tf.keras.layers.Layer แต่ยกเว้นในกรณีที่มีการโต้ตอบกับฟีเจอร์ของ Keras โดยเฉพาะ จะนำไปใช้เมื่อตกแต่งวิธี tf.Module เช่นกัน

เลเยอร์ที่สร้างด้วย tf.compat.v1.get_variable

ลองนึกภาพว่าคุณมีเลเยอร์ที่ใช้งานโดยตรงบน tf.compat.v1.get_variable ดังนี้:

def dense(self, inputs, units):
  out = inputs
  with tf.compat.v1.variable_scope("dense"):
    # The weights are created with a `regularizer`,
    kernel = tf.compat.v1.get_variable(
        shape=[out.shape[-1], units],
        regularizer=tf.keras.regularizers.L2(),
        initializer=tf.compat.v1.initializers.glorot_normal,
        name="kernel")
    bias = tf.compat.v1.get_variable(
        shape=[units,],
        initializer=tf.compat.v1.initializers.zeros,
        name="bias")
    out = tf.linalg.matmul(out, kernel)
    out = tf.compat.v1.nn.bias_add(out, bias)
  return out

ใช้แผ่นชิมเพื่อเปลี่ยนเป็นเลเยอร์และเรียกใช้อินพุต

class DenseLayer(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    out = inputs
    with tf.compat.v1.variable_scope("dense"):
      # The weights are created with a `regularizer`,
      # so the layer should track their regularization losses
      kernel = tf.compat.v1.get_variable(
          shape=[out.shape[-1], self.units],
          regularizer=tf.keras.regularizers.L2(),
          initializer=tf.compat.v1.initializers.glorot_normal,
          name="kernel")
      bias = tf.compat.v1.get_variable(
          shape=[self.units,],
          initializer=tf.compat.v1.initializers.zeros,
          name="bias")
      out = tf.linalg.matmul(out, kernel)
      out = tf.compat.v1.nn.bias_add(out, bias)
    return out

layer = DenseLayer(10)
x = tf.random.normal(shape=(8, 20))
layer(x)
WARNING:tensorflow:From /tmp/ipykernel_27038/795621215.py:7: The name tf.keras.utils.track_tf1_style_variables is deprecated. Please use tf.compat.v1.keras.utils.track_tf1_style_variables instead.
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[-0.51018804, -0.58145535,  0.25050664, -0.09880018,  0.71741414,
        -0.08512568,  0.33404148,  0.50894034,  0.19362557,  0.03945067],
       [-0.66160053,  0.43442816, -0.6187523 ,  0.00753711,  1.3946855 ,
         0.22528797,  0.55661404, -1.6155301 ,  1.5854199 , -0.4165327 ],
       [ 0.15855707,  0.43848652,  0.04762229,  0.22020248,  0.88300526,
         0.31525093, -0.10912375,  0.03332198,  1.3462385 , -0.37986106],
       [ 0.02546233, -0.01084138,  0.0417656 ,  1.1082407 ,  0.926408  ,
         0.46938205,  1.0183189 ,  1.2039868 , -0.09619217, -0.50863194],
       [-1.6222394 ,  0.17156005, -0.07482994,  0.646423  ,  1.0284312 ,
         2.3619173 ,  0.6322627 ,  0.5350776 , -2.2700598 , -0.8211552 ],
       [-1.1044651 ,  0.7303245 ,  1.0183476 ,  1.2858934 ,  0.4575533 ,
         0.93400717,  0.5323913 , -0.01242167,  0.8308919 ,  0.03202473],
       [ 0.3880633 , -1.2345276 ,  0.7713047 , -0.33720714,  1.0418141 ,
        -1.055242  , -1.6942265 ,  1.705035  ,  0.8671215 ,  0.8162696 ],
       [ 0.02216246, -0.5235669 ,  0.01065174, -1.1682817 ,  0.44079733,
         0.25890222, -1.0779501 ,  0.37716752, -0.27636313, -0.6359312 ]],
      dtype=float32)>

เข้าถึงตัวแปรที่ติดตามและการสูญเสียการทำให้เป็นมาตรฐานที่บันทึกไว้เช่นเลเยอร์ Keras มาตรฐาน

layer.trainable_variables
layer.losses
2021-12-04 02:24:42.941890: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
[<tf.Tensor: shape=(), dtype=float32, numpy=0.10789324>]

หากต้องการดูว่าน้ำหนักถูกนำมาใช้ซ้ำทุกครั้งที่คุณเรียกใช้เลเยอร์ ให้ตั้งค่าน้ำหนักทั้งหมดเป็นศูนย์และเรียกเลเยอร์นั้นอีกครั้ง

print("Resetting variables to zero:", [var.name for var in layer.trainable_variables])

for var in layer.trainable_variables:
  var.assign(var * 0.0)

# Note: layer.losses is not a live view and
# will get reset only at each layer call
print("layer.losses:", layer.losses)
print("calling layer again.")
out = layer(x)
print("layer.losses: ", layer.losses)
out
Resetting variables to zero: ['dense/bias:0', 'dense/kernel:0']
layer.losses: [<tf.Tensor: shape=(), dtype=float32, numpy=0.0>]
calling layer again.
layer.losses:  [<tf.Tensor: shape=(), dtype=float32, numpy=0.0>]
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>

คุณสามารถใช้เลเยอร์ที่แปลงแล้วโดยตรงในการสร้างแบบจำลองการทำงานของ Keras เช่นกัน

inputs = tf.keras.Input(shape=(20))
outputs = DenseLayer(10)(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

x = tf.random.normal(shape=(8, 20))
model(x)

# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.1345337>]

โมเดลที่สร้างด้วย tf.compat.v1.layers

ลองนึกภาพว่าคุณมีเลเยอร์หรือโมเดลที่ใช้งานโดยตรงบน tf.compat.v1.layers ดังนี้:

def model(self, inputs, units):
  with tf.compat.v1.variable_scope('model'):
    out = tf.compat.v1.layers.conv2d(
        inputs, 3, 3,
        kernel_regularizer="l2")
    out = tf.compat.v1.layers.flatten(out)
    out = tf.compat.v1.layers.dense(
        out, units,
        kernel_regularizer="l2")
    return out

ใช้แผ่นชิมเพื่อเปลี่ยนเป็นเลเยอร์และเรียกใช้อินพุต

class CompatV1LayerModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('model'):
      out = tf.compat.v1.layers.conv2d(
          inputs, 3, 3,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.flatten(out)
      out = tf.compat.v1.layers.dense(
          out, self.units,
          kernel_regularizer="l2")
      return out

layer = CompatV1LayerModel(10)
x = tf.random.normal(shape=(8, 5, 5, 5))
layer(x)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/convolutional.py:575: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:541: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  app.launch_new_instance()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:261: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[ 2.4439096 , -0.2912227 ,  1.5531251 ,  1.284059  ,  0.10077369,
        -0.4231838 ,  1.0458903 , -0.01530766,  0.07358164, -0.6108157 ],
       [-0.4576063 ,  0.34942552,  2.3044965 ,  1.1483003 , -1.2211238 ,
         0.5634397 ,  0.73821646, -0.07581732,  0.5747937 , -0.66470885],
       [-2.2948585 , -2.709268  ,  1.7494816 , -0.9808065 , -2.9099958 ,
         0.5067346 , -1.011502  ,  2.559535  , -3.0888772 ,  0.3522656 ],
       [ 1.7788265 ,  0.8846102 ,  0.45562026,  0.01498583, -0.12482446,
        -0.32868862, -0.7743829 ,  2.3106992 , -0.0997327 , -0.7715093 ],
       [ 0.40295708,  0.04771695, -0.21336336, -0.13069987,  2.279875  ,
         2.7284563 ,  0.6444641 , -1.1919906 ,  0.96321577,  1.0182515 ],
       [ 0.47900966,  0.04906505,  1.1335449 ,  0.2907704 ,  0.7732022 ,
         0.68217   ,  0.51932573, -0.45156685,  2.081223  ,  1.068861  ],
       [ 0.10084352,  1.6456002 ,  0.63820475,  1.5959243 ,  0.22463399,
         0.07713126,  0.7467398 , -1.5435244 ,  1.2494736 , -0.07683721],
       [ 2.1396816 ,  1.5613532 , -1.1726325 , -0.88917583,  1.6447946 ,
        -1.0071977 , -1.8496083 ,  1.1887017 ,  2.1971662 ,  2.1175954 ]],
      dtype=float32)>

เข้าถึงตัวแปรที่ติดตามและการสูญเสียการทำให้เป็นมาตรฐานที่บันทึกไว้เช่นเลเยอร์ Keras มาตรฐาน

layer.trainable_variables
layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03623246>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.14618248>]

หากต้องการดูว่าน้ำหนักถูกนำมาใช้ซ้ำทุกครั้งที่คุณเรียกใช้เลเยอร์ ให้ตั้งค่าน้ำหนักทั้งหมดเป็นศูนย์และเรียกเลเยอร์นั้นอีกครั้ง

print("Resetting variables to zero:", [var.name for var in layer.trainable_variables])

for var in layer.trainable_variables:
  var.assign(var * 0.0)

out = layer(x)
print("layer.losses: ", layer.losses)
out
Resetting variables to zero: ['model/conv2d/bias:0', 'model/conv2d/kernel:0', 'model/dense/bias:0', 'model/dense/kernel:0']
layer.losses:  [<tf.Tensor: shape=(), dtype=float32, numpy=0.0>, <tf.Tensor: shape=(), dtype=float32, numpy=0.0>]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  app.launch_new_instance()
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>

คุณสามารถใช้เลเยอร์ที่แปลงแล้วโดยตรงในการสร้างแบบจำลองการทำงานของ Keras เช่นกัน

inputs = tf.keras.Input(shape=(5, 5, 5))
outputs = CompatV1LayerModel(10)(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

x = tf.random.normal(shape=(8, 5, 5, 5))
model(x)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/base.py:573: UserWarning: `layer.updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.
  _add_elements_to_collection(self.updates, tf.compat.v1.GraphKeys.UPDATE_OPS)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  app.launch_new_instance()
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[ 0.19487001,  0.54727787,  1.1044168 , -0.6613899 , -0.26437742,
        -1.1580509 , -0.24707682,  0.97752655,  0.59436107,  0.13125825],
       [ 0.48974586, -1.3510125 ,  0.7186962 , -0.8996632 , -0.60448873,
         0.06332532,  0.31494308,  0.23021704, -1.9166642 ,  0.3890404 ],
       [-0.06499191, -0.21485235,  0.01158494,  1.4407377 , -0.0488929 ,
        -0.37594396, -0.4386894 , -0.08751169,  1.0905663 , -1.5450519 ],
       [-2.2749739 , -2.4603422 , -1.3834419 , -2.8800466 ,  0.8954872 ,
        -3.0429187 , -0.7885461 ,  1.6037437 , -3.1845028 , -1.0725503 ],
       [ 0.98735195, -0.45159122,  0.892656  ,  0.477053  ,  0.31193537,
        -0.44723228, -0.01815075, -0.47465172, -1.665448  , -2.105824  ],
       [-2.5408387 , -1.7552321 , -1.924145  , -0.6395873 ,  0.4081779 ,
        -0.48731515, -3.2637763 , -1.4409767 , -2.032539  ,  0.10204412],
       [ 2.1583526 ,  0.78955674, -0.07266375,  0.06652926,  2.1300716 ,
        -1.6256162 ,  0.56154627, -0.76179224,  2.2985756 , -1.5504618 ],
       [ 2.062847  ,  0.971378  , -1.0830508 ,  1.8224751 , -0.3542943 ,
         0.74113446, -0.6204865 ,  1.4503044 , -0.4979878 , -0.4383126 ]],
      dtype=float32)>
# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03079858>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.12991619>]

จับภาพการอัปเดตการทำให้เป็นมาตรฐานของแบทช์และ training โมเดล args

ใน TF1.x คุณทำการทำให้เป็นมาตรฐานของแบทช์ดังนี้:

  x_norm = tf.compat.v1.layers.batch_normalization(x, training=training)

  # ...

  update_ops = tf.compat.v1.get_collection(tf.GraphKeys.UPDATE_OPS)
  train_op = optimizer.minimize(loss)
  train_op = tf.group([train_op, update_ops])

โปรดทราบว่า:

  1. การอัปเดตค่าเฉลี่ยเคลื่อนที่ของแบทช์ทำให้เป็นมาตรฐานถูกติดตามโดย get_collection ซึ่งถูกเรียกแยกจากเลเยอร์
  2. tf.compat.v1.layers.batch_normalization ต้องการอาร์กิวเมนต์ training (โดยทั่วไปเรียกว่า is_training เมื่อใช้เลเยอร์การทำให้เป็นมาตรฐานของแบทช์ TF-Slim)

ใน TF2 เนื่องจาก การดำเนินการที่กระตือรือร้น และการพึ่งพาการควบคุมอัตโนมัติ การอัปเดตค่าเฉลี่ยเคลื่อนที่ของแบทช์จะเป็นมาตรฐานจะดำเนินการทันที ไม่จำเป็นต้องรวบรวมแยกจากคอลเลกชันอัพเดต และเพิ่มเป็นการพึ่งพาการควบคุมอย่างชัดเจน

นอกจากนี้ หากคุณให้อาร์กิวเมนต์การส่งต่อของ tf.keras.layers.Layer เป็นอาร์กิวเมนต์ training Keras จะสามารถส่งผ่านเฟสการฝึกปัจจุบันและเลเยอร์ที่ซ้อนอยู่ได้เช่นเดียวกับเลเยอร์อื่นๆ ดูเอกสาร API สำหรับ tf.keras.Model สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ Keras จัดการกับอาร์กิวเมนต์ training

หากคุณกำลังตกแต่งวิธี tf.Module คุณต้องแน่ใจว่าได้ส่งอาร์กิวเมนต์ training ทั้งหมดตามความจำเป็นด้วยตนเอง อย่างไรก็ตาม การอัปเดตค่าเฉลี่ยเคลื่อนที่ของการทำให้เป็นมาตรฐานของแบตช์จะยังคงใช้โดยอัตโนมัติโดยไม่จำเป็นต้องพึ่งพาการควบคุมอย่างชัดเจน

ข้อมูลโค้ดต่อไปนี้สาธิตวิธีการฝังเลเยอร์การทำให้เป็นมาตรฐานของแบตช์ในชิมและวิธีใช้งานในแบบจำลอง Keras (ใช้ได้กับ tf.keras.layers.Layer )

class CompatV1BatchNorm(tf.keras.layers.Layer):

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    print("Forward pass called with `training` =", training)
    with v1.variable_scope('batch_norm_layer'):
      return v1.layers.batch_normalization(x, training=training)
print("Constructing model")
inputs = tf.keras.Input(shape=(5, 5, 5))
outputs = CompatV1BatchNorm()(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

print("Calling model in inference mode")
x = tf.random.normal(shape=(8, 5, 5, 5))
model(x, training=False)

print("Moving average variables before training: ",
      {var.name: var.read_value() for var in model.non_trainable_variables})

# Notice that when running TF2 and eager execution, the batchnorm layer directly
# updates the moving averages while training without needing any extra control
# dependencies
print("calling model in training mode")
model(x, training=True)

print("Moving average variables after training: ",
      {var.name: var.read_value() for var in model.non_trainable_variables})
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:7: UserWarning: `tf.layers.batch_normalization` is deprecated and will be removed in a future version. Please use `tf.keras.layers.BatchNormalization` instead. In particular, `tf.control_dependencies(tf.GraphKeys.UPDATE_OPS)` should not be used (consult the `tf.keras.layers.BatchNormalization` documentation).
  import sys
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/normalization.py:463: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs, training=training)
Constructing model
Forward pass called with `training` = None
Calling model in inference mode
Forward pass called with `training` = False
Moving average variables before training:  {'batch_norm_layer/batch_normalization/moving_mean:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=array([0., 0., 0., 0., 0.], dtype=float32)>, 'batch_norm_layer/batch_normalization/moving_variance:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=array([1., 1., 1., 1., 1.], dtype=float32)>}
calling model in training mode
Forward pass called with `training` = True
Moving average variables after training:  {'batch_norm_layer/batch_normalization/moving_mean:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([-0.00177554, -0.00036542, -0.00099426, -0.00112544,  0.0008541 ],
      dtype=float32)>, 'batch_norm_layer/batch_normalization/moving_variance:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([1.0005339, 1.0003369, 0.9976748, 1.0001523, 1.0009514],
      dtype=float32)>}

การใช้ซ้ำตัวแปรตามขอบเขตตัวแปร

การสร้างตัวแปรใดๆ ในการส่งต่อโดยอิงตาม get_variable จะคงไว้ซึ่งการตั้งชื่อตัวแปรแบบเดียวกันและนำความหมายมาใช้ใหม่ซึ่งขอบเขตของตัวแปรมีใน TF1.x สิ่งนี้เป็นจริงตราบใดที่คุณมีขอบเขตภายนอกที่ไม่ว่างเปล่าอย่างน้อยหนึ่งขอบเขตสำหรับ tf.compat.v1.layers ใดๆ ที่มีชื่อที่สร้างขึ้นโดยอัตโนมัติตามที่กล่าวไว้ข้างต้น

การดำเนินการอย่างกระตือรือร้น & tf.function

ตามที่เห็นด้านบน วิธีการตกแต่งสำหรับ tf.keras.layers.Layer และ tf.Module จะทำงานภายในการดำเนินการที่กระตือรือร้นและยังเข้ากันได้กับ tf.function ซึ่งหมายความว่าคุณสามารถใช้ pdb และเครื่องมือแบบโต้ตอบอื่นๆ เพื่อดำเนินการส่งต่อในขณะที่ทำงาน

กลยุทธ์การจัดจำหน่าย

การเรียก get_variable ภายใน @track_tf1_style_variables -decorated วิธีการเลเยอร์หรือโมดูลใช้การสร้างตัวแปร tf.Variable มาตรฐานภายใต้ประทุน ซึ่งหมายความว่าคุณสามารถใช้กับกลยุทธ์การกระจายต่างๆ ที่มีอยู่กับ tf.distribute เช่น MirroredStrategy และ TPUStrategy

ซ้อน tf.Variable s, tf.Module s, tf.keras.layers & tf.keras.models ในการโทรตกแต่ง

การตกแต่งการเรียกเลเยอร์ของคุณใน tf.compat.v1.keras.utils.track_tf1_style_variables จะเพิ่มเฉพาะการติดตามโดยปริยายของตัวแปรที่สร้างขึ้น (และนำกลับมาใช้ใหม่) ผ่าน tf.compat.v1.get_variable เท่านั้น จะไม่บันทึกน้ำหนักที่สร้างขึ้นโดยตรงโดยการเรียก tf.Variable เช่นที่ใช้โดยเลเยอร์ Keras ทั่วไปและ tf.Module ส่วนใหญ่ ส่วนนี้อธิบายวิธีจัดการกับกรณีและปัญหาที่ซ้อนกันเหล่านี้

(ประเพณีที่มีอยู่แล้ว) tf.keras.layers และ tf.keras.models

สำหรับการใช้งานเลเยอร์และโมเดล Keras ที่ซ้อนกันอยู่แล้ว ให้ใช้ tf.compat.v1.keras.utils.get_or_create_layer แนะนำเฉพาะสำหรับการทำให้การย้ายข้อมูลของ Keras ที่ซ้อนกัน TF1.x ที่มีอยู่ง่ายขึ้นเท่านั้น รหัสใหม่ควรใช้การตั้งค่าแอตทริบิวต์ที่ชัดเจนตามที่อธิบายไว้ด้านล่างสำหรับ tf.Variables และ tf.Modules

ในการใช้ tf.compat.v1.keras.utils.get_or_create_layer ให้ห่อโค้ดที่สร้างโมเดลที่ซ้อนกันเป็นเมธอด แล้วส่งต่อไปยังเมธอด ตัวอย่าง:

class NestedModel(tf.keras.Model):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  def build_model(self):
    inp = tf.keras.Input(shape=(5, 5))
    dense_layer = tf.keras.layers.Dense(
        10, name="dense", kernel_regularizer="l2",
        kernel_initializer=tf.compat.v1.ones_initializer())
    model = tf.keras.Model(inputs=inp, outputs=dense_layer(inp))
    return model

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    # Get or create a nested model without assigning it as an explicit property
    model = tf.compat.v1.keras.utils.get_or_create_layer(
        "dense_model", self.build_model)
    return model(inputs)

layer = NestedModel(10)
layer(tf.ones(shape=(5,5)))
<tf.Tensor: shape=(5, 10), dtype=float32, numpy=
array([[5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.]], dtype=float32)>

วิธีนี้ช่วยให้แน่ใจว่าเลเยอร์ที่ซ้อนกันเหล่านี้ถูกนำมาใช้ซ้ำอย่างถูกต้องและติดตามโดยเทนเซอร์โฟลว์ โปรดทราบว่ายังคงต้องใช้ตัวตกแต่ง @track_tf1_style_variables ในวิธีการที่เหมาะสม วิธีการสร้างแบบจำลองที่ส่งผ่านไปยัง get_or_create_layer (ในกรณีนี้คือ self.build_model ) ไม่ควรมีข้อโต้แย้งใดๆ

มีการติดตามน้ำหนัก:

assert len(layer.weights) == 2
weights = {x.name: x for x in layer.variables}

assert set(weights.keys()) == {"dense/bias:0", "dense/kernel:0"}

layer.weights
[<tf.Variable 'dense/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]], dtype=float32)>,
 <tf.Variable 'dense/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>]

และการสูญเสียการทำให้เป็นมาตรฐานเช่นกัน:

tf.add_n(layer.losses)
<tf.Tensor: shape=(1,), dtype=float32, numpy=array([0.5], dtype=float32)>
ตัวยึดตำแหน่ง33

การย้ายข้อมูลส่วนเพิ่ม: tf.Variables และ tf.Modules

หากคุณต้องการฝังการเรียก tf.Variable หรือ tf.Module ไว้ในวิธีที่ตกแต่งแล้ว (เช่น หากคุณกำลังติดตามการย้ายข้อมูลส่วนเพิ่มไปยัง TF2 API ที่ไม่ใช่แบบเดิมที่อธิบายไว้ในคู่มือนี้) คุณยังต้องติดตามสิ่งเหล่านี้อย่างชัดเจน โดยมีข้อกำหนดดังต่อไปนี้

  • ตรวจสอบให้แน่ใจอย่างชัดเจนว่าตัวแปร/โมดูล/เลเยอร์ถูกสร้างขึ้นเพียงครั้งเดียว
  • แนบไว้อย่างชัดเจนเป็นแอตทริบิวต์ของอินสแตนซ์ เช่นเดียวกับที่คุณทำเมื่อกำหนด โมดูลหรือเลเยอร์ทั่วไป
  • นำออบเจ็กต์ที่สร้างไว้แล้วมาใช้ใหม่อย่างชัดเจนในการเรียกที่ตามมา

เพื่อให้แน่ใจว่าไม่มีการสร้างน้ำหนักขึ้นใหม่ในการโทรแต่ละครั้งและนำกลับมาใช้ใหม่อย่างถูกต้อง นอกจากนี้ สิ่งนี้ยังช่วยให้แน่ใจว่าน้ำหนักที่มีอยู่และการสูญเสียการทำให้เป็นมาตรฐานได้รับการติดตาม

นี่คือตัวอย่างลักษณะของสิ่งนี้:

class NestedLayer(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def __call__(self, inputs):
    out = inputs
    with tf.compat.v1.variable_scope("inner_dense"):
      # The weights are created with a `regularizer`,
      # so the layer should track their regularization losses
      kernel = tf.compat.v1.get_variable(
          shape=[out.shape[-1], self.units],
          regularizer=tf.keras.regularizers.L2(),
          initializer=tf.compat.v1.initializers.glorot_normal,
          name="kernel")
      bias = tf.compat.v1.get_variable(
          shape=[self.units,],
          initializer=tf.compat.v1.initializers.zeros,
          name="bias")
      out = tf.linalg.matmul(out, kernel)
      out = tf.compat.v1.nn.bias_add(out, bias)
    return out

class WrappedDenseLayer(tf.keras.layers.Layer):

  def __init__(self, units, **kwargs):
    super().__init__(**kwargs)
    self.units = units
    # Only create the nested tf.variable/module/layer/model
    # once, and then reuse it each time!
    self._dense_layer = NestedLayer(self.units)

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('outer'):
      outputs = tf.compat.v1.layers.dense(inputs, 3)
      outputs = tf.compat.v1.layers.dense(inputs, 4)
      return self._dense_layer(outputs)

layer = WrappedDenseLayer(10)

layer(tf.ones(shape=(5, 5)))
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:38: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:39: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
<tf.Tensor: shape=(5, 10), dtype=float32, numpy=
array([[-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731]],
      dtype=float32)>

โปรดทราบว่าจำเป็นต้องมีการติดตามโมดูลที่ซ้อนกันอย่างชัดเจน แม้ว่าจะมีการตกแต่งด้วยมัณฑนากร track_tf1_style_variables เนื่องจากแต่ละโมดูล/เลเยอร์ที่มีเมธอดที่ตกแต่งแล้วจะมีที่เก็บตัวแปรที่เกี่ยวข้องกัน

มีการติดตามน้ำหนักอย่างถูกต้อง:

assert len(layer.weights) == 6
weights = {x.name: x for x in layer.variables}

assert set(weights.keys()) == {"outer/inner_dense/bias:0",
                               "outer/inner_dense/kernel:0",
                               "outer/dense/bias:0",
                               "outer/dense/kernel:0",
                               "outer/dense_1/bias:0",
                               "outer/dense_1/kernel:0"}

layer.trainable_weights
[<tf.Variable 'outer/inner_dense/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/inner_dense/kernel:0' shape=(4, 10) dtype=float32, numpy=
 array([[-0.20786692,  0.14702448, -0.2577947 ,  0.1885891 ,  0.28935957,
          0.02086618, -0.20579144, -0.7509229 , -0.23490003,  0.00370591],
        [ 0.09247629, -0.37428686, -0.6002815 , -0.2702465 ,  0.20350575,
          0.34964404, -0.32633537,  0.50722903, -0.0419833 , -0.61815673],
        [ 0.24821116,  0.15504731, -0.12409697, -0.2506969 ,  0.22316858,
         -0.44847375, -0.08295754, -0.8262154 ,  0.7674222 , -0.40613693],
        [-0.7447006 ,  0.2992331 , -0.45639235,  0.0669547 ,  0.39443025,
          0.3182467 ,  0.10884362,  0.5395837 ,  0.32210502, -0.30076835]],
       dtype=float32)>,
 <tf.Variable 'outer/dense/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/dense/kernel:0' shape=(5, 3) dtype=float32, numpy=
 array([[ 0.6283595 , -0.80413634, -0.5471641 ],
        [ 0.25296038, -0.7657203 ,  0.5884425 ],
        [-0.7180575 , -0.29509914,  0.44014376],
        [ 0.81024987,  0.39888996,  0.80002993],
        [-0.32921118, -0.7010279 ,  0.820375  ]], dtype=float32)>,
 <tf.Variable 'outer/dense_1/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/dense_1/kernel:0' shape=(5, 4) dtype=float32, numpy=
 array([[ 0.7941524 , -0.58552563,  0.46828055, -0.44095916],
        [-0.16019303,  0.27973688, -0.60373306, -0.20117629],
        [ 0.6345844 ,  0.30732214,  0.18921828,  0.37930095],
        [-0.50815696, -0.2471816 , -0.10282421,  0.21441567],
        [-0.71987414,  0.18304104, -0.5701992 ,  0.4926386 ]],
       dtype=float32)>]

เช่นเดียวกับการสูญเสียการทำให้เป็นมาตรฐาน:

layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.058749676>]
ตัวยึดตำแหน่ง39

โปรดทราบว่าหาก NestedLayer ไม่ใช่ Keras tf.Module แทน ตัวแปรจะยังคงถูกติดตาม แต่การสูญเสียการทำให้เป็นมาตรฐานจะไม่ถูกติดตามโดยอัตโนมัติ ดังนั้น คุณจะต้องติดตามแยกกันอย่างชัดเจน

คำแนะนำเกี่ยวกับชื่อตัวแปร

การเรียก tf.Variable และเลเยอร์ Keras อย่างชัดเจนใช้ชื่อเลเยอร์ / กลไกการสร้างชื่อตัวแปรอัตโนมัติที่แตกต่างจากที่คุณอาจเคยใช้จากการรวมกันของ get_variable และ variable_scopes แม้ว่าชิมจะทำให้ชื่อตัวแปรของคุณตรงกันสำหรับตัวแปรที่สร้างโดย get_variable แม้ว่าจะเปลี่ยนจากกราฟ TF1.x ไปเป็น TF2 ความกระตือรือร้นในการดำเนินการ & tf.function แต่ก็ไม่สามารถรับประกันได้เหมือนกันสำหรับชื่อตัวแปรที่สร้างขึ้นสำหรับการเรียก tf.Variable และเลเยอร์ Keras ที่ คุณฝังอยู่ภายในวิธีการของคุณมัณฑนากร เป็นไปได้ด้วยซ้ำที่ตัวแปรหลายตัวจะใช้ชื่อเดียวกันในการดำเนินการที่กระตือรือร้นของ TF2 และ tf.function

คุณควรใช้ความระมัดระวังเป็นพิเศษกับสิ่งนี้เมื่อปฏิบัติตามหัวข้อเกี่ยวกับการตรวจสอบความถูกต้องและการทำแผนที่จุดตรวจ TF1.x ในภายหลังในคู่มือนี้

ใช้ tf.compat.v1.make_template ในเมธอดการตกแต่ง

ขอแนะนำให้คุณใช้โดยตรง tf.compat.v1.keras.utils.track_tf1_style_variables แทนการใช้ tf.compat.v1.make_template เนื่องจากเป็นเลเยอร์ที่บางกว่าที่ด้านบนของ TF2

ทำตามคำแนะนำในส่วนนี้สำหรับโค้ด TF1.x ก่อนหน้าซึ่งใช้ tf.compat.v1.make_template แล้ว

เนื่องจาก tf.compat.v1.make_template ล้อมโค้ดที่ใช้ get_variable มัณฑนากร track_tf1_style_variables ช่วยให้คุณใช้เทมเพลตเหล่านี้ในการเรียกเลเยอร์และติดตามน้ำหนักและการสูญเสียการทำให้เป็นมาตรฐานได้สำเร็จ

อย่างไรก็ตาม อย่าลืมเรียก make_template เพียงครั้งเดียว แล้วใช้เทมเพลตเดิมซ้ำในการเรียกแต่ละเลเยอร์ มิฉะนั้น เทมเพลตใหม่จะถูกสร้างขึ้นทุกครั้งที่คุณเรียกเลเยอร์พร้อมกับตัวแปรชุดใหม่

ตัวอย่างเช่น,

class CompatV1TemplateScaleByY(tf.keras.layers.Layer):

  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    def my_op(x, scalar_name):
      var1 = tf.compat.v1.get_variable(scalar_name,
                            shape=[],
                            regularizer=tf.compat.v1.keras.regularizers.L2(),
                            initializer=tf.compat.v1.constant_initializer(1.5))
      return x * var1
    self.scale_by_y = tf.compat.v1.make_template('scale_by_y', my_op, scalar_name='y')

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('layer'):
      # Using a scope ensures the `scale_by_y` name will not be incremented
      # for each instantiation of the layer.
      return self.scale_by_y(inputs)

layer = CompatV1TemplateScaleByY()

out = layer(tf.ones(shape=(2, 3)))
print("weights:", layer.weights)
print("regularization loss:", layer.losses)
print("output:", out)
weights: [<tf.Variable 'layer/scale_by_y/y:0' shape=() dtype=float32, numpy=1.5>]
regularization loss: [<tf.Tensor: shape=(), dtype=float32, numpy=0.022499999>]
output: tf.Tensor(
[[1.5 1.5 1.5]
 [1.5 1.5 1.5]], shape=(2, 3), dtype=float32)
ตัวยึดตำแหน่ง41

การย้ายข้อมูลส่วนเพิ่มไปยัง Native TF2

ดังที่กล่าวไว้ก่อนหน้านี้ track_tf1_style_variables ช่วยให้คุณสามารถผสม tf.Variable เชิงวัตถุสไตล์ TF2 / tf.keras.layers.Layer / tf.Module กับ tf.compat.v1.get_variable แบบเดิม / tf.compat.v1.layers การใช้งานภายในโมดูล/เลเยอร์ที่ตกแต่งเดียวกัน

ซึ่งหมายความว่าหลังจากที่คุณสร้างโมเดล TF1.x ที่เข้ากันได้กับ TF2 อย่างสมบูรณ์แล้ว คุณสามารถเขียนส่วนประกอบโมเดลใหม่ทั้งหมดด้วย TF2 API ดั้งเดิม (ไม่ใช่ tf.compat.v1 ) และให้ทำงานร่วมกันกับโค้ดเก่าของคุณ

อย่างไรก็ตาม หากคุณยังคงแก้ไขส่วนประกอบรุ่นเก่าของคุณ คุณอาจเลือกที่จะสลับการใช้งาน tf.compat.v1 สไตล์ดั้งเดิมของคุณแบบค่อยเป็นค่อยไปไปเป็น API เชิงวัตถุแบบเนทีฟล้วนๆ ที่แนะนำสำหรับโค้ด TF2 ที่เขียนใหม่

การใช้งาน tf.compat.v1.get_variable สามารถแทนที่ด้วยการโทร self.add_weight หากคุณกำลังตกแต่งเลเยอร์/โมเดล Keras หรือการเรียก tf.Variable หากคุณกำลังตกแต่งวัตถุ Keras หรือ tf.Module s

tf.compat.v1.layers เชิงฟังก์ชันและเชิงวัตถุโดยทั่วไปสามารถแทนที่ด้วยเลเยอร์ tf.keras.layers ที่เทียบเท่ากันโดยไม่ต้องเปลี่ยนแปลงอาร์กิวเมนต์

คุณอาจพิจารณาชิ้นส่วนต่างๆ ของโมเดลหรือรูปแบบทั่วไปลงในแต่ละเลเยอร์/โมดูลระหว่างการย้ายส่วนเพิ่มไปยัง API ดั้งเดิม ซึ่งอาจใช้ track_tf1_style_variables

หมายเหตุเกี่ยวกับ Slim และ contrib.layers

โค้ด TF 1.x รุ่นเก่าจำนวนมากใช้ไลบรารี Slim ซึ่งบรรจุด้วย TF 1.x เป็น tf.contrib.layers การแปลงโค้ดโดยใช้ Slim เป็น Native TF 2 นั้นมีความเกี่ยวข้องมากกว่าการแปลง v1.layers อันที่จริง การแปลงโค้ด Slim ของคุณเป็น v1.layers ก่อนนั้นอาจสมเหตุสมผล แล้วจึงแปลงเป็น Keras ด้านล่างนี้คือคำแนะนำทั่วไปสำหรับการแปลงโค้ด Slim

  • ตรวจสอบให้แน่ใจว่าอาร์กิวเมนต์ทั้งหมดมีความชัดเจน ลบ arg_scopes ถ้าเป็นไปได้ หากคุณยังต้องการใช้ ให้แบ่ง normalizer_fn และ activation_fn เป็นเลเยอร์ของตัวเอง
  • เลเยอร์ Conv. แบบแยกได้จะจับคู่กับเลเยอร์ Keras ที่แตกต่างกันอย่างน้อยหนึ่งเลเยอร์ (เลเยอร์ Keras ในเชิงลึก เชิงลึก และแบบแยกได้)
  • Slim และ v1.layers มีชื่ออาร์กิวเมนต์และค่าเริ่มต้นต่างกัน
  • โปรดทราบว่าอาร์กิวเมนต์บางข้อมีมาตราส่วนต่างกัน

การโยกย้ายไปยัง Native TF2 โดยไม่สนใจความเข้ากันได้ของจุดตรวจ

ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็นถึงการย้ายโมเดลที่เพิ่มขึ้นไปยัง API ดั้งเดิมโดยไม่พิจารณาความเข้ากันได้ของจุดตรวจสอบ

class CompatModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = tf.compat.v1.layers.conv2d(
          inputs, 3, 3,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.flatten(out)
      out = tf.compat.v1.layers.dropout(out, training=training)
      out = tf.compat.v1.layers.dense(
          out, self.units,
          kernel_regularizer="l2")
      return out

ถัดไป แทนที่ compat.v1 API ด้วยสิ่งที่เทียบเท่าเชิงวัตถุดั้งเดิมในลักษณะทีละส่วน เริ่มต้นด้วยการเปลี่ยนเลเยอร์ Convolution เป็นวัตถุ Keras ที่สร้างขึ้นในตัวสร้างเลเยอร์

class PartiallyMigratedModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units
    self.conv_layer = tf.keras.layers.Conv2D(
      3, 3,
      kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_layer(inputs)
      out = tf.compat.v1.layers.flatten(out)
      out = tf.compat.v1.layers.dropout(out, training=training)
      out = tf.compat.v1.layers.dense(
          out, self.units,
          kernel_regularizer="l2")
      return out

ใช้คลาส v1.keras.utils.DeterministicRandomTestTool เพื่อตรวจสอบว่าการเปลี่ยนแปลงที่เพิ่มขึ้นนี้ทำให้โมเดลมีลักษณะการทำงานเหมือนเดิมหรือไม่

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = CompatModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  original_output = layer(inputs)

  # Grab the regularization loss as well
  original_regularization_loss = tf.math.add_n(layer.losses)

print(original_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.dropout` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dropout` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:413: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs, training=training)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:17: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = PartiallyMigratedModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: `tf.layers.dropout` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dropout` instead.
  from ipykernel import kernelapp as app
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:18: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

ตอนนี้คุณได้แทนที่ compat.v1.layers แต่ละรายการด้วยเลเยอร์ Keras ดั้งเดิมแล้ว

class NearlyFullyNativeModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units
    self.conv_layer = tf.keras.layers.Conv2D(
      3, 3,
      kernel_regularizer="l2")
    self.flatten_layer = tf.keras.layers.Flatten()
    self.dense_layer = tf.keras.layers.Dense(
      self.units,
      kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_layer(inputs)
      out = self.flatten_layer(out)
      out = self.dense_layer(out)
      return out
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = NearlyFullyNativeModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

สุดท้าย ให้ลบการใช้งาน variable_scope ที่เหลือ (ไม่จำเป็น) และตัวตกแต่ง track_tf1_style_variables เอง

ตอนนี้คุณเหลือรุ่นของโมเดลที่ใช้ API ดั้งเดิมทั้งหมด

class FullyNativeModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units
    self.conv_layer = tf.keras.layers.Conv2D(
      3, 3,
      kernel_regularizer="l2")
    self.flatten_layer = tf.keras.layers.Flatten()
    self.dense_layer = tf.keras.layers.Dense(
      self.units,
      kernel_regularizer="l2")

  def call(self, inputs):
    out = self.conv_layer(inputs)
    out = self.flatten_layer(out)
    out = self.dense_layer(out)
    return out
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = FullyNativeModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

การรักษาความเข้ากันได้ของจุดตรวจระหว่างการโยกย้ายไปยัง Native TF2

กระบวนการย้ายด้านบนไปเป็น TF2 API ดั้งเดิมได้เปลี่ยนทั้งชื่อตัวแปร (เนื่องจาก Keras APIs สร้างชื่อน้ำหนักที่แตกต่างกันมาก) และเส้นทางเชิงวัตถุที่ชี้ไปที่น้ำหนักที่แตกต่างกันในโมเดล ผลกระทบของการเปลี่ยนแปลงเหล่านี้คือ การเปลี่ยนแปลงเหล่านี้จะทำลายจุดตรวจตามชื่อสไตล์ TF1 ที่มีอยู่หรือจุดตรวจสอบเชิงวัตถุสไตล์ TF2

อย่างไรก็ตาม ในบางกรณี คุณอาจใช้จุดตรวจตามชื่อเดิมของคุณและค้นหาการแมปของตัวแปรกับชื่อใหม่ได้โดยใช้แนวทางเช่นเดียวกับที่มีรายละเอียดใน คู่มือการใช้จุดตรวจ TF1.x ซ้ำ

เคล็ดลับบางประการในการทำให้สิ่งนี้เป็นไปได้มีดังนี้:

  • ตัวแปรทั้งหมดยังมีอาร์กิวเมนต์ name ที่คุณสามารถตั้งค่าได้
  • โมเดล Keras ยังใช้อาร์กิวเมนต์ name ตามที่ตั้งค่าเป็นคำนำหน้าสำหรับตัวแปร
  • ฟังก์ชัน v1.name_scope สามารถใช้เพื่อตั้งค่าคำนำหน้าชื่อตัวแปรได้ ซึ่งแตกต่างจาก tf.variable_scope มาก มีผลกับชื่อเท่านั้น ไม่ติดตามตัวแปรและการนำกลับมาใช้ใหม่

เมื่อคำนึงถึงตัวชี้ด้านบนแล้ว ตัวอย่างโค้ดต่อไปนี้จะสาธิตเวิร์กโฟลว์ที่คุณสามารถปรับให้เข้ากับโค้ดของคุณเพื่ออัปเดตส่วนต่างๆ ของโมเดลในขณะที่อัปเดตจุดตรวจพร้อมกัน

  1. เริ่มต้นด้วยการเปลี่ยน tf.compat.v1.layers สไตล์การทำงานไปเป็นเวอร์ชันเชิงวัตถุ
class FunctionalStyleCompatModel(tf.keras.layers.Layer):

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = tf.compat.v1.layers.conv2d(
          inputs, 3, 3,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.conv2d(
          out, 4, 4,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.conv2d(
          out, 5, 5,
          kernel_regularizer="l2")
      return out

layer = FunctionalStyleCompatModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:8: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  # This is added back by InteractiveShellApp.init_path()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
['model/conv2d/bias:0',
 'model/conv2d/kernel:0',
 'model/conv2d_1/bias:0',
 'model/conv2d_1/kernel:0',
 'model/conv2d_2/bias:0',
 'model/conv2d_2/kernel:0']
  1. ถัดไป กำหนดอ็อบเจ็กต์ compat.v1.layer และตัวแปรใดๆ ที่สร้างโดย compat.v1.get_variable เป็นคุณสมบัติของ tf.keras.layers.Layer / tf.Module ที่เมธอดตกแต่งด้วย track_tf1_style_variables (โปรดทราบว่า TF2 เชิงวัตถุใดๆ จุดตรวจสอบลักษณะจะบันทึกทั้งเส้นทางตามชื่อตัวแปรและเส้นทางเชิงวัตถุใหม่)
class OOStyleCompatModel(tf.keras.layers.Layer):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.conv_1 = tf.compat.v1.layers.Conv2D(
          3, 3,
          kernel_regularizer="l2")
    self.conv_2 = tf.compat.v1.layers.Conv2D(
          4, 4,
          kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_1(inputs)
      out = self.conv_2(out)
      out = tf.compat.v1.layers.conv2d(
          out, 5, 5,
          kernel_regularizer="l2")
      return out

layer = OOStyleCompatModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:19: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
['model/conv2d/kernel:0',
 'model/conv2d/bias:0',
 'model/conv2d_1/kernel:0',
 'model/conv2d_1/bias:0',
 'model/conv2d_2/bias:0',
 'model/conv2d_2/kernel:0']
ตัวยึดตำแหน่ง60
  1. บันทึกจุดตรวจสอบที่โหลดใหม่ ณ จุดนี้เพื่อบันทึกเส้นทางทั้งโดยชื่อตัวแปร (สำหรับ compat.v1.layers) หรือโดยกราฟวัตถุเชิงวัตถุ
weights = {v.name: v for v in layer.weights}
assert weights['model/conv2d/kernel:0'] is layer.conv_1.kernel
assert weights['model/conv2d_1/bias:0'] is layer.conv_2.bias
  1. ตอนนี้คุณสามารถสลับ compat.v1.layers เชิงวัตถุสำหรับเลเยอร์ Keras ดั้งเดิมในขณะที่ยังสามารถโหลดจุดตรวจสอบที่บันทึกไว้ล่าสุด ตรวจสอบให้แน่ใจว่าคุณรักษาชื่อตัวแปรไว้สำหรับ compat.v1.layers ที่เหลือ โดยยังคงบันทึก variable_scopes สร้างขึ้นโดยอัตโนมัติของเลเยอร์ที่ถูกแทนที่ เลเยอร์/ตัวแปรที่สับเปลี่ยนเหล่านี้จะใช้เฉพาะเส้นทางแอตทริบิวต์ของวัตถุไปยังตัวแปรในจุดตรวจสอบแทนเส้นทางชื่อตัวแปร

โดยทั่วไป คุณสามารถแทนที่การใช้ compat.v1.get_variable ในตัวแปรที่แนบมากับคุณสมบัติโดย:

  • เปลี่ยนเป็นใช้ tf.Variable , OR
  • อัปเดตโดยใช้ tf.keras.layers.Layer.add_weight โปรดทราบว่าหากคุณไม่ได้สลับเลเยอร์ทั้งหมดในคราวเดียว การทำเช่นนี้อาจเปลี่ยนการตั้งชื่อเลเยอร์/ตัวแปรที่สร้างขึ้นโดยอัตโนมัติสำหรับ compat.v1.layers ที่เหลือซึ่งไม่มีอาร์กิวเมนต์ name หากเป็นกรณีนี้ คุณต้องรักษาชื่อตัวแปรสำหรับ compat.v1.layers ที่เหลืออยู่โดยเปิดและปิด variable_scope ด้วยตนเองซึ่งสอดคล้องกับชื่อขอบเขตที่สร้างขึ้นของ compat.v1.layer ที่ถูกลบ มิฉะนั้น เส้นทางจากจุดตรวจที่มีอยู่อาจขัดแย้งกัน และการโหลดจุดตรวจจะทำงานไม่ถูกต้อง
def record_scope(scope_name):
  """Record a variable_scope to make sure future ones get incremented."""
  with tf.compat.v1.variable_scope(scope_name):
    pass

class PartiallyNativeKerasLayersModel(tf.keras.layers.Layer):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.conv_1 = tf.keras.layers.Conv2D(
          3, 3,
          kernel_regularizer="l2")
    self.conv_2 = tf.keras.layers.Conv2D(
          4, 4,
          kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_1(inputs)
      record_scope('conv2d') # Only needed if follow-on compat.v1.layers do not pass a `name` arg
      out = self.conv_2(out)
      record_scope('conv2d_1') # Only needed if follow-on compat.v1.layers do not pass a `name` arg
      out = tf.compat.v1.layers.conv2d(
          out, 5, 5,
          kernel_regularizer="l2")
      return out

layer = PartiallyNativeKerasLayersModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:26: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
['partially_native_keras_layers_model/model/conv2d_13/kernel:0',
 'partially_native_keras_layers_model/model/conv2d_13/bias:0',
 'partially_native_keras_layers_model/model/conv2d_14/kernel:0',
 'partially_native_keras_layers_model/model/conv2d_14/bias:0',
 'model/conv2d_2/bias:0',
 'model/conv2d_2/kernel:0']

การบันทึกจุดตรวจสอบในขั้นตอนนี้หลังจากสร้างตัวแปรจะทำให้มี เฉพาะ เส้นทางของวัตถุที่มีอยู่ในปัจจุบันเท่านั้น

ตรวจสอบให้แน่ใจว่าคุณได้บันทึกขอบเขตของ compat.v1.layers ที่ถูกลบออกเพื่อรักษาชื่อน้ำหนักที่สร้างขึ้นโดยอัตโนมัติสำหรับ compat.v1.layers ที่เหลือ

weights = set(v.name for v in layer.weights)
assert 'model/conv2d_2/kernel:0' in weights
assert 'model/conv2d_2/bias:0' in weights
  1. ทำซ้ำขั้นตอนข้างต้นจนกว่าคุณจะแทนที่ compat.v1.layers และ compat.v1.get_variable s ทั้งหมดในแบบจำลองของคุณด้วยค่าเทียบเท่าเนทีฟทั้งหมด
class FullyNativeKerasLayersModel(tf.keras.layers.Layer):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.conv_1 = tf.keras.layers.Conv2D(
          3, 3,
          kernel_regularizer="l2")
    self.conv_2 = tf.keras.layers.Conv2D(
          4, 4,
          kernel_regularizer="l2")
    self.conv_3 = tf.keras.layers.Conv2D(
          5, 5,
          kernel_regularizer="l2")


  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_1(inputs)
      out = self.conv_2(out)
      out = self.conv_3(out)
      return out

layer = FullyNativeKerasLayersModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
['fully_native_keras_layers_model/model/conv2d_16/kernel:0',
 'fully_native_keras_layers_model/model/conv2d_16/bias:0',
 'fully_native_keras_layers_model/model/conv2d_17/kernel:0',
 'fully_native_keras_layers_model/model/conv2d_17/bias:0',
 'fully_native_keras_layers_model/model/conv2d_18/kernel:0',
 'fully_native_keras_layers_model/model/conv2d_18/bias:0']

อย่าลืมทดสอบเพื่อให้แน่ใจว่าจุดตรวจที่อัปเดตใหม่ยังคงทำงานตามที่คุณคาดหวัง ใช้เทคนิคที่อธิบายไว้ในคู่มือการ ตรวจสอบความถูกต้องของตัวเลข ในทุกขั้นตอนที่เพิ่มขึ้นของกระบวนการนี้ เพื่อให้แน่ใจว่าโค้ดที่โอนย้ายของคุณทำงานอย่างถูกต้อง

การจัดการการเปลี่ยนแปลงพฤติกรรมของ TF1.x เป็น TF2 ที่ไม่ครอบคลุมโดยการจำลองแบบจำลอง shims

ชิมแบบจำลองที่อธิบายในคู่มือนี้ทำให้แน่ใจได้ว่าตัวแปร เลเยอร์ และการสูญเสียการทำให้เป็นมาตรฐานที่สร้างด้วย get_variable , tf.compat.v1.layers และ ความหมาย variable_scope จะยังคงทำงานเหมือนเดิมเมื่อใช้การเรียกใช้งานแบบกระตือรือร้นและ tf.function โดยไม่ต้อง พึ่งพาคอลเลกชัน

ข้อมูลนี้ไม่ครอบคลุมความหมายเฉพาะของ TF1.x ทั้งหมด ที่โมเดล Forward Pass ของคุณอาจใช้ ในบางกรณี แผ่นชิมอาจไม่เพียงพอที่จะทำให้โมเดลของคุณส่งต่อการส่งผ่านใน TF2 ได้ด้วยตัวเอง อ่าน คู่มือพฤติกรรม TF1.x เทียบกับ TF2 เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับความแตกต่างทางพฤติกรรมระหว่าง TF1.x และ TF2