E SAME ’और the VALID’ के बीच अंतर क्या है tf.nn.max_pool में टेंसोफ़्लो?


309

Difference SAME ’और the VALID’ के पेडिंग में क्या अंतर tf.nn.max_poolहै tensorflow?

मेरी राय में, 'VALID' का अर्थ है कि जब हम अधिकतम पूल करते हैं तो किनारों के बाहर कोई भी शून्य गद्दी नहीं होगी।

ए गाइड के अनुसार डीप लर्निंग के लिए अंकगणित के लिए , यह कहता है कि पूल ऑपरेटर में कोई पैडिंग नहीं होगी, यानी सिर्फ 'वैलिड' का उपयोग करें tensorflow। लेकिन अधिकतम पूल में 'SAME' पैडिंग क्या है tensorflow?


3
चेक tensorflow.org/api_guides/python/... जानकारी के लिए, यह कैसे tf यह किया है।
गैब्रियलचू


4
पैडिंग और स्ट्राइड कैसे काम करता है, यह समझने के लिए इन अद्भुत gifs को देखें। लिंक
दीपक

1
@GabrielChu आपका लिंक मर गया प्रतीत होता है और अब सामान्य अवलोकन के लिए पुनर्निर्देशित है।
मैट

2.0 में अपग्रेड होने के कारण, चीजों को केरस द्वारा बदल दिया जाएगा और मुझे विश्वास है कि आप केरस दस्तावेजों में पूलिंग की जानकारी पा सकते हैं। @ मट्ट
गेब्रियलचू

जवाबों:


163

मैं इसे स्पष्ट करने के लिए एक उदाहरण दूंगा:

  • x: आकृति की इनपुट छवि [2, 3], 1 चैनल
  • valid_pad: 2x2 कर्नेल, स्ट्राइड 2 और वैलिड पैडिंग के साथ अधिकतम पूल।
  • same_pad: 2x2 कर्नेल, स्ट्राइड 2 और एसएएमई पैडिंग के साथ अधिकतम पूल (यह जाने का क्लासिक तरीका है)

उत्पादन आकार हैं:

  • valid_pad: यहाँ, कोई पैडिंग नहीं है, इसलिए आउटपुट आकार [1, 1] है
  • same_pad: यहाँ, हम चित्र को आकृति [२, ४] ( -infअधिकतम पूल लागू करने के साथ ) में रखते हैं, इसलिए आउटपुट आकार [१, २] है

x = tf.constant([[1., 2., 3.],
                 [4., 5., 6.]])

x = tf.reshape(x, [1, 2, 3, 1])  # give a shape accepted by tf.nn.max_pool

valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

valid_pad.get_shape() == [1, 1, 1, 1]  # valid_pad is [5.]
same_pad.get_shape() == [1, 1, 2, 1]   # same_pad is  [5., 6.]


603

यदि आपको अस्सी कला पसंद है:

  • "VALID" = बिना गद्दी के:

       inputs:         1  2  3  4  5  6  7  8  9  10 11 (12 13)
                      |________________|                dropped
                                     |_________________|
  • "SAME" = शून्य गद्दी के साथ:

                   pad|                                      |pad
       inputs:      0 |1  2  3  4  5  6  7  8  9  10 11 12 13|0  0
                   |________________|
                                  |_________________|
                                                 |________________|

इस उदाहरण में:

  • इनपुट चौड़ाई = 13
  • फ़िल्टर चौड़ाई = 6
  • कठोर = ५

टिप्पणियाँ:

  • "VALID" केवल दाएं-सबसे कॉलम (या नीचे-सबसे पंक्तियों) को कभी छोड़ता है।
  • "SAME" समान रूप से बाएं और दाएं पैड करने की कोशिश करता है, लेकिन यदि स्तंभों की मात्रा विषम है, तो यह अतिरिक्त कॉलम को दाईं ओर जोड़ देगा, जैसा कि इस उदाहरण में है (एक ही तर्क लंबवत लागू होता है: एक अतिरिक्त पंक्ति हो सकती है तल पर शून्य)।

संपादित करें :

