TensorFlow वितरण आकार को समझना

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें
import collections

import tensorflow as tf
tf.compat.v2.enable_v2_behavior()

import tensorflow_probability as tfp
tfd = tfp.distributions
tfb = tfp.bijectors

मूल बातें

TensorFlow वितरण आकृतियों से जुड़ी तीन महत्वपूर्ण अवधारणाएँ हैं:

  • घटना आकार वितरण से एक भी ड्रॉ के आकार का वर्णन करता है; यह आयामों पर निर्भर हो सकता है। अदिश वितरणों के लिए, घटना आकार है [] । एक 5-आयामी MultivariateNormal के लिए, घटना आकार है [5]
  • बैच आकार स्वतंत्र, हूबहू वितरित नहीं करता है, एक वितरण के "बैच" उर्फ वर्णन करता है।
  • नमूना आकार स्वतंत्र वर्णन करता है, हूबहू वितरित वितरण परिवार से बैचों की खींचता है।

घटना आकार और बैच आकार एक की संपत्ति हैं Distribution जबकि नमूना आकार के एक विशिष्ट कॉल साथ जुड़ा हुआ है, वस्तु sample या log_prob

इस नोटबुक का उद्देश्य उदाहरणों के माध्यम से इन अवधारणाओं को स्पष्ट करना है, इसलिए यदि यह तुरंत स्पष्ट नहीं है, तो चिंता न करें!

इन अवधारणाओं के एक और वैचारिक अवलोकन के लिए, को देखने के इस ब्लॉग पोस्ट

TensorFlow ईगर पर एक नोट।

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

अदिश वितरण

जैसा कि हम ऊपर वर्णित है, एक Distribution वस्तु घटना और बैच आकार को परिभाषित किया है। हम वितरण का वर्णन करने के लिए एक उपयोगिता के साथ शुरू करेंगे:

def describe_distributions(distributions):
  print('\n'.join([str(d) for d in distributions]))

की एक घटना आकार के साथ वितरण: इस भाग में हम अदिश वितरण का पता लगाने जाएगा [] । एक विशिष्ट उदाहरण प्वासों बंटन, एक द्वारा निर्दिष्ट है rate :

poisson_distributions = [
    tfd.Poisson(rate=1., name='One Poisson Scalar Batch'),
    tfd.Poisson(rate=[1., 10., 100.], name='Three Poissons'),
    tfd.Poisson(rate=[[1., 10., 100.,], [2., 20., 200.]],
                name='Two-by-Three Poissons'),
    tfd.Poisson(rate=[1.], name='One Poisson Vector Batch'),
    tfd.Poisson(rate=[[1.]], name='One Poisson Expanded Batch')
]

describe_distributions(poisson_distributions)
tfp.distributions.Poisson("One_Poisson_Scalar_Batch", batch_shape=[], event_shape=[], dtype=float32)
tfp.distributions.Poisson("Three_Poissons", batch_shape=[3], event_shape=[], dtype=float32)
tfp.distributions.Poisson("Two_by_Three_Poissons", batch_shape=[2, 3], event_shape=[], dtype=float32)
tfp.distributions.Poisson("One_Poisson_Vector_Batch", batch_shape=[1], event_shape=[], dtype=float32)
tfp.distributions.Poisson("One_Poisson_Expanded_Batch", batch_shape=[1, 1], event_shape=[], dtype=float32)

इसलिए इसकी घटना आकार हमेशा होता है प्वासों बंटन, एक अदिश वितरण है [] । यदि हम अधिक दरें निर्दिष्ट करते हैं, तो ये बैच आकार में दिखाई देती हैं। उदाहरणों की अंतिम जोड़ी दिलचस्प है: केवल एक ही दर है, लेकिन क्योंकि वह दर गैर-रिक्त आकार के साथ एक numpy सरणी में एम्बेडेड है, वह आकार बैच आकार बन जाता है।

मानक सामान्य वितरण भी एक अदिश राशि है। यह घटना आकार है [] बस प्वासों के लिए की तरह, है, लेकिन हम प्रसारण की हमारी पहली उदाहरण देखने के लिए इसके साथ चलने लगेगा। सामान्य का उपयोग कर निर्दिष्ट किया जाता है loc और scale पैरामीटर:

