ดูบน TensorFlow.org | ทำงานใน Google Colab | ดูบน GitHub | ดาวน์โหลดโน๊ตบุ๊ค |
เมื่อย้ายรหัส TensorFlow ของคุณจาก TF1.x เป็น TF2 แนวทางปฏิบัติที่ดีคือต้องแน่ใจว่ารหัสที่คุณโอนย้ายจะทำงานในลักษณะเดียวกันใน TF2 เช่นเดียวกับใน TF1.x
คู่มือนี้ครอบคลุมตัวอย่างโค้ดการย้ายข้อมูลด้วย tf.compat.v1.keras.utils.track_tf1_style_variables
modeling shim ที่ใช้กับ tf.keras.layers.Layer
อ่านคู่มือการจับคู่ แบบจำลอง เพื่อหาข้อมูลเพิ่มเติมเกี่ยวกับแผ่นชิมแบบจำลอง TF2
คู่มือนี้มีรายละเอียดแนวทางที่คุณสามารถใช้เพื่อ:
- ตรวจสอบความถูกต้องของผลลัพธ์ที่ได้จากแบบจำลองการฝึกอบรมโดยใช้รหัสที่ย้ายมา
- ตรวจสอบความสมมูลเชิงตัวเลขของโค้ดของคุณในเวอร์ชัน TensorFlow
ติดตั้ง
pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is available only in
# Tensorflow 2.8
pip install -q tf-nightly
pip install -q tf_slim
import tensorflow as tf
import tensorflow.compat.v1 as v1
import numpy as np
import tf_slim as slim
import sys
from contextlib import contextmanager
!git clone --depth=1 https://github.com/tensorflow/models.git
import models.research.slim.nets.inception_resnet_v2 as inception
Cloning into 'models'... remote: Enumerating objects: 3192, done.[K remote: Counting objects: 100% (3192/3192), done.[K remote: Compressing objects: 100% (2696/2696), done.[K remote: Total 3192 (delta 848), reused 1381 (delta 453), pack-reused 0[K Receiving objects: 100% (3192/3192), 33.39 MiB | 12.89 MiB/s, done. Resolving deltas: 100% (848/848), done.
หากคุณกำลังใส่รหัสส่งต่อที่ไม่สำคัญลงใน shim คุณต้องการรู้ว่ามันทำงานแบบเดียวกับที่ทำใน TF1.x ตัวอย่างเช่น ลองใส่โมเดล TF-Slim Inception-Resnet-v2 ทั้งหมดลงในชิมดังนี้:
# TF1 Inception resnet v2 forward pass based on slim layers
def inception_resnet_v2(inputs, num_classes, is_training):
with slim.arg_scope(
inception.inception_resnet_v2_arg_scope(batch_norm_scale=True)):
return inception.inception_resnet_v2(inputs, num_classes, is_training=is_training)
class InceptionResnetV2(tf.keras.layers.Layer):
"""Slim InceptionResnetV2 forward pass as a Keras layer"""
def __init__(self, num_classes, **kwargs):
super().__init__(**kwargs)
self.num_classes = num_classes
@tf.compat.v1.keras.utils.track_tf1_style_variables
def call(self, inputs, training=None):
is_training = training or False
# Slim does not accept `None` as a value for is_training,
# Keras will still pass `None` to layers to construct functional models
# without forcing the layer to always be in training or in inference.
# However, `None` is generally considered to run layers in inference.
with slim.arg_scope(
inception.inception_resnet_v2_arg_scope(batch_norm_scale=True)):
return inception.inception_resnet_v2(
inputs, self.num_classes, is_training=is_training)
WARNING:tensorflow:From /tmp/ipykernel_27382/2131234657.py:8: The name tf.keras.utils.track_tf1_style_variables is deprecated. Please use tf.compat.v1.keras.utils.track_tf1_style_variables instead.
เมื่อมันเกิดขึ้น เลเยอร์นี้ใช้งานได้จริงอย่างสมบูรณ์เมื่อแกะกล่อง (พร้อมการติดตามการสูญเสียการทำให้เป็นมาตรฐานที่แม่นยำ)
อย่างไรก็ตาม นี่ไม่ใช่สิ่งที่คุณอยากจะมองข้ามไป ทำตามขั้นตอนด้านล่างเพื่อตรวจสอบว่ามีพฤติกรรมเหมือนใน TF1.x หรือไม่ จนถึงการสังเกตการสมมูลเชิงตัวเลขที่สมบูรณ์แบบ ขั้นตอนเหล่านี้ยังสามารถช่วยคุณหาสามเหลี่ยมว่าส่วนใดของการส่งลูกไปข้างหน้าทำให้เกิดความแตกต่างจาก TF1.x (ระบุว่ามีความแตกต่างเกิดขึ้นในรูปแบบการส่งต่อหรือไม่เมื่อเทียบกับส่วนอื่นของแบบจำลอง)
ขั้นตอนที่ 1: ตรวจสอบว่าตัวแปรถูกสร้างขึ้นเพียงครั้งเดียว
สิ่งแรกที่คุณควรตรวจสอบคือ คุณได้สร้างแบบจำลองอย่างถูกต้องในลักษณะที่นำตัวแปรมาใช้ซ้ำในการเรียกแต่ละครั้ง แทนที่จะสร้างและใช้ตัวแปรใหม่โดยไม่ได้ตั้งใจในแต่ละครั้ง ตัวอย่างเช่น หากโมเดลของคุณสร้างเลเยอร์ Keras ใหม่ หรือการเรียก tf.Variable
ในการส่งต่อการส่งต่อแต่ละครั้ง เป็นไปได้มากว่าจะไม่สามารถดักจับตัวแปรและสร้างตัวแปรใหม่ได้ในแต่ละครั้ง
ด้านล่างนี้คือขอบเขตตัวจัดการบริบทสองขอบเขตที่คุณสามารถใช้เพื่อตรวจจับเมื่อโมเดลของคุณกำลังสร้างตัวแปรใหม่และดีบั๊กว่าส่วนใดของโมเดลกำลังทำอยู่
@contextmanager
def assert_no_variable_creations():
"""Assert no variables are created in this context manager scope."""
def invalid_variable_creator(next_creator, **kwargs):
raise ValueError("Attempted to create a new variable instead of reusing an existing one. Args: {}".format(kwargs))
with tf.variable_creator_scope(invalid_variable_creator):
yield
@contextmanager
def catch_and_raise_created_variables():
"""Raise all variables created within this context manager scope (if any)."""
created_vars = []
def variable_catcher(next_creator, **kwargs):
var = next_creator(**kwargs)
created_vars.append(var)
return var
with tf.variable_creator_scope(variable_catcher):
yield
if created_vars:
raise ValueError("Created vars:", created_vars)
ขอบเขตแรก ( assert_no_variable_creations()
) จะทำให้เกิดข้อผิดพลาดทันทีเมื่อคุณพยายามสร้างตัวแปรภายในขอบเขต สิ่งนี้ช่วยให้คุณตรวจสอบ stacktrace (และใช้การดีบักเชิงโต้ตอบ) เพื่อดูว่าโค้ดใดที่สร้างตัวแปรแทนการใช้ตัวแปรที่มีอยู่ซ้ำ
ขอบเขตที่สอง ( catch_and_raise_created_variables()
) จะเพิ่มข้อยกเว้นที่ส่วนท้ายของขอบเขตหากมีการสร้างตัวแปรใดๆ ขึ้น ข้อยกเว้นนี้จะรวมรายการของตัวแปรทั้งหมดที่สร้างขึ้นในขอบเขต สิ่งนี้มีประโยชน์ในการหาว่าชุดของน้ำหนักทั้งหมดที่แบบจำลองของคุณสร้างนั้นคืออะไร ในกรณีที่คุณมองเห็นรูปแบบทั่วไป อย่างไรก็ตาม การระบุบรรทัดโค้ดที่สร้างตัวแปรเหล่านั้นจะมีประโยชน์น้อยกว่า
ใช้ขอบเขตทั้งสองด้านล่างเพื่อตรวจสอบว่าเลเยอร์ InceptionResnetV2 แบบ shim ไม่ได้สร้างตัวแปรใหม่ใด ๆ หลังจากการเรียกครั้งแรก (น่าจะใช้ซ้ำ)
model = InceptionResnetV2(1000)
height, width = 299, 299
num_classes = 1000
inputs = tf.ones( (1, height, width, 3))
# Create all weights on the first call
model(inputs)
# Verify that no new weights are created in followup calls
with assert_no_variable_creations():
model(inputs)
with catch_and_raise_created_variables():
model(inputs)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py:2212: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead. warnings.warn('`layer.apply` is deprecated and ' /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tf_slim/layers/layers.py:684: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead. outputs = layer.apply(inputs, training=is_training) /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/legacy_tf_layers/core.py:332: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead. warnings.warn('`tf.layers.flatten` is deprecated and '
ในตัวอย่างด้านล่าง สังเกตว่านักตกแต่งเหล่านี้ทำงานอย่างไรบนเลเยอร์ที่สร้างน้ำหนักใหม่อย่างไม่ถูกต้องในแต่ละครั้ง แทนที่จะนำน้ำหนักที่มีอยู่มาใช้ซ้ำ
class BrokenScalingLayer(tf.keras.layers.Layer):
"""Scaling layer that incorrectly creates new weights each time:"""
@tf.compat.v1.keras.utils.track_tf1_style_variables
def call(self, inputs):
var = tf.Variable(initial_value=2.0)
bias = tf.Variable(initial_value=2.0, name='bias')
return inputs * var + bias
model = BrokenScalingLayer()
inputs = tf.ones( (1, height, width, 3))
model(inputs)
try:
with assert_no_variable_creations():
model(inputs)
except ValueError as err:
import traceback
traceback.print_exc()
Traceback (most recent call last): File "/tmp/ipykernel_27382/1128777590.py", line 7, in <module> model(inputs) File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler raise e.with_traceback(filtered_tb) from None File "/tmp/ipykernel_27382/3224979076.py", line 6, in call var = tf.Variable(initial_value=2.0) File "/tmp/ipykernel_27382/1829430118.py", line 5, in invalid_variable_creator raise ValueError("Attempted to create a new variable instead of reusing an existing one. Args: {}".format(kwargs)) ValueError: Exception encountered when calling layer "broken_scaling_layer" (type BrokenScalingLayer). Attempted to create a new variable instead of reusing an existing one. Args: {'initial_value': 2.0, 'trainable': None, 'validate_shape': True, 'caching_device': None, 'name': None, 'variable_def': None, 'dtype': None, 'import_scope': None, 'constraint': None, 'synchronization': <VariableSynchronization.AUTO: 0>, 'aggregation': <VariableAggregation.NONE: 0>, 'shape': None} Call arguments received: • inputs=tf.Tensor(shape=(1, 299, 299, 3), dtype=float32)
model = BrokenScalingLayer()
inputs = tf.ones( (1, height, width, 3))
model(inputs)
try:
with catch_and_raise_created_variables():
model(inputs)
except ValueError as err:
print(err)
('Created vars:', [<tf.Variable 'broken_scaling_layer_1/Variable:0' shape=() dtype=float32, numpy=2.0>, <tf.Variable 'broken_scaling_layer_1/bias:0' shape=() dtype=float32, numpy=2.0>])
คุณสามารถแก้ไขเลเยอร์ได้โดยตรวจสอบให้แน่ใจว่าเลเยอร์นั้นสร้างน้ำหนักเพียงครั้งเดียวแล้วนำกลับมาใช้ซ้ำในแต่ละครั้ง
class FixedScalingLayer(tf.keras.layers.Layer):
"""Scaling layer that incorrectly creates new weights each time:"""
def __init__(self):
super().__init__()
self.var = None
self.bias = None
@tf.compat.v1.keras.utils.track_tf1_style_variables
def call(self, inputs):
if self.var is None:
self.var = tf.Variable(initial_value=2.0)
self.bias = tf.Variable(initial_value=2.0, name='bias')
return inputs * self.var + self.bias
model = FixedScalingLayer()
inputs = tf.ones( (1, height, width, 3))
model(inputs)
with assert_no_variable_creations():
model(inputs)
with catch_and_raise_created_variables():
model(inputs)
การแก้ไขปัญหา
ต่อไปนี้คือสาเหตุทั่วไปบางประการที่ทำให้โมเดลของคุณอาจสร้างน้ำหนักใหม่โดยไม่ได้ตั้งใจ แทนที่จะใช้น้ำหนักที่มีอยู่ซ้ำ:
- มันใช้การเรียก
tf.Variable
อย่างชัดเจนโดยไม่ต้องใช้tf.Variables
ที่สร้างไว้แล้วซ้ำ แก้ไขปัญหานี้โดยตรวจสอบก่อนว่าไม่ได้สร้างไว้หรือไม่ จากนั้นจึงนำสิ่งที่มีอยู่กลับมาใช้ใหม่ - มันสร้างเลเยอร์ Keras หรือโมเดลโดยตรงในการส่งต่อในแต่ละครั้ง (ตรงข้ามกับ
tf.compat.v1.layers
) แก้ไขปัญหานี้โดยตรวจสอบก่อนว่าไม่ได้สร้างไว้หรือไม่ จากนั้นจึงนำสิ่งที่มีอยู่กลับมาใช้ใหม่ - มันถูกสร้างขึ้นบน
tf.compat.v1.layers
แต่ล้มเหลวในการกำหนดชื่อที่ชัดเจนของcompat.v1.layers
ทั้งหมดหรือรวมการใช้งานcompat.v1.layer
ของคุณภายในชื่อvariable_scope
ซึ่งทำให้ชื่อเลเยอร์ที่สร้างอัตโนมัติเพิ่มขึ้นใน แต่ละรุ่นโทร. แก้ไขปัญหานี้โดยใส่ชื่อtf.compat.v1.variable_scope
ไว้ในวิธีการตกแต่งชิมของคุณ ซึ่งจะรวมการใช้งานtf.compat.v1.layers
ทั้งหมดของคุณ
ขั้นตอนที่ 2: ตรวจสอบว่าจำนวนตัวแปร ชื่อ และรูปร่างตรงกัน
ขั้นตอนที่สองคือ ตรวจสอบให้แน่ใจว่าเลเยอร์ของคุณที่ทำงานใน TF2 สร้างจำนวนน้ำหนักเท่ากัน โดยมีรูปร่างเหมือนกัน เช่นเดียวกับโค้ดที่เกี่ยวข้องใน TF1.x
คุณสามารถผสมการตรวจสอบด้วยตนเองเพื่อดูว่าตรงกันหรือไม่ และทำการตรวจสอบโดยทางโปรแกรมในการทดสอบหน่วยดังที่แสดงด้านล่าง
# Build the forward pass inside a TF1.x graph, and
# get the counts, shapes, and names of the variables
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
height, width = 299, 299
num_classes = 1000
inputs = tf.ones( (1, height, width, 3))
out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=False)
tf1_variable_names_and_shapes = {
var.name: (var.trainable, var.shape) for var in tf.compat.v1.global_variables()}
num_tf1_variables = len(tf.compat.v1.global_variables())
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer_v1.py:1694: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead. warnings.warn('`layer.apply` is deprecated and '
ถัดไป ทำเช่นเดียวกันกับเลเยอร์ที่พันด้วยแผ่นชิมใน TF2 สังเกตว่าโมเดลนี้ถูกเรียกหลายครั้งก่อนที่จะหยิบตุ้มน้ำหนัก สิ่งนี้ทำเพื่อทดสอบการใช้ตัวแปรอย่างมีประสิทธิภาพ
height, width = 299, 299
num_classes = 1000
model = InceptionResnetV2(num_classes)
# The weights will not be created until you call the model
inputs = tf.ones( (1, height, width, 3))
# Call the model multiple times before checking the weights, to verify variables
# get reused rather than accidentally creating additional variables
out, endpoints = model(inputs, training=False)
out, endpoints = model(inputs, training=False)
# Grab the name: shape mapping and the total number of variables separately,
# because in TF2 variables can be created with the same name
num_tf2_variables = len(model.variables)
tf2_variable_names_and_shapes = {
var.name: (var.trainable, var.shape) for var in model.variables}
2021-12-04 02:27:27.209445: 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.
# Verify that the variable counts, names, and shapes all match:
assert num_tf1_variables == num_tf2_variables
assert tf1_variable_names_and_shapes == tf2_variable_names_and_shapes
เลเยอร์ InceptionResnetV2 ที่ใช้แผ่นชิมผ่านการทดสอบนี้ อย่างไรก็ตาม ในกรณีที่ไม่ตรงกัน คุณสามารถเรียกใช้ผ่านส่วนต่าง (ข้อความหรืออื่น ๆ ) เพื่อดูว่าความแตกต่างอยู่ที่ไหน
ข้อมูลนี้สามารถให้เบาะแสได้ว่าส่วนใดของแบบจำลองที่ไม่เป็นไปตามที่คาดไว้ คุณสามารถใช้ pdb การดีบักเชิงโต้ตอบ และจุดสั่งหยุดเพื่อเจาะลึกเข้าไปในส่วนต่างๆ ของโมเดลที่ดูน่าสงสัย และดีบักสิ่งที่ผิดพลาดในเชิงลึกยิ่งขึ้น
การแก้ไขปัญหา
ให้ความสนใจอย่างใกล้ชิดกับชื่อของตัวแปรใดๆ ที่สร้างขึ้นโดยตรงโดยการเรียก
tf.Variable
และเลเยอร์/โมเดล Keras อย่างชัดเจน เนื่องจากความหมายการสร้างชื่อตัวแปรอาจแตกต่างกันเล็กน้อยระหว่างกราฟ TF1.x และฟังก์ชัน TF2 เช่น การดำเนินการที่กระตือรือร้นและtf.function
แม้ว่าทุกอย่าง อย่างอื่นทำงานอย่างถูกต้อง หากเป็นกรณีนี้สำหรับคุณ ให้ปรับการทดสอบของคุณเพื่อพิจารณาความหมายการตั้งชื่อที่แตกต่างกันเล็กน้อยบางครั้งคุณอาจพบว่า
tf.Variable
s,tf.keras.layers.Layer
s หรือtf.keras.Model
ที่สร้างขึ้นในการส่งต่อของลูปการฝึกของคุณหายไปจากรายการตัวแปร TF2 แม้ว่าจะถูกจับโดยการรวบรวมตัวแปร ใน TF1.x แก้ไขปัญหานี้โดยกำหนดตัวแปร/เลเยอร์/โมเดลที่ forward pass ของคุณสร้างให้กับแอตทริบิวต์ของอินสแตนซ์ในโมเดลของคุณ ดู ที่นี่ สำหรับข้อมูลเพิ่มเติม
ขั้นตอนที่ 3: รีเซ็ตตัวแปรทั้งหมด ตรวจสอบการเทียบเท่าตัวเลขโดยปิดการสุ่มทั้งหมด
ขั้นตอนต่อไปคือการตรวจสอบความสมมูลเชิงตัวเลขสำหรับทั้งเอาต์พุตจริงและการติดตามการสูญเสียการทำให้เป็นมาตรฐาน เมื่อคุณแก้ไขแบบจำลองโดยที่ไม่มีการสร้างตัวเลขสุ่มที่เกี่ยวข้อง (เช่น ในระหว่างการอนุมาน)
วิธีที่แน่นอนในการทำเช่นนี้อาจขึ้นอยู่กับรุ่นเฉพาะของคุณ แต่ในรุ่นส่วนใหญ่ (เช่นรุ่นนี้) คุณสามารถทำได้โดย:
- การเริ่มต้นน้ำหนักให้เป็นค่าเดียวกันโดยไม่มีการสุ่ม ซึ่งสามารถทำได้โดยการรีเซ็ตเป็นค่าคงที่หลังจากสร้างแล้ว
- การรันโมเดลในโหมดอนุมานเพื่อหลีกเลี่ยงการทริกเกอร์เลเยอร์ dropout ใด ๆ ที่อาจเป็นแหล่งของการสุ่ม
รหัสต่อไปนี้สาธิตวิธีที่คุณสามารถเปรียบเทียบผลลัพธ์ TF1.x และ TF2 ด้วยวิธีนี้
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
height, width = 299, 299
num_classes = 1000
inputs = tf.ones( (1, height, width, 3))
out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=False)
# Rather than running the global variable initializers,
# reset all variables to a constant value
var_reset = tf.group([var.assign(tf.ones_like(var) * 0.001) for var in tf.compat.v1.global_variables()])
sess.run(var_reset)
# Grab the outputs & regularization loss
reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
tf1_output = sess.run(out)
print("Regularization loss:", tf1_regularization_loss)
tf1_output[0][:5]
Regularization loss: 0.001182976 array([0.00299837, 0.00299837, 0.00299837, 0.00299837, 0.00299837], dtype=float32)
รับผล TF2
height, width = 299, 299
num_classes = 1000
model = InceptionResnetV2(num_classes)
inputs = tf.ones((1, height, width, 3))
# Call the model once to create the weights
out, endpoints = model(inputs, training=False)
# Reset all variables to the same fixed value as above, with no randomness
for var in model.variables:
var.assign(tf.ones_like(var) * 0.001)
tf2_output, endpoints = model(inputs, training=False)
# Get the regularization loss
tf2_regularization_loss = tf.math.add_n(model.losses)
print("Regularization loss:", tf2_regularization_loss)
tf2_output[0][:5]
Regularization loss: tf.Tensor(0.0011829757, shape=(), dtype=float32) <tf.Tensor: shape=(5,), dtype=float32, numpy= array([0.00299837, 0.00299837, 0.00299837, 0.00299837, 0.00299837], dtype=float32)>
# Create a dict of tolerance values
tol_dict={'rtol':1e-06, 'atol':1e-05}
# Verify that the regularization loss and output both match
# when we fix the weights and avoid randomness by running inference:
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)
ตัวเลขตรงกันระหว่าง TF1.x และ TF2 เมื่อคุณลบแหล่งที่มาของการสุ่มออก และเลเยอร์ InceptionResnetV2
ที่เข้ากันได้กับ TF2 จะผ่านการทดสอบ
หากคุณกำลังสังเกตผลลัพธ์ที่แตกต่างกันสำหรับโมเดลของคุณเอง คุณสามารถใช้การพิมพ์หรือ pdb และการดีบักเชิงโต้ตอบเพื่อระบุตำแหน่งและสาเหตุที่ผลลัพธ์เริ่มแตกต่าง การดำเนินการอย่างกระตือรือร้นสามารถทำให้สิ่งนี้ง่ายขึ้นอย่างมาก คุณยังสามารถใช้วิธีการระเหยเพื่อเรียกใช้เฉพาะส่วนเล็กๆ ของแบบจำลองบนอินพุตกลางแบบตายตัว และแยกจุดที่ไดเวอร์เจนซ์เกิดขึ้น
ตาข่ายแบบบางจำนวนมาก (และรุ่นอื่นๆ) ที่สะดวกสบายยังมีจุดสิ้นสุดระดับกลางที่คุณตรวจสอบได้
ขั้นตอนที่ 4: จัดแนวการสร้างตัวเลขสุ่ม ตรวจสอบความเท่าเทียมกันของตัวเลขทั้งในการฝึกและการอนุมาน
ขั้นตอนสุดท้ายคือการตรวจสอบว่าโมเดล TF2 เป็นตัวเลขที่ตรงกับโมเดล TF1.x แม้ว่าจะทำบัญชีสำหรับการสร้างตัวเลขสุ่มในการเริ่มต้นตัวแปรและในการส่งต่อเอง (เช่น เลเยอร์ดรอปเอาต์ระหว่างการส่งต่อ)
คุณสามารถทำได้โดยใช้เครื่องมือทดสอบด้านล่างเพื่อสร้างความหมายของการสร้างตัวเลขสุ่มที่ตรงกันระหว่างกราฟ/เซสชัน TF1.x และการดำเนินการที่กระตือรือร้น
กราฟ/เซสชันดั้งเดิมของ TF1 และการดำเนินการที่กระตือรือร้นของ TF2 ใช้ความหมายการสร้างตัวเลขสุ่มแบบระบุสถานะที่แตกต่างกัน
ใน tf.compat.v1.Session
หากไม่มีการระบุเมล็ด การสร้างตัวเลขสุ่มจะขึ้นอยู่กับจำนวนการดำเนินการในกราฟ ณ เวลาที่เพิ่มการดำเนินการแบบสุ่ม และจำนวนครั้งที่รันกราฟ ในการดำเนินการอย่างกระฉับกระเฉง การสร้างหมายเลขสุ่มแบบเก็บสถานะขึ้นอยู่กับโกลบอลซีด เมล็ดสุ่มปฏิบัติการ และจำนวนครั้งที่ดำเนินการกับการดำเนินการกับเมล็ดสุ่มที่ให้มา ดู tf.random.set_seed
สำหรับข้อมูลเพิ่มเติม
คลาส v1.keras.utils.DeterministicRandomTestTool
ต่อไปนี้มี scope()
ที่สามารถทำให้การดำเนินการสุ่มเก็บสถานะใช้เมล็ดพันธุ์เดียวกันในทั้งกราฟ/เซสชัน TF1 และการดำเนินการที่กระตือรือร้น
เครื่องมือนี้มีโหมดการทดสอบสองโหมด:
-
constant
ที่ซึ่งใช้เมล็ดเดียวกันสำหรับทุกการดำเนินการไม่ว่าจะเรียกกี่ครั้งและ, -
num_random_ops
ซึ่งใช้จำนวนของการดำเนินการสุ่ม stateful ที่สังเกตก่อนหน้านี้เป็นเมล็ดการดำเนินการ
สิ่งนี้ใช้กับทั้งการสุ่มเก็บสถานะที่ใช้สำหรับการสร้างและการเริ่มต้นตัวแปร และกับการดำเนินการสุ่มเก็บสถานะที่ใช้ในการคำนวณ (เช่น สำหรับเลเยอร์การเลื่อนออก)
สร้างเมตริกซ์สุ่มสามตัวเพื่อแสดงวิธีใช้เครื่องมือนี้เพื่อสร้างตัวเลขสุ่มแบบเก็บสถานะที่ตรงกันระหว่างเซสชันและการดำเนินการที่กระตือรือร้น
random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
a = tf.random.uniform(shape=(3,1))
a = a * 3
b = tf.random.uniform(shape=(3,3))
b = b * 3
c = tf.random.uniform(shape=(3,3))
c = c * 3
graph_a, graph_b, graph_c = sess.run([a, b, c])
graph_a, graph_b, graph_c
(array([[2.5063772], [2.7488918], [1.4839486]], dtype=float32), array([[2.5063772, 2.7488918, 1.4839486], [1.5633398, 2.1358476, 1.3693532], [0.3598416, 1.8287641, 2.5314465]], dtype=float32), array([[2.5063772, 2.7488918, 1.4839486], [1.5633398, 2.1358476, 1.3693532], [0.3598416, 1.8287641, 2.5314465]], dtype=float32))
random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
a = tf.random.uniform(shape=(3,1))
a = a * 3
b = tf.random.uniform(shape=(3,3))
b = b * 3
c = tf.random.uniform(shape=(3,3))
c = c * 3
a, b, c
(<tf.Tensor: shape=(3, 1), dtype=float32, numpy= array([[2.5063772], [2.7488918], [1.4839486]], dtype=float32)>, <tf.Tensor: shape=(3, 3), dtype=float32, numpy= array([[2.5063772, 2.7488918, 1.4839486], [1.5633398, 2.1358476, 1.3693532], [0.3598416, 1.8287641, 2.5314465]], dtype=float32)>, <tf.Tensor: shape=(3, 3), dtype=float32, numpy= array([[2.5063772, 2.7488918, 1.4839486], [1.5633398, 2.1358476, 1.3693532], [0.3598416, 1.8287641, 2.5314465]], dtype=float32)>)
# Demonstrate that the generated random numbers match
np.testing.assert_allclose(graph_a, a.numpy(), **tol_dict)
np.testing.assert_allclose(graph_b, b.numpy(), **tol_dict)
np.testing.assert_allclose(graph_c, c.numpy(), **tol_dict)
อย่างไรก็ตาม โปรดสังเกตว่าในโหมด constant
เนื่องจาก b
และ c
ถูกสร้างขึ้นด้วยเมล็ดเดียวกันและมีรูปร่างเหมือนกัน พวกมันจึงมีค่าเท่ากันทุกประการ
np.testing.assert_allclose(b.numpy(), c.numpy(), **tol_dict)
ติดตามการสั่งซื้อ
หากคุณกังวลเกี่ยวกับตัวเลขสุ่มบางตัวที่ตรงกันในโหมด constant
จะลดความมั่นใจในการทดสอบการสมมูลเชิงตัวเลข (เช่น หากน้ำหนักหลายตัวใช้ค่าเริ่มต้นเดียวกัน) คุณสามารถใช้โหมด num_random_ops
เพื่อหลีกเลี่ยงปัญหานี้ได้ ในโหมด num_random_ops
ตัวเลขสุ่มที่สร้างขึ้นจะขึ้นอยู่กับลำดับของการสุ่มปฏิบัติการในโปรแกรม
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
a = tf.random.uniform(shape=(3,1))
a = a * 3
b = tf.random.uniform(shape=(3,3))
b = b * 3
c = tf.random.uniform(shape=(3,3))
c = c * 3
graph_a, graph_b, graph_c = sess.run([a, b, c])
graph_a, graph_b, graph_c
(array([[2.5063772], [2.7488918], [1.4839486]], dtype=float32), array([[0.45038545, 1.9197761 , 2.4536333 ], [1.0371652 , 2.9898582 , 1.924583 ], [0.25679827, 1.6579313 , 2.8418403 ]], dtype=float32), array([[2.9634383 , 1.0862181 , 2.6042497 ], [0.70099247, 2.3920312 , 1.0470468 ], [0.18173039, 0.8359269 , 1.0508587 ]], dtype=float32))
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
a = tf.random.uniform(shape=(3,1))
a = a * 3
b = tf.random.uniform(shape=(3,3))
b = b * 3
c = tf.random.uniform(shape=(3,3))
c = c * 3
a, b, c
(<tf.Tensor: shape=(3, 1), dtype=float32, numpy= array([[2.5063772], [2.7488918], [1.4839486]], dtype=float32)>, <tf.Tensor: shape=(3, 3), dtype=float32, numpy= array([[0.45038545, 1.9197761 , 2.4536333 ], [1.0371652 , 2.9898582 , 1.924583 ], [0.25679827, 1.6579313 , 2.8418403 ]], dtype=float32)>, <tf.Tensor: shape=(3, 3), dtype=float32, numpy= array([[2.9634383 , 1.0862181 , 2.6042497 ], [0.70099247, 2.3920312 , 1.0470468 ], [0.18173039, 0.8359269 , 1.0508587 ]], dtype=float32)>)
# Demonstrate that the generated random numbers match
np.testing.assert_allclose(graph_a, a.numpy(), **tol_dict)
np.testing.assert_allclose(graph_b, b.numpy(), **tol_dict )
np.testing.assert_allclose(graph_c, c.numpy(), **tol_dict)
# Demonstrate that with the 'num_random_ops' mode,
# b & c took on different values even though
# their generated shape was the same
assert not np.allclose(b.numpy(), c.numpy(), **tol_dict)
อย่างไรก็ตาม โปรดสังเกตว่าในโหมดนี้ การสร้างแบบสุ่มมีความอ่อนไหวต่อลำดับของโปรแกรม ดังนั้นตัวเลขสุ่มที่สร้างต่อไปนี้จึงไม่ตรงกัน
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
a = tf.random.uniform(shape=(3,1))
a = a * 3
b = tf.random.uniform(shape=(3,3))
b = b * 3
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
b_prime = tf.random.uniform(shape=(3,3))
b_prime = b_prime * 3
a_prime = tf.random.uniform(shape=(3,1))
a_prime = a_prime * 3
assert not np.allclose(a.numpy(), a_prime.numpy())
assert not np.allclose(b.numpy(), b_prime.numpy())
เพื่อให้สามารถแก้ไขจุดบกพร่องรูปแบบต่างๆ เนื่องจากลำดับการติดตาม DeterministicRandomTestTool
ในโหมด num_random_ops
ช่วยให้คุณเห็นจำนวนการดำเนินการสุ่มที่ติดตามด้วยคุณสมบัติ operation_seed
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
print(random_tool.operation_seed)
a = tf.random.uniform(shape=(3,1))
a = a * 3
print(random_tool.operation_seed)
b = tf.random.uniform(shape=(3,3))
b = b * 3
print(random_tool.operation_seed)
0 1 2
หากคุณต้องการพิจารณาลำดับการติดตามที่แตกต่างกันในการทดสอบของคุณ คุณสามารถตั้งค่า operation_seed
ที่เพิ่มค่าอัตโนมัติได้อย่างชัดเจน ตัวอย่างเช่น คุณสามารถใช้เพื่อสร้างตัวเลขสุ่มที่ตรงกันในคำสั่งสองโปรแกรมที่แตกต่างกัน
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
print(random_tool.operation_seed)
a = tf.random.uniform(shape=(3,1))
a = a * 3
print(random_tool.operation_seed)
b = tf.random.uniform(shape=(3,3))
b = b * 3
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
random_tool.operation_seed = 1
b_prime = tf.random.uniform(shape=(3,3))
b_prime = b_prime * 3
random_tool.operation_seed = 0
a_prime = tf.random.uniform(shape=(3,1))
a_prime = a_prime * 3
np.testing.assert_allclose(a.numpy(), a_prime.numpy(), **tol_dict)
np.testing.assert_allclose(b.numpy(), b_prime.numpy(), **tol_dict)
0 1ตัวยึดตำแหน่ง46
อย่างไรก็ตาม DeterministicRandomTestTool
ไม่อนุญาตให้ใช้เมล็ดพันธุ์การทำงานที่ใช้แล้วซ้ำ ดังนั้นตรวจสอบให้แน่ใจว่าลำดับที่เพิ่มขึ้นอัตโนมัติไม่สามารถทับซ้อนกันได้ เนื่องจากการดำเนินการอย่างกระตือรือร้นจะสร้างตัวเลขที่แตกต่างกันสำหรับการใช้งานที่ตามมาของเมล็ดการดำเนินการเดียวกัน ในขณะที่กราฟและเซสชัน TF1 ไม่สร้างข้อผิดพลาด ดังนั้น การเพิ่มข้อผิดพลาดจะช่วยรักษาเซสชันและการสร้างตัวเลขสุ่มแบบเก็บสถานะไว้เสมอ
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
random_tool.operation_seed = 1
b_prime = tf.random.uniform(shape=(3,3))
b_prime = b_prime * 3
random_tool.operation_seed = 0
a_prime = tf.random.uniform(shape=(3,1))
a_prime = a_prime * 3
try:
c = tf.random.uniform(shape=(3,1))
raise RuntimeError("An exception should have been raised before this, " +
"because the auto-incremented operation seed will " +
"overlap an already-used value")
except ValueError as err:
print(err)
This `DeterministicRandomTestTool` object is trying to re-use the already-used operation seed 1. It cannot guarantee random numbers will match between eager and sessions when an operation seed is reused. You most likely set `operation_seed` explicitly but used a value that caused the naturally-incrementing operation seed sequences to overlap with an already-used seed.
การยืนยันการอนุมาน
ตอนนี้ คุณสามารถใช้ DeterministicRandomTestTool
เพื่อให้แน่ใจว่าโมเดล InceptionResnetV2
ตรงกันในการอนุมาน แม้ว่าจะใช้งานการเริ่มต้นน้ำหนักแบบสุ่มก็ตาม สำหรับเงื่อนไขการทดสอบที่แข็งแกร่งขึ้นเนื่องจากลำดับโปรแกรมที่ตรงกัน ให้ใช้โหมด num_random_ops
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
height, width = 299, 299
num_classes = 1000
inputs = tf.ones( (1, height, width, 3))
out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=False)
# Initialize the variables
sess.run(tf.compat.v1.global_variables_initializer())
# Grab the outputs & regularization loss
reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
tf1_output = sess.run(out)
print("Regularization loss:", tf1_regularization_loss)
Regularization loss: 1.2254326
height, width = 299, 299
num_classes = 1000
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
model = InceptionResnetV2(num_classes)
inputs = tf.ones((1, height, width, 3))
tf2_output, endpoints = model(inputs, training=False)
# Grab the regularization loss as well
tf2_regularization_loss = tf.math.add_n(model.losses)
print("Regularization loss:", tf2_regularization_loss)
Regularization loss: tf.Tensor(1.2254325, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
# when using the DeterministicRandomTestTool:
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)
กำลังตรวจสอบการฝึกอบรม
เนื่องจาก DeterministicRandomTestTool
ใช้งานได้กับการดำเนินการสุ่มแบบเก็บสถานะ ทั้งหมด (รวมถึงทั้งการเริ่มต้นน้ำหนักและการคำนวณ เช่น เลเยอร์ที่เลื่อนออก) คุณสามารถใช้มันเพื่อตรวจสอบแบบจำลองที่ตรงกันในโหมดการฝึกได้เช่นกัน คุณสามารถใช้โหมด num_random_ops
ได้อีกครั้ง เนื่องจากลำดับโปรแกรมของ stateful random ops ตรงกัน
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
height, width = 299, 299
num_classes = 1000
inputs = tf.ones( (1, height, width, 3))
out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=True)
# Initialize the variables
sess.run(tf.compat.v1.global_variables_initializer())
# Grab the outputs & regularization loss
reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
tf1_output = sess.run(out)
print("Regularization loss:", tf1_regularization_loss)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/layers/normalization/batch_normalization.py:532: _colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version. Instructions for updating: Colocations handled automatically by placer. Regularization loss: 1.22548
height, width = 299, 299
num_classes = 1000
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
model = InceptionResnetV2(num_classes)
inputs = tf.ones((1, height, width, 3))
tf2_output, endpoints = model(inputs, training=True)
# Grab the regularization loss as well
tf2_regularization_loss = tf.math.add_n(model.losses)
print("Regularization loss:", tf2_regularization_loss)
Regularization loss: tf.Tensor(1.2254798, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
# when using the DeterministicRandomTestTool
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)
คุณได้ตรวจสอบแล้วว่าโมเดล InceptionResnetV2
ทำงานอย่างกระตือรือร้นโดยมีมัณฑนากรรอบๆ tf.keras.layers.Layer
จับคู่ตัวเลขกับเครือข่ายที่บางเฉียบที่ทำงานในกราฟและเซสชัน TF1
ตัวอย่างเช่น การเรียกเลเยอร์ InceptionResnetV2
โดยตรงด้วย training=True
interleaves การเริ่มต้นตัวแปรด้วยลำดับการเลื่อนออกตามลำดับการสร้างเครือข่าย
ในทางกลับกัน ก่อนอื่นให้ใส่ tf.keras.layers.Layer
decorator ใน Keras functional model จากนั้นจึงเรียกโมเดลด้วย training=True
เทียบเท่ากับการเริ่มต้นตัวแปรทั้งหมด จากนั้นจึงใช้เลเยอร์ dropout สิ่งนี้จะสร้างลำดับการติดตามที่แตกต่างกันและชุดตัวเลขสุ่มที่แตกต่างกัน
อย่างไรก็ตาม ค่าเริ่มต้น mode='constant'
ไม่ไวต่อความแตกต่างเหล่านี้ในลำดับการติดตาม และจะผ่านไปโดยไม่มีการทำงานเพิ่มเติม แม้ว่าจะฝังเลเยอร์ในโมเดลการทำงานของ Keras
random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
height, width = 299, 299
num_classes = 1000
inputs = tf.ones( (1, height, width, 3))
out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=True)
# Initialize the variables
sess.run(tf.compat.v1.global_variables_initializer())
# Get the outputs & regularization losses
reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
tf1_output = sess.run(out)
print("Regularization loss:", tf1_regularization_loss)
Regularization loss: 1.2239965
height, width = 299, 299
num_classes = 1000
random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
keras_input = tf.keras.Input(shape=(height, width, 3))
layer = InceptionResnetV2(num_classes)
model = tf.keras.Model(inputs=keras_input, outputs=layer(keras_input))
inputs = tf.ones((1, height, width, 3))
tf2_output, endpoints = model(inputs, training=True)
# Get the regularization loss
tf2_regularization_loss = tf.math.add_n(model.losses)
print("Regularization loss:", tf2_regularization_loss)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py:1345: 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. warnings.warn('`layer.updates` will be removed in a future version. ' /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) Regularization loss: tf.Tensor(1.2239964, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
# when using the DeterministicRandomTestTool
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)
ขั้นตอนที่ 3b หรือ 4b (ทางเลือก): การทดสอบด้วยจุดตรวจที่มีอยู่แล้ว
หลังจากขั้นตอนที่ 3 หรือขั้นตอนที่ 4 ข้างต้น การเรียกใช้การทดสอบการสมมูลเชิงตัวเลขอาจเป็นประโยชน์เมื่อเริ่มต้นจากจุดตรวจสอบตามชื่อที่มีอยู่แล้ว หากคุณมีบางส่วน วิธีนี้สามารถทดสอบได้ว่าการโหลดจุดตรวจแบบเดิมของคุณทำงานอย่างถูกต้องและตัวแบบทำงานถูกต้องหรือไม่ คู่มือการ ใช้จุดตรวจ TF1.x ซ้ำจะครอบคลุมถึงวิธีการใช้จุดตรวจ TF1.x ที่มีอยู่ก่อนแล้วและโอนไปยังจุดตรวจ TF2
การทดสอบและการแก้ไขปัญหาเพิ่มเติม
เมื่อคุณเพิ่มการทดสอบการสมมูลเชิงตัวเลขมากขึ้น คุณอาจเลือกที่จะเพิ่มการทดสอบที่ยืนยันว่าการคำนวณการไล่ระดับสีของคุณตรงกัน (หรือแม้แต่การอัปเดตเครื่องมือเพิ่มประสิทธิภาพของคุณ)
Backpropagation และการคำนวณไล่ระดับมีแนวโน้มที่จะเกิดความไม่เสถียรของตัวเลขทศนิยมมากกว่าการส่งต่อแบบจำลอง ซึ่งหมายความว่าเนื่องจากการทดสอบความสมมูลครอบคลุมส่วนที่ไม่ได้แยกจากการฝึกของคุณ คุณอาจเริ่มเห็นความแตกต่างของตัวเลขที่ไม่สำคัญระหว่างการวิ่งอย่างกระตือรือร้นและกราฟ TF1 ของคุณ ซึ่งอาจเกิดจากการเพิ่มประสิทธิภาพกราฟของ TensorFlow ที่ทำสิ่งต่างๆ เช่น แทนที่นิพจน์ย่อยในกราฟด้วยการดำเนินการทางคณิตศาสตร์น้อยลง
เพื่อแยกว่าน่าจะเป็นกรณีนี้หรือไม่ คุณสามารถเปรียบเทียบโค้ด TF1 ของคุณกับการคำนวณ TF2 ที่เกิดขึ้นภายใน tf.function
(ซึ่งใช้การเพิ่มประสิทธิภาพกราฟผ่านเหมือนกราฟ TF1) แทนที่จะใช้การคำนวณที่กระตือรือร้นอย่างแท้จริง อีกวิธีหนึ่ง คุณสามารถลองใช้ tf.config.optimizer.set_experimental_options
เพื่อปิดใช้งานการส่งผ่านการปรับให้เหมาะสม เช่น "arithmetic_optimization"
ก่อนการคำนวณ TF1 ของคุณ เพื่อดูว่าผลลัพธ์มีตัวเลขใกล้เคียงกับผลการคำนวณ TF2 ของคุณหรือไม่ ในการรันการฝึกจริงของคุณ ขอแนะนำให้คุณใช้ tf.function
ที่เปิดใช้งานการผ่านการปรับให้เหมาะสมเพื่อเหตุผลด้านประสิทธิภาพ แต่คุณอาจพบว่ามีประโยชน์ในการปิดการใช้งานพวกเขาในการทดสอบหน่วยสมมูลเชิงตัวเลขของคุณ
ในทำนองเดียวกัน คุณอาจพบว่าเครื่องมือเพิ่มประสิทธิภาพ tf.compat.v1.train
และเครื่องมือเพิ่มประสิทธิภาพ TF2 มีคุณสมบัติตัวเลขทศนิยมแตกต่างกันเล็กน้อยจากเครื่องมือเพิ่มประสิทธิภาพ TF2 แม้ว่าสูตรทางคณิตศาสตร์ที่พวกเขากำลังแสดงจะเหมือนกันก็ตาม สิ่งนี้ไม่น่าจะเป็นปัญหาในการฝึกซ้อมของคุณ แต่อาจต้องใช้ความอดทนเชิงตัวเลขที่สูงขึ้นในการทดสอบหน่วยสมมูล