Pengantar grafik dan fungsi tf

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

Ringkasan

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

Dalam panduan ini, Anda akan mempelajari 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 besar gambaran yang mencakup bagaimana tf.function memungkinkan Anda untuk beralih dari eksekusi bersemangat ke eksekusi grafik. Untuk spesifikasi tf.function yang lebih lengkap, buka panduan tf.function .

Apa itu grafik?

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

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

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

Ini adalah tampilan grafik TensorFlow yang mewakili jaringan saraf dua lapis 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 penerjemah Python, seperti aplikasi seluler, perangkat yang disematkan, dan server backend. TensorFlow menggunakan grafik sebagai format untuk model yang disimpan saat mengekspornya dari Python.

Grafik juga mudah dioptimalkan, memungkinkan kompiler untuk melakukan transformasi seperti:

  • Simpulkan nilai tensor secara statis dengan melipat simpul 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 membuat TensorFlow Anda berjalan cepat , berjalan secara paralel , dan berjalan secara efisien di beberapa perangkat .

Namun, Anda masih ingin mendefinisikan model pembelajaran mesin Anda (atau perhitungan lainnya) dengan Python untuk kenyamanan, dan kemudian secara otomatis membuat grafik saat Anda membutuhkannya.

Mempersiapkan

import tensorflow as tf
import timeit
from datetime import datetime

Memanfaatkan grafik

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

# 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, Function terlihat seperti fungsi biasa yang Anda tulis menggunakan operasi TensorFlow. Namun, di bawahnya sangat berbeda . Sebuah Function merangkum beberapa tf.Graph di belakang satu API . Begitulah Function dapat memberi Anda manfaat dari 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 melihat bahwa Anda tidak perlu mendefinisikan 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 ekstra untuk menjadi bagian dari grafik. tf.function menggunakan perpustakaan 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 output untuk memeriksa hasil yang tepat. Ini tidak mudah dibaca, jadi tidak perlu melihat terlalu hati-hati!

# 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 retval_, do_return
            (do_return, retval_) = vars_

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

        def else_body():
            nonlocal retval_, do_return
            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
          }
        }
      }
    }
    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
          }
        }
      }
    }
    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
          }
        }
      }
    }
    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
          }
        }
      }
    }
    node_def {
      name: "cond/Identity"
      op: "Identity"
      input: "cond/Const_3:output:0"
      attr {
        key: "T"
        value {
          type: DT_BOOL
        }
      }
    }
    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
          }
        }
      }
    }
    node_def {
      name: "cond/Identity_1"
      op: "Identity"
      input: "cond/Const_4:output:0"
      attr {
        key: "T"
        value {
          type: DT_INT32
        }
      }
    }
    ret {
      key: "cond_identity"
      value: "cond/Identity:output:0"
    }
    ret {
      key: "cond_identity_1"
      value: "cond/Identity_1:output:0"
    }
    attr {
      key: "_construction_context"
      value {
        s: "kEagerRuntime"
      }
    }
    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
          }
        }
      }
    }
    node_def {
      name: "cond/Identity"
      op: "Identity"
      input: "cond/Const:output:0"
      attr {
        key: "T"
        value {
          type: DT_BOOL
        }
      }
    }
    node_def {
      name: "cond/Identity_1"
      op: "Identity"
      input: "cond_identity_1_x"
      attr {
        key: "T"
        value {
          type: DT_INT32
        }
      }
    }
    ret {
      key: "cond_identity"
      value: "cond/Identity:output:0"
    }
    ret {
      key: "cond_identity_1"
      value: "cond/Identity_1:output:0"
    }
    attr {
      key: "_construction_context"
      value {
        s: "kEagerRuntime"
      }
    }
    arg_attr {
      key: 0
      value {
        attr {
          key: "_output_shapes"
          value {
            list {
              shape {
              }
            }
          }
        }
      }
    }
  }
}
versions {
  producer: 898
  min_consumer: 12
}

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

Polimorfisme: satu Function , banyak grafik

Sebuah tf.Graph dikhususkan untuk tipe input tertentu (misalnya, tensor dengan tipe dtype tertentu atau objek dengan id() yang sama).

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

Function menyimpan tf.Graph yang sesuai dengan tanda tangan itu dalam 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 observes 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, 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=[1, -1])
  Returns:
    float32 Tensor, shape=(2,)

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

Menggunakan tf.function