normal_distributions = [
    tfd.Normal(loc=0., scale=1., name='Standard'),
    tfd.Normal(loc=[0.], scale=1., name='Standard Vector Batch'),
    tfd.Normal(loc=[0., 1., 2., 3.], scale=1., name='Different Locs'),
    tfd.Normal(loc=[0., 1., 2., 3.], scale=[[1.], [5.]],
               name='Broadcasting Scale')
]

describe_distributions(normal_distributions)
tfp.distributions.Normal("Standard", batch_shape=[], event_shape=[], dtype=float32)
tfp.distributions.Normal("Standard_Vector_Batch", batch_shape=[1], event_shape=[], dtype=float32)
tfp.distributions.Normal("Different_Locs", batch_shape=[4], event_shape=[], dtype=float32)
tfp.distributions.Normal("Broadcasting_Scale", batch_shape=[2, 4], event_shape=[], dtype=float32)

दिलचस्प उदाहरण से ऊपर है Broadcasting Scale वितरण। loc पैरामीटर आकार [4] , और scale पैरामीटर आकार [2, 1] । का उपयोग करते हुए Numpy प्रसारण नियमों , बैच आकार है [2, 4] । परिभाषित करने के लिए एक बराबर (लेकिन कम सुरुचिपूर्ण और नहीं-अनुशंसित) जिस तरह से "Broadcasting Scale" वितरण होगा:

describe_distributions(
    [tfd.Normal(loc=[[0., 1., 2., 3], [0., 1., 2., 3.]],
                scale=[[1., 1., 1., 1.], [5., 5., 5., 5.]])])
tfp.distributions.Normal("Normal", batch_shape=[2, 4], event_shape=[], dtype=float32)

हम देख सकते हैं कि प्रसारण संकेतन क्यों उपयोगी है, हालांकि यह सिरदर्द और बग का एक स्रोत भी है।

नमूना स्केलर वितरण

दो मुख्य बातें हम वितरण के साथ कर सकते हैं: हम कर सकते हैं sample उन लोगों से है और हम गणना कर सकता है log_prob रों। आइए पहले नमूने का पता लगाएं। बुनियादी नियम है जब हम एक वितरण से नमूना है, जिसके परिणामस्वरूप टेन्सर आकार है कि [sample_shape, batch_shape, event_shape] जहां, batch_shape और event_shape द्वारा प्रदान की जाती Distribution वस्तु, और sample_shape करने के लिए कॉल द्वारा प्रदान की गई sample । अदिश वितरणों के लिए, event_shape = [] , इसलिए टेन्सर नमूना से लौटे आकार होगा [sample_shape, batch_shape] । चलो यह कोशिश करते हैं:

def describe_sample_tensor_shape(sample_shape, distribution):
    print('Sample shape:', sample_shape)
    print('Returned sample tensor shape:',
          distribution.sample(sample_shape).shape)

def describe_sample_tensor_shapes(distributions, sample_shapes):
    started = False
    for distribution in distributions:
      print(distribution)
      for sample_shape in sample_shapes:
        describe_sample_tensor_shape(sample_shape, distribution)
      print()

sample_shapes = [1, 2, [1, 5], [3, 4, 5]]
describe_sample_tensor_shapes(poisson_distributions, sample_shapes)
tfp.distributions.Poisson("One_Poisson_Scalar_Batch", batch_shape=[], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1,)
Sample shape: 2
Returned sample tensor shape: (2,)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5)

tfp.distributions.Poisson("Three_Poissons", batch_shape=[3], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 3)
Sample shape: 2
Returned sample tensor shape: (2, 3)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 3)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 3)

tfp.distributions.Poisson("Two_by_Three_Poissons", batch_shape=[2, 3], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 2, 3)
Sample shape: 2
Returned sample tensor shape: (2, 2, 3)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 2, 3)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 2, 3)

tfp.distributions.Poisson("One_Poisson_Vector_Batch", batch_shape=[1], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 1)
Sample shape: 2
Returned sample tensor shape: (2, 1)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 1)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 1)

tfp.distributions.Poisson("One_Poisson_Expanded_Batch", batch_shape=[1, 1], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 1, 1)
Sample shape: 2
Returned sample tensor shape: (2, 1, 1)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 1, 1)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 1, 1)
describe_sample_tensor_shapes(normal_distributions, sample_shapes)
tfp.distributions.Normal("Standard", batch_shape=[], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1,)
Sample shape: 2
Returned sample tensor shape: (2,)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5)

