ช่วยปกป้อง Great Barrier Reef กับ TensorFlow บน Kaggle เข้าร่วมท้าทาย

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

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

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

การดำเนินการอย่างกระตือรือร้นเป็นแพลตฟอร์มการเรียนรู้ของเครื่องที่ยืดหยุ่นสำหรับการวิจัยและการทดลอง โดยให้:

  • อินเตอร์เฟซที่ใช้งานง่าย -Structure รหัสของคุณตามธรรมชาติและใช้งูหลามโครงสร้างข้อมูล ทำซ้ำอย่างรวดเร็วในโมเดลขนาดเล็กและข้อมูลขนาดเล็ก
  • ได้ง่ายขึ้นการแก้จุดบกพร่อง Ops -Call โดยตรงในการตรวจสอบรูปแบบการทำงานและการทดสอบการเปลี่ยนแปลง ใช้เครื่องมือแก้ไขข้อบกพร่อง Python มาตรฐานสำหรับการรายงานข้อผิดพลาดทันที
  • การควบคุมการไหลของธรรมชาติที่ใช้งานการควบคุมการไหลหลามแทนการควบคุมการไหลกราฟลดความซับซ้อนของสเปคของแบบจำลองแบบไดนามิก

การดำเนินการอย่างกระตือรือร้นสนับสนุนการดำเนินการ TensorFlow และการเร่งความเร็ว GPU ส่วนใหญ่

การตั้งค่าและการใช้งานพื้นฐาน

import os

import tensorflow as tf

import cProfile

ใน Tensorflow 2.0 การดำเนินการแบบกระตือรือร้นจะเปิดใช้งานตามค่าเริ่มต้น

tf.executing_eagerly()
True

ตอนนี้คุณสามารถเรียกใช้การดำเนินการ TensorFlow และผลลัพธ์จะกลับมาทันที:

x = [[2.]]
m = tf.matmul(x, x)
print("hello, {}".format(m))
hello, [[4.]]

การเปิดใช้งานการดำเนินการอย่างกระตือรือร้นจะเปลี่ยนวิธีการทำงานของการดำเนินการ TensorFlow—ขณะนี้ การดำเนินการดังกล่าวจะประเมินและคืนค่าเป็น Python ทันที tf.Tensor วัตถุค่าอ้างอิงคอนกรีตแทนการจับสัญลักษณ์โหนดในกราฟการคำนวณ เนื่องจากมีไม่ได้เป็นกราฟการคำนวณเพื่อสร้างและเรียกในภายหลังในเซสชั่นมันเป็นเรื่องง่ายในการตรวจสอบผลการใช้ print() หรือดีบัก การประเมิน การพิมพ์ และการตรวจสอบค่าเทนเซอร์ไม่ทำลายขั้นตอนของการคำนวณไล่ระดับ

การดำเนินการกระตือรือร้นที่ทำงานอย่างมี NumPy การดำเนินงาน NumPy ยอมรับ tf.Tensor ข้อโต้แย้ง TensorFlow tf.math การดำเนินการแปลงวัตถุหลามและอาร์เรย์ NumPy เพื่อ tf.Tensor วัตถุ tf.Tensor.numpy วิธีการส่งกลับค่าของวัตถุเป็น NumPy ndarray

a = tf.constant([[1, 2],
                 [3, 4]])
print(a)
tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32)
# Broadcasting support
b = tf.add(a, 1)
print(b)
tf.Tensor(
[[2 3]
 [4 5]], shape=(2, 2), dtype=int32)
# Operator overloading is supported
print(a * b)
tf.Tensor(
[[ 2  6]
 [12 20]], shape=(2, 2), dtype=int32)
# Use NumPy values
import numpy as np

c = np.multiply(a, b)
print(c)
[[ 2  6]
 [12 20]]
# Obtain numpy value from a tensor:
print(a.numpy())
# => [[1 2]
#     [3 4]]
[[1 2]
 [3 4]]

การไหลของการควบคุมแบบไดนามิก

