स्वचालित भेदभाव

From Vigyanwiki

गणित और कंप्यूटर बीजगणित में, स्वचालित अवकलन (स्व-अवकलन, ऑटोडिफ़, या एआडी), जिसे कलनविधीय अवकलन तथा अभिकलनीय अवकलन भी कहा जाता है,[1][2] और यह कंप्यूटर प्रोग्राम द्वारा निर्दिष्ट फलन के आंशिक अवकलज का मूल्यांकन करने के लिए तकनीकों का एक समुच्चय है।

स्वचालित अवकलन इस तथ्य का फायदा उठाता है कि प्रत्येक कंप्यूटर प्रोग्राम, चाहे कितना भी जटिल क्यों न हो, प्राथमिक अंकगणितीय संचालन (जोड़, घटाव, गुणा, भाग, आदि) और प्राथमिक फलनो (ऍक्स्प, लॉग, साइन, कॉस, आदि) के अनुक्रम को निष्पादित करता है। इन परिचालनों में श्रृंखला नियम को बार-बार लागू करने से, यादृच्छिक रूप से क्रम के आंशिक अवकलज की गणना स्वचालित रूप से, सटीकता से काम करने के लिए की जा सकती है, और मूल प्रोग्राम की तुलना में अधिक अंकगणितीय संचालन के एक छोटे स्थिर कारक का उपयोग किया जा सकता है।

अन्य अवकलन विधियों से अंतर

चित्र 1, स्वचालित अवकलन प्रतीकात्मक अवकलन से कैसे संबंधित है

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

अग्रगामी और उत्क्रम संचयन

समग्र फलनों के आंशिक अवकलजों का श्रृंखला नियम

स्वचालित अवकलन के लिए मूल, संयुक्त फलनो के आंशिक अवकलज के श्रृंखला नियम द्वारा प्रदान किए गए अंतर का अपघटन है। सरल संयोजन

के लिए श्रृंखला नियम
देता है

दो प्रकार के स्वचालित अवकलन

आमतौर पर, स्वचालित अवकलन के दो अलग-अलग तरीके प्रस्तुत किए जाते हैं।

  • अग्रगामी संचयन (जिसे समानयन, अग्रगामी मोड या स्पर्शी मोड भी कहा जाता है)
  • उत्क्रम संचयन (जिसे अधोशीर्ष, उत्क्रम मोड या सहखंडज मोड भी कहा जाता है)

अग्रगामी संचयन निर्दिष्ट करता है कि कोई व्यक्ति श्रृंखला नियम को अंदर से (अर्थात, पहले की गणना करें और फिर की तथा अंत में की गणना करें) बाहर तक चंक्रमण करता है, जबकि उत्क्रम संचयन में बाहर से अंदर (पहले की गणना करें और फिर की और अंत में की गणना करें) तक चंक्रमण करता है।

  • अग्रगामी संचयन पुनरावर्ती संबंध की गणना करता है, के साथ , और,
  • उत्क्रम संचयन पुनरावर्ती संबंध की गणना करता है, के साथ

आंशिक अवकलज का मूल्य, जिसे सीड कहा जाता है, अग्रगामी या पश्चगामी प्रसारित होता है और प्रारंभ में या होता है। अग्रगामी संचयन फलन का मूल्यांकन करता है और एक पास में एक स्वतंत्र चर के संबंध में अवकलज की गणना करता है। प्रत्येक स्वतंत्र चर के लिए एक अलग पास आवश्यक है जिसमें उस स्वतंत्र चर के संबंध में अवकलज को एक () और अन्य सभी को शून्य () पर निर्धारित किया जाता है। इसके उत्क्रम, उत्क्रम संचयन के लिए आंशिक अवकलज के लिए मूल्यांकन किए गए आंशिक फलनो की आवश्यकता होती है। इसलिए उत्क्रम संचयन पहले फलन का मूल्यांकन करता है और एक अतिरिक्त पास में सभी स्वतंत्र चर के संबंध में अवकलज की गणना करता है।

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

  • nm के साथ फलन f : RnRm के लिए उत्क्रम संचयन की तुलना में अग्रगामी संचयन अधिक कुशल है क्योंकि उत्क्रम संचयन के लिए m स्वीप की तुलना में केवल n स्वीप आवश्यक हैं।
  • फलन f : RnRm के लिए nm के साथ अग्रगामी संचयन की तुलना में उत्क्रम संचयन अधिक कुशल है क्योंकि अग्रगामी संचयन के लिए n स्वीप की तुलना में केवल m स्वीप आवश्यक है।