Sejauh ini, Anda telah mempelajari cara 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 suatu Function dapat dieksekusi baik dengan penuh semangat maupun sebagai grafik. Secara default, Function mengeksekusi 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 0 4 4 7], shape=(5,), dtype=int32)
tf.Tensor([3 6 3 0 6], shape=(5,), dtype=int32)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=11>

Untuk memverifikasi bahwa grafik Function Anda melakukan perhitungan yang sama dengan fungsi Python yang setara, Anda dapat membuatnya dieksekusi dengan bersemangat 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=11>
# 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 yang bersemangat. Fungsi print Python adalah salah satu contoh perbedaan kedua mode ini. Mari kita periksa apa yang terjadi ketika Anda menyisipkan pernyataan print ke fungsi Anda 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 outputnya mengejutkan? get_MSE hanya dicetak sekali meskipun dipanggil tiga kali.

Untuk menjelaskan, pernyataan print dieksekusi ketika Function menjalankan kode asli untuk membuat grafik dalam proses yang dikenal sebagai "tracing" . Pelacakan menangkap operasi TensorFlow ke dalam grafik, dan print tidak direkam 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 ketahui saat mengubah fungsi menjadi Function . Pelajari lebih lanjut di bagian Batasan kinerja yang lebih baik dengan panduan tf.function .

Eksekusi tidak ketat

Eksekusi grafik hanya mengeksekusi operasi yang diperlukan untuk menghasilkan efek yang dapat diamati, yang meliputi:

  • Nilai balik dari fungsi
  • Efek samping terkenal yang terdokumentasi seperti:

Perilaku ini biasanya dikenal sebagai "Eksekusi non-ketat", dan berbeda dari eksekusi bersemangat, yang melangkah melalui semua operasi program, diperlukan atau tidak.

Secara khusus, pemeriksaan kesalahan runtime tidak dihitung sebagai efek yang dapat diamati. Jika operasi dilewati karena tidak perlu, itu tidak dapat meningkatkan kesalahan runtime.

Dalam contoh berikut, operasi "tidak perlu" tf.gather dilewati selama eksekusi grafik, sehingga kesalahan runtime InvalidArgumentError tidak dimunculkan seperti pada eksekusi bersemangat. Jangan mengandalkan kesalahan yang muncul saat menjalankan grafik.

def unused_return_eager(x):
  # Get index 1 will fail when `len(x) == 1`
  tf.gather(x, [1]) # unused 
  return x

try:
  print(unused_return_eager(tf.constant([0.0])))
except tf.errors.InvalidArgumentError as e:
  # All operations are run during eager execution so an error is raised.
  print(f'{type(e).__name__}: {e}')
tf.Tensor([0.], shape=(1,), dtype=float32)
@tf.function
def unused_return_graph(x):
  tf.gather(x, [1]) # unused
  return x

# Only needed operations are run during graph exection. The error is not raised.
print(unused_return_graph(tf.constant([0.0])))
tf.Tensor([0.], shape=(1,), dtype=float32)

praktik terbaik tf.function

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

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

Melihat kecepatannya

tf.function biasanya meningkatkan kinerja kode Anda, tetapi jumlah percepatan tergantung pada jenis komputasi yang Anda jalankan. Komputasi kecil dapat didominasi oleh overhead pemanggilan graf. Anda dapat mengukur perbedaan kinerja seperti:

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: 2.5637862179974036
power_as_graph = tf.function(power)
print("Graph execution:", timeit.timeit(lambda: power_as_graph(x, 100), number=1000))
Graph execution: 0.6832536700021592

tf.function biasanya digunakan untuk mempercepat loop pelatihan, dan Anda dapat mempelajarinya lebih lanjut di Menulis loop pelatihan dari awal dengan Keras.

Performa dan trade-off

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

Tidak peduli seberapa besar model Anda, Anda ingin menghindari tracing sesering mungkin. Panduan tf.function membahas cara menyetel spesifikasi input dan menggunakan argumen tensor untuk menghindari penelusuran ulang. Jika Anda menemukan Anda mendapatkan kinerja yang sangat buruk, ada baiknya untuk memeriksa apakah Anda menelusuri kembali secara tidak sengaja.

Kapan Pelacakan Function ?

Untuk mengetahui kapan Function Anda melacak, 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)

Argumen Python baru selalu memicu pembuatan grafik baru, karenanya penelusuran ekstra.

Langkah selanjutnya

Anda dapat mempelajari lebih lanjut tentang tf.function di halaman referensi API dan dengan mengikuti kinerja yang lebih baik dengan panduan tf.function .