नाम के बारे में:

  • "SAME"पैडिंग के साथ , यदि आप 1 के स्ट्राइड का उपयोग करते हैं, तो लेयर के आउटपुट के इनपुट के समान स्थानिक आयाम होंगे।
  • "VALID"पैडिंग के साथ , कोई "मेड-अप" पैडिंग इनपुट नहीं है। परत केवल वैध इनपुट डेटा का उपयोग करती है

क्या यह कहना उचित है कि "SAME" का अर्थ है "शून्य-पैडिंग का उपयोग यह सुनिश्चित करने के लिए कि फ़िल्टर का आकार बदलना नहीं है यदि छवि चौड़ाई फ़िल्टर की चौड़ाई से अधिक नहीं है या छवि की ऊँचाई फ़िल्टर की ऊँचाई से अधिक नहीं है "? के रूप में "अगर फिल्टर चौड़ाई के कई तक शून्य के साथ पैड" अगर चौड़ाई समस्या है?
स्टैटसॉरसेरेस

2
मेरे स्वयं के प्रश्न का उत्तर देना: नहीं, यह शून्य पैडिंग की बात नहीं है। आप इनपुट (शून्य गद्दी सहित) के साथ काम करने के लिए फ़िल्टर आकार चुनते हैं, लेकिन आप फ़िल्टर आकार के बाद शून्य गद्दी का चयन नहीं करते हैं।
स्टैटसॉरसिएस

मुझे आपके अपने उत्तर @StatsSorceress समझ में नहीं आ रहे हैं। यह मुझे लगता है कि आप पर्याप्त शून्य जोड़ते हैं (संभव के रूप में सममित रूप में) ताकि सभी इनपुट कुछ फिल्टर द्वारा कवर किए जाएं, क्या मैं सही हूं?
गुइलिफ़िक्स

2
महान जवाब, बस जोड़ने के लिए: इस मामले में कि टेंसर मान नकारात्मक हो सकते हैं, अधिकतम_पुलिंग के लिए पैडिंग है -inf
टॉन्स 29

क्या होगा यदि इनपुट चौड़ाई एक समान संख्या है जब ksize = 2, stride = 2 और SAME पैडिंग के साथ? ... तो यह शून्य-गद्देदार सही नहीं होना चाहिए? .... मैं यह कह रहा हूं जब मैं डार्कफ्लो कोड रेपो देखता हूं। , वे अधिकतम पैड के लिए SAME पैड, स्ट्राइड = 2, ksize = 2 का उपयोग कर रहे हैं .... अधिकतम छवि की चौड़ाई 416 पिक्सेल चौड़ाई से 208 पिक्सेल तक कम हो जाने के बाद। क्या कोई इसे स्पष्ट कर सकता है?
केविंदी

161

जब stride1 है (पूलिंग की तुलना में अधिक विशिष्ट है), हम निम्नलिखित अंतर के बारे में सोच सकते हैं:

  • "SAME": आउटपुट का आकार इनपुट आकार के समान है । इसके लिए फ़िल्टर विंडो को इनपुट मैप से बाहर खिसकना पड़ता है, इसलिए पैड की आवश्यकता होती है।
  • "VALID": फ़िल्टर विंडो इनपुट मैप के अंदर मान्य स्थिति में रहती है , इसलिए आउटपुट का आकार छोटा हो जाता है filter_size - 1। कोई गद्दी नहीं होती है।

65
यह आखिरकार मददगार है। इस बिंदु तक, यह दिखाई दिया कि SAMEऔर VALIDसाथ ही कहा जा सकता है fooऔरbar
omatai

7
मुझे लगता है कि "आउटपुट का आकार इनपुट आकार के समान है " केवल सच है जब स्ट्राइड की लंबाई 1. है
omsrisagar

92

TensorFlow कनवल्शन उदाहरण के बीच अंतर के बारे में एक सिंहावलोकन देता है SAMEऔर VALID:

  • के लिए SAMEगद्दी, उत्पादन ऊंचाई और चौड़ाई की गणना इस प्रकार किया गया है:

    out_height = ceil(float(in_height) / float(strides[1]))
    out_width  = ceil(float(in_width) / float(strides[2]))

