Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

TensorFlow Efektif 2

Ada beberapa perubahan di TensorFlow 2.0 untuk membuat pengguna TensorFlow lebih produktif. TensorFlow 2.0 menghapus API yang berlebihan , membuat API lebih konsisten ( RNN Terpadu , Pengoptimal Terpadu ), dan lebih terintegrasi dengan waktu proses Python dengan eksekusi Eager .

Banyak RFC telah menjelaskan perubahan yang membuat TensorFlow 2.0. Panduan ini menyajikan visi seperti apa pengembangan di TensorFlow 2.0 seharusnya. Diasumsikan Anda sudah terbiasa dengan TensorFlow 1.x.

Ringkasan singkat tentang perubahan besar

Pembersihan API

Banyak API hilang atau dipindahkan di TF 2.0. Beberapa perubahan besar termasuk menghapus tf.app , tf.flags , dan tf.logging untuk mendukung absl-py sumber terbuka sekarang, mengatur ulang proyek yang tinggal di tf.contrib , dan membersihkan namespace tf.* oleh memindahkan fungsi yang tf.math digunakan ke dalam tf.math seperti tf.math . Beberapa API telah diganti dengan 2.0 yang setara - tf.summary , tf.keras.metrics , dan tf.keras.optimizers . Cara termudah untuk menerapkan penggantian nama ini secara otomatis adalah dengan menggunakan skrip peningkatan v2 .

Eksekusi yang bersemangat

TensorFlow 1.X mengharuskan pengguna untuk menyatukan pohon sintaksis abstrak (grafik) secara manual dengan melakukan panggilan API tf.* . Kemudian mengharuskan pengguna untuk secara manual mengompilasi pohon sintaksis abstrak dengan meneruskan sekumpulan tensor keluaran dan tensor masukan ke panggilan session.run() . TensorFlow 2.0 dieksekusi dengan bersemangat (seperti yang biasanya dilakukan Python) dan di 2.0, grafik dan sesi harus terasa seperti detail implementasi.

Salah satu produk sampingan penting dari eager execution adalah bahwa tf.control_dependencies() tidak lagi diperlukan, karena semua baris kode dieksekusi secara berurutan (dalam fungsi tf.function , kode dengan efek samping dieksekusi dalam urutan tertulis).

Tidak ada lagi global

TensorFlow 1.X sangat bergantung pada namespace global implisit. Ketika Anda memanggil tf.Variable() , itu akan dimasukkan ke dalam grafik default, dan itu akan tetap di sana, bahkan jika Anda kehilangan jejak variabel Python yang menunjuk ke sana. Anda kemudian dapat memulihkan tf.Variable , tetapi hanya jika Anda tahu nama yang digunakan untuk membuatnya. Ini sulit dilakukan jika Anda tidak mengontrol pembuatan variabel. Akibatnya, semua jenis mekanisme berkembang biak untuk mencoba membantu pengguna menemukan variabel mereka lagi, dan untuk kerangka kerja menemukan variabel yang dibuat pengguna: Cakupan variabel, koleksi global, metode pembantu seperti tf.get_global_step() , tf.global_variables_initializer() , pengoptimal secara implisit menghitung gradien pada semua variabel yang dapat dilatih, dan seterusnya. TensorFlow 2.0 meniadakan semua mekanisme ini ( Variabel 2.0 RFC ) untuk mendukung mekanisme default: Lacak variabel Anda! Jika Anda kehilangan jejak tf.Variable , sampah dikumpulkan.

Persyaratan untuk melacak variabel membuat beberapa pekerjaan tambahan bagi pengguna, tetapi dengan objek Keras (lihat di bawah), beban diminimalkan.

Fungsi, bukan sesi

