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 Eager-এ একটি নোট।

এই সমগ্র নোটবুক ব্যবহার করে লেখা হয় 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)

তাই তার ঘটনা আকৃতি সবসময় পইসন বিতরণের, একটি স্কেলার বন্টন হয় [] । যদি আমরা আরো হার নির্দিষ্ট করি, এইগুলি ব্যাচ আকারে দেখায়। উদাহরণগুলির চূড়ান্ত জোড়া আকর্ষণীয়: শুধুমাত্র একটি একক হার আছে, কিন্তু যেহেতু সেই হারটি খালি নেই এমন একটি নম্পি অ্যারেতে এমবেড করা হয়েছে, সেই আকারটি ব্যাচ আকারে পরিণত হয়।

স্ট্যান্ডার্ড নরমাল ডিস্ট্রিবিউশনও একটি স্কেলার। এটা তোলে ইভেন্টে আকৃতি হয় [] শুধু পইসন জন্য মতো, কিন্তু আমরা সম্প্রচার আমাদের প্রথম উদাহরণ দেখতে এটি সঙ্গে খেলা করব। সাধারন ব্যবহার উল্লেখ করা হয় 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 , যা কিছুটা trickier হয়। 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' একটি Singleton প্রতিলিপি আছে, যে সময়ের উপযুক্ত সংখ্যা Singleton। অন্য কোন পরিস্থিতি একটি ত্রুটি. (স্কালে ডিস্ট্রিবিউশন, আমরা কেবল বিরুদ্ধে সম্প্রচার 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)>

ঠিক equivalently, আমরা ব্যবহার করতে পারেন 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>

আমরা এমন একটি ইভেন্টের আকৃতি সঙ্গে একটি MULTINOMIAL নির্মিত [6] । পুনর্নির্মাণ Bijector আমাদের একটি ঘটনা আকৃতি সঙ্গে একটি বন্টন হিসাবে এই বিবেচনা করতে পারবেন [2, 3]

একজন Bijector একটি differentiable, এক-টু-এক একটি খোলা উপসেট উপর ফাংশন প্রতিনিধিত্ব করে \({\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 , যা দরকারী দুটি ভিন্ন "পাঁচ বের্নুলির সেট" পরিণত করতে যদি আমরা একটি মুদ্রা এর "সারি" বিবেচনা করতে ফ্লিপ একটি একক ফলাফল হিসাবে একটি প্রদত্ত প্যাটার্ন উত্ক্রান্ত:

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 একটি বিতরণ তৈরি করতে যেখানে পৃথক ঘটনা দুই-বাই-পাঁচটি বের্নুলির একটি সেট আছে:

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 আসলে এই ভাবে বাস্তবায়িত হয়নি।)