बहुपरतीय परसेप्ट्रॉन में त्रुटियों की पश्चसंचरण, यंत्र अधिगम में उपयोग की जाने वाली तकनीक, उत्क्रम संचयन की एक विशेष स्थिति है।[2]

अग्रगामी संचयन की शुरुआत 1964 में आर.ई. वेंगर्ट द्वारा की गई थी।।[3] एंड्रियास ग्रिवैंक के अनुसार, 1960 के दशक के उत्तरार्ध से उत्क्रम संचयन का सुझाव दिया गया है, लेकिन आविष्कारक अज्ञात है।[4] सेप्पो लिन्नैनमा ने 1976 में उत्क्रम संचयन प्रकाशित किया।[5]

अग्रगामी संचयन

अग्रगामी संचयन

अग्रगामी संचयन एडी में, व्यक्ति पहले स्वतंत्र चर को निर्धारित करता है जिसके संबंध में अवकलन किया जाता है और प्रत्येक उप-व्यंजक के अवकलज की पुनरावर्ती गणना करता है। कलम और कागज की गणना में, इसमें श्रृंखला नियम में आंतरिक फलनो के अवकलज को बार-बार प्रतिस्थापित करना सम्मिलित है,

इसे जैकोबियन के आव्यूह गुणन के रूप में कई चर के लिए सामान्यीकृत किया जा सकता है।

उत्क्रम संचयन की तुलना में, अग्रगामी संचयन स्वाभाविक रूप से लागू करना आसान है क्योंकि अवकलज सूचना का प्रवाह मूल्यांकन के क्रम के साथ मेल खाता है। प्रत्येक चर को इसके अवकलज (संख्यात्मक मान के रूप में संग्रहीत, प्रतीकात्मक व्यंजक नहीं),

के साथ संवर्धित किया गया है ,जैसा कि बिंदु द्वारा दर्शाया गया है। फिर मूल्यांकन चरणों के साथ अवकलज की गणना की जाती है और श्रृंखला नियम के माध्यम से अन्य अवकलज के साथ जोड़ा जाता है। श्रृंखला नियम का उपयोग करते हुए, यदि के पास अभिकलनीय ग्राफ़ में पूर्ववर्ती हैं, तो

चित्र 2, अभिकलनीय ग्राफ़ के साथ अग्रगामी संचयन का उदाहरण

उदाहरण के तौर पर, फलन पर विचार करें,

स्पष्टता के लिए, व्यक्तिगत उप-व्यंजको को चर के साथ वर्गीकृत किया गया है .

जिस स्वतंत्र चर का विभेदीकरण किया जाता है उसका चयन सीड मूल्यों 1 और 2 को प्रभावित करता है। x1 के संबंध में इस फलन के अवकलज में रुचि को देखते हुए, सीड मान को इस पर निर्धारित किया जाना चाहिए,

सीड मान निर्धारित होने के साथ, मान दिखाए गए अनुसार श्रृंखला नियम का उपयोग करके प्रसारित होते हैं। चित्र 2 एक अभिकलनीय ग्राफ़ के रूप में इस प्रक्रिया का सचित्र चित्रण दिखाता है।

मूल्य की गणना करने के लिए संचालन अवकलज की गणना करने के लिए संचालन
(seed)
(seed)

इस उदाहरण फलन की प्रवणता की गणना करने के लिए, जिसके लिए न केवल बल्कि की भी आवश्यकता होती है, सीड मान का उपयोग करके अभिकलनीय ग्राफ़ पर एक अतिरिक्त स्वीप किया जाता है।

कार्यान्वयन

छद्म कोड

अग्रगामी संचयन एक पास में, फलन और अवकलज (लेकिन केवल एक स्वतंत्र चर के लिए) की गणना करता है। संबंधित विधि कॉल एक चर V के संबंध में व्यंजक Z को प्राप्त करने की अपेक्षा करती है। विधि मूल्यांकन किए गए फलन और इसके अवकलन की एक जोड़ी की पुनरावृत्ति है। यह विधि एक चर तक पहुंचने तक व्यंजक वृक्ष को पुनरावर्ती रूप से चंक्रमण करती है। यदि इस चर के संबंध में अवकलज का अनुरोध किया जाता है, तो इसका अवकलज 1, 0 होगा अन्यथा। फिर आंशिक फलन के साथ-साथ आंशिक अवकलज का मूल्यांकन किया जाता है।[6]