Panggilan session.run() hampir seperti panggilan fungsi: Anda menentukan input dan fungsi yang akan dipanggil, dan Anda mendapatkan kembali satu set output. Di TensorFlow 2.0, Anda bisa menghias fungsi Python menggunakan tf.function() untuk menandainya sebagai kompilasi JIT sehingga TensorFlow menjalankannya sebagai grafik tunggal ( Functions 2.0 RFC ). Mekanisme ini memungkinkan TensorFlow 2.0 mendapatkan semua manfaat mode grafik:

  • Performa: Fungsi dapat dioptimalkan (pemangkasan node, fusi kernel, dll.)
  • Portabilitas: Fungsi ini dapat diekspor / diimpor kembali ( SavedModel 2.0 RFC ), memungkinkan pengguna untuk menggunakan kembali dan berbagi fungsi TensorFlow modular.
# TensorFlow 1.X
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# TensorFlow 2.0
outputs = f(input)

Dengan kemampuan untuk menyelingi kode Python dan TensorFlow secara bebas, pengguna dapat memanfaatkan ekspresi Python. Namun TensorFlow portabel dijalankan dalam konteks tanpa interpreter Python, seperti seluler, C ++, dan JavaScript. Untuk membantu pengguna menghindari keharusan menulis ulang kode mereka saat menambahkan @tf.function , AutoGraph mengonversi subset konstruksi Python menjadi setara TensorFlow:

  • for / while -> tf.while_loop ( break dan continue didukung)
  • if -> tf.cond
  • for _ in dataset -> dataset.reduce

AutoGraph mendukung pengumpulan aliran kontrol yang sewenang-wenang, yang memungkinkan penerapan banyak program ML kompleks secara berkinerja dan ringkas seperti model urutan, pembelajaran penguatan, loop pelatihan khusus, dan banyak lagi.

Rekomendasi untuk TensorFlow 2.0 idiomatik

Ubah kode Anda menjadi fungsi yang lebih kecil

Pola penggunaan umum di TensorFlow 1.X adalah strategi "wastafel dapur", di mana penyatuan semua kemungkinan penghitungan telah diatur sebelumnya, dan kemudian tensor yang dipilih dievaluasi melalui session.run() . Di TensorFlow 2.0, pengguna harus mengubah kode mereka menjadi fungsi yang lebih kecil yang dipanggil sesuai kebutuhan. Secara umum, tidak perlu menghias setiap fungsi yang lebih kecil ini dengan tf.function ; hanya gunakan tf.function untuk menghias komputasi tingkat tinggi - misalnya, satu langkah pelatihan atau penerusan model Anda.

Gunakan lapisan dan model Keras untuk mengelola variabel

Model dan lapisan Keras menawarkan variables praktis dan properti trainable_variables , yang mengumpulkan semua variabel dependen secara rekursif. Hal ini memudahkan untuk mengelola variabel secara lokal ke tempat mereka digunakan.

Kontras:

def dense(x, W, b):
  return tf.nn.sigmoid(tf.matmul(x, W) + b)

@tf.function
def multilayer_perceptron(x, w0, b0, w1, b1, w2, b2 ...):
  x = dense(x, w0, b0)
  x = dense(x, w1, b1)
  x = dense(x, w2, b2)
  ...

# You still have to manage w_i and b_i, and their shapes are defined far away from the code.

dengan versi Keras:

# Each layer can be called, with a signature equivalent to linear(x)
layers = [tf.keras.layers.Dense(hidden_size, activation=tf.nn.sigmoid) for _ in range(n)]
perceptron = tf.keras.Sequential(layers)

# layers[3].trainable_variables => returns [w3, b3]
# perceptron.trainable_variables => returns [w0, b0, ...]

Lapisan / model Keras mewarisi dari tf.train.Checkpointable dan terintegrasi dengan @tf.function , yang memungkinkan untuk langsung memeriksa atau mengekspor ModelSimpan dari objek Keras. Anda tidak perlu menggunakan API Keras .fit() untuk memanfaatkan integrasi ini.

