วิธีการใช้ Gradient Clipping ใน TensorFlow


97

พิจารณาโค้ดตัวอย่าง

ฉันต้องการทราบวิธีใช้การตัดแบบไล่ระดับกับเครือข่ายนี้บน RNN ซึ่งมีความเป็นไปได้ที่จะมีการไล่ระดับสีแบบระเบิด

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

นี่เป็นตัวอย่างที่สามารถใช้ได้ แต่จะแนะนำได้ที่ไหน ใน def ของ 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)

แต่สิ่งนี้ไม่สมเหตุสมผลเนื่องจากเทนเซอร์ _X เป็นอินพุตไม่ใช่สิ่งที่จะถูกตัดจบ?

ฉันต้องกำหนดเครื่องมือเพิ่มประสิทธิภาพของตัวเองสำหรับสิ่งนี้หรือมีตัวเลือกที่ง่ายกว่านี้ไหม

คำตอบ:


145

การตัดแบบไล่ระดับจะต้องเกิดขึ้นหลังจากคำนวณการไล่ระดับสี แต่ก่อนที่จะนำไปใช้เพื่ออัปเดตพารามิเตอร์ของโมเดล ในตัวอย่างของคุณทั้งสองสิ่งนั้นได้รับการจัดการโดยAdamOptimizer.minimize()วิธีการ

เพื่อที่จะตัดการไล่ระดับสีของคุณคุณจะต้องชัดเจนคำนวณคลิปและนำไปใช้ตามที่อธิบายในส่วนนี้ในเอกสาร API TensorFlow ของ โดยเฉพาะอย่างยิ่งคุณจะต้องแทนที่การเรียกใช้minimize()วิธีการดังต่อไปนี้:

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 ขอบคุณสำหรับโพสต์ คุณรู้หรือไม่ว่าขั้นตอนต่อไปคือการเรียกใช้เครื่องมือเพิ่มประสิทธิภาพซ้ำแล้วซ้ำอีก? โดยปกติแล้วเครื่องมือเพิ่มประสิทธิภาพจะถูกสร้างอินสแตนซ์optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) จากนั้นการทำซ้ำของเครื่องมือเพิ่มประสิทธิภาพจะทำoptimizer.run()แต่การใช้optimizer.run()ดูเหมือนจะไม่ได้ผลในกรณีนี้?
applecider

6
โอเคเข้าใจแล้วoptimizer.apply_gradients(capped_gvs)ว่าต้องมอบหมายอะไรบางอย่างx = optimizer.apply_gradients(capped_gvs)จากนั้นภายในเซสชันของคุณคุณสามารถฝึกเป็นx.run(...)
applecider

4
ตะโกนออกไป @ remi-cuingnet สำหรับข้อเสนอแนะการแก้ไขที่ดี (ซึ่งน่าเสียดายที่ถูกปฏิเสธโดยผู้ตรวจสอบอย่างเร่งด่วน)
Styrke

สิ่งนี้ทำให้ฉันUserWarning: Converting sparse IndexedSlices to a dense Tensor with 148331760 elements. This may consume a large amount of memory.ดังนั้นการไล่ระดับสีที่เบาบางของฉันจึงถูกเปลี่ยนเป็นหนาแน่น มีความคิดอย่างไรที่จะเอาชนะปัญหานี้?
Pekka

8
วิธีที่ถูกต้องในการไล่ระดับสีของคลิป (ตามเอกสารเทนเซอร์โฟลว์นักวิทยาศาสตร์คอมพิวเตอร์และตรรกะ) เป็นไปtf.clip_by_global_normตามที่ @danijar แนะนำ
gdelab

118

แม้จะเป็นที่นิยม แต่คุณอาจต้องการตัดการไล่ระดับสีทั้งหมดตามบรรทัดฐานทั่วโลก:

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

การตัดแต่ละเมทริกซ์ไล่ระดับสีทีละรายการจะเปลี่ยนมาตราส่วนสัมพัทธ์ แต่ก็เป็นไปได้เช่นกัน:

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 เทปจะคำนวณการไล่ระดับสีเครื่องมือเพิ่มประสิทธิภาพมาจาก Keras และเราไม่จำเป็นต้องจัดเก็บตัวอัปเดตเนื่องจากจะทำงานโดยอัตโนมัติโดยไม่ส่งต่อไปยังเซสชัน:

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
ตัวอย่างดีด้วยclip_by_global_norm()! สิ่งนี้อธิบายไว้the correct way to perform gradient clippingในเอกสารtensorflow
MZHm

9
@Escachator มันเป็นเชิงประจักษ์และจะขึ้นอยู่กับรุ่นของคุณและอาจเป็นงาน สิ่งที่ฉันทำคือการนึกภาพบรรทัดฐานการไล่ระดับสีtf.global_norm(gradients)เพื่อดูว่าเป็นช่วงปกติจากนั้นจึงคลิปด้านบนเล็กน้อยเพื่อป้องกันค่าผิดปกติจากการฝึกอบรม
danijar

1
คุณจะยังโทรopt.minimize()ตามหรือคุณจะเรียกสิ่งที่แตกต่างออกไปเช่นopt.run()ที่แนะนำในบางความคิดเห็นเกี่ยวกับคำตอบอื่น ๆ
reese0106

3
@ reese0106 ไม่ใช่optimizer.minimize(loss)เป็นเพียงชวเลขสำหรับการคำนวณและใช้การไล่ระดับสี คุณสามารถเรียกใช้ตัวอย่างในคำตอบของฉันด้วยsess.run(optimize).
danijar