tfp.distributions.Normal("Standard_Vector_Batch", batch_shape=[1], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 1)
Sample shape: 2
Returned sample tensor shape: (2, 1)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 1)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 1)

tfp.distributions.Normal("Different_Locs", batch_shape=[4], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 4)
Sample shape: 2
Returned sample tensor shape: (2, 4)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 4)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 4)

tfp.distributions.Normal("Broadcasting_Scale", batch_shape=[2, 4], event_shape=[], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 2, 4)
Sample shape: 2
Returned sample tensor shape: (2, 2, 4)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 2, 4)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 2, 4)

सब के बारे में के बारे में कहने के लिए है कि sample : लौटे नमूना tensors आकार [sample_shape, batch_shape, event_shape]

कम्प्यूटिंग log_prob अदिश वितरण के लिए

अब चलो पर एक नज़र डालते हैं log_prob , जो कुछ हद तक जटिल काम है। log_prob इनपुट के रूप में एक (गैर खाली) टेन्सर स्थान (रों), जिस पर गणना करने के लिए प्रतिनिधित्व करने लग जाते हैं log_prob वितरण के लिए। सबसे सरल मामले में, इस टेन्सर प्रपत्र की एक आकार होगा [sample_shape, batch_shape, event_shape] , जहां batch_shape और event_shape मैच वितरण के बैच और घटना आकार। याद एक बार फिर कि अदिश वितरण के लिए, event_shape = [] , तो इनपुट टेन्सर आकार [sample_shape, batch_shape] इस मामले में, हम आकार का एक टेन्सर वापस मिल [sample_shape, batch_shape] :

three_poissons = tfd.Poisson(rate=[1., 10., 100.], name='Three Poissons')
three_poissons
<tfp.distributions.Poisson 'Three_Poissons' batch_shape=[3] event_shape=[] dtype=float32>
three_poissons.log_prob([[1., 10., 100.], [100., 10., 1]])  # sample_shape is [2].
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[  -1.       ,   -2.0785608,   -3.2223587],
       [-364.73938  ,   -2.0785608,  -95.39484  ]], dtype=float32)>
three_poissons.log_prob([[[[1., 10., 100.], [100., 10., 1.]]]])  # sample_shape is [1, 1, 2].
<tf.Tensor: shape=(1, 1, 2, 3), dtype=float32, numpy=
array([[[[  -1.       ,   -2.0785608,   -3.2223587],
         [-364.73938  ,   -2.0785608,  -95.39484  ]]]], dtype=float32)>

नोट कैसे पहले उदाहरण में, इनपुट और आउटपुट आकार [2, 3] और दूसरे उदाहरण वे आकार में [1, 1, 2, 3]

बस इतना ही कहना था, अगर यह प्रसारण के लिए नहीं होता। एक बार जब हम प्रसारण को ध्यान में रखते हैं तो ये नियम हैं। हम इसे पूर्ण व्यापकता में वर्णित करते हैं और अदिश वितरण के लिए सरलीकरण नोट करते हैं:

  1. परिभाषित n = len(batch_shape) + len(event_shape) । (अदिश वितरणों के लिए, len(event_shape)=0 ।)
  2. इनपुट टेन्सर तो t की तुलना में कम है n आयाम, पैड अपने आकार आकार के आयाम जोड़कर 1 छोड़ दिया पर यह वास्तव में है जब तक n आयाम। जिसके परिणामस्वरूप टेन्सर कॉल t'
  3. प्रसारण n की सबसे दायीं ओर आयाम t' के खिलाफ [batch_shape, event_shape] वितरण आप एक कंप्यूटिंग रहे हैं की log_prob के लिए। और अधिक विस्तार से: आयाम जहां के लिए t' पहले से ही वितरण से मेल खाता है, कुछ भी नहीं, और आयाम जहां के लिए t' एक सिंगलटन को दोहराने की है, कि कई बार की उपयुक्त संख्या सिंगलटन। कोई अन्य स्थिति एक त्रुटि है। (अदिश वितरण के लिए, हम केवल के खिलाफ प्रसारित batch_shape , event_shape = के बाद से [] ।)
  4. अब हम अंत में गणना करने के लिए कर रहे हैं log_prob । जिसके परिणामस्वरूप टेन्सर आकार होगा [sample_shape, batch_shape] , जहां sample_shape के किसी भी आयाम होने के लिए परिभाषित किया गया है t या t' की बाईं करने के लिए n : -rightmost आयाम sample_shape = shape(t)[:-n]