तथा

  • के लिए VALIDगद्दी, उत्पादन ऊंचाई और चौड़ाई की गणना इस प्रकार किया गया है:

    out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
    out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))

46

पैडिंग इनपुट डेटा के आकार को बढ़ाने के लिए एक ऑपरेशन है। 1-आयामी डेटा के मामले में आप केवल स्थिरांक के साथ सरणी को जोड़ते / पूर्व-निर्धारित करते हैं, 2-मंद में आप इन स्थिरांक के साथ मैट्रिक्स को घेरते हैं। N- मंद में आप स्थिरांक के साथ अपने n- मंद हाइपरक्यूब को घेरते हैं। अधिकांश मामलों में यह निरंतर शून्य होता है और इसे शून्य-गद्दी कहा जाता है।

यहां p=12-डी टेंसर के साथ शून्य-पैडिंग का एक उदाहरण दिया गया है : यहां छवि विवरण दर्ज करें


आप अपनी कर्नेल के लिए मनमाने ढंग से पैडिंग का उपयोग कर सकते हैं, लेकिन कुछ पैडिंग मानों का उपयोग अन्य लोगों की तुलना में अधिक बार किया जाता है:

  • वैलिड पैडिंग । सबसे आसान मामला है, इसका मतलब बिल्कुल नहीं है। बस अपने डेटा को वही छोड़ दें जो वह था।
  • कभी-कभी पेडिंग को HALF पैडिंग कहा जाता है । इसे एसएएमई कहा जाता है क्योंकि एक स्ट्राइड = 1 (या पूलिंग) के साथ एक कनवल्शन के लिए इसे इनपुट के समान आकार के आउटपुट का उत्पादन करना चाहिए। आकार के कर्नेल के लिए इसे HALF कहा जाता हैk यहां छवि विवरण दर्ज करें
  • फुल पैडिंग अधिकतम पैडिंग है जिसके परिणामस्वरूप सिर्फ गद्देदार तत्वों पर कोई विश्वास नहीं होता है। आकार की एक कर्नेल के लिए k, यह पैडिंग के बराबर है k - 1

टीएफ में मनमाने ढंग से पैडिंग का उपयोग करने के लिए, आप उपयोग कर सकते हैं tf.pad()


32

त्वरित स्पष्टीकरण

VALID: कोई भी पैडिंग लागू न करें, अर्थात, मान लें कि सभी आयाम मान्य हैं ताकि इनपुट छवि पूरी तरह से फ़िल्टर द्वारा कवर हो जाए और आपके द्वारा निर्दिष्ट स्ट्राइड हो जाए।

SAME: इनपुट (यदि आवश्यक हो) के लिए पैडिंग लागू करें ताकि इनपुट छवि पूरी तरह से फ़िल्टर द्वारा कवर हो जाए और आपके द्वारा निर्दिष्ट स्ट्राइड हो जाए। स्ट्राइड 1 के लिए, यह सुनिश्चित करेगा कि आउटपुट इमेज का आकार समान हो इनपुट के ।

टिप्पणियाँ

  • यह कंफर्ट लेयर्स के साथ-साथ मैक्स पूल लेयर्स पर भी इसी तरह से लागू होता है
  • "मान्य" शब्द थोड़ा गलत है क्योंकि अगर आप छवि का हिस्सा छोड़ देते हैं तो चीजें "अमान्य" नहीं हो जाती हैं। शायद ही कभी आप भी ऐसा चाहते होंगे। इसे शायद बुलाया जाना चाहिए थाNO_PADDING जगह ।
  • शब्द "वही" एक मिथ्या नाम भी है क्योंकि यह केवल 1 के स्ट्राइड के लिए समझ में आता है जब आउटपुट आयाम इनपुट आयाम के समान होता है। 2 के स्ट्राइड के लिए, आउटपुट आयाम आधा होगा, उदाहरण के लिए। इसकी AUTO_PADDINGजगह शायद बुलाया जाना चाहिए था ।
  • में SAME(यानी ऑटो पैड मोड), Tensorflow प्रसार गद्दी के लिए समान रूप से कोशिश दोनों छोड़ दिया और सही पर होगा।
  • में VALID(यानी कोई पैडिंग मोड), Tensorflow सही और / या नीचे कोशिकाओं ड्रॉप करता है, तो अपने फ़िल्टर और कदम पूरा कवर इनपुट छवि नहीं है जाएगा।