ประโยชน์ที่สำคัญของการดำเนินการอย่างกระตือรือร้นคือ ฟังก์ชันทั้งหมดของภาษาโฮสต์จะพร้อมใช้งานในขณะที่โมเดลของคุณกำลังทำงาน ดังนั้นสำหรับตัวอย่างเช่นมันเป็นเรื่องง่ายที่จะเขียน FizzBuzz :

def fizzbuzz(max_num):
  counter = tf.constant(0)
  max_num = tf.convert_to_tensor(max_num)
  for num in range(1, max_num.numpy()+1):
    num = tf.constant(num)
    if int(num % 3) == 0 and int(num % 5) == 0:
      print('FizzBuzz')
    elif int(num % 3) == 0:
      print('Fizz')
    elif int(num % 5) == 0:
      print('Buzz')
    else:
      print(num.numpy())
    counter += 1
fizzbuzz(15)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

มีเงื่อนไขที่ขึ้นอยู่กับค่าเทนเซอร์และจะพิมพ์ค่าเหล่านี้เมื่อรันไทม์

ฝึกฝนอย่างกระตือรือร้น

การคำนวณการไล่ระดับสี

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

คุณสามารถใช้ tf.GradientTape ในการฝึกอบรมและ / หรือการไล่ระดับสีในการคำนวณความกระตือรือร้น มีประโยชน์อย่างยิ่งสำหรับการฝึกวนซ้ำที่ซับซ้อน

เนื่องจากการดำเนินการที่แตกต่างกันสามารถเกิดขึ้นได้ในระหว่างการโทรแต่ละครั้ง การดำเนินการส่งต่อทั้งหมดจะถูกบันทึกไว้ใน "เทป" ในการคำนวณการไล่ระดับสี ให้เล่นเทปย้อนกลับแล้วทิ้ง โดยเฉพาะอย่างยิ่ง tf.GradientTape เพียงหนึ่งสามารถคำนวณการไล่ระดับสี; การเรียกที่ตามมาทำให้เกิดข้อผิดพลาดรันไทม์

w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
  loss = w * w

grad = tape.gradient(loss, w)
print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)
tf.Tensor([[2.]], shape=(1, 1), dtype=float32)

ฝึกนางแบบ

ตัวอย่างต่อไปนี้สร้างแบบจำลองหลายชั้นที่จำแนกตัวเลขที่เขียนด้วยลายมือ MNIST มาตรฐาน มันแสดงให้เห็นถึงเครื่องมือเพิ่มประสิทธิภาพและ API เลเยอร์เพื่อสร้างกราฟที่ฝึกได้ในสภาพแวดล้อมการดำเนินการที่กระตือรือร้น

# Fetch and format the mnist data
(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()

dataset = tf.data.Dataset.from_tensor_slices(
  (tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),
   tf.cast(mnist_labels,tf.int64)))
dataset = dataset.shuffle(1000).batch(32)
# Build the model
mnist_model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu',
                         input_shape=(None, None, 1)),
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])

แม้จะไม่มีการฝึกอบรม ให้เรียกใช้แบบจำลองและตรวจสอบผลลัพธ์ในการดำเนินการอย่างกระตือรือร้น:

for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
Logits:  [[-0.01775933 -0.01194787 -0.08372174 -0.06535977  0.00338565 -0.01974326
  -0.04763228  0.00904049 -0.00144051 -0.01944664]]

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

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

loss_history = []
def train_step(images, labels):
  with tf.GradientTape() as tape:
    logits = mnist_model(images, training=True)

    # Add asserts to check the shape of the output.
    tf.debugging.assert_equal(logits.shape, (32, 10))

    loss_value = loss_object(labels, logits)

  loss_history.append(loss_value.numpy().mean())
  grads = tape.gradient(loss_value, mnist_model.trainable_variables)
  optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables))
def train(epochs):
  for epoch in range(epochs):
    for (batch, (images, labels)) in enumerate(dataset):
      train_step(images, labels)
    print ('Epoch {} finished'.format(epoch))
train(epochs = 3)
Epoch 0 finished
Epoch 1 finished
Epoch 2 finished
import matplotlib.pyplot as plt

plt.plot(loss_history)
plt.xlabel('Batch #')
plt.ylabel('Loss [entropy]')
Text(0, 0.5, 'Loss [entropy]')