यदि आप इसका अर्थ नहीं जानते हैं तो यह एक गड़बड़ हो सकती है, तो आइए कुछ उदाहरणों पर काम करते हैं:

three_poissons.log_prob([10.])
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([-16.104412 ,  -2.0785608, -69.05272  ], dtype=float32)>

टेन्सर [10.] (आकार के साथ [1] ) भर में प्रसारित किया जाता है batch_shape 3 की, तो हम मान 10 पर सभी तीन Poissons 'लॉग संभावना का मूल्यांकन।

three_poissons.log_prob([[[1.], [10.]], [[100.], [1000.]]])
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[-1.0000000e+00, -7.6974149e+00, -9.5394836e+01],
        [-1.6104412e+01, -2.0785608e+00, -6.9052719e+01]],

       [[-3.6473938e+02, -1.4348087e+02, -3.2223587e+00],
        [-5.9131279e+03, -3.6195427e+03, -1.4069575e+03]]], dtype=float32)>

उपरोक्त उदाहरण में, इनपुट टेन्सर आकार [2, 2, 1] , जबकि वितरण वस्तु से प्रत्येक के लिए 3. तो का एक बैच आकार [2, 2] नमूना आयाम है, बशर्ते एकल मान broadcats प्रत्येक के लिए हो जाता है तीन पॉइसों में से।

एक संभवतः उपयोगी तरीका यह सोचने के लिए: क्योंकि three_poissons है batch_shape = [2, 3] , के लिए एक कॉल log_prob एक टेन्सर जिसका आखिरी आयाम या तो 1 या 3 है रखना चाहिए; कुछ और त्रुटि है। (Numpy प्रसारण नियमों को पूरी तरह से आकार का एक टेन्सर के बराबर होने के रूप में एक अदिश के विशेष मामले का इलाज [1] ।)

आइए परीक्षण के साथ और अधिक जटिल प्वासों बंटन के साथ खेल से हमारे चॉप batch_shape = [2, 3] :

poisson_2_by_3 = tfd.Poisson(
    rate=[[1., 10., 100.,], [2., 20., 200.]],
    name='Two-by-Three Poissons')
poisson_2_by_3.log_prob(1.)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[  -1.       ,   -7.697415 ,  -95.39484  ],
       [  -1.3068528,  -17.004269 , -194.70169  ]], dtype=float32)>
poisson_2_by_3.log_prob([1.])  # Exactly equivalent to above, demonstrating the scalar special case.
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[  -1.       ,   -7.697415 ,  -95.39484  ],
       [  -1.3068528,  -17.004269 , -194.70169  ]], dtype=float32)>
poisson_2_by_3.log_prob([[1., 1., 1.], [1., 1., 1.]])  # Another way to write the same thing. No broadcasting.
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[  -1.       ,   -7.697415 ,  -95.39484  ],
       [  -1.3068528,  -17.004269 , -194.70169  ]], dtype=float32)>
poisson_2_by_3.log_prob([[1., 10., 100.]])  # Input is [1, 3] broadcast to [2, 3].
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ -1.       ,  -2.0785608,  -3.2223587],
       [ -1.3068528,  -5.14709  , -33.90767  ]], dtype=float32)>
poisson_2_by_3.log_prob([[1., 10., 100.], [1., 10., 100.]])  # Equivalent to above. No broadcasting.
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ -1.       ,  -2.0785608,  -3.2223587],
       [ -1.3068528,  -5.14709  , -33.90767  ]], dtype=float32)>
poisson_2_by_3.log_prob([[1., 1., 1.], [2., 2., 2.]])  # No broadcasting.
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[  -1.       ,   -7.697415 ,  -95.39484  ],
       [  -1.3068528,  -14.701683 , -190.09653  ]], dtype=float32)>
poisson_2_by_3.log_prob([[1.], [2.]])  # Equivalent to above. Input shape [2, 1] broadcast to [2, 3].
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[  -1.       ,   -7.697415 ,  -95.39484  ],
       [  -1.3068528,  -14.701683 , -190.09653  ]], dtype=float32)>

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

