24

मान लीजिए कि आपको एक सक्रियण फ़ंक्शन बनाने की आवश्यकता है जो केवल पूर्व-परिभाषित tensorflow बिल्डिंग-ब्लॉक का उपयोग करके संभव नहीं है, आप क्या कर सकते हैं?टेन्सफोर्लो में केवल पायथन के साथ कस्टम सक्रियण फ़ंक्शन कैसे बनाएं?

तो टेन्सफोर्लो में अपना स्वयं का सक्रियण कार्य करना संभव है। लेकिन यह काफी जटिल है, आपको इसे सी ++ में लिखना है और पूरे tensorflow [1][2] को पुन: संकलित करना है।

क्या कोई आसान तरीका है?

+1

यह भी देखें [आप केरास के साथ एक कस्टम सक्रियण फ़ंक्शन कैसे बनाते हैं?] (Http://stackoverflow.com/q/43915482/562769) –

+0

किसी भी सॉफ़्टवेयर के साथ पूर्ण स्वतंत्रता रखना मुश्किल है, लेकिन यदि आप हमें देते हैं एक विचार क्या सक्रियण समारोह (फ़ंक्शन परिवार) जिसे आप बनाने की कोशिश कर रहे हैं, कोई भी आपकी मदद करने में सक्षम हो सकता है। – user1700890

उत्तर

41

हाँ वहाँ है!

क्रेडिट: यह लेकिन जानकारी खोजने के लिए और यह काम कर पाने के मुश्किल था यहाँ सिद्धांतों से एक उदाहरण की प्रतिलिपि बनाने और कोड here और here पाया।

आवश्यकताएँ: शुरू करने से पहले, इसके लिए सफल होने में सक्षम होने के लिए दो आवश्यकताएं हैं। सबसे पहले आपको अपने सक्रियण को numpy arrays पर फ़ंक्शन के रूप में लिखने में सक्षम होना चाहिए। दूसरा, आपको उस कार्य के व्युत्पन्न को या तो टेन्सफोर्लो (आसान) में फ़ंक्शन के रूप में लिखना होगा या सबसे खराब स्थिति परिदृश्य में numpy arrays पर फ़ंक्शन के रूप में लिखना होगा।

लेखन सक्रियण समारोह:

तो चलो उदाहरण के लिए इस समारोह है जो हम एक सक्रियण समारोह का उपयोग करना चाहते हैं करते हैं:

def spiky(x): 
    r = x % 1 
    if r <= 0.5: 
     return r 
    else: 
     return 0 

कौन सा रूप में देखने के लिए इस प्रकार है: Spiky Activation

पहला कदम इसे एक गंदे फ़ंक्शन में बना रहा है, यह आसान है:

import numpy as np 
np_spiky = np.vectorize(spiky) 

अब हमें इसके व्युत्पन्न लिखना चाहिए।

एक्टिवेशन की ढाल: हमारे मामले में यह आसान है, यह 1 है अगर एक्स आधुनिक 1 < 0.5 और 0 अन्यथा। तो:

def d_spiky(x): 
    r = x % 1 
    if r <= 0.5: 
     return 1 
    else: 
     return 0 
np_d_spiky = np.vectorize(d_spiky) 

अब इसमें से एक टेंसरफ्लो फ़ंक्शन बनाने के कठिन हिस्से के लिए।

एक tensorflow एफसीटी करने के लिए एक numpy एफसीटी बनाना: हम एक tensorflow समारोह में np_d_spiky बनाकर शुरू कर देंगे। वहाँ tensorflow tf.py_func(func, inp, Tout, stateful=stateful, name=name)[doc] जो एक tensorflow समारोह के लिए किसी भी numpy समारोह बदल देती है में एक समारोह है, तो हम इसका इस्तेमाल कर सकते हैं: tensors की सूची पर

import tensorflow as tf 
from tensorflow.python.framework import ops 

np_d_spiky_32 = lambda x: np_d_spiky(x).astype(np.float32) 


def tf_d_spiky(x,name=None): 
    with ops.op_scope([x], name, "d_spiky") as name: 
     y = tf.py_func(np_d_spiky_32, 
         [x], 
         [tf.float32], 
         name=name, 
         stateful=False) 
     return y[0] 

tf.py_func में कार्य करता है (और tensors की सूची लौटाता है), इसलिए हम है [x] (और y[0] लौटाएं)। stateful विकल्प tensorflow को बताना है कि फ़ंक्शन हमेशा एक ही इनपुट (स्टेटफुल = झूठी) के लिए एक ही आउटपुट देता है, जिस स्थिति में टेंसफोर्लो बस टेंसफोर्लो ग्राफ कर सकता है, यह हमारा मामला है और शायद अधिकांश स्थितियों में यह मामला होगा।इस बिंदु पर सावधान रहने की एक बात यह है कि numpy float64 का उपयोग किया जाता है लेकिन tensorflow float32 का उपयोग करता है, इसलिए आपको इसे अपने टेंसरफ़्लो फ़ंक्शन में परिवर्तित करने से पहले float32 का उपयोग करने के लिए अपने फ़ंक्शन को कनवर्ट करने की आवश्यकता है अन्यथा tensorflow शिकायत करेगा। यही कारण है कि हमें पहले np_d_spiky_32 बनाने की आवश्यकता है।

ग्रेडियेंट्स के बारे में क्या? केवल उपर्युक्त करने में समस्या यह है कि भले ही हमारे पास tf_d_spiky है जो np_d_spiky का टेंसफोर्लो संस्करण है, हम इसे सक्रियण फ़ंक्शन के रूप में उपयोग नहीं कर पाएंगे क्योंकि हम चाहते थे क्योंकि tensorflow को नहीं पता कि ग्रेडियेंट की गणना कैसे करें वह समारोह

हैक ग्रेडिएंट पाने के लिए: के रूप में सूत्रों का कहना है कि ऊपर उल्लेख किया में विस्तार से बताया, वहाँ एक समारोह tf.RegisterGradient[doc] और tf.Graph.gradient_override_map[doc] का उपयोग करने का ढ़ाल परिभाषित करने के लिए एक हैक है। harpone से कोड को कॉपी करने हम इसे एक ही समय में ढाल को परिभाषित करने के लिए tf.py_func समारोह को संशोधित कर सकते हैं:

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) 

