python - Tensorflow: अजगर में ढाल के साथ op कैसे लिखें?




neural-network gradient-descent (2)

मैं अजगर में एक TensorFlow op लिखना चाहूंगा, लेकिन मैं चाहूंगा कि इसे अलग किया जा सके (एक ढाल की गणना करने में सक्षम)।

यह सवाल पूछता है कि अजगर में ऑप कैसे लिखा जाता है, और इसका जवाब py_func (जिसका कोई ग्रेडिएंट नहीं है) का उपयोग करने का सुझाव देता है: टेंसरफ़्लो: पायथन में एक ऑप लिखना

TF दस्तावेज़ीकरण केवल C ++ कोड से शुरू होने वाले ऑप्‍शन को जोड़ने का वर्णन करता है: https://www.tensorflow.org/versions/r0.10/how_tos/adding_an_op/index.html

मेरे मामले में, मैं प्रोटोटाइप कर रहा हूं, इसलिए मुझे इस बात की परवाह नहीं है कि यह GPU पर चलता है या नहीं, और मुझे इस बात की परवाह नहीं है कि TF python API के अलावा कुछ भी उपयोग करने योग्य है।


यहां एक विशिष्ट py_func here ग्रेडिएंट जोड़ने का एक उदाहरण दिया गया है

यहाँ मुद्दा discussion


हां, जैसा कि @ यारोस्लाव के उत्तर में उल्लेख किया गया है, यह संभव है और कुंजी वह लिंक है जो वह here और here संदर्भित करता here । मैं एक ठोस उदाहरण देकर इस उत्तर पर विस्तार से बताना चाहता हूं।

मोडुलो ओपरेशन : आइए टेंसोफ़्लो में तत्व-वार मोडुलो ऑपरेशन को लागू करें (यह पहले से मौजूद है लेकिन इसकी ढाल परिभाषित नहीं है, लेकिन उदाहरण के लिए हम इसे खरोंच से लागू करेंगे)।

Numpy फ़ंक्शन: पहला चरण उस खराबी को परिभाषित करना है जिसे हम सुपीरियर सरणियों के लिए चाहते हैं। तत्व-वार मोडुलो ऑपेरेशन पहले से ही सुपी में लागू है, इसलिए यह आसान है:

import numpy as np
def np_mod(x,y):
    return (x % y).astype(np.float32)

.astype(np.float32) का कारण यह है कि डिफ़ॉल्ट रूप से टेंसरफ़्लो फ़्लोट 32 प्रकार लेता है और यदि आप इसे फ़्लोटि 64 (संख्यात्मक डिफ़ॉल्ट) देते हैं तो यह शिकायत करेगा।

ग्रेडिएंट फंक्शन: आगे हमें ऑप्रेशन के प्रत्येक इनपुट के लिए अपने ओपेरेशन के लिए ग्रेडिएंट फंक्शन को परिभाषित करना होगा। फ़ंक्शन को बहुत विशिष्ट रूप लेने की आवश्यकता है। यह opperation op के टेंसरफ्लो प्रतिनिधित्व और आउटपुट ग्रैडिएंट के ग्रेडिएंट को लेने की जरूरत है और कहता है कि ग्रेडिएंट्स को कैसे प्रचारित किया जाए। हमारे मामले में, mod ऑपेरेशन के ग्रेडिएंट आसान हैं, व्युत्पन्न 1 पहले तर्क के संबंध में है और दूसरे के संबंध में (लगभग हर जगह, और स्पॉट की एक सीमित संख्या में अनंत, लेकिन आइए इसे अनदेखा https://math.stackexchange.com/questions/1849280/derivative-of-remainder-function-wrt-denominator , https://math.stackexchange.com/questions/1849280/derivative-of-remainder-function-wrt-denominator देखें विवरण)। तो हमारे पास

def modgrad(op, grad):
    x = op.inputs[0] # the first argument (normally you need those to calculate the gradient, like the gradient of x^2 is 2x. )
    y = op.inputs[1] # the second argument

    return grad * 1, grad * tf.neg(tf.floordiv(x, y)) #the propagated gradient with respect to the first and second argument respectively

ग्रेड फ़ंक्शन को n-tuple वापस करने की आवश्यकता होती है, जहां n ऑपरेशन के तर्कों की संख्या होती है। ध्यान दें कि हमें इनपुट के टेंसरफ्लो कार्यों को वापस करने की आवश्यकता है।

ग्रेडिएंट्स के साथ TF फ़ंक्शन करना: जैसा कि ऊपर वर्णित स्रोतों में बताया गया है, tf.RegisterGradient [doc] और tf.Graph.gradient_override_map [doc] का उपयोग करके फ़ंक्शन के ग्रेडिएंट्स को परिभाषित करने के लिए एक हैक है।

कोड को here से कॉपी करते here हम tf.py_func फ़ंक्शन को उसी में ग्रेडिएंट को परिभाषित करने के लिए संशोधित कर सकते हैं:

import tensorflow as tf

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)  # see _MySquareGrad for grad example
    g = tf.get_default_graph()
    with g.gradient_override_map({"PyFunc": rnd_name}):
        return tf.py_func(func, inp, Tout, stateful=stateful, name=name)

stateful ऑप्शन टेंसरफ्लो को बताना है कि क्या फंक्शन हमेशा एक ही इनपुट (स्टेटफुल = फाल्स) के लिए एक ही आउटपुट देता है जिस स्थिति में टेंसोफ़्लो केवल टेंसरफ़्लो ग्राफ हो सकता है, यह हमारा मामला है और ज्यादातर स्थितियों में शायद यही होगा।

सभी को एक साथ मिलाकर: अब जबकि हमारे पास सभी टुकड़े हैं, हम उन सभी को एक साथ जोड़ सकते हैं:

from tensorflow.python.framework import ops

def tf_mod(x,y, name=None):

    with ops.op_scope([x,y], name, "mod") as name:
        z = py_func(np_mod,
                        [x,y],
                        [tf.float32],
                        name=name,
                        grad=modgrad)  # <-- here's the call to the gradient
        return z[0]

tf.py_func सूचियों पर कार्य करता है (और tf.py_func सूची लौटाता है), इसीलिए हमारे पास [x,y] (और वापसी z[0] ) है। और अब हम कर चुके हैं। और हम इसका परीक्षण कर सकते हैं।

परीक्षा:

with tf.Session() as sess:

    x = tf.constant([0.3,0.7,1.2,1.7])
    y = tf.constant([0.2,0.5,1.0,2.9])
    z = tf_mod(x,y)
    gr = tf.gradients(z, [x,y])
    tf.initialize_all_variables().run()

    print(x.eval(), y.eval(),z.eval(), gr[0].eval(), gr[1].eval())

[0.30000001 0.69999999 1.20000005 1.70000005] [0.2 0.5 1. 2.9000001] [0.10000001 0.19999999 0.20000005 1.70000005] [1. 1. 1. 1.] [-1। -1। -1। 0.]

सफलता!






gradient-descent