Berikut adalah contoh pembelajaran transfer yang menunjukkan bagaimana Keras memudahkan untuk mengumpulkan subset variabel yang relevan. Katakanlah Anda melatih model berkepala banyak dengan bagasi bersama:

trunk = tf.keras.Sequential([...])
head1 = tf.keras.Sequential([...])
head2 = tf.keras.Sequential([...])

path1 = tf.keras.Sequential([trunk, head1])
path2 = tf.keras.Sequential([trunk, head2])

# Train on primary dataset
for x, y in main_dataset:
  with tf.GradientTape() as tape:
    # training=True is only needed if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    prediction = path1(x, training=True)
    loss = loss_fn_head1(prediction, y)
  # Simultaneously optimize trunk and head1 weights.
  gradients = tape.gradient(loss, path1.trainable_variables)
  optimizer.apply_gradients(zip(gradients, path1.trainable_variables))

# Fine-tune second head, reusing the trunk
for x, y in small_dataset:
  with tf.GradientTape() as tape:
    # training=True is only needed if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    prediction = path2(x, training=True)
    loss = loss_fn_head2(prediction, y)
  # Only optimize head2 weights, not trunk weights
  gradients = tape.gradient(loss, head2.trainable_variables)
  optimizer.apply_gradients(zip(gradients, head2.trainable_variables))

# You can publish just the trunk computation for other people to reuse.
tf.saved_model.save(trunk, output_path)

Gabungkan tf.data.Datasets dan @ tf.function

Saat melakukan iterasi pada data pelatihan yang sesuai dengan memori, silakan gunakan iterasi Python biasa. Jika tidak, tf.data.Dataset adalah cara terbaik untuk mengalirkan data pelatihan dari disk. Set data bersifat iterable (bukan iterator) , dan berfungsi seperti iterable Python lainnya dalam mode Eager. Anda dapat sepenuhnya memanfaatkan fitur prefetching / streaming asinkron kumpulan data dengan membungkus kode Anda dalam tf.function() , yang menggantikan iterasi Python dengan operasi grafik yang setara menggunakan AutoGraph.

@tf.function
def train(model, dataset, optimizer):
  for x, y in dataset:
    with tf.GradientTape() as tape:
      # training=True is only needed if there are layers with different
      # behavior during training versus inference (e.g. Dropout).
      prediction = model(x, training=True)
      loss = loss_fn(prediction, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

Jika Anda menggunakan API Keras .fit() , Anda tidak perlu khawatir tentang iterasi .fit() data.

model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)

Manfaatkan AutoGraph dengan aliran kontrol Python

AutoGraph menyediakan cara untuk mengubah aliran kontrol yang bergantung pada data menjadi mode grafik yang setara seperti tf.cond dan tf.while_loop . tf.while_loop .

Satu tempat umum di mana aliran kontrol bergantung data muncul adalah dalam model sekuens. tf.keras.layers.RNN membungkus sel RNN, memungkinkan Anda untuk membatalkan pengulangan secara statis atau dinamis. Demi demonstrasi, Anda dapat menerapkan ulang unroll dinamis sebagai berikut:

class DynamicRNN(tf.keras.Model):

  def __init__(self, rnn_cell):
    super(DynamicRNN, self).__init__(self)
    self.cell = rnn_cell

  def call(self, input_data):
    # [batch, time, features] -> [time, batch, features]
    input_data = tf.transpose(input_data, [1, 0, 2])
    outputs = tf.TensorArray(tf.float32, input_data.shape[0])
    state = self.cell.zero_state(input_data.shape[1], dtype=tf.float32)
    for i in tf.range(input_data.shape[0]):
      output, state = self.cell(input_data[i], state)
      outputs = outputs.write(i, output)
    return tf.transpose(outputs.stack(), [1, 0, 2]), state

Untuk gambaran umum yang lebih rinci tentang fitur AutoGraph, lihat panduan .

tf.metrics menggabungkan data dan tf.summary mencatatnya