अब हम लगभग कर लिया है, केवल एक चीज स्नातक समारोह हम ऊपर को पास किए जाने कि है py_func फ़ंक्शन को एक विशेष रूप लेना आवश्यक है। संचालन से पहले इसे एक ऑपरेशन, और पिछले ग्रेडियेंट में लेना होगा और ऑपरेशन के बाद पिछड़े ग्रेडियेंट को प्रसारित करना होगा।

ढाल फंक्शन: यही वजह है कि x = op.inputs[0]

def spikygrad(op, grad): 
    x = op.inputs[0] 

    n_gr = tf_d_spiky(x) 
    return grad * n_gr 

सक्रियण समारोह केवल एक इनपुट है,: इसलिए हमारे काँटेदार सक्रियण समारोह के लिए है कि हम इसे कैसे करना होगा। यदि ऑपरेशन में कई इनपुट थे, तो हमें प्रत्येक इनपुट के लिए एक ट्यूपल, एक ढाल वापस करने की आवश्यकता होगी। उदाहरण के लिए यदि ऑपरेशन a-ba के संबंध में ढाल +1 है और b-1 के संबंध में है तो हमारे पास return +1*grad,-1*grad होगा। ध्यान दें कि हमें इनपुट के tensorflow कार्यों को वापस करने की आवश्यकता है, यही कारण है कि tf_d_spiky, np_d_spiky की आवश्यकता नहीं होती क्योंकि यह टेन्सफोर्लो टेंसर पर कार्य नहीं कर सकता है।