poisson_2_by_3.log_prob([[[1., 1., 1.], [1., 1., 1.]], [[2., 2., 2.], [2., 2., 2.]]])  # Input shape [2, 2, 3].
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[  -1.       ,   -7.697415 ,  -95.39484  ],
        [  -1.3068528,  -17.004269 , -194.70169  ]],

       [[  -1.6931472,   -6.087977 ,  -91.48282  ],
        [  -1.3068528,  -14.701683 , -190.09653  ]]], dtype=float32)>

या हम प्रसारण को अंतिम बैच आयाम को संभालने दे सकते हैं:

poisson_2_by_3.log_prob([[[1.], [1.]], [[2.], [2.]]])  # Input shape [2, 2, 1].
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[  -1.       ,   -7.697415 ,  -95.39484  ],
        [  -1.3068528,  -17.004269 , -194.70169  ]],

       [[  -1.6931472,   -6.087977 ,  -91.48282  ],
        [  -1.3068528,  -14.701683 , -190.09653  ]]], dtype=float32)>

हम (शायद कुछ हद तक स्वाभाविक रूप से) प्रसारण को केवल पहले बैच आयाम को संभालने दे सकते हैं:

poisson_2_by_3.log_prob([[[1., 1., 1.]], [[2., 2., 2.]]])  # Input shape [2, 1, 3].
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[  -1.       ,   -7.697415 ,  -95.39484  ],
        [  -1.3068528,  -17.004269 , -194.70169  ]],

       [[  -1.6931472,   -6.087977 ,  -91.48282  ],
        [  -1.3068528,  -14.701683 , -190.09653  ]]], dtype=float32)>

या फिर हम संभाल दोनों बैच आयाम प्रसारण दे सकता है:

poisson_2_by_3.log_prob([[[1.]], [[2.]]])  # Input shape [2, 1, 1].
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[  -1.       ,   -7.697415 ,  -95.39484  ],
        [  -1.3068528,  -17.004269 , -194.70169  ]],

       [[  -1.6931472,   -6.087977 ,  -91.48282  ],
        [  -1.3068528,  -14.701683 , -190.09653  ]]], dtype=float32)>

उपरोक्त ने ठीक काम किया जब हमारे पास केवल दो मूल्य थे जो हम चाहते थे, लेकिन मान लीजिए कि हमारे पास मूल्यों की एक लंबी सूची थी जिसे हम प्रत्येक बैच बिंदु पर मूल्यांकन करना चाहते थे। उसके लिए, निम्न संकेतन, जो आकार 1 के अतिरिक्त आयामों को आकृति के दाईं ओर जोड़ता है, अत्यंत उपयोगी है:

poisson_2_by_3.log_prob(tf.constant([1., 2.])[..., tf.newaxis, tf.newaxis])
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[  -1.       ,   -7.697415 ,  -95.39484  ],
        [  -1.3068528,  -17.004269 , -194.70169  ]],

       [[  -1.6931472,   -6.087977 ,  -91.48282  ],
        [  -1.3068528,  -14.701683 , -190.09653  ]]], dtype=float32)>

इस का एक उदाहरण है strided टुकड़ा अंकन , जो जानने लायक है।

करने के लिए वापस जा रहे हैं three_poissons संपूर्णता के लिए, की तरह एक ही उदाहरण दिखता है:

three_poissons.log_prob([[1.], [10.], [50.], [100.]])
<tf.Tensor: shape=(4, 3), dtype=float32, numpy=
array([[  -1.       ,   -7.697415 ,  -95.39484  ],
       [ -16.104412 ,   -2.0785608,  -69.05272  ],
       [-149.47777  ,  -43.34851  ,  -18.219261 ],
       [-364.73938  , -143.48087  ,   -3.2223587]], dtype=float32)>
three_poissons.log_prob(tf.constant([1., 10., 50., 100.])[..., tf.newaxis])  # Equivalent to above.
<tf.Tensor: shape=(4, 3), dtype=float32, numpy=
array([[  -1.       ,   -7.697415 ,  -95.39484  ],
       [ -16.104412 ,   -2.0785608,  -69.05272  ],
       [-149.47777  ,  -43.34851  ,  -18.219261 ],
       [-364.73938  , -143.48087  ,   -3.2223587]], dtype=float32)>