19

मैं इस जवाब को आधिकारिक टेंसोफ़्लो डॉक्स https://www.tensorflow.org/api_guides/python/nn#Convolution से उद्धृत कर रहा हूं, जो 'SAME' की पैडिंग के लिए आउटपुट ऊंचाई और चौड़ाई के रूप में गणना की गई है:

out_height = ceil(float(in_height) / float(strides[1]))
out_width  = ceil(float(in_width) / float(strides[2]))

और शीर्ष और बाएँ पर पैडिंग की गणना निम्नानुसार की जाती है:

pad_along_height = max((out_height - 1) * strides[1] +
                    filter_height - in_height, 0)
pad_along_width = max((out_width - 1) * strides[2] +
                   filter_width - in_width, 0)
pad_top = pad_along_height // 2
pad_bottom = pad_along_height - pad_top
pad_left = pad_along_width // 2
pad_right = pad_along_width - pad_left

'वैध' पैडिंग के लिए, आउटपुट ऊंचाई और चौड़ाई निम्नानुसार गणना की जाती है:

out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))

और गद्दी मूल्य हमेशा शून्य हैं।


1
सच कहूँ तो यह एकमात्र वैध और पूर्ण उत्तर है, चारों ओर सीमित नहीं है। और यह सब डॉक्स से एक उद्धरण है। +1
पी-जीएन

1
इस उत्तर को इधर-उधर करने के लिए बहुत उपयोगी है, विशेष रूप से क्योंकि आप जिस बिंदु को इंगित करते हैं वह अब काम नहीं करता है और ऐसा लगता है कि Google ने tf वेबसाइट से उस जानकारी को मिटा दिया है!
डैनियल

12

पैडिंग के तीन विकल्प हैं: वैध (नो पैडिंग), एक ही (या आधा), पूर्ण। आप स्पष्टीकरण (थीनो में) यहाँ पा सकते हैं: http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html

  • मान्य या कोई पेडिंग नहीं:

वैध गद्दी में कोई शून्य गद्दी शामिल नहीं है, इसलिए यह केवल वैध इनपुट को कवर करता है, कृत्रिम रूप से उत्पन्न शून्य को शामिल नहीं करता है। आउटपुट की लंबाई ((इनपुट की लंबाई) है - (k-1)) कर्नेल आकार k के लिए यदि स्ट्राइड s = 1।

  • एक ही या आधा गद्दी:

एक ही पैडिंग आउटपुट का आकार इनपुट के साथ समान होता है जब s = 1 होता है। यदि s = 1 है, तो zeros गद्देदार की संख्या (k-1) है।

  • पूर्ण गद्दी:

फुल पेडिंग का मतलब है कि कर्नेल पूरे इनपुट पर चलता है, इसलिए अंत में, कर्नेल केवल एक इनपुट और शून्य को पूरा कर सकता है। शून्य गद्देदार की संख्या 2 (k-1) है यदि s = 1। आउटपुट की लंबाई ((इनपुट की लंबाई) + (k-1) है अगर s = 1।

इसलिए, गद्दी की संख्या: (मान्य) <= (वही) <= (पूर्ण)


8

पैडिंग ऑन / ऑफ। आपके इनपुट के प्रभावी आकार को निर्धारित करता है।

VALID:कोई गद्दी नहीं। कन्वोक्यूशन आदि ऑप्स केवल उन स्थानों पर किए जाते हैं जो "मान्य" हैं, यानी आपके टेंसर की सीमाओं के बहुत करीब नहीं।
3x3 की कर्नेल के साथ और 10x10 की छवि के साथ, आप सीमाओं के अंदर 8x8 क्षेत्र पर दृढ़ संकल्प प्रदर्शन करेंगे।

SAME:पैडिंग प्रदान की जाती है। जब भी आपका ऑपरेशन किसी पड़ोस (चाहे कितना बड़ा हो) का संदर्भ देता है, तो शून्य मान प्रदान किया जाता है जब वह पड़ोस मूल टेंसर के बाहर तक फैलता है ताकि उस ऑपरेशन को सीमा मूल्यों पर भी काम करने की अनुमति मिल सके।
3x3 की कर्नेल के साथ और 10x10 की छवि के साथ, आप पूरे 10x10 क्षेत्र पर दृढ़ प्रदर्शन करेंगे।


8

वैलिड पैडिंग: यह जीरो पैडिंग के साथ है। आशा है कि कोई भ्रम नहीं है।

x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
print (valid_pad.get_shape()) # output-->(1, 2, 1, 1)

एक ही पैडिंग: यह पहली जगह में समझने के लिए एक तरह से मुश्किल है क्योंकि हमें आधिकारिक डॉक्स में उल्लिखित दो शर्तों पर अलग से विचार करना होगा ।

चलो इनपुट के रूप में , आउटपुट के रूप में , के रूप में गद्दी , के रूप में और कर्नेल आकार के रूप में (केवल एक ही आयाम माना जाता है)

केस 01 ::

केस 02 ::

की गणना इस प्रकार की जाती है कि न्यूनतम मान जो पैडिंग के लिए लिया जा सकता है। चूंकि मूल्य ज्ञात है, इस सूत्र का उपयोग करके मूल्य पाया जा सकता है

आइए इस उदाहरण पर काम करते हैं:

x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
print (same_pad.get_shape()) # --> output (1, 2, 2, 1)

यहाँ x का आयाम (3,4) है। फिर यदि क्षैतिज दिशा ली जाती है (3):

यदि लंबवत दिशा ली गई है (4):

आशा है कि यह समझने में मदद करेगा कि वास्तव में TF में SAME पैडिंग कैसे काम करता है।


7

यहाँ स्पष्टीकरण के आधार पर और ट्रिस्टन के उत्तर के आधार पर , मैं आमतौर पर पवित्रता जांच के लिए इन त्वरित कार्यों का उपयोग करता हूं।

# a function to help us stay clean
def getPaddings(pad_along_height,pad_along_width):
    # if even.. easy..
    if pad_along_height%2 == 0:
        pad_top = pad_along_height / 2
        pad_bottom = pad_top
    # if odd
    else:
        pad_top = np.floor( pad_along_height / 2 )
        pad_bottom = np.floor( pad_along_height / 2 ) +1
    # check if width padding is odd or even
    # if even.. easy..
    if pad_along_width%2 == 0:
        pad_left = pad_along_width / 2
        pad_right= pad_left
    # if odd
    else:
        pad_left = np.floor( pad_along_width / 2 )
        pad_right = np.floor( pad_along_width / 2 ) +1
        #
    return pad_top,pad_bottom,pad_left,pad_right

# strides [image index, y, x, depth]
# padding 'SAME' or 'VALID'
# bottom and right sides always get the one additional padded pixel (if padding is odd)
def getOutputDim (inputWidth,inputHeight,filterWidth,filterHeight,strides,padding):
    if padding == 'SAME':
        out_height = np.ceil(float(inputHeight) / float(strides[1]))
        out_width  = np.ceil(float(inputWidth) / float(strides[2]))
        #
        pad_along_height = ((out_height - 1) * strides[1] + filterHeight - inputHeight)
        pad_along_width = ((out_width - 1) * strides[2] + filterWidth - inputWidth)
        #
        # now get padding
        pad_top,pad_bottom,pad_left,pad_right = getPaddings(pad_along_height,pad_along_width)
        #
        print 'output height', out_height
        print 'output width' , out_width
        print 'total pad along height' , pad_along_height
        print 'total pad along width' , pad_along_width
        print 'pad at top' , pad_top
        print 'pad at bottom' ,pad_bottom
        print 'pad at left' , pad_left
        print 'pad at right' ,pad_right

    elif padding == 'VALID':
        out_height = np.ceil(float(inputHeight - filterHeight + 1) / float(strides[1]))
        out_width  = np.ceil(float(inputWidth - filterWidth + 1) / float(strides[2]))
        #
        print 'output height', out_height
        print 'output width' , out_width
        print 'no padding'


# use like so
getOutputDim (80,80,4,4,[1,1,1,1],'SAME')

6

योग करने के लिए, 'वैध' पैडिंग का अर्थ है, कोई पैडिंग नहीं। इनपुट आकार और कर्नेल आकार के आधार पर दृढ़ परत का आउटपुट आकार सिकुड़ता है।

इसके विपरीत, 'समान' पैडिंग का अर्थ है पैडिंग का उपयोग करना। जब स्ट्राइड को 1 के रूप में सेट किया जाता है, तो कनवल्शन की गणना करते समय इनपुट डेटा के चारों ओर '0-बॉर्डर' की एक निश्चित संख्या को जोड़कर, अवक्षेपणीय परत का आउटपुट आकार इनपुट आकार के रूप में बना रहता है।

आशा है कि यह सहज वर्णन मदद करता है।


5

सामान्य सूत्र

यहां, डब्ल्यू और एच इनपुट की चौड़ाई और ऊंचाई हैं, एफ फिल्टर आयाम हैं, पी पैडिंग आकार है (यानी, गद्देदार होने के लिए पंक्तियों या स्तंभों की संख्या)

SAME पैडिंग के लिए:

एक ही पैडिंग

मान्य पैडिंग के लिए:

वैलिड पैडिंग


2

YvesgereY के शानदार उत्तर को लागू करते हुए, मुझे यह दृश्य अत्यंत मददगार लगा:

पैडिंग दृश्य

पैडिंग ' मान्य है ' पहला आंकड़ा है। फ़िल्टर विंडो छवि के अंदर रहती है।

पैडिंग ' वही ' तीसरा आंकड़ा है। आउटपुट एक ही आकार का है।


यह इस लेख पर मिला ।


0

Tensorflow 2.0 संगत जवाब : विस्तृत विवरण ऊपर दिए गए हैं, "मान्य" और "समान" पैडिंग के बारे में।

हालाँकि, मैं Tensorflow 2.x (>= 2.0)समुदाय के लाभ के लिए अलग-अलग पूलिंग फ़ंक्शंस और उनके संबंधित कमांड निर्दिष्ट करूंगा ।

1.x में कार्य :

tf.nn.max_pool

tf.keras.layers.MaxPool2D

Average Pooling => None in tf.nn, tf.keras.layers.AveragePooling2D

2.x में कार्य :

tf.nn.max_poolयदि 2.x में प्रयोग किया जाता है और tf.compat.v1.nn.max_pool_v2या tf.compat.v2.nn.max_pool, 1.x से 2. x के लिए चले, तो

tf.keras.layers.MaxPool2D अगर 2.x और में उपयोग किया जाता है

tf.compat.v1.keras.layers.MaxPool2Dया tf.compat.v1.keras.layers.MaxPooling2Dया tf.compat.v2.keras.layers.MaxPool2Dया tf.compat.v2.keras.layers.MaxPooling2D, 1.x से 2. x के लिए चले, तो

Average Pooling => tf.nn.avg_pool2dया tf.keras.layers.AveragePooling2Dयदि TF 2.x और में उपयोग किया जाता है

tf.compat.v1.nn.avg_pool_v2या tf.compat.v2.nn.avg_poolया tf.compat.v1.keras.layers.AveragePooling2Dया tf.compat.v1.keras.layers.AvgPool2Dया tf.compat.v2.keras.layers.AveragePooling2Dया tf.compat.v2.keras.layers.AvgPool2D, 1.x से 2. x के लिए चले, तो

Tensorflow 1.x से 2.x में माइग्रेशन के बारे में अधिक जानकारी के लिए, कृपया इस माइग्रेशन गाइड को देखें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.