Bagaimana cara menerapkan pemotongan gradien di TensorFlow?

96

Mempertimbangkan kode contoh .

Saya ingin tahu Bagaimana cara menerapkan pemotongan gradien pada jaringan ini di RNN di mana ada kemungkinan gradien yang meledak.

tf.clip_by_value(t, clip_value_min, clip_value_max, name=None)

Ini adalah contoh yang dapat digunakan tetapi di mana saya memperkenalkan ini? Di def dari RNN

    lstm_cell = rnn_cell.BasicLSTMCell(n_hidden, forget_bias=1.0)
    # Split data because rnn cell needs a list of inputs for the RNN inner loop
    _X = tf.split(0, n_steps, _X) # n_steps
tf.clip_by_value(_X, -1, 1, name=None)

Tapi ini tidak masuk akal karena tensor _X adalah input dan bukan grad yang akan dipotong?

Apakah saya harus menentukan Pengoptimal saya sendiri untuk ini atau adakah opsi yang lebih sederhana?

Arsenal Fanatic
sumber

Jawaban:

143

Pemotongan gradien perlu terjadi setelah menghitung gradien, tetapi sebelum menerapkannya untuk memperbarui parameter model. Dalam contoh Anda, kedua hal tersebut ditangani oleh AdamOptimizer.minimize()metode.

Untuk memangkas gradien, Anda harus menghitung, memotong, dan menerapkannya secara eksplisit seperti yang dijelaskan di bagian ini dalam dokumentasi API TensorFlow . Secara khusus, Anda perlu mengganti panggilan ke minimize()metode dengan sesuatu seperti berikut:

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
gvs = optimizer.compute_gradients(cost)
capped_gvs = [(tf.clip_by_value(grad, -1., 1.), var) for grad, var in gvs]
train_op = optimizer.apply_gradients(capped_gvs)
Styrke
sumber
4
Styrke, terima kasih atas kirimannya. Tahukah Anda apa langkah selanjutnya untuk benar-benar menjalankan iterasi pengoptimal? Biasanya, pengoptimal dibuat optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) dan kemudian pengulangan pengoptimal dilakukan optimizer.run()tetapi penggunaan optimizer.run()tampaknya tidak berfungsi dalam kasus ini?
apelecider
6
Oke, mengerti optimizer.apply_gradients(capped_gvs)yang perlu ditugaskan ke sesuatu x = optimizer.apply_gradients(capped_gvs)maka dalam sesi Anda, Anda dapat berlatih sebagaix.run(...)
applecider
3
Shout-out to @ remi-cuingnet untuk saran edit yang bagus . (Yang sayangnya ditolak oleh pengulas yang tergesa-gesa)
Styrke
Ini memberi saya UserWarning: Converting sparse IndexedSlices to a dense Tensor with 148331760 elements. This may consume a large amount of memory.Jadi entah bagaimana gradien renggang saya diubah menjadi padat. Ada ide bagaimana mengatasi masalah ini?
Pekka
8
Sebenarnya cara yang benar untuk memotong gradien (menurut dokumen tensorflow, ilmuwan komputer, dan logika) adalah dengan tf.clip_by_global_norm, seperti yang disarankan oleh @danijar
gdelab
116

Terlepas dari apa yang tampaknya populer, Anda mungkin ingin memotong seluruh gradien dengan norma globalnya:

optimizer = tf.train.AdamOptimizer(1e-3)
gradients, variables = zip(*optimizer.compute_gradients(loss))
gradients, _ = tf.clip_by_global_norm(gradients, 5.0)
optimize = optimizer.apply_gradients(zip(gradients, variables))

Memotong setiap matriks gradien secara individual mengubah skala relatifnya tetapi juga memungkinkan:

optimizer = tf.train.AdamOptimizer(1e-3)
gradients, variables = zip(*optimizer.compute_gradients(loss))
gradients = [
    None if gradient is None else tf.clip_by_norm(gradient, 5.0)
    for gradient in gradients]
optimize = optimizer.apply_gradients(zip(gradients, variables))

Di TensorFlow 2, sebuah pita menghitung gradien, pengoptimal berasal dari Keras, dan kita tidak perlu menyimpan op pembaruan karena ini berjalan secara otomatis tanpa meneruskannya ke sesi:

optimizer = tf.keras.optimizers.Adam(1e-3)
# ...
with tf.GradientTape() as tape:
  loss = ...
variables = ...
gradients = tape.gradient(loss, variables)
gradients, _ = tf.clip_by_global_norm(gradients, 5.0)
optimizer.apply_gradients(zip(gradients, variables))
danijar
sumber
10
Contoh yang bagus dengan clip_by_global_norm()! Ini juga dijelaskan seperti the correct way to perform gradient clippingdalam dokumen tensorflow
MZHm
9
@Escachator Ini empiris dan akan tergantung pada model Anda dan mungkin tugasnya. Apa yang saya lakukan adalah memvisualisasikan norma gradien tf.global_norm(gradients)untuk melihat kisaran biasanya dan kemudian klip sedikit di atasnya untuk mencegah pencilan mengacaukan pelatihan.
danijar
1
apakah Anda akan tetap menelepon opt.minimize()setelahnya atau apakah Anda akan memanggil sesuatu yang berbeda seperti opt.run()yang disarankan dalam beberapa komentar di jawaban lain?
reese0106
3
@ reese0106 Tidak, optimizer.minimize(loss)ini hanyalah singkatan untuk menghitung dan menerapkan gradien. Anda dapat menjalankan contoh di jawaban saya dengan sess.run(optimize).
danijar
1
Jadi jika saya menggunakan tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)dalam fungsi eksperimen, maka Anda optimizeakan mengganti jawaban saya train_op? Sekarang saya train_op = optimizer.minimize(loss, global_step=global_step))jadi saya mencoba untuk memastikan saya menyesuaikan sesuai ...
reese0106
10