png

ตัวแปรและตัวเพิ่มประสิทธิภาพ

tf.Variable วัตถุเก็บแน่นอน tf.Tensor เหมือนค่าเข้าถึงในระหว่างการฝึกอบรมเพื่อให้ความแตกต่างได้ง่ายขึ้นโดยอัตโนมัติ

คอลเลกชั่นของตัวแปรสามารถถูกห่อหุ้มเป็นเลเยอร์หรือแบบจำลอง พร้อมกับวิธีการที่ดำเนินการกับตัวแปรเหล่านั้น ดู ชั้นที่กำหนดเอง Keras และรูปแบบ รายละเอียด แตกต่างที่สำคัญระหว่างชั้นและรูปแบบคือรูปแบบการเพิ่มวิธีการเช่น Model.fit , Model.evaluate และ Model.save

ตัวอย่างเช่น ตัวอย่างการแยกความแตกต่างอัตโนมัติด้านบนสามารถเขียนใหม่ได้:

class Linear(tf.keras.Model):
  def __init__(self):
    super(Linear, self).__init__()
    self.W = tf.Variable(5., name='weight')
    self.B = tf.Variable(10., name='bias')
  def call(self, inputs):
    return inputs * self.W + self.B
# A toy dataset of points around 3 * x + 2
NUM_EXAMPLES = 2000
training_inputs = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise

# The loss function to be optimized
def loss(model, inputs, targets):
  error = model(inputs) - targets
  return tf.reduce_mean(tf.square(error))

def grad(model, inputs, targets):
  with tf.GradientTape() as tape:
    loss_value = loss(model, inputs, targets)
  return tape.gradient(loss_value, [model.W, model.B])

ต่อไป:

  1. สร้างแบบจำลอง
  2. อนุพันธ์ของฟังก์ชันการสูญเสียที่สัมพันธ์กับพารามิเตอร์แบบจำลอง
  3. กลยุทธ์การอัพเดทตัวแปรตามอนุพันธ์
model = Linear()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

print("Initial loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))

steps = 300
for i in range(steps):
  grads = grad(model, training_inputs, training_outputs)
  optimizer.apply_gradients(zip(grads, [model.W, model.B]))
  if i % 20 == 0:
    print("Loss at step {:03d}: {:.3f}".format(i, loss(model, training_inputs, training_outputs)))
Initial loss: 69.909
Loss at step 000: 67.145
Loss at step 020: 30.170
Loss at step 040: 13.859
Loss at step 060: 6.659
Loss at step 080: 3.479
Loss at step 100: 2.074
Loss at step 120: 1.453
Loss at step 140: 1.178
Loss at step 160: 1.056
Loss at step 180: 1.003
Loss at step 200: 0.979
Loss at step 220: 0.968
Loss at step 240: 0.963
Loss at step 260: 0.961
Loss at step 280: 0.960
print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
Final loss: 0.960
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 2.9515867233276367, B = 2.0210201740264893

การบันทึกตามวัตถุ

tf.keras.Model รวมถึงความสะดวกสบาย save_weights วิธีที่ช่วยให้คุณสามารถสร้างด่าน:

model.save_weights('weights')
status = model.load_weights('weights')

ใช้ tf.train.Checkpoint คุณสามารถใช้การควบคุมเต็มรูปแบบผ่านกระบวนการนี้

ในส่วนนี้จะเป็นรุ่นที่หายากของ คู่มือการฝึกอบรมด่าน

x = tf.Variable(10.)
checkpoint = tf.train.Checkpoint(x=x)
x.assign(2.)   # Assign a new value to the variables and save.
checkpoint_path = './ckpt/'
checkpoint.save(checkpoint_path)
'./ckpt/-1'
x.assign(11.)  # Change the variable after saving.

# Restore values from the checkpoint
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))

print(x)  # => 2.0
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=2.0>

เพื่อบันทึกและรุ่นโหลด tf.train.Checkpoint เก็บรัฐภายในของวัตถุโดยไม่ต้องมีตัวแปรที่ซ่อนอยู่ การบันทึกสถานะของการเป็น model การ optimizer และเป็นขั้นตอนที่ทั่วโลกผ่านพวกเขาไปยัง tf.train.Checkpoint :