def spikygrad2(op, grad): 
    x = op.inputs[0] 
    r = tf.mod(x,1) 
    n_gr = tf.to_float(tf.less_equal(r, 0.5)) 
    return grad * n_gr 

यह सब एक साथ संयोजन:: वैकल्पिक रूप से हम व्युत्पन्न का उपयोग कर tensorflow कार्यों लिख सकता अब हम

np_spiky_32 = lambda x: np_spiky(x).astype(np.float32) 

def tf_spiky(x, name=None): 

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

और: अब जब हम सभी टुकड़ों है, हम उन सब को एक साथ गठजोड़ कर सकते हैं कार्य पूर्ण। और हम इसका परीक्षण कर सकते हैं।

टेस्ट:

with tf.Session() as sess: 

    x = tf.constant([0.2,0.7,1.2,1.7]) 
    y = tf_spiky(x) 
    tf.initialize_all_variables().run() 

    print(x.eval(), y.eval(), tf.gradients(y, [x])[0].eval()) 

[0.2 ०.६९९९९९९९ १.२,००,००,००५ १.७,००,००,००५] [0.2 0. .२,००,००,००५ 0.] [1. 0. 1. 0.]

सफलता!

+0

यह कितना अच्छा सीख गया? – lahwran

+2

@lahwran यह वास्तव में एक सक्रियण समारोह नहीं है जिसे आप वास्तविक जीवन में उपयोग करना चाहते हैं। यदि आपको ऐसा करने की ज़रूरत है तो कस्टम एक्टिवेशन फ़ंक्शन को कार्यान्वित करने का यह एक उदाहरण है। –

+0

पूरी तरह से, यही कारण है कि मैं उत्सुक था कि क्या आप इसे काम करने के लिए प्राप्त कर चुके हैं: पी – lahwran

5

क्यों न केवल उन कार्यों का उपयोग करें जो आपके नए फ़ंक्शन को बनाने के लिए पहले से ही टेंसफोर्लो में उपलब्ध हैं?

your answer में spiky समारोह के लिए, इस रूप में

def spiky(x): 
    r = tf.floormod(x, tf.constant(1)) 
    cond = tf.less_equal(r, tf.constant(0.5)) 
    return tf.where(cond, r, tf.constant(0)) 

इस प्रकार दिखाई दे सकता है मैं इस पर विचार करेंगे काफी हद तक बहुत आसान (यहां तक ​​कि किसी भी ढ़ाल की गणना करने की जरूरत नहीं) और जब तक आप वास्तव में विदेशी बातें करना चाहता हूँ, मैं मुश्किल से कल्पना कर सकते हैं कि tensorflow अत्यधिक जटिल सक्रियण कार्यों के निर्माण के लिए बिल्डिंग ब्लॉक प्रदान नहीं करता है।

+1

हां, वास्तव में, टीएफ प्राइमेटिव्स के साथ स्पाइक किया जा सकता है, लेकिन स्पाकी सिर्फ एक साधारण उदाहरण है जो उस कार्य की जटिलता से अत्यधिक उलझन में नहीं है जिसे मैं वास्तव में कार्यान्वित करना चाहता हूं। जो काम मैं वास्तव में कार्यान्वित करना चाहता था दुर्भाग्य से टीएफ प्राइमेटिव के साथ लागू नहीं किया जा सकता था। –

+1

प्रश्न का पूरा बिंदु यह है: जब आप टीएफ प्राइमेटिव के साथ सक्रियण फ़ंक्शन को तैयार नहीं कर सकते हैं तो आप क्या करते हैं। –

+1

@patapouf_ai मुझे पहले ही यह उम्मीद है, लेकिन यह आपके प्रश्न से स्पष्ट नहीं है। इस सवाल की लोकप्रियता के कारण, मैंने सोचा कि इस समाधान को इंगित करना भी एक अच्छा विचार हो सकता है (उन लोगों के लिए जो छोटे से अनुभव वाले लोगों के लिए अपने स्वयं के सक्रियण कार्यों को बनाने की कोशिश कर रहे हैं)। –

संबंधित मुद्दे