बहुभिन्नरूपी वितरण

अब हम बहुभिन्नरूपी वितरणों की ओर मुड़ते हैं, जिनमें गैर-रिक्त घटना आकार होता है। आइए बहुराष्ट्रीय वितरणों को देखें।

multinomial_distributions = [
    # Multinomial is a vector-valued distribution: if we have k classes,
    # an individual sample from the distribution has k values in it, so the
    # event_shape is `[k]`.
    tfd.Multinomial(total_count=100., probs=[.5, .4, .1],
                    name='One Multinomial'),
    tfd.Multinomial(total_count=[100., 1000.], probs=[.5, .4, .1],
                    name='Two Multinomials Same Probs'),
    tfd.Multinomial(total_count=100., probs=[[.5, .4, .1], [.1, .2, .7]],
                    name='Two Multinomials Same Counts'),
    tfd.Multinomial(total_count=[100., 1000.],
                    probs=[[.5, .4, .1], [.1, .2, .7]],
                    name='Two Multinomials Different Everything')

]

describe_distributions(multinomial_distributions)
tfp.distributions.Multinomial("One_Multinomial", batch_shape=[], event_shape=[3], dtype=float32)
tfp.distributions.Multinomial("Two_Multinomials_Same_Probs", batch_shape=[2], event_shape=[3], dtype=float32)
tfp.distributions.Multinomial("Two_Multinomials_Same_Counts", batch_shape=[2], event_shape=[3], dtype=float32)
tfp.distributions.Multinomial("Two_Multinomials_Different_Everything", batch_shape=[2], event_shape=[3], dtype=float32)

नोट कैसे पिछले तीन उदाहरण में, batch_shape हमेशा होता है [2] , लेकिन हम या तो एक साझा करने के लिए प्रसारण का उपयोग कर सकते total_count या किसी साझा probs क्योंकि हुड के नीचे वे एक ही आकार के लिए प्रसारित किया जाता है, (या कोई भी नहीं)।

नमूनाकरण सीधा है, जिसे हम पहले से जानते हैं:

describe_sample_tensor_shapes(multinomial_distributions, sample_shapes)
tfp.distributions.Multinomial("One_Multinomial", batch_shape=[], event_shape=[3], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 3)
Sample shape: 2
Returned sample tensor shape: (2, 3)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 3)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 3)

tfp.distributions.Multinomial("Two_Multinomials_Same_Probs", batch_shape=[2], event_shape=[3], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 2, 3)
Sample shape: 2
Returned sample tensor shape: (2, 2, 3)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 2, 3)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 2, 3)

tfp.distributions.Multinomial("Two_Multinomials_Same_Counts", batch_shape=[2], event_shape=[3], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 2, 3)
Sample shape: 2
Returned sample tensor shape: (2, 2, 3)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 2, 3)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 2, 3)

tfp.distributions.Multinomial("Two_Multinomials_Different_Everything", batch_shape=[2], event_shape=[3], dtype=float32)
Sample shape: 1
Returned sample tensor shape: (1, 2, 3)
Sample shape: 2
Returned sample tensor shape: (2, 2, 3)
Sample shape: [1, 5]
Returned sample tensor shape: (1, 5, 2, 3)
Sample shape: [3, 4, 5]
Returned sample tensor shape: (3, 4, 5, 2, 3)

कंप्यूटिंग लॉग संभावनाएं समान रूप से सीधी हैं। आइए विकर्ण बहुभिन्नरूपी सामान्य वितरण के साथ एक उदाहरण पर काम करें। (मल्टीनोमियल्स बहुत ब्रॉडकास्ट फ्रेंडली नहीं हैं, क्योंकि काउंट्स और प्रायिकता पर बाधाओं का मतलब है कि ब्रॉडकास्टिंग अक्सर अस्वीकार्य मान उत्पन्न करेगा।) हम एक ही माध्य लेकिन विभिन्न पैमानों (मानक विचलन) के साथ 2 3-आयामी वितरणों के एक बैच का उपयोग करेंगे:

two_multivariate_normals = tfd.MultivariateNormalDiag(loc=[1., 2., 3.], scale_identity_multiplier=[1., 2.])
two_multivariate_normals
<tfp.distributions.MultivariateNormalDiag 'MultivariateNormalDiag' batch_shape=[2] event_shape=[3] dtype=float32>