model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
checkpoint_dir = 'path/to/model_dir'
if not os.path.exists(checkpoint_dir):
  os.makedirs(checkpoint_dir)
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
root = tf.train.Checkpoint(optimizer=optimizer,
                           model=model)

root.save(checkpoint_prefix)
root.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f4ba0648310>

ตัวชี้วัดเชิงวัตถุ

tf.keras.metrics จะถูกเก็บไว้เป็นวัตถุ ปรับปรุงตัวชี้วัดโดยการส่งผ่านข้อมูลใหม่ที่จะ callable และดึงผลโดยใช้ tf.keras.metrics.result วิธีตัวอย่างเช่น:

m = tf.keras.metrics.Mean("loss")
m(0)
m(5)
m.result()  # => 2.5
m([8, 9])
m.result()  # => 5.5
<tf.Tensor: shape=(), dtype=float32, numpy=5.5>

บทสรุปและเทนเซอร์บอร์ด

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

คุณสามารถใช้ tf.summary บันทึกสรุปของตัวแปรในการดำเนินความกระตือรือร้น ยกตัวอย่างเช่นการบันทึกบทสรุปของ loss หนึ่งครั้งในทุกขั้นตอนการฝึกอบรม 100:

logdir = "./tb/"
writer = tf.summary.create_file_writer(logdir)

steps = 1000
with writer.as_default():  # or call writer.set_as_default() before the loop.
  for i in range(steps):
    step = i + 1
    # Calculate loss with your real train function.
    loss = 1 - 0.001 * step
    if step % 100 == 0:
      tf.summary.scalar('loss', loss, step=step)
ls tb/
events.out.tfevents.1632342765.kokoro-gcp-ubuntu-prod-230753280.22287.0.v2

หัวข้อการสร้างความแตกต่างอัตโนมัติขั้นสูง

โมเดลไดนามิก

tf.GradientTape นอกจากนี้ยังสามารถใช้ในรูปแบบไดนามิก ตัวอย่างนี้เป็น สาย backtracking ค้นหา ลักษณะขั้นตอนวิธีการเช่นรหัส NumPy ปกติยกเว้นมีการไล่ระดับสีและอนุพันธ์ได้แม้จะมีการควบคุมการไหลที่ซับซ้อน:

def line_search_step(fn, init_x, rate=1.0):
  with tf.GradientTape() as tape:
    # Variables are automatically tracked.
    # But to calculate a gradient from a tensor, you must `watch` it.
    tape.watch(init_x)
    value = fn(init_x)
  grad = tape.gradient(value, init_x)
  grad_norm = tf.reduce_sum(grad * grad)
  init_value = value
  while value > init_value - rate * grad_norm:
    x = init_x - rate * grad
    value = fn(x)
    rate /= 2.0
  return x, value

การไล่ระดับสีแบบกำหนดเอง

การไล่ระดับสีแบบกำหนดเองเป็นวิธีที่ง่ายในการแทนที่การไล่ระดับสี ภายในฟังก์ชันไปข้างหน้า ให้กำหนดความลาดชันที่สัมพันธ์กับอินพุต เอาต์พุต หรือผลลัพธ์ระดับกลาง ตัวอย่างเช่น นี่เป็นวิธีง่ายๆ ในการตัดบรรทัดฐานของการไล่ระดับสีในการผ่านย้อนกลับ:

@tf.custom_gradient
def clip_gradient_by_norm(x, norm):
  y = tf.identity(x)
  def grad_fn(dresult):
    return [tf.clip_by_norm(dresult, norm), None]
  return y, grad_fn

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

def log1pexp(x):
  return tf.math.log(1 + tf.exp(x))

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# The gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# However, x = 100 fails because of numerical instability.
grad_log1pexp(tf.constant(100.)).numpy()
nan

นี่ log1pexp ฟังก์ชั่นสามารถประยุกต์การวิเคราะห์ด้วยการไล่ระดับสีที่กำหนดเอง การดำเนินการดังต่อ reuses ค่าสำหรับ tf.exp(x) ที่มีการคำนวณในช่วงข้างหน้าผ่านทำให้มีประสิทธิภาพมากขึ้นโดยการกำจัดการคำนวณซ้ำซ้อน:

@tf.custom_gradient
def log1pexp(x):
  e = tf.exp(x)
  def grad(dy):
    return dy * (1 - 1 / (1 + e))
  return tf.math.log(1 + e), grad

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# As before, the gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# And the gradient computation also works at x = 100.
grad_log1pexp(tf.constant(100.)).numpy()
1.0

ประสิทธิภาพ

การประมวลผลจะถูกถ่ายโอนไปยัง GPU โดยอัตโนมัติในระหว่างการดำเนินการอย่างกระตือรือร้น หากคุณต้องการควบคุมที่คำนวณทำงานคุณสามารถใส่ไว้ใน tf.device('/gpu:0') บล็อก (หรือเทียบเท่าซีพียู):

import time

def measure(x, steps):
  # TensorFlow initializes a GPU the first time it's used, exclude from timing.
  tf.matmul(x, x)
  start = time.time()
  for i in range(steps):
    x = tf.matmul(x, x)
  # tf.matmul can return before completing the matrix multiplication
  # (e.g., can return after enqueing the operation on a CUDA stream).
  # The x.numpy() call below will ensure that all enqueued operations
  # have completed (and will also copy the result to host memory,
  # so we're including a little more than just the matmul operation
  # time).
  _ = x.numpy()
  end = time.time()
  return end - start

shape = (1000, 1000)
steps = 200
print("Time to multiply a {} matrix by itself {} times:".format(shape, steps))

# Run on CPU:
with tf.device("/cpu:0"):
  print("CPU: {} secs".format(measure(tf.random.normal(shape), steps)))

# Run on GPU, if available:
if tf.config.list_physical_devices("GPU"):
  with tf.device("/gpu:0"):
    print("GPU: {} secs".format(measure(tf.random.normal(shape), steps)))
else:
  print("GPU: not found")
Time to multiply a (1000, 1000) matrix by itself 200 times:
CPU: 1.007401466369629 secs
GPU: 0.04124784469604492 secs

tf.Tensor วัตถุสามารถคัดลอกไปยังอุปกรณ์ที่แตกต่างกันในการดำเนินการการดำเนินงาน:

if tf.config.list_physical_devices("GPU"):
  x = tf.random.normal([10, 10])

  x_gpu0 = x.gpu()
  x_cpu = x.cpu()

  _ = tf.matmul(x_cpu, x_cpu)    # Runs on CPU
  _ = tf.matmul(x_gpu0, x_gpu0)  # Runs on GPU:0
WARNING:tensorflow:From /tmp/ipykernel_22287/406964202.py:4: _EagerTensorBase.gpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.
WARNING:tensorflow:From /tmp/ipykernel_22287/406964202.py:5: _EagerTensorBase.cpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.

เกณฑ์มาตรฐาน

สำหรับรูปแบบการคำนวณหนักเช่น ResNet50 ฝึกอบรมเกี่ยวกับ GPU ประสิทธิภาพการทำงานของการดำเนินการกระตือรือร้นที่จะเปรียบกับ tf.function การดำเนินการ แต่ช่องว่างนี้ขยายใหญ่ขึ้นสำหรับโมเดลที่มีการคำนวณน้อย และมีงานที่ต้องทำเพื่อปรับเส้นทางฮอตโค้ดให้เหมาะสมสำหรับโมเดลที่มีการดำเนินการขนาดเล็กจำนวนมาก

ทำงานกับฟังก์ชั่น

ในขณะที่การดำเนินการอย่างกระตือรือร้นทำให้การพัฒนาและการดีบักมีการโต้ตอบกันมากขึ้น การดำเนินการกราฟลักษณะ TensorFlow 1.x มีข้อดีสำหรับการฝึกอบรมแบบกระจาย การเพิ่มประสิทธิภาพการทำงาน และการใช้งานจริง เพื่อลดช่องว่างนี้ TensorFlow 2.0 เปิดตัว function s ผ่าน tf.function API สำหรับข้อมูลเพิ่มเติมโปรดดูที่ tf.function คู่มือ