2017-05-08 25 views
26

Tôi muốn thay thế hoặc sửa đổi độ dốc của một op hoặc một phần của biểu đồ trong chuỗi lưu lượng. Nó sẽ là lý tưởng nếu tôi có thể sử dụng gradient hiện có trong tính toán.Tensorflow: Cách thay thế hoặc sửa đổi độ dốc?

Trong một số cách, điều này ngược lại với những gì tf.stop_gradient() thực hiện: thay vì thêm phép tính bị bỏ qua khi tính toán độ dốc, tôi muốn tính toán chỉ được sử dụng khi tính toán độ dốc.

Một ví dụ đơn giản sẽ là một cái gì đó mà chỉ đơn giản là quy mô gradients bằng cách nhân chúng với một hằng số (nhưng không nhân tính toán chuyển tiếp bởi một hằng số). Một ví dụ khác sẽ là một cái gì đó mà clip gradient đến một phạm vi nhất định.

Trả lời

17

Đầu tiên xác định độ dốc tùy chỉnh của bạn:

@tf.RegisterGradient("CustomGrad") 
def _const_mul_grad(unused_op, grad): 
    return 5.0 * grad 

Vì bạn muốn gì xảy ra trong đường chuyền về phía trước, ghi đè gradient của một hoạt động bản sắc với độ dốc mới của bạn:

g = tf.get_default_graph() 
with g.gradient_override_map({"Identity": "CustomGrad"}): 
    output = tf.identity(input, name="Identity") 

Dưới đây là một ví dụ làm việc với một lớp mà clip gradient trong ngược vượt qua và không có gì trong những tiền đạo vượt qua, bằng cách sử dụng phương pháp tương tự:

import tensorflow as tf 

@tf.RegisterGradient("CustomClipGrad") 
def _clip_grad(unused_op, grad): 
    return tf.clip_by_value(grad, -0.1, 0.1) 

input = tf.Variable([3.0], dtype=tf.float32) 

g = tf.get_default_graph() 
with g.gradient_override_map({"Identity": "CustomClipGrad"}): 
    output_clip = tf.identity(input, name="Identity") 
grad_clip = tf.gradients(output_clip, input) 

# output without gradient clipping in the backwards pass for comparison: 
output = tf.identity(input) 
grad = tf.gradients(output, input) 

with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    print("with clipping:", sess.run(grad_clip)[0]) 
    print("without clipping:", sess.run(grad)[0]) 
+0

Điều này có sửa đổi các gradient sau này trong chuỗi hay không? Ví dụ: –

+1

@KevinP, để cắt bớt: các gradient sẽ chỉ được cắt bớt 1 lần trong quá trình truyền ngược của thao tác nhận dạng. Nhưng tất cả các lớp trước đó trong chuỗi sẽ bị ảnh hưởng bởi điều đó, bởi vì mỗi lớp sử dụng các gradient của lớp sau của nó để vượt qua. Nhưng các lớp trước đó tự chúng sẽ không được nén lại. – BlueSun

+0

Cảm ơn. Toàn bộ backprop so với phía trước làm cho câu hỏi khó hiểu hơn dự định. Tôi đã có nghĩa là sau này trong chuỗi gradient backprop. –

10

sử dụng optimizer.compute_gradients hoặc tf.gradient để có được gradient gốc
sau đó làm bất cứ điều gì bạn muốn
cuối cùng, sử dụng optimizer.apply_gradients

Tôi tìm thấy một example từ github

+0

Cảm ơn bạn, đây là thú vị. Tôi nghĩ rằng nó thay thế gradient hoàn chỉnh (kết thúc đến cuối) mặc dù, và chỉ cho trình tối ưu hóa. Tôi muốn thay thế gradient của một op duy nhất, trong khi cho phép gradient từ các op khác truyền bá thông qua cách chúng bình thường; Tôi không nhất thiết phải biết phải làm gì với gradient cuối cùng. Một ví dụ sẽ có một tf.matmult() trong đó tính toán chuyển tiếp được thực hiện bình thường, nhưng gradient là clip (grad, min, max) trong đó grad là gradient gốc, và có được sử dụng trong một đồ thị lớn hơn. –

+1

