مشاهده در 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 Distributions وجود دارد:
- شکل رویداد توصیف شکل یک قرعه کشی تنها از توزیع؛ ممکن است به ابعاد مختلف بستگی داشته باشد. برای توزیع اسکالر، شکل رویداد است
[]
. برای MultivariateNormal 5 بعدی، شکل رویداد است[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]
. با استفاده از نامپای قوانین پخش ، شکل دسته ای است [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
: تانسورها نمونه بازگشت شکل دارند [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]
.
اگر صدا و سیما نبود، تمام چیزی که میتوانست بگوییم همین بود. در اینجا قوانینی وجود دارد که ما پخش را در نظر گرفتیم. ما آن را به طور کلی توصیف می کنیم و به ساده سازی برای توزیع های اسکالر توجه می کنیم:
- تعریف
n = len(batch_shape) + len(event_shape)
. (برای توزیع اسکالر،len(event_shape)=0
). - اگر تانسور ورودی
t
کمتر ازn
ابعاد، پد شکل آن با اضافه کردن ابعاد اندازه1
در سمت چپ تا زمانی که دقیقاn
ابعاد. پاسخ در نتیجه تانسورt'
. - پخش
n
ابعاد سمت راست ازt'
در برابر[batch_shape, event_shape]
از توزیع شما در حال محاسبهlog_prob
برای. با جزئیات بیشتر: برای ابعاد که در آنt'
در حال حاضر منطبق بر توزیع، کاری انجام ندادن، و برای ابعاد که در آنt'
یک تک قلو، تکرار که تک به تعداد مناسب از بار. هر وضعیت دیگری یک خطا است. (برای توزیع اسکالر، ما تنها در برابر پخشbatch_shape
، از event_shape =[]
.) - در حال حاضر ما در نهایت قادر به محاسبه هستید
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 است، بنابراین ما ارزیابی احتمال ورود هر سه Poissons 'در ارزش 10.
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 را؛ هر چیز دیگری خطا است (قوانین رادیو و تلویزیون نامپای درمان حالت خاصی از یک اسکالر به عنوان کاملا به یک تانسور شکل معادل [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)>
تکنیک های دستکاری شکل
The Reshape Bijector
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
به نوبه خود این را به دو «مجموعه از پنج برنولی" متفاوت، مفید است که اگر ما می خواهیم به در نظر گرفتن "ردیف" از سکه 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
برای ایجاد یک توزیع که در آن حوادث فردی هستند مجموعه ای از دو و پنج است برنولی:
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
است که در واقع این راه اجرا نمی شود.)