Catat tanggalnya! Google I / O mengembalikan 18-20 Mei Daftar sekarang
Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Pengantar grafik dan fungsi tf

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Gambaran

Panduan ini membahas di bawah permukaan TensorFlow dan Keras untuk melihat cara kerja TensorFlow. Jika Anda justru ingin segera memulai dengan Keras, lihat koleksi panduan Keras kami .

Dalam panduan ini, Anda akan melihat inti dari bagaimana TensorFlow memungkinkan Anda membuat perubahan sederhana pada kode Anda untuk mendapatkan grafik, bagaimana grafik disimpan dan direpresentasikan, dan bagaimana Anda dapat menggunakannya untuk mempercepat model Anda.

Ini adalah gambaran umum gambaran besar yang mencakup bagaimana tf.function memungkinkan Anda beralih dari eksekusi bersemangat ke eksekusi grafik. Untuk spesifikasi yang lebih lengkap dari tf.function , lihat panduan tf.function .

Apa itu grafik?

Dalam tiga panduan sebelumnya, Anda telah melihat TensorFlow berjalan dengan penuh semangat . Ini berarti operasi TensorFlow dijalankan oleh Python, operasi demi operasi, dan mengembalikan hasil ke Python.

Sementara eager execution memiliki beberapa keunggulan unik, eksekusi grafik memungkinkan portabilitas di luar Python dan cenderung menawarkan kinerja yang lebih baik. Eksekusi grafik berarti bahwa komputasi tensor dijalankan sebagai grafik TensorFlow , terkadang disebut sebagai tf.Graph atau hanya "grafik".

Grafik adalah struktur data yang berisi sekumpulan objek tf.Operation , yang merepresentasikan unit komputasi; dan tf.Tensor Objek tf.Tensor , yang merepresentasikan unit data yang mengalir di antara operasi. Mereka didefinisikan dalam konteks tf.Graph . Karena grafik ini adalah struktur data, grafik ini dapat disimpan, dijalankan, dan dipulihkan semuanya tanpa kode Python asli.

Seperti inilah tampilan grafik TensorFlow yang mewakili jaringan neural dua lapisan saat divisualisasikan di TensorBoard.

Grafik TensorFlow sederhana

Manfaat grafik

Dengan grafik, Anda memiliki banyak fleksibilitas. Anda dapat menggunakan grafik TensorFlow di lingkungan yang tidak memiliki interpreter Python, seperti aplikasi seluler, perangkat tersemat, dan server backend. TensorFlow menggunakan grafik sebagai format untuk model yang disimpan saat mengekspornya dari Python.

Grafik juga mudah dioptimalkan, memungkinkan kompiler melakukan transformasi seperti:

  • Secara statis menyimpulkan nilai tensor dengan melipat node konstan dalam komputasi Anda ("pelipatan konstan") .
  • Pisahkan sub-bagian dari komputasi yang independen dan pisahkan di antara utas atau perangkat.
  • Sederhanakan operasi aritmatika dengan menghilangkan subekspresi umum.

Ada seluruh sistem pengoptimalan, Grappler , untuk melakukan ini dan percepatan lainnya.

Singkatnya, grafik sangat berguna dan memungkinkan TensorFlow Anda berjalan cepat , berjalan paralel , dan berjalan efisien di banyak perangkat .

Namun, Anda masih ingin menentukan model pembelajaran mesin kami (atau komputasi lain) dengan Python untuk kenyamanan, dan kemudian secara otomatis membuat grafik saat Anda membutuhkannya.

Memanfaatkan grafik

Anda membuat dan menjalankan grafik di TensorFlow dengan menggunakan tf.function , baik sebagai panggilan langsung atau sebagai dekorator. tf.function mengambil fungsi biasa sebagai input dan mengembalikan sebuah Function . Function adalah callable Python yang membuat grafik TensorFlow dari fungsi Python. Anda menggunakan Function dengan cara yang sama seperti padanan Python-nya.