Untuk mencatat ringkasan, gunakan tf.summary.(scalar|histogram|...) dan alihkan ke penulis menggunakan manajer konteks. (Jika Anda menghilangkan manajer konteks, tidak ada yang terjadi.) Tidak seperti TF 1.x, ringkasan dikirimkan langsung ke penulis; tidak ada add_summary() "merge" yang terpisah dan tidak ada panggilan add_summary() terpisah, yang berarti nilai step harus disediakan di situs panggilan.

summary_writer = tf.summary.create_file_writer('/tmp/summaries')
with summary_writer.as_default():
  tf.summary.scalar('loss', 0.1, step=42)

Untuk menggabungkan data sebelum mencatatnya sebagai ringkasan, gunakan tf.metrics . Metrik bersifat stateful: Metrik mengakumulasi nilai dan mengembalikan hasil kumulatif saat Anda memanggil .result() . Hapus nilai yang terakumulasi dengan .reset_states() .

def train(model, optimizer, dataset, log_freq=10):
  avg_loss = tf.keras.metrics.Mean(name='loss', dtype=tf.float32)
  for images, labels in dataset:
    loss = train_step(model, optimizer, images, labels)
    avg_loss.update_state(loss)
    if tf.equal(optimizer.iterations % log_freq, 0):
      tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations)
      avg_loss.reset_states()

def test(model, test_x, test_y, step_num):
  # training=False is only needed if there are layers with different
  # behavior during training versus inference (e.g. Dropout).
  loss = loss_fn(model(test_x, training=False), test_y)
  tf.summary.scalar('loss', loss, step=step_num)

train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train')
test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test')

with train_summary_writer.as_default():
  train(model, optimizer, dataset)

with test_summary_writer.as_default():
  test(model, test_x, test_y, optimizer.iterations)

Visualisasikan ringkasan yang dihasilkan dengan mengarahkan TensorBoard ke direktori log ringkasan:

tensorboard --logdir /tmp/summaries

Gunakan tf.config.experimental_run_functions_eagerly () saat debugging

Di TensorFlow 2.0, eksekusi Eager memungkinkan Anda menjalankan kode langkah demi langkah untuk memeriksa bentuk, tipe data, dan nilai. API tertentu, seperti tf.function , tf.keras , dll. Dirancang untuk menggunakan eksekusi Grafik, untuk performa dan portabilitas. Saat tf.config.experimental_run_functions_eagerly(True) debug, gunakan tf.config.experimental_run_functions_eagerly(True) untuk menggunakan eksekusi Eager di dalam kode ini.

Sebagai contoh:

@tf.function
def f(x):
  if x > 0:
    import pdb
    pdb.set_trace()
    x = x + 1
  return x

tf.config.experimental_run_functions_eagerly(True)
f(tf.constant(1))
>>> f()
-> x = x + 1
(Pdb) l
  6     @tf.function
  7     def f(x):
  8       if x > 0:
  9         import pdb
 10         pdb.set_trace()
 11  ->     x = x + 1
 12       return x
 13
 14     tf.config.experimental_run_functions_eagerly(True)
 15     f(tf.constant(1))
[EOF]

Ini juga berfungsi di dalam model Keras dan API lain yang mendukung eksekusi Eager:

class CustomModel(tf.keras.models.Model):

  @tf.function
  def call(self, input_data):
    if tf.reduce_mean(input_data) > 0:
      return input_data
    else:
      import pdb
      pdb.set_trace()
      return input_data // 2


tf.config.experimental_run_functions_eagerly(True)
model = CustomModel()
model(tf.constant([-2, -4]))
>>> call()
-> return input_data // 2
(Pdb) l
 10         if tf.reduce_mean(input_data) > 0:
 11           return input_data
 12         else:
 13           import pdb
 14           pdb.set_trace()
 15  ->       return input_data // 2
 16
 17
 18     tf.config.experimental_run_functions_eagerly(True)
 19     model = CustomModel()
 20     model(tf.constant([-2, -4]))