TensorFlow'da gradyan kırpma nasıl uygulanır?


97

Örnek kodu göz önünde bulundurarak .

Gradyanların patlaması olasılığının olduğu RNN'de bu ağda gradyan kırpmanın nasıl uygulanacağını bilmek istiyorum.

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

Bu, kullanılabilecek bir örnek ama bunu nerede tanıtabilirim? RNN'nin aksine

    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)

Ancak bu, kesilecek olan grad değil, tensör _X girdi olduğundan mantıklı değil mi?

Bunun için kendi Doktorumu tanımlamam gerekiyor mu yoksa daha basit bir seçenek var mı?

Yanıtlar:


145

Degrade kırpma, degradeleri hesapladıktan sonra, ancak modelin parametrelerini güncellemek için bunları uygulamadan önce yapılmalıdır. Örneğinizde, bunların her ikisi de AdamOptimizer.minimize()yöntem tarafından ele alınmaktadır .

Degradelerinizi kırpmak için, bunları TensorFlow'un API belgelerinde bu bölümde açıklandığı gibi açıkça hesaplamanız, kırpmanız ve uygulamanız gerekir . Özellikle, minimize()yönteme yapılan çağrıyı aşağıdaki gibi bir şeyle değiştirmeniz gerekir :

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)

4
Styrke, gönderi için teşekkürler. İyileştiricinin yinelemesini gerçekten çalıştırmak için sonraki adımların ne olduğunu biliyor musunuz? Tipik olarak, bir eniyileyici olarak somutlaştırılır optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) ve daha sonra bir iyileştirici yinelemesi yapılır, optimizer.run()ancak optimizer.run()bu durumda kullanılması işe yaramıyor gibi görünüyor?
applecider

6
Tamam anladım optimizer.apply_gradients(capped_gvs), bir şeye atanması gerekiyor, x = optimizer.apply_gradients(capped_gvs)o zaman seansınızda şu şekilde eğitebilirsinizx.run(...)
applecider

4
Güzel düzenleme önerisi için @ remi-cuingnet'e seslenin . (Maalesef aceleci eleştirmenler tarafından reddedildi)
Styrke

Bu bana bir UserWarning: Converting sparse IndexedSlices to a dense Tensor with 148331760 elements. This may consume a large amount of memory.şekilde seyrek gradyanlarım yoğun hale dönüştürüyor. Bu sorunun nasıl üstesinden gelineceği hakkında bir fikriniz var mı?
Pekka

8
Aslında gradyanları kırpmanın doğru yolu (tensorflow belgelerine, bilgisayar bilimcilerine ve mantığa göre) ile tf.clip_by_global_norm, @danijar tarafından önerildiği gibi
gdelab

118

Popüler gibi görünen şeye rağmen, muhtemelen tüm gradyanı küresel normuna göre kırpmak istersiniz:

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))

Her gradyan matrisini ayrı ayrı kırpmak, göreceli ölçeklerini değiştirir ancak aynı zamanda mümkündür:

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))

TensorFlow 2'de, bir bant gradyanları hesaplar, optimize ediciler Keras'tan gelir ve güncelleme operasyonunu bir oturuma aktarmadan otomatik olarak çalıştığı için saklamamız gerekmez:

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))

10
İyi örnek clip_by_global_norm()! Bu aynı zamanda the correct way to perform gradient clippingtensorflow belgelerinde olduğu gibi açıklanmaktadır : tensorflow.org/versions/r1.2/api_docs/python/tf/…
MZHm

9
@Escachator Deneyseldir ve modelinize ve muhtemelen görevinize bağlı olacaktır. Yaptığım şey, gradyan normunu görselleştirmek için tf.global_norm(gradients)normal aralığını görmek ve ardından aykırı değerlerin eğitimi karıştırmasını önlemek için bunun biraz üstüne kırpmaktır.
danijar

1
Yine de arar opt.minimize()mıydınız yoksa opt.run()diğer cevaplarla ilgili bazı yorumlarda önerildiği gibi farklı bir şey mi çağırırdınız?
reese0106

3
@ reese0106 Hayır, optimizer.minimize(loss)gradyanları hesaplamak ve uygulamak için sadece bir kısaltmadır. Cevabımdaki örneği ile çalıştırabilirsiniz sess.run(optimize).
danijar

1
Öyleyse, tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)bir deney işlevi içinde kullansaydım , o zaman sizin doğru işlevimi optimizedeğiştirir train_opmiydiniz? Şu anda benim train_op = optimizer.minimize(loss, global_step=global_step))bu yüzden buna göre ayarladığımdan emin olmaya çalışıyorum ...
reese0106

10

Bu aslında belgelerde doğru bir şekilde açıklanmıştır. :

Minimize () işlevini çağırmak, hem degradeleri hesaplamayı hem de bunları değişkenlere uygulamayı halleder. Degradeleri uygulamadan önce işlemek istiyorsanız, bunun yerine optimize ediciyi üç adımda kullanabilirsiniz:

  • Compute_gradients () ile degradeleri hesaplayın.
  • Degradeleri istediğiniz gibi işleyin.
  • İşlenmiş degradeleri apply_gradients () ile uygulayın.

Sağladıkları örnekte şu 3 adımı kullanıyorlar:

# 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)

İşte MyCappergradyanınızı kapatan herhangi bir işlev. Yararlı işlevlerin listesi (dışında tf.clip_by_value()) burada .


Yine de arar opt.minimize()mıydınız yoksa opt.run()diğer cevaplarla ilgili bazı yorumlarda önerildiği gibi farklı bir şey mi çağırırdınız?
reese0106

@ reese0106 Hayır, örneğin (sizin yaptığınız opt.apply_gradients(...)gibi) bir değişkene atamanız gerekir . Ve ana train_stepopt.minimize()sess.run([train_step, ...], feed_dict)
döngünüzde

Gradyanın, modeldeki tüm parametrelere göre kayıp türevlerinin vektörü olarak tanımlandığını unutmayın. TensorFlow, her değişken ve gradyan için bir tuple içeren bir Python listesi olarak temsil eder. Bu, gradyan normunu kırpmak anlamına gelir, her tensörü ayrı ayrı kesemezsiniz, listeyi bir kerede dikkate almanız gerekir (örneğin kullanarak tf.clip_by_global_norm(list_of_tensors)).
danijar

8

Gradyan kırpma fikrini anlamak isteyenler için (normlara göre):

Gradyan normu belirli bir eşik değerinden büyük olduğunda, gradyan normunu, eşik içinde kalması için keseriz. Bu eşik bazen olarak ayarlanır 5.

Gradyan g ve max_norm_threshold j olsun .

Şimdi, eğer || g || > j , yapıyoruz:

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

Bu, tf.clip_by_norm


Eşiği elle seçmem gerekirse, bunu yapmanın yaygın bir yöntemi var mı?
ningyuwhut

Bu, bazı gazetelerde önerilen bir tür kara büyüdür. Aksi takdirde, çok sayıda deney yapmanız ve hangisinin daha iyi çalıştığını bulmanız gerekir.
kmario23

4

IMO'nun en iyi çözümü, optimize edicinizi TF'nin tahminci dekoratörüyle sarmalamaktır 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)

Bu şekilde, bunu yalnızca bir kez tanımlamanız gerekir ve her gradyan hesaplamasından sonra çalıştırmazsınız.

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


2

Gradyan Kırpma temelde gradyanların patlaması veya kaybolması durumunda yardımcı olur. Kaybınızın çok yüksek olduğunu söyleyin, bu da Nan değerleri ile sonuçlanabilecek üstel gradyanların ağ üzerinden akmasına neden olur. Bunun üstesinden gelmek için degradeleri belirli bir aralıktaki (-1'den 1'e veya koşullara göre herhangi bir aralık) kırparız.

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

burada gradeler _ve_vars, gradyan çiftleridir (tf.compute_gradients aracılığıyla hesaplarsınız) ve bunların uygulanacağı değişkenlerdir.

Kırpma işleminden sonra değerini bir optimize edici kullanarak uygularız. optimizer.apply_gradients(clipped_value)


0

Tf.keras için çok kolay!

optimizer = tf.keras.optimizers.Adam(clipvalue=1.0)

Bu iyileştirici, tüm degradeleri aradaki değerlere kırpacaktır [-1.0, 1.0].

Dokümanlara bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.