(नोट कि हालांकि हम वितरण जहां तराजू पहचान के गुणकों थे, इस पर एक प्रतिबंध नहीं है, हम दे सकते हैं scale के बजाय scale_identity_multiplier ।)

अब आइए प्रत्येक बैच बिंदु की लॉग प्रायिकता का मूल्यांकन उसके माध्य और एक स्थानांतरित माध्य पर करें:

two_multivariate_normals.log_prob([[[1., 2., 3.]], [[3., 4., 5.]]])  # Input has shape [2,1,3].
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[-2.7568154, -4.836257 ],
       [-8.756816 , -6.336257 ]], dtype=float32)>

वास्तव में समतुल्य रूप में, हम उपयोग कर सकते हैं https://www.tensorflow.org/api_docs/cc/class/tensorflow/ops/strided-slice एक अतिरिक्त आकार = एक निरंतर के बीच में 1 आयाम सम्मिलित करने के लिए:

two_multivariate_normals.log_prob(
    tf.constant([[1., 2., 3.], [3., 4., 5.]])[:, tf.newaxis, :])  # Equivalent to above.
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[-2.7568154, -4.836257 ],
       [-8.756816 , -6.336257 ]], dtype=float32)>

दूसरी ओर, अगर हम अतिरिक्त आयाम डालने नहीं करते हैं, हम पारित [1., 2., 3.] पहले बैच बात करने के लिए और [3., 4., 5.] दूसरी रहे हैं:

two_multivariate_normals.log_prob(tf.constant([[1., 2., 3.], [3., 4., 5.]]))
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-2.7568154, -6.336257 ], dtype=float32)>

आकार हेरफेर तकनीक

द रीशेप बिजेक्टर

Reshape bijector एक वितरण की event_shape नयी आकृति प्रदान करने के लिए इस्तेमाल किया जा सकता है। आइए एक उदाहरण देखें:

six_way_multinomial = tfd.Multinomial(total_count=1000., probs=[.3, .25, .2, .15, .08, .02])
six_way_multinomial
<tfp.distributions.Multinomial 'Multinomial' batch_shape=[] event_shape=[6] dtype=float32>

हम की एक घटना आकार के साथ एक बहुपद बनाया [6] । नयी आकृति प्रदान Bijector हम में से एक घटना आकार के साथ एक वितरण के रूप में इस का इलाज करने के लिए अनुमति देता है [2, 3]

एक Bijector एक विभेदक, एक-से-एक का एक खुला सबसेट पर समारोह का प्रतिनिधित्व करता है \({\mathbb R}^n\)। Bijectors साथ संयोजन के रूप में उपयोग किया जाता TransformedDistribution , जो मॉडल एक वितरण \(p(y)\) एक आधार वितरण के मामले में \(p(x)\) और एक Bijector प्रतिनिधित्व करता है कि \(Y = g(X)\)। आइए इसे क्रिया में देखें:

transformed_multinomial = tfd.TransformedDistribution(
    distribution=six_way_multinomial,
    bijector=tfb.Reshape(event_shape_out=[2, 3]))
transformed_multinomial
<tfp.distributions.TransformedDistribution 'reshapeMultinomial' batch_shape=[] event_shape=[2, 3] dtype=float32>
six_way_multinomial.log_prob([500., 100., 100., 150., 100., 50.])
<tf.Tensor: shape=(), dtype=float32, numpy=-178.22021>
transformed_multinomial.log_prob([[500., 100., 100.], [150., 100., 50.]])
<tf.Tensor: shape=(), dtype=float32, numpy=-178.22021>

यह केवल एक चीज है Reshape bijector कर सकते हैं: यह बैच आयाम या इसके विपरीत में घटना आयाम चालू नहीं कर सकता।

स्वतंत्र वितरण

Independent वितरण एक भी वितरण के रूप में एक वितरण स्वतंत्र, गैर जरूरी-समान के संग्रह (उर्फ का एक बैच) के इलाज के लिए प्रयोग किया जाता है। अधिक संक्षेप में, Independent में आयाम कन्वर्ट करने के लिए अनुमति देता है batch_shape में आयामों को event_shape । हम उदाहरण के द्वारा वर्णन करेंगे:

two_by_five_bernoulli = tfd.Bernoulli(
    probs=[[.05, .1, .15, .2, .25], [.3, .35, .4, .45, .5]],
    name="Two By Five Bernoulli")
two_by_five_bernoulli
<tfp.distributions.Bernoulli 'Two_By_Five_Bernoulli' batch_shape=[2, 5] event_shape=[] dtype=int32>

हम इसे दो-बाई-पांच प्रकार के सिक्कों के रूप में सोच सकते हैं जिनमें शीर्षों की संबद्ध प्रायिकताएं होती हैं। आइए एक और शून्य के एक विशेष, मनमाना समुच्चय की प्रायिकता का मूल्यांकन करें:

pattern = [[1., 0., 0., 1., 0.], [0., 0., 1., 1., 1.]]
two_by_five_bernoulli.log_prob(pattern)
<tf.Tensor: shape=(2, 5), dtype=float32, numpy=
array([[-2.9957323 , -0.10536052, -0.16251892, -1.609438  , -0.2876821 ],
       [-0.35667497, -0.4307829 , -0.9162907 , -0.7985077 , -0.6931472 ]],
      dtype=float32)>

हम उपयोग कर सकते हैं Independent है, जो उपयोगी है दो अलग अलग "पाँच Bernoulli के के सेट" में इस बारी करने के अगर हम एक सिक्के के "पंक्ति" पर विचार करना चाहते flips एक भी परिणाम के रूप में किसी दिए गए पैटर्न में आ रहा है:

two_sets_of_five = tfd.Independent(
    distribution=two_by_five_bernoulli,
    reinterpreted_batch_ndims=1,
    name="Two Sets Of Five")
two_sets_of_five
<tfp.distributions.Independent 'Two_Sets_Of_Five' batch_shape=[2] event_shape=[5] dtype=int32>

गणितीय रूप से, हम सेट में पांच "स्वतंत्र" सिक्का फ़्लिप की लॉग संभावनाओं को जोड़कर पांच के प्रत्येक "सेट" की लॉग संभावना की गणना कर रहे हैं, जहां वितरण का नाम मिलता है:

two_sets_of_five.log_prob(pattern)
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-5.160732 , -3.1954036], dtype=float32)>

हम आगे भी जा सकते हैं और उपयोग कर सकते हैं Independent एक वितरण बनाने के लिए जहां अलग-अलग घटनाओं में दो-दर-पाँच Bernoulli के का एक सेट कर रहे हैं:

one_set_of_two_by_five = tfd.Independent(
    distribution=two_by_five_bernoulli, reinterpreted_batch_ndims=2,
    name="One Set Of Two By Five")
one_set_of_two_by_five.log_prob(pattern)
<tf.Tensor: shape=(), dtype=float32, numpy=-8.356134>

यह के नजरिए से यह देखते हुए कि लायक sample , का उपयोग करते हुए Independent बदल जाता है कुछ भी नहीं:

describe_sample_tensor_shapes(
    [two_by_five_bernoulli,
     two_sets_of_five,
     one_set_of_two_by_five],
    [[3, 5]])
tfp.distributions.Bernoulli("Two_By_Five_Bernoulli", batch_shape=[2, 5], event_shape=[], dtype=int32)
Sample shape: [3, 5]
Returned sample tensor shape: (3, 5, 2, 5)

tfp.distributions.Independent("Two_Sets_Of_Five", batch_shape=[2], event_shape=[5], dtype=int32)
Sample shape: [3, 5]
Returned sample tensor shape: (3, 5, 2, 5)

tfp.distributions.Independent("One_Set_Of_Two_By_Five", batch_shape=[], event_shape=[2, 5], dtype=int32)
Sample shape: [3, 5]
Returned sample tensor shape: (3, 5, 2, 5)

पाठक के लिए एक विदाई अभ्यास के रूप में, हम का एक वेक्टर बैच के बीच मतभेद और समानता पर विचार करने का सुझाव Normal वितरण और एक MultivariateNormalDiag एक नमूना और लॉग संभावना के नजरिए से वितरण। हम कैसे उपयोग कर सकते हैं Independent एक के निर्माण के लिए MultivariateNormalDiag के बैच से अपने Normal रों? (ध्यान दें कि MultivariateNormalDiag वास्तव में इस तरह से लागू नहीं है।)