如何理解 PyMC 模型中 yield 的使用?
How to make sense of the use of `yield` in PyMC models?
我自己不是 PyMC 的用户,但最近我偶然发现 this article 显示了一些 PyMC 模型的片段:
def linear_regression(x):
scale = yield tfd.HalfCauchy(0, 1)
coefs = yield tfd.Normal(tf.zeros(x.shape[1]), 1, )
predictions = yield tfd.Normal(tf.linalg.matvec(x, coefs), scale)
return predictions
作者建议网友
would be uncomfortable with bar = yield foo
我确实不舒服。我试图理解这个生成器,但看不出它如何使用。
这是我的思考过程。如果我执行 foo = linear_regression(bar)
并执行 foo
(例如 next(foo)
),它会将 return 的值 scale
给我。但是,这也会将局部变量 scale
变为 None
。同样,如果再次执行foo
,我可以得到coefs
的值,但是本地的coefs
会变成None
。本地scale
和coefs
都是None
,predictions
如何求值?
或者有没有办法在不触发 scale
和 coefs
上的 yield
的情况下评估 foo
,并直接在 predictions
上产生?
这里有什么黑魔法?需要帮助。
披露:我是 original linked article.
的作者
我认为您的主要误解是:Python 生成器不仅可以为您生成值,您还可以使用 向生成器发送回 值 generator.send()
.因此,bar = yield foo
会产生 foo
给你;生成器将等到您向它发送另一个值(可以是 None
,如果您只调用 next(generator)
就会发生这种情况!),将该值分配给 bar
,然后继续 运行 发电机。
这是一个简单的例子:
>>> def add_one_generator():
... x = 0
... while True:
... x = yield x + 1
...
>>> gen = add_one_generator()
>>> y = gen.send(None) # First sent value must be None, to start the generator
>>> print(y)
1
>>> z = gen.send(2)
>>> print(z)
3
注意当我send(2)
时,生成器将发送的值赋值给x
,然后恢复执行。在这种情况下,这再次意味着 yield x + 1
,这就是产生的 z
是 3
.
的原因
有关此模式的更多信息及其有用的原因,请查看 this Whosebug answer。
下面是一些伪代码,可以让我们更加了解 PyMC4 中(可能)的工作方式:
>>> def linear_regression(x):
... scale = yield tfd.HalfCauchy(0, 1)
... coefs = yield tfd.Normal(tf.zeros(x.shape[1]), 1, )
... predictions = yield tfd.Normal(tf.linalg.matvec(x, coefs), scale)
... return predictions
>>> model = linear_regression(data)
>>> next_distribution = model.send(None)
>>> scale = pymc_do_things(next_distribution)
>>> coefs = pymc_do_things(model.send(scale))
>>> predictions = pymc_do_things(model.send(coefs))
我自己不是 PyMC 的用户,但最近我偶然发现 this article 显示了一些 PyMC 模型的片段:
def linear_regression(x):
scale = yield tfd.HalfCauchy(0, 1)
coefs = yield tfd.Normal(tf.zeros(x.shape[1]), 1, )
predictions = yield tfd.Normal(tf.linalg.matvec(x, coefs), scale)
return predictions
作者建议网友
would be uncomfortable with
bar = yield foo
我确实不舒服。我试图理解这个生成器,但看不出它如何使用。
这是我的思考过程。如果我执行 foo = linear_regression(bar)
并执行 foo
(例如 next(foo)
),它会将 return 的值 scale
给我。但是,这也会将局部变量 scale
变为 None
。同样,如果再次执行foo
,我可以得到coefs
的值,但是本地的coefs
会变成None
。本地scale
和coefs
都是None
,predictions
如何求值?
或者有没有办法在不触发 scale
和 coefs
上的 yield
的情况下评估 foo
,并直接在 predictions
上产生?
这里有什么黑魔法?需要帮助。
披露:我是 original linked article.
的作者我认为您的主要误解是:Python 生成器不仅可以为您生成值,您还可以使用 向生成器发送回 值 generator.send()
.因此,bar = yield foo
会产生 foo
给你;生成器将等到您向它发送另一个值(可以是 None
,如果您只调用 next(generator)
就会发生这种情况!),将该值分配给 bar
,然后继续 运行 发电机。
这是一个简单的例子:
>>> def add_one_generator():
... x = 0
... while True:
... x = yield x + 1
...
>>> gen = add_one_generator()
>>> y = gen.send(None) # First sent value must be None, to start the generator
>>> print(y)
1
>>> z = gen.send(2)
>>> print(z)
3
注意当我send(2)
时,生成器将发送的值赋值给x
,然后恢复执行。在这种情况下,这再次意味着 yield x + 1
,这就是产生的 z
是 3
.
有关此模式的更多信息及其有用的原因,请查看 this Whosebug answer。
下面是一些伪代码,可以让我们更加了解 PyMC4 中(可能)的工作方式:
>>> def linear_regression(x):
... scale = yield tfd.HalfCauchy(0, 1)
... coefs = yield tfd.Normal(tf.zeros(x.shape[1]), 1, )
... predictions = yield tfd.Normal(tf.linalg.matvec(x, coefs), scale)
... return predictions
>>> model = linear_regression(data)
>>> next_distribution = model.send(None)
>>> scale = pymc_do_things(next_distribution)
>>> coefs = pymc_do_things(model.send(scale))
>>> predictions = pymc_do_things(model.send(coefs))