tuple<float,float>eval(Expression Z, Expression V) { यदि चर(Z) है
     यदि (Z=V) पुनरावृत्ति {valueOf(Z),1};
     अन्यथा पुनरावृत्ति {valueOf(Z),0};
  अन्यथा यदि (Z = X + Y)
     {x,x'} = eval(X,V);
     {y,y'} = eval(Y,V);
     पुनरावृत्ति {x+y, x'+y'};
  अन्यथा यदि (Z = X - Y)
     {x,x'} = eval(X,V);
     {y,y'} = eval(Y,V);
     पुनरावृत्ति {x-y, x'-y'};
  अन्यथा यदि (Z = X * Y)
     {x,x'} = eval(X,V);
     {y,y'} = eval(Y,V);
     पुनरावृत्ति {x*y, x'*y+x*y'};                                              
सी++
#include <iostream>
#include <string>
  #include <map>
     typedef struct dual { float v,d; } dual;
    struct Expression {                                 virtual dual eval(std::map<std::string,float>         &vals, Expression *v) { return {0,0}; };               };                                                   struct Plus: public Expression {                 Expression *a, *b;                         Plus(Expression *a, Expression *b): a{a}, b{b} {}      dual eval(std::map<std::string,float> &vals, Expression *v) {                                                dual x=a->eval(vals,v);                              dual y=b->eval(vals,v);                            return {x.v+y.v, x.d+y.d};                                                                     }                                                     };                                                struct Var: public Expression {                       std::string s;                                            Var(std::string s) : s{s} {}                            dual eval(std::map<std::string,float> &vals,  Expression *v) {                                                     return {vals[s], this==v?1.0f:0.0f};                     }                                                      };                                                   int main (){                             std,,map<std,,string,float> dict;
  dict.insert(std,,pair<std,,string,int>( x ,1));
  dict.insert(std,,pair<std,,string,int>( y ,-3));
  dict.insert(std,,pair<std,,string,int>( z ,4));
  Var x( x ), y( y ), z( z );
  Mul m1(&x,&z); Mul m2(&y,&z); Plus p(&m1,&m2); // x*z+y*z
  std,,cout << x, << p.eval(dict,&x).d << , << y, << p.eval(dict,&y).d << , << z, << p. eval(dict,&z).d << std,,endl;
  पुनरावृत्ति 0;

उत्क्रम संचयन

उत्क्रम संचयन एडी में, अवकलित किए जाने वाले आश्रित चर को तय किया जाता है और अवकलज की गणना प्रत्येक उप-व्यंजक के संबंध में पुनरावर्ती रूप से की जाती है। कलम और कागज की गणना में, बाहरी फलनो के अवकलज को श्रृंखला नियम में बार-बार प्रतिस्थापित किया जाता है,

उत्क्रम संचयन में, ब्याज की मात्रा सहायक होती है, जिसे एक बार से दर्शाया जाता है, यह उपव्यंजक के संबंध में चुने गए आश्रित चर का अवकलज है,
श्रृंखला नियम का उपयोग करते हुए, यदि के पासअभिकलनीय ग्राफ़ में परवर्ती हैं, तो

उत्क्रम संचयन श्रृंखला नियम को बाहर से अंदर तक, या चित्र 3 में अभिकलनीय ग्राफ की स्थिति में, ऊपर से नीचे तक चंक्रमण करता है। उदाहरण फलन अदिश-मूल्यवान है, और इस प्रकार अवकलज गणना के लिए केवल एक सीड है, और (दो-घटक) प्रवणता की गणना करने के लिए अभिकलनीय ग्राफ के केवल एक स्वीप की आवश्यकता होती है। अग्रगामी संचयन की तुलना में यह केवल आधा काम है, लेकिन उत्क्रम संचयन के लिए मध्यवर्ती चर wi के भंडारण की आवश्यकता होती है जो उन्हें टेप या वेंगर्ट सूची[7] (हालाँकि, वेंगर्ट ने अग्रगामी संचयन प्रकाशित किया, न कि उत्क्रम संचय[3]) के रूप में ज्ञात डेटा संरचना में उत्पन्न करते हैं, जो अभिकलनीय ग्राफ़ बड़ा होने पर महत्वपूर्ण मेमोरी का उपभोग कर सकता है। मध्यवर्ती चरों के केवल एक उपसमूह को संग्रहीत करके और फिर मूल्यांकन को दोहराकर आवश्यक कार्य चरों का पुनर्निर्माण करके इसे कुछ हद तक कम किया जा सकता है, एक तकनीक जिसे पुनर्भौतिकीकरण के रूप में जाना जाता है। जाँच बिन्दु का उपयोग मध्यस्थ अवस्थाओ को बचाने के लिए भी किया जाता है।

चित्र 3, अभिकलनीय ग्राफ़ के साथ उत्क्रम संचयन का उदाहरण

उत्क्रम संचयन का उपयोग करके अवकलज की गणना करने के संचालन को नीचे दी गई तालिका में दिखाया गया है (उत्क्रमित क्रम पर ध्यान दें),

अवकलज की गणना करने के लिए संचालन

किसी गणना के डेटा प्रवाह ग्राफ़ को उसकी मूल गणना की प्रवणता की गणना करने के लिए प्रकलित किया जा सकता है। यह प्रत्येक प्रारंभिक नोड के लिए एक सहखंडज नोड जोड़कर किया जाता है, जो सहखंडज किनारों से जुड़ा होता है जो कि प्रारंभिक किनारों के समानांतर होता है लेकिन उत्क्रम दिशा में बहता है। निकटवर्ती ग्राफ में नोड्स प्रारंभिक में नोड्स द्वारा गणना किए गए फलनो के अवकलज द्वारा गुणन का प्रतिनिधित्व करते हैं। उदाहरण के लिए, मूल में जोड़ के कारण जोड़ में बहिर्गमांक हो जाता है, सहखंडज में बहिर्गमांक के कारण जोड़ में वृद्धि होती है,[lower-alpha 1] प्रारंभिक कारणों में एक एकल फलन y = f(x), सहखंडज में = ȳ f′(x) आदि होते है।

कार्यान्वयन

छद्म कोड

उत्क्रम संचयन के लिए दो पास की आवश्यकता होती है, अग्रगामी पास में, फलन का पहले मूल्यांकन किया जाता है और आंशिक परिणाम कैश किए जाते हैं। उत्क्रम पास में, आंशिक अवकलज की गणना की जाती है और पहले से प्राप्त मूल्य को पृष्‍ठ संचरण किया जाता है। संबंधित विधि कॉल से अपेक्षा की जाती है कि व्यंजक Z को व्युत्पन्न किया जाए और मूल व्यंजक के व्युत्पन्न मूल्य के साथ सीड किया जाए। शीर्ष व्यंजक के लिए, Z, Z के संबंध में व्युत्पन्न, यह 1 है। यह विधि एक चर तक पहुंचने तक व्यंजक वृक्ष को पुनरावर्ती रूप से चंक्रमण करती है और अवकलज व्यंजक में वर्तमान सीड मान जोड़ती है।[8][9]

 void derive(Expression Z, float seed) {              यदि (Z = X + Y)
     अवकलज (X, सीड);
     अवकलज (Y, सीड);
  अन्यथा यदि (Z = X - Y)
     अवकलज (X, सीड);
     अवकलज(Y,-सीड);
  अन्यथा यदि (Z = X * Y)
     अवकलज(X,valueOf(X)*seed);
     अवकलज(Y,seed*valueOf(Y));
  अन्यथा यदि वैरिएबल (जेड) है
     आंशिकDerivativeOf(Z) += बीज;                       }
पायथन

बिना टेप के पायथन में कार्यान्वयन।

import math

class Var:
    def __init__(self, value, children=None):
        self.value = value
        self.children = children or []
        self.grad = 0

    def __add__(self, other):
        return Var(self.value + other.value, [(1, self), (1, other)])

    def __mul__(self, other):
        return Var(self.value * other.value, [(other.value, self), (self.value, other)])

    def sin(self):
        return Var(math.sin(self.value), [(math.cos(self.value), self)])

    def calc_grad(self, grad=1):
        self.grad += grad
        for coef, child in self.children:
            child.calc_grad(grad * coef)

# Example: f(x, y) = x * y + sin(x)
x = Var(2)
y = Var(3)
f = x * y + x.sin()

# Calculation of partial derivatives
f.calc_grad()

print("f =", f.value)
print("∂f/∂x =", x.grad)
print("∂f/∂y =", y.grad)


सी++
  आगे तैरना = 0, पीछे = 0;
  वर्चुअल फ्लोट eval(std,,map<std,,string,float> &vals) = 0;
  आभासी शून्य वापस(फ्लोट बीज) {पिछड़ा+=बीज; };

}; स्ट्रक्चर प्लस, सार्वजनिक व्यंजक {

  व्यंजक *ए, *बी;
  प्लस(व्यंजक *ए, व्यंजक *बी), ए{ए}, बी{बी} {}
  फ्लोट eval(std,,map<std,,string,float> &vals) {
     पिछड़ा=0;
     अग्रगामी=a->eval(vals); अग्रगामी+=बी->ईवल(वैल);
     आगे लौटें;
  }
  शून्य वापस (फ्लोट बीज) {
     व्यंजक,,वापस(बीज);
     ए->वापस(बीज);
     बी->वापस(बीज);
  }

}; संरचना मूल, सार्वजनिक व्यंजक {

  व्यंजक *ए, *बी;
  मूल(व्यंजक *ए, व्यंजक *बी), ए{ए}, बी{बी} {}
  फ्लोट eval(std,,map<std,,string,float> &vals) {
     पिछड़ा=0;
     अग्रगामी=a->eval(vals); आगे*=b->eval(vals);
     आगे लौटें;
  }
  शून्य वापस (फ्लोट बीज) {
     व्यंजक,,वापस(बीज);
     a->पीछे(बीज * b->आगे);
     बी->पीछे(बीज * ए->आगे);
  }

}; संरचना वार, सार्वजनिक व्यंजक {

  एसटीडी,,स्ट्रिंग एस;
  Var(std,,string s)), s{s} {}
  फ्लोट eval(std,,map<std,,string,float> &vals) {
     अग्रगामी=वैल्स[एस];
     पिछड़ा=0;
     आगे लौटें;
  }
  शून्य वापस (फ्लोट बीज) {
     व्यंजक,,वापस(बीज);
     std,,cout << s <<t, << पिछड़ा << ,�;
  }

}; मुख्य प्रवेश बिंदु (){

  std,,map<std,,string,float> dict;
  dict.insert(std,,pair<std,,string,int>( x ,1));
  dict.insert(std,,pair<std,,string,int>( y ,-3));
  dict.insert(std,,pair<std,,string,int>( z ,4));
  वर x( x ), y( y ), z( z ); मूल m1(&x,&z); मूल m2(&y,&z); प्लस p(&m1,&m2); // x*z+y*z
  std,,cout << p.eval(dict) << std,,endl;
  पी.बैक(1); std,,cout << std,,endl;
  पुनरावृत्ति 0;

} </सिंटैक्सहाइलाइट>

आगे और पीछे संचयन से परे

आगे और पीछे संचयन श्रृंखला नियम को पार करने के केवल दो (चरम) तरीके हैं। संपूर्ण जैकोबियन की गणना करने की समस्या f : RnRm अंकगणितीय परिचालनों की न्यूनतम संख्या के साथ इष्टतम जैकोबियन संचयन (ओजेए) समस्या के रूप में जाना जाता है, जो एनपी-पूर्ण है।[10] इस प्रमाण के केंद्र में यह विचार है कि ग्राफ़ के किनारों को लेबल करने वाले स्थानीय आंशिक भागों के बीच बीजगणितीय निर्भरताएँ मौजूद हो सकती हैं। विशेष रूप से, दो या दो से अधिक एज लेबल को बराबर के रूप में पहचाना जा सकता है। समस्या की जटिलता अभी भी खुली है यदि यह मान लिया जाए कि सभी किनारे के लेबल अद्वितीय और बीजगणितीय रूप से स्वतंत्र हैं।

दोहरी संख्याओं का उपयोग करके स्वचालित अवकलन

वास्तविक संख्याओं के क्षेत्र में बीजगणित को बढ़ाकर और एक नया अंकगणित प्राप्त करके अग्रगामी मोड स्वचालित अवकलन पूरा किया जाता है। संख्या पर किसी फलन के अवकलज का प्रतिनिधित्व करने के लिए प्रत्येक संख्या में एक अतिरिक्त घटक जोड़ा जाता है, और सभी अंकगणितीय ऑपरेटरों को संवर्धित बीजगणित के लिए विस्तारित किया जाता है। संवर्धित बीजगणित दोहरी संख्याओं का बीजगणित है।

हर नंबर बदलें संख्या के साथ , कहाँ एक वास्तविक संख्या है, लेकिन संपत्ति के साथ एक अमूर्त संख्या है (एक अतिसूक्ष्म; सहज अतिसूक्ष्म विश्लेषण देखें)। इसके प्रयोग से ही नियमित अंकगणित मिलता है

का उपयोग करते हुए .

अब, इस संवर्धित अंकगणित में बहुपदों की गणना की जा सकती है। अगर , तब

कहाँ के अवकलज को दर्शाता है इसके पहले तर्क के संबंध में, और , जिसे बीज कहा जाता है, मनमाने ढंग से चुना जा सकता है।

नए अंकगणित में क्रमित जोड़े, लिखे गए तत्व सम्मिलित हैं , जैसा कि ऊपर वर्णित है, पहले घटक पर सामान्य अंकगणित और दूसरे घटक पर प्रथम क्रम अवकलन अंकगणित के साथ। बहुपदों पर उपरोक्त परिणामों को विश्लेषणात्मक कार्यों तक विस्तारित करने से बुनियादी अंकगणित और नए अंकगणित के लिए कुछ मानक कार्यों की एक सूची मिलती है,