import tensorflow as tf
import timeit
from datetime import datetime
# Define a Python function.
def a_regular_function(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# `a_function_that_uses_a_graph` is a TensorFlow `Function`.
a_function_that_uses_a_graph = tf.function(a_regular_function)

# Make some tensors.
x1 = tf.constant([[1.0, 2.0]])
y1 = tf.constant([[2.0], [3.0]])
b1 = tf.constant(4.0)

orig_value = a_regular_function(x1, y1, b1).numpy()
# Call a `Function` like a Python function.
tf_function_value = a_function_that_uses_a_graph(x1, y1, b1).numpy()
assert(orig_value == tf_function_value)

Di luar, sebuah Function tampak seperti fungsi biasa yang Anda tulis menggunakan operasi TensorFlow. Di bawahnya , bagaimanapun, adalah sangat berbeda. Sebuah Function merangkum beberapa tf.Graph di belakang satu API . Begitulah cara Function dapat memberi Anda manfaat eksekusi grafik , seperti kecepatan dan kemampuan penerapan.

tf.function berlaku untuk suatu fungsi dan semua fungsi lain yang dipanggilnya :

def inner_function(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# Use the decorator to make `outer_function` a `Function`.
@tf.function
def outer_function(x):
  y = tf.constant([[2.0], [3.0]])
  b = tf.constant(4.0)

  return inner_function(x, y, b)

# Note that the callable will create a graph that
# includes `inner_function` as well as `outer_function`.
outer_function(tf.constant([[1.0, 2.0]])).numpy()
array([[12.]], dtype=float32)

Jika Anda telah menggunakan TensorFlow 1.x, Anda akan menyadari bahwa Anda tidak perlu lagi menentukan Placeholder atau tf.Session .

Mengubah fungsi Python menjadi grafik

Setiap fungsi yang Anda tulis dengan TensorFlow akan berisi campuran operasi TF bawaan dan logika Python, seperti klausa if-then , loop, break , return , continue , dan banyak lagi. Meskipun operasi TensorFlow mudah ditangkap oleh tf.Graph , logika khusus Python perlu menjalani langkah tambahan untuk menjadi bagian dari grafik. tf.function menggunakan pustaka yang disebut AutoGraph ( tf.autograph ) untuk mengubah kode Python menjadi kode penghasil grafik.

def simple_relu(x):
  if tf.greater(x, 0):
    return x
  else:
    return 0

# `tf_simple_relu` is a TensorFlow `Function` that wraps `simple_relu`.
tf_simple_relu = tf.function(simple_relu)

print("First branch, with graph:", tf_simple_relu(tf.constant(1)).numpy())
print("Second branch, with graph:", tf_simple_relu(tf.constant(-1)).numpy())
First branch, with graph: 1
Second branch, with graph: 0

Meskipun sepertinya Anda tidak perlu melihat grafik secara langsung, Anda dapat memeriksa keluarannya untuk melihat hasil yang tepat. Ini tidak mudah dibaca, jadi tidak perlu melihat terlalu teliti!

# This is the graph-generating output of AutoGraph.
print(tf.autograph.to_code(simple_relu))
def tf__simple_relu(x):
    with ag__.FunctionScope('simple_relu', 'fscope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as fscope:
        do_return = False
        retval_ = ag__.UndefinedReturnValue()

        def get_state():
            return (do_return, retval_)

        def set_state(vars_):
            nonlocal do_return, retval_
            (do_return, retval_) = vars_

        def if_body():
            nonlocal do_return, retval_
            try:
                do_return = True
                retval_ = ag__.ld(x)
            except:
                do_return = False
                raise

        def else_body():
            nonlocal do_return, retval_
            try:
                do_return = True
                retval_ = 0
            except:
                do_return = False
                raise
        ag__.if_stmt(ag__.converted_call(ag__.ld(tf).greater, (ag__.ld(x), 0), None, fscope), if_body, else_body, get_state, set_state, ('do_return', 'retval_'), 2)
        return fscope.ret(retval_, do_return)
# This is the graph itself.
print(tf_simple_relu.get_concrete_function(tf.constant(1)).graph.as_graph_def())
node {
  name: "x"
  op: "Placeholder"
  attr {
    key: "_user_specified_name"
    value {
      s: "x"
    }
  }
  attr {
    key: "dtype"
    value {
      type: DT_INT32
    }
  }
  attr {
    key: "shape"
    value {
      shape {
      }
    }
  }
}
node {
  name: "Greater/y"
  op: "Const"
  attr {
    key: "dtype"
    value {
      type: DT_INT32
    }
  }
  attr {
    key: "value"
    value {
      tensor {
        dtype: DT_INT32
        tensor_shape {
        }
        int_val: 0
      }
    }
  }
}
node {
  name: "Greater"
  op: "Greater"
  input: "x"
  input: "Greater/y"
  attr {
    key: "T"
    value {
      type: DT_INT32
    }
  }
}
node {
  name: "cond"
  op: "StatelessIf"
  input: "Greater"
  input: "x"
  attr {
    key: "Tcond"
    value {
      type: DT_BOOL
    }
  }
  attr {
    key: "Tin"
    value {
      list {
        type: DT_INT32
      }
    }
  }
  attr {
    key: "Tout"
    value {
      list {
        type: DT_BOOL
        type: DT_INT32
      }
    }
  }
  attr {
    key: "_lower_using_switch_merge"
    value {
      b: true
    }
  }
  attr {
    key: "_read_only_resource_inputs"
    value {
      list {
      }
    }
  }
  attr {
    key: "else_branch"
    value {
      func {
        name: "cond_false_34"
      }
    }
  }
  attr {
    key: "output_shapes"
    value {
      list {
        shape {
        }
        shape {
        }
      }
    }
  }
  attr {
    key: "then_branch"
    value {
      func {
        name: "cond_true_33"
      }
    }
  }
}
node {
  name: "cond/Identity"
  op: "Identity"
  input: "cond"
  attr {
    key: "T"
    value {
      type: DT_BOOL
    }
  }
}
node {
  name: "cond/Identity_1"
  op: "Identity"
  input: "cond:1"
  attr {
    key: "T"
    value {
      type: DT_INT32
    }
  }
}
node {
  name: "Identity"
  op: "Identity"
  input: "cond/Identity_1"
  attr {
    key: "T"
    value {
      type: DT_INT32
    }
  }
}
library {
  function {
    signature {
      name: "cond_false_34"
      input_arg {
        name: "cond_placeholder"
        type: DT_INT32
      }
      output_arg {
        name: "cond_identity"
        type: DT_BOOL
      }
      output_arg {
        name: "cond_identity_1"
        type: DT_INT32
      }
    }
    node_def {
      name: "cond/Const"
      op: "Const"
      attr {
        key: "dtype"
        value {
          type: DT_BOOL
        }
      }
      attr {
        key: "value"
        value {
          tensor {
            dtype: DT_BOOL
            tensor_shape {
            }
            bool_val: true
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const"
      }
    }
    node_def {
      name: "cond/Const_1"
      op: "Const"
      attr {
        key: "dtype"
        value {
          type: DT_BOOL
        }
      }
      attr {
        key: "value"
        value {
          tensor {
            dtype: DT_BOOL
            tensor_shape {
            }
            bool_val: true
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_1"
      }
    }
    node_def {
      name: "cond/Const_2"
      op: "Const"
      attr {
        key: "dtype"
        value {
          type: DT_INT32
        }
      }
      attr {
        key: "value"
        value {
          tensor {
            dtype: DT_INT32
            tensor_shape {
            }
            int_val: 0
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_2"
      }
    }
    node_def {
      name: "cond/Const_3"
      op: "Const"
      attr {
        key: "dtype"
        value {
          type: DT_BOOL
        }
      }
      attr {
        key: "value"
        value {
          tensor {
            dtype: DT_BOOL
            tensor_shape {
            }
            bool_val: true
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_3"
      }
    }
    node_def {
      name: "cond/Identity"
      op: "Identity"
      input: "cond/Const_3:output:0"
      attr {
        key: "T"
        value {
          type: DT_BOOL
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity"
      }
    }
    node_def {
      name: "cond/Const_4"
      op: "Const"
      attr {
        key: "dtype"
        value {
          type: DT_INT32
        }
      }
      attr {
        key: "value"
        value {
          tensor {
            dtype: DT_INT32
            tensor_shape {
            }
            int_val: 0
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_4"
      }
    }
    node_def {
      name: "cond/Identity_1"
      op: "Identity"
      input: "cond/Const_4:output:0"
      attr {
        key: "T"
        value {
          type: DT_INT32
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity_1"
      }
    }
    ret {
      key: "cond_identity"
      value: "cond/Identity:output:0"
    }
    ret {
      key: "cond_identity_1"
      value: "cond/Identity_1:output:0"
    }
    arg_attr {
      key: 0
      value {
        attr {
          key: "_output_shapes"
          value {
            list {
              shape {
              }
            }
          }
        }
      }
    }
  }
  function {
    signature {
      name: "cond_true_33"
      input_arg {
        name: "cond_identity_1_x"
        type: DT_INT32
      }
      output_arg {
        name: "cond_identity"
        type: DT_BOOL
      }
      output_arg {
        name: "cond_identity_1"
        type: DT_INT32
      }
    }
    node_def {
      name: "cond/Const"
      op: "Const"
      attr {
        key: "dtype"
        value {
          type: DT_BOOL
        }
      }
      attr {
        key: "value"
        value {
          tensor {
            dtype: DT_BOOL
            tensor_shape {
            }
            bool_val: true
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const"
      }
    }
    node_def {
      name: "cond/Identity"
      op: "Identity"
      input: "cond/Const:output:0"
      attr {
        key: "T"
        value {
          type: DT_BOOL
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity"
      }
    }
    node_def {
      name: "cond/Identity_1"
      op: "Identity"
      input: "cond_identity_1_x"
      attr {
        key: "T"
        value {
          type: DT_INT32
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity_1"
      }
    }
    ret {
      key: "cond_identity"
      value: "cond/Identity:output:0"
    }
    ret {
      key: "cond_identity_1"
      value: "cond/Identity_1:output:0"
    }
    arg_attr {
      key: 0
      value {
        attr {
          key: "_output_shapes"
          value {
            list {
              shape {
              }
            }
          }
        }
      }
    }
  }
}
versions {
  producer: 561
  min_consumer: 12
}

tf.function , tf.function akan bekerja tanpa pertimbangan khusus. Namun, ada beberapa peringatan, dan panduan fungsi tf dapat membantu di sini, serta referensi AutoGraph lengkap.

Polimorfisme: satu Function , banyak grafik

Sebuah tf.Graph dikhususkan untuk jenis input tertentu (misalnya, tensor dengandtype tertentu atau objek dengan id() sama id() ).

Setiap kali Anda memanggil Function dengan dtypes dan bentuk baru dalam argumennya, Function membuat tf.Graph baru untuk argumen baru. dtypes dan bentuk dari masukan tf.Graph dikenal sebagai tanda tangan masukan atau hanya tanda tangan .

Function menyimpan tf.Graph sesuai dengan tanda tangan itu di ConcreteFunction . ConcreteFunction adalah pembungkus di sekitar tf.Graph .

@tf.function
def my_relu(x):
  return tf.maximum(0., x)

# `my_relu` creates new graphs as it sees more signatures.
print(my_relu(tf.constant(5.5)))
print(my_relu([1, -1]))
print(my_relu(tf.constant([3., -3.])))
tf.Tensor(5.5, shape=(), dtype=float32)
tf.Tensor([1. 0.], shape=(2,), dtype=float32)
tf.Tensor([3. 0.], shape=(2,), dtype=float32)

Jika Function telah dipanggil dengan tanda tangan itu, Function tidak membuat tf.Graph baru.

# These two calls do *not* create new graphs.
print(my_relu(tf.constant(-2.5))) # Signature matches `tf.constant(5.5)`.
print(my_relu(tf.constant([-1., 1.]))) # Signature matches `tf.constant([3., -3.])`.
tf.Tensor(0.0, shape=(), dtype=float32)
tf.Tensor([0. 1.], shape=(2,), dtype=float32)

Karena didukung oleh banyak grafik, sebuah Function bersifat polimorfik . Itu memungkinkannya untuk mendukung lebih banyak jenis input daripada yang dapat diwakili oleh satu tf.Graph , serta untuk mengoptimalkan setiap tf.Graph untuk kinerja yang lebih baik.

# There are three `ConcreteFunction`s (one for each graph) in `my_relu`.
# The `ConcreteFunction` also knows the return type and shape!
print(my_relu.pretty_printed_concrete_signatures())
my_relu(x)
  Args:
    x: float32 Tensor, shape=()
  Returns:
    float32 Tensor, shape=()

my_relu(x)
  Args:
    x: float32 Tensor, shape=(2,)
  Returns:
    float32 Tensor, shape=(2,)

my_relu(x=[1, -1])
  Returns:
    float32 Tensor, shape=(2,)

Menggunakan tf.function

Sejauh ini, Anda telah melihat bagaimana Anda dapat mengubah fungsi Python menjadi grafik hanya dengan menggunakan tf.function sebagai dekorator atau pembungkus. Namun dalam praktiknya, membuat tf.function berfungsi dengan benar bisa jadi rumit! Di bagian berikut, Anda akan mempelajari cara membuat kode Anda berfungsi seperti yang diharapkan dengan tf.function .

Eksekusi grafik vs. eksekusi bersemangat

Kode dalam sebuah Function dapat dieksekusi dengan penuh semangat dan sebagai grafik. Secara default, Function menjalankan kodenya sebagai grafik:

@tf.function
def get_MSE(y_true, y_pred):
  sq_diff = tf.pow(y_true - y_pred, 2)
  return tf.reduce_mean(sq_diff)
y_true = tf.random.uniform([5], maxval=10, dtype=tf.int32)
y_pred = tf.random.uniform([5], maxval=10, dtype=tf.int32)
print(y_true)
print(y_pred)
tf.Tensor([1 2 3 6 8], shape=(5,), dtype=int32)
tf.Tensor([0 1 8 7 5], shape=(5,), dtype=int32)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=7>

Untuk memverifikasi bahwa grafik Function Anda melakukan komputasi yang sama dengan fungsi Python yang setara, Anda dapat membuatnya dieksekusi dengan penuh semangat dengan tf.config.run_functions_eagerly(True) . Ini adalah sakelar yang mematikan kemampuan Function untuk membuat dan menjalankan grafik , alih-alih mengeksekusi kode secara normal.

tf.config.run_functions_eagerly(True)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=7>
# Don't forget to set it back when you are done.
tf.config.run_functions_eagerly(False)

Namun, Function dapat berperilaku berbeda di bawah grafik dan eksekusi bersemangat. Fungsi print Python adalah salah satu contoh bagaimana kedua mode ini berbeda. Mari kita lihat apa yang terjadi ketika Anda memasukkan pernyataan print ke fungsi kita dan memanggilnya berulang kali.

@tf.function
def get_MSE(y_true, y_pred):
  print("Calculating MSE!")
  sq_diff = tf.pow(y_true - y_pred, 2)
  return tf.reduce_mean(sq_diff)

Perhatikan apa yang dicetak:

error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
Calculating MSE!

Apakah hasilnya mengejutkan? get_MSE hanya dicetak sekali meskipun dipanggil tiga kali.

Untuk menjelaskan, pernyataan print dijalankan ketika Function menjalankan kode asli untuk membuat grafik dalam proses yang dikenal sebagai "penelusuran" . Pelacakan menangkap operasi TensorFlow ke dalam grafik, dan print tidak ditangkap dalam grafik. Grafik itu kemudian dieksekusi untuk ketiga panggilan tanpa pernah menjalankan kode Python lagi .

Sebagai pemeriksaan kewarasan, mari matikan eksekusi grafik untuk membandingkan:

# Now, globally set everything to run eagerly to force eager execution.
tf.config.run_functions_eagerly(True)
# Observe what is printed below.
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
Calculating MSE!
Calculating MSE!
Calculating MSE!
tf.config.run_functions_eagerly(False)

print adalah efek samping Python , dan ada perbedaan lain yang harus Anda waspadai saat mengubah fungsi menjadi Function .

tf.function praktik terbaik tf.function

Mungkin perlu beberapa saat untuk terbiasa dengan perilaku Function . Untuk memulai dengan cepat, pengguna pertama kali harus bermain-main dengan fungsi dekorasi mainan dengan fungsi @tf.function untuk mendapatkan pengalaman @tf.function dari bersemangat ke eksekusi grafik.

Mendesain untuk tf.function mungkin merupakan pilihan terbaik Anda untuk menulis program TensorFlow yang kompatibel dengan grafik. Berikut beberapa tip:

  • Beralih antara eager dan eksekusi grafik lebih awal dan sering dengan tf.config.run_functions_eagerly untuk menunjukkan jika / ketika dua mode berbeda.
  • Buat tf.Variable di luar fungsi Python dan modifikasi di dalam. Hal yang sama berlaku untuk objek yang menggunakan tf.Variable , sepertikeras.layers , keras.Model s, dan tf.optimizers .
  • Hindari menulis fungsi yang bergantung pada variabel luar Python , tidak termasuk objek tf.Variables dan Keras.
  • Lebih suka menulis fungsi yang menggunakan tensor dan jenis TensorFlow lainnya sebagai masukan. Anda bisa memasukkan tipe objek lain tapi hati-hati !
  • Sertakan komputasi sebanyak mungkin di bawah fungsi tf.function memaksimalkan perolehan kinerja. Misalnya, hiasi seluruh langkah pelatihan atau seluruh loop pelatihan.

Melihat percepatannya

tf.function biasanya meningkatkan kinerja kode Anda, tetapi jumlah percepatannya tergantung pada jenis komputasi yang Anda jalankan. Perhitungan kecil dapat didominasi oleh overhead pemanggilan grafik. Anda dapat mengukur perbedaan kinerja seperti ini:

x = tf.random.uniform(shape=[10, 10], minval=-1, maxval=2, dtype=tf.dtypes.int32)

def power(x, y):
  result = tf.eye(10, dtype=tf.dtypes.int32)
  for _ in range(y):
    result = tf.matmul(x, result)
  return result
print("Eager execution:", timeit.timeit(lambda: power(x, 100), number=1000))
Eager execution: 1.777665522999996
power_as_graph = tf.function(power)
print("Graph execution:", timeit.timeit(lambda: power_as_graph(x, 100), number=1000))
Graph execution: 0.5308018169999968

tf.function biasanya digunakan untuk mempercepat pelatihan loop, seperti yang Anda lihat di sini dengan Keras.

Performa dan kompromi

Grafik dapat mempercepat kode Anda, tetapi proses pembuatannya memiliki beberapa overhead. Untuk beberapa fungsi, pembuatan grafik membutuhkan waktu lebih lama daripada eksekusi grafik. Investasi ini biasanya dibayar kembali dengan cepat dengan peningkatan performa dari eksekusi berikutnya, tetapi penting untuk diperhatikan bahwa beberapa langkah pertama dari pelatihan model besar bisa lebih lambat karena pelacakan.

Tidak peduli seberapa besar model Anda, Anda ingin menghindari sering-sering melacak. Panduan tf.function membahas cara menyetel spesifikasi input dan menggunakan argumen tensor untuk menghindari penelusuran ulang. Jika Anda mendapati kinerja Anda sangat buruk, sebaiknya periksa apakah Anda melakukan penelusuran ulang secara tidak sengaja.

Kapan sebuah Function tracing?

Untuk mengetahui kapan Function Anda menelusuri, tambahkan pernyataan print ke kodenya. Sebagai aturan praktis, Function akan mengeksekusi pernyataan print setiap kali dilacak.

@tf.function
def a_function_with_python_side_effect(x):
  print("Tracing!") # An eager-only side effect.
  return x * x + tf.constant(2)

# This is traced the first time.
print(a_function_with_python_side_effect(tf.constant(2)))
# The second time through, you won't see the side effect.
print(a_function_with_python_side_effect(tf.constant(3)))
Tracing!
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(11, shape=(), dtype=int32)
# This retraces each time the Python argument changes,
# as a Python argument could be an epoch count or other
# hyperparameter.
print(a_function_with_python_side_effect(2))
print(a_function_with_python_side_effect(3))
Tracing!
tf.Tensor(6, shape=(), dtype=int32)
Tracing!
tf.Tensor(11, shape=(), dtype=int32)

Di sini, Anda melihat pelacakan ekstra karena argumen Python baru selalu memicu pembuatan grafik baru.

Langkah selanjutnya

Anda dapat membaca diskusi yang lebih mendalam di halaman referensi API tf.function dan di panduan .