Ini sebenarnya dijelaskan dengan benar dalam dokumentasi. :

Memanggil minimalkan () menangani komputasi gradien dan menerapkannya ke variabel. Jika Anda ingin memproses gradien sebelum menerapkannya, Anda dapat menggunakan pengoptimal dalam tiga langkah:

  • Hitung gradien dengan compute_gradients ().
  • Proses gradien sesuai keinginan.
  • Terapkan gradien yang diproses dengan apply_gradients ().

Dan dalam contoh yang mereka berikan, mereka menggunakan 3 langkah berikut:

# Create an optimizer.
opt = GradientDescentOptimizer(learning_rate=0.1)

# Compute the gradients for a list of variables.
grads_and_vars = opt.compute_gradients(loss, <list of variables>)

# grads_and_vars is a list of tuples (gradient, variable).  Do whatever you
# need to the 'gradient' part, for example cap them, etc.
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]

# Ask the optimizer to apply the capped gradients.
opt.apply_gradients(capped_grads_and_vars)

Berikut MyCapperadalah fungsi apa pun yang membatasi gradien Anda. Daftar fungsi yang berguna (selain tf.clip_by_value()) ada di sini .

Salvador Dali
sumber
apakah Anda akan tetap menelepon opt.minimize()setelahnya atau apakah Anda akan memanggil sesuatu yang berbeda seperti opt.run()yang disarankan dalam beberapa komentar di jawaban lain?
reese0106
@ reese0106 Tidak, Anda perlu menetapkan opt.apply_gradients(...)ke variabel seperti train_stepmisalnya (seperti yang Anda lakukan opt.minimize(). Dan di loop utama Anda, Anda menyebutnya seperti biasa untuk melatihsess.run([train_step, ...], feed_dict)
dsalaj
Perlu diingat bahwa gradien didefinisikan sebagai vektor turunan kerugian wrt ke semua parameter dalam model. TensorFlow merepresentasikannya sebagai daftar Python yang berisi tupel untuk setiap variabel dan gradiennya. Ini berarti untuk memotong norma gradien, Anda tidak dapat memotong setiap tensor satu per satu, Anda perlu mempertimbangkan daftar tersebut sekaligus (mis. Menggunakan tf.clip_by_global_norm(list_of_tensors)).
danijar
8

Bagi mereka yang ingin memahami gagasan pemotongan gradien (menurut norma):

Setiap kali norma gradien lebih besar dari ambang tertentu, kami memotong norma gradien sehingga tetap dalam ambang. Ambang batas ini terkadang disetel ke 5.

Biarkan gradien menjadi g dan max_norm_threshold menjadi j .

Sekarang, jika || g || > j , kami melakukan:

g = ( j * g ) / || g ||

Ini adalah implementasi yang dilakukan di tf.clip_by_norm

kmario23
sumber
jika saya perlu memilih ambang secara manual, apakah ada metode umum untuk melakukan ini?
ningyuwhut
Ini semacam ilmu hitam yang disarankan dalam beberapa makalah. Jika tidak, Anda harus melakukan banyak eksperimen dan mencari tahu mana yang bekerja lebih baik.
kmario23
4

IMO solusi terbaik adalah membungkus pengoptimal Anda dengan dekorator penaksir TF tf.contrib.estimator.clip_gradients_by_norm:

original_optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
optimizer = tf.contrib.estimator.clip_gradients_by_norm(original_optimizer, clip_norm=5.0)
train_op = optimizer.minimize(loss)

Dengan cara ini Anda hanya perlu mendefinisikan ini sekali, dan tidak menjalankannya setelah setiap perhitungan gradien.

Dokumentasi: https://www.tensorflow.org/api_docs/python/tf/contrib/estimator/clip_gradients_by_norm

Ido Cohn
sumber
2

Pemotongan Gradien pada dasarnya membantu jika gradien meledak atau menghilang. Katakan kerugian Anda terlalu tinggi yang akan mengakibatkan gradien eksponensial mengalir melalui jaringan yang dapat menghasilkan nilai Nan. Untuk mengatasinya, kami memotong gradien dalam rentang tertentu (-1 hingga 1 atau rentang apa pun sesuai kondisi).

clipped_value=tf.clip_by_value(grad, -range, +range), var) for grad, var in grads_and_vars

di mana lulusan _and_vars adalah pasangan gradien (yang Anda hitung melalui tf.compute_gradients) dan variabelnya akan diterapkan.

Setelah pemotongan, kami hanya menerapkan nilainya menggunakan pengoptimal. optimizer.apply_gradients(clipped_value)

Raj
sumber