hãy xem [compute_gradients] (https://www.tensorflow.org/api_docs/python/tf/train/AdamOptimizer#compute_gradients), nó trả về một danh sách '(gradient, variable)' pairs vì vậy tôi nghĩ bạn có thể chỉ sửa đổi "độ dốc" bạn muốn, như [this] (https://github.com/KelvinLu/krotos-convnet/blob/e37218aeaf10b73d77dfac911be46d8ab689e41d/krotos/convnet/model/training.py#L27), tìm 'var' bạn muốn – xxi

6

Cách chung nhất để làm điều đó là bằng cách sử dụng https://www.tensorflow.org/api_docs/python/tf/RegisterGradient

Dưới đây, tôi đã triển khai thực hiện trích xuất dốc ngược, có thể sử dụng với matmul, như thể hiện ở đây, hoặc bất kỳ op khác:

import tensorflow as tf 
import numpy as np 

# from https://gist.github.com/harpone/3453185b41d8d985356cbe5e57d67342 
def py_func(func, inp, Tout, stateful=True, name=None, grad=None): 

    # Need to generate a unique name to avoid duplicates: 
    rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8)) 

    tf.RegisterGradient(rnd_name)(grad) 
    g = tf.get_default_graph() 
    with g.gradient_override_map({"PyFunc": rnd_name}): 
     return tf.py_func(func, inp, Tout, stateful=stateful, name=name) 

def clip_grad(x, clip_value, name=None): 
    """" 
    scales backpropagated gradient so that 
    its L2 norm is no more than `clip_value` 
    """ 
    with tf.name_scope(name, "ClipGrad", [x]) as name: 
     return py_func(lambda x : x, 
         [x], 
         [tf.float32], 
         name=name, 
         grad=lambda op, g : tf.clip_by_norm(g, clip_value))[0] 

Ví dụ sử dụng:

with tf.Session() as sess: 
    x = tf.constant([[1., 2.], [3., 4.]]) 
    y = tf.constant([[1., 2.], [3., 4.]]) 

    print('without clipping') 
    z = tf.matmul(x, y) 
    print(tf.gradients(tf.reduce_sum(z), x)[0].eval()) 

    print('with clipping') 
    z = tf.matmul(clip_grad(x, 1.0), clip_grad(y, 0.5)) 
    print(tf.gradients(tf.reduce_sum(z), x)[0].eval()) 

    print('with clipping between matmuls') 
    z = tf.matmul(clip_grad(tf.matmul(x, y), 1.0), y) 
    print(tf.gradients(tf.reduce_sum(z), x)[0].eval()) 

Output:

without clipping 
[[ 3. 7.] 
[ 3. 7.]] 
with clipping 
[[ 0.278543 0.6499337] 
[ 0.278543 0.6499337]] 
with clipping between matmuls 
[[ 1.57841039 3.43536377] 
[ 1.57841039 3.43536377]] 
+0

MaxB: Cảm ơn bạn! Điều này có vẻ hữu ích. Tôi không chắc làm thế nào để xác định một op mới trong python thông qua ... là nó chỉ là một chức năng với một trang trí? Bạn có thể làm một ví dụ đầy đủ của matmult với gradients cắt bớt? –

+0

@AlexI Nó không phải dễ dàng, nhưng nó có thể thực hiện được: http://stackoverflow.com/questions/37924071/tensorflow-writing-an-op-in-python Nếu bạn chỉ muốn cắt các gradient, tôi đề nghị bạn xác định một "danh tính op "mà không có gì khác ngoài việc cắt gradient. Ngoài ra, hãy xem https://www.tensorflow.org/extend/adding_an_op#implement_the_gradient_in_python – MaxB

+0

@AlexI Tôi đã triển khai thực hiện cắt giảm độ dốc ngược thực tế. Xem chỉnh sửa – MaxB

7

Giả sử các tính toán về phía trước được

y = f(x) 

Và bạn muốn nó backpropagate như

y = b(x) 

Một hack đơn giản sẽ là:

y = b(x) + tf.stop_gradient(f(x) - b(x)) 
+0

Nó phải được tf.stop_gradient, sửa đổi. @lvelin – Bily

Các vấn đề liên quan