1
ดังนั้นถ้าฉันใช้tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)ภายในฟังก์ชันการทดลองคุณoptimizeจะแทนที่ฉันtrain_opถูกต้องหรือไม่? ตอนนี้ฉันtrain_op = optimizer.minimize(loss, global_step=global_step))ก็เลยพยายามทำให้แน่ใจว่าฉันปรับตัวตามนั้น ...
reese0106

10

สิ่งนี้ได้อธิบายไว้อย่างถูกต้องในเอกสารประกอบ :

การเรียกย่อขนาด () จะดูแลทั้งการคำนวณการไล่ระดับสีและการนำไปใช้กับตัวแปร หากคุณต้องการประมวลผลการไล่ระดับสีก่อนนำไปใช้คุณสามารถใช้เครื่องมือเพิ่มประสิทธิภาพแทนได้ในสามขั้นตอน:

  • คำนวณการไล่ระดับสีด้วย compute_gradients ()
  • ประมวลผลการไล่ระดับสีตามที่คุณต้องการ
  • ใช้การไล่ระดับสีที่ประมวลผลด้วย apply_gradients ()

และในตัวอย่างที่ระบุให้ใช้ 3 ขั้นตอนเหล่านี้:

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

นี่MyCapperคือฟังก์ชันใด ๆ ที่ จำกัด การไล่ระดับสีของคุณ รายชื่อของฟังก์ชันที่มีประโยชน์อื่น ๆ (กว่าtf.clip_by_value()) เป็นที่นี่


คุณจะยังโทรopt.minimize()ตามหรือคุณจะเรียกสิ่งที่แตกต่างออกไปเช่นopt.run()ที่แนะนำในบางความคิดเห็นเกี่ยวกับคำตอบอื่น ๆ
reese0106

@ reese0106 ไม่คุณต้องกำหนดopt.apply_gradients(...)ตัวแปรtrain_stepให้เป็นตัวอย่างเช่น (เช่นเดียวกับที่คุณต้องการopt.minimize()และในลูปหลักของคุณคุณเรียกมันตามปกติในการฝึกsess.run([train_step, ...], feed_dict)
dsalaj

โปรดทราบว่าการไล่ระดับสีถูกกำหนดให้เป็นเวกเตอร์ของอนุพันธ์ของการสูญเสีย wrt ไปยังพารามิเตอร์ทั้งหมดในแบบจำลอง TensorFlow แสดงว่าเป็นรายการ Python ที่มีทูเพิลสำหรับแต่ละตัวแปรและการไล่ระดับสี ซึ่งหมายความว่าในการตัดบรรทัดฐานการไล่ระดับสีคุณไม่สามารถตัดแต่ละเทนเซอร์ทีละตัวคุณต้องพิจารณารายการพร้อมกัน (เช่นใช้tf.clip_by_global_norm(list_of_tensors))
danijar

8

สำหรับผู้ที่ต้องการทำความเข้าใจแนวคิดของการตัดแบบไล่ระดับสี (ตามบรรทัดฐาน):

เมื่อใดก็ตามที่บรรทัดฐานการไล่ระดับสีมีค่ามากกว่าเกณฑ์เฉพาะเราจะตัดบรรทัดฐานการไล่ระดับสีเพื่อให้อยู่ในเกณฑ์ บางครั้งเกณฑ์นี้ถูกตั้งค่าเป็น5เกณฑ์นี้บางครั้งการตั้งค่าให้

ให้การไล่ระดับสีเป็นgและ max_norm_threshold เป็นjเจ

ตอนนี้ถ้า || ก. || > jเราทำ:

= ( j * g ) / || ||

นี่คือการใช้งานที่ทำใน tf.clip_by_norm


หากฉันต้องการเลือกเกณฑ์ด้วยมือมีวิธีการทั่วไปในการดำเนินการนี้หรือไม่?
ningyuwhut

นี่คือมนต์ดำประเภทหนึ่งที่แนะนำในเอกสารบางฉบับ มิฉะนั้นคุณจะต้องทำการทดลองมากมายและค้นหาว่าอันไหนทำงานได้ดีกว่ากัน
kmario23

4

IMO ทางออกที่ดีที่สุดคือการตัดเพิ่มประสิทธิภาพของคุณกับ 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)

ด้วยวิธีนี้คุณจะต้องกำหนดเพียงครั้งเดียวเท่านั้นและไม่ต้องเรียกใช้หลังจากการคำนวณการไล่ระดับสี

เอกสารประกอบ: https://www.tensorflow.org/api_docs/python/tf/contrib/estimator/clip_gradients_by_norm


2

Gradient Clipping โดยทั่วไปจะช่วยในกรณีของการไล่ระดับสีที่ระเบิดหรือหายไปกล่าวว่าการสูญเสียของคุณสูงเกินไปซึ่งจะส่งผลให้การไล่ระดับสีแบบเอ็กซ์โพเนนเชียลไหลผ่านเครือข่ายซึ่งอาจส่งผลให้ค่าน่าน เพื่อเอาชนะสิ่งนี้เราตัดการไล่ระดับสีภายในช่วงที่กำหนด (-1 ถึง 1 หรือช่วงใดก็ได้ตามเงื่อนไข)

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

โดยที่ grads _and_vars คือคู่ของการไล่ระดับสี (ซึ่งคุณคำนวณผ่าน tf.compute_gradients) และตัวแปรของมันจะถูกนำไปใช้

หลังจากตัดเราก็ใช้ค่าของมันโดยใช้เครื่องมือเพิ่มประสิทธิภาพ optimizer.apply_gradients(clipped_value)


0

เป็นเรื่องง่ายสำหรับ tf.keras!

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

[-1.0, 1.0]เพิ่มประสิทธิภาพนี้จะตัดการไล่ระดับสีเป็นค่าระหว่าง

ดูเอกสาร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.