Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
a7310185
提交
a7310185
authored
1月 08, 2010
作者:
James Bergstra
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
updated randomstreams documentation to work for shared_randomstreams
上级
7a271305
显示空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
75 行增加
和
114 行删除
+75
-114
randomstreams.txt
doc/topics/randomstreams.txt
+69
-109
shared_randomstreams.py
theano/tensor/shared_randomstreams.py
+6
-5
没有找到文件。
doc/topics/randomstreams.txt
浏览文件 @
a7310185
...
@@ -6,149 +6,109 @@ Using RandomStreams
...
@@ -6,149 +6,109 @@ Using RandomStreams
Since Theano uses a functional design, producing pseudo-random numbers in a
Since Theano uses a functional design, producing pseudo-random numbers in a
graph is not quite as straightforward as it is in numpy. But close. If you are using theano's
graph is not quite as straightforward as it is in numpy. But close. If you are using theano's
modu
les, then a RandomStreams object is probably what you want. If you are
shared variab
les, then a RandomStreams object is probably what you want. If you are
using the function interface directly
(not Module and Method) then have a look
using the function interface directly
, or you are using Module then this tutorial will be useful but not exactly what you want.
at the :api:`RandomFunction` Op.
Have a look
at the :api:`RandomFunction` Op.
I'm going to use the term "random stream" to mean the sequence of random
The way to think about putting randomness into theano's computations is to
numbers that comes from a numpy RandomState object (starting from a particular
put random variables in your graph. Theano will allocate a numpy RandomState
state). Try to think about putting random variables in your graph, rather than
object for each such variable, and draw from it as necessary. I'll call this sort of sequence of
random number
generators.
random number
s a *random stream*.
Here's a brief example:
Brief example
-----------------------
-------------
.. code-block:: python
from theano.tensor import RandomStreams
m = Module()
m.random = RandomStreams(seed=234)
rv_u = m.random.uniform((2,2))
rv_n = m.random.normal((2,2))
m.fn = Method([], rv_u)
m.gn = Method([], rv_n)
m.nearly_zeros = Method([], rv_u + rv_u - 2 * rv_u)
made = m.make()
made.random.initialize()
fn_val0 = made.fn()
fn_val1 = made.fn() #different numbers from fn_val0
Here's a brief example. The setup code is:
Let's walk through it.
.. code-block:: python
>>> from theano.tensor import RandomStreams
from theano.tensor.shared_randomstreams import RandomStreams
>>> m = Module()
srng = RandomStreams(seed=234)
>>> m.random = RandomStreams(seed=234)
rv_u = srng.random.uniform((2,2))
>>> rv_u = m.random.uniform((2,2))
rv_n = srng.random.normal((2,2))
>>> rv_n = m.random.normal((2,2))
f = function([], rv_u, updates=[rv_u.update])
g = function([], rv_n) #omitting rv_n.update
nearly_zeros = function([], rv_u + rv_u - 2 * rv_u, updates=[rv_u.update])
Here, 'rv_u' represents a random stream of 2x2 matrices of draws from a uniform
Here, 'rv_u' represents a random stream of 2x2 matrices of draws from a uniform
distribution. Likewise, 'rv_n' represenents a random stream of 2x2 matrices of
distribution. Likewise, 'rv_n' represenents a random stream of 2x2 matrices of
draws from a normal distribution.
draws from a normal distribution.
The distributions that are implemented are
defined in :ref:`tensor.shared_randomstreams.RandomStreams`.
>>> m.fn = Method([], rv_u)
Now let's use these things. If we call f(), we get random uniform numbers.
>>> m.gn = Method([], rv_n)
Since we are updating the internal state of the random number generator (via
the ``updates`` argument, we get different random numbers every time.
As usual, we can define methods that operate on Module members (the RandomState
>>> f_val0 = f()
object for each of fn and gn).
>>> f_val1 = f() #different numbers from f_val0
>>> m.nearly_zeros = Method([], rv_u + rv_u - 2 * rv_u)
When we omit the updates argument (as in ``g``) to ``function``, then the
random number generator state is not affected by calling the returned function. So for example,
calling ``g`` multiple times will return the same numbers.
This function will always return a 2x2 matrix of small numbers, or possibly
>>> g_val0 = g() # different numbers from f_val0 and f_val1
zeros. It illustrates that random variables are not re-drawn every time they
>>> g_val0 = g() # same numbers as g_val0 !!!
are used, they are only drawn once per method call.
An important remark is that a random variable is drawn at most once during any
single function execution. So the ``nearly_zeros`` function is guaranteed to
return approximately 0 (except for rounding error) even though the ``rv_u``
random variable appears three times in the output expression.
>>>
made = m.make(
)
>>>
nearly_zeros = function([], rv_u + rv_u - 2 * rv_u, updates=[rv_u.update]
)
When we compile things with m.make(), the RandomStreams instance (m.random)
emits an RandomStreamsInstance object (here called ``made.random``) containing a numpy
RandomState instance for each stream.
>>> assert isinstance(made.random[rv_u.rng], numpy.random.RandomState)
Internal Attributes
--------------------
These RandomState objects can be accessed using normal indexing syntax.
The random variables returned by methods like ``RandomStreams.uniform`` have
some useful internal attributes.
>>> fn_val0 = made.fn()
The one we used above is the ``update`` attribute. ``rv_u.update`` is a pair
>>> fn_val1 = made.fn()
whose first element is a shared variable whose value is a numpy RandomState,
and whose second element is an [symbolic] expression for the next value of that
RandomState after drawing samples.
Finally, we can use our methods to draw random numbers. Every call will of
The first element of the ``update`` attribute is also accessible as
course, draw different ones!
``rv_u.rng``. A random variable can be re-seeded by seeding or assigning to
``rv_u.rng.value``.
The ``RandomStreams`` object itself has an ``updates()`` method that returns a
list of all the (state, new_state) update pairs from the random variables it
has returned. This can be a convenient shortcut to enumerating all
the random variables in a large graph in the ``update`` paramter of function.
Seedings Streams
Seedings Streams
----------------
----------------
All of the streams in a RandomStreams container can be seeded at once using the
Random variables can be seeded individually or collectively.
seed method of a RandomStreamsInstance.
>>> made.random.seed(seed_value)
Of course, a RandomStreamsInstance can contain several RandomState instances and
these will _not_ all be seeded to the same seed_value. They will all be seeded
deterministically and probably uniquely as a function of the seed_value.
Seeding the generator in this way makes it possible to repeat random streams.
>>> made.random.seed(777)
>>> f0 = made.fn()
>>> made.random.seed(999)
>>> f1 = made.fn()
Here we have different values in f0 and f1 because they were created from
You can seed just one random variable by seeding or assigning to the
generators seeded differently
.
``.rng.value`` attribute
.
>>> made.random.seed(777)
>>> rv_u.rng.value.seed(89234) # seeds the generator for rv_u
>>> f2 = made.fn()
If we re-seed the generator with 777 and call fn again, we'll find that we
You can also seed *all* of the random variables allocated by a ``RandomStreams``
re-drew the f0 values.
object by that object's ``seed`` method. This seed will be used to seed a
temporary random number generator, that will in turn generate seeds for each
of the random variables.
>>>
assert(numpy.all(f2 == f0))
>>>
srng.seed(902340) # seeds rv_u and rv_n with different seeds each
Sharing Streams between
Method
s
Sharing Streams between
Function
s
-------------------------------
-------------------------------
--
Streams in a Module, like other Members of a Module, are shared between Methods.
As usual for shared variables, the random number generators used for random
This means that when one Method updates the state of a stream, it updates the
variables are common between functions. So our ``nearly_zeros`` function will
state for other methods in that ModuleInstance too
.
update the state of the generators used in function ``f`` above
.
For example:
For example:
>>> m = Module()
>>> state_after_v0 = rv_u.rng.value.get_state()
>>> m.random = RandomStreams(seed=234)
>>> nearly_zeros() # this affects rv_u's generator
>>> rv_u = m.random.uniform((2,2))
>>> v1 = f()
>>> m.fn = Method([], rv_u)
>>> rv_u.rng.value.set_state(state_after_v0)
>>> m.gn = Method([], rv_u)
>>> v2 = f() # v2 != v1
>>> made = m.make()
>>> made.random.initialize()
>>> fn_val0 = made.fn()
>>> gn_val0 = made.gn()
At this point, fn_val0 != gn_val0 because made.fn() updated the random state
after it was called.
Compiled Modules are independent
--------------------------------
The RandomState objects are created only at the time of calling `make`, and
calling make repeatedly will create multiple independent RandomStreamsInstance
objects. So, for example, if we were to hijack the previous example like this:
>>> made = m.make()
>>> made_again = m.make()
>>> made.random.initialize()
>>> made_again.random.initialize()
>>> fn_val = made.fn()
>>> gn_val = made.gn()
>>> gn_val_ = made_again.gn()
>>> fn_val_ = made_again.fn()
We could call f and g in different orders in the two modules, and find that
``numpy.all(fn_val == fn_val_)`` and ``numpy.all(gn_val == gn_val_)``.
...
...
theano/tensor/shared_randomstreams.py
浏览文件 @
a7310185
...
@@ -25,7 +25,7 @@ def randomstate_constructor(value, name=None, strict=False):
...
@@ -25,7 +25,7 @@ def randomstate_constructor(value, name=None, strict=False):
class
RandomStreams
(
object
):
class
RandomStreams
(
object
):
"""Module component with similar interface to numpy.random (numpy.random.RandomState)"""
"""Module component with similar interface to numpy.random (numpy.random.RandomState)"""
random_state_variabl
es
=
[]
state_updat
es
=
[]
"""A list of pairs of the form (input_r, output_r). This will be over-ridden by the module
"""A list of pairs of the form (input_r, output_r). This will be over-ridden by the module
instance to contain stream generators.
instance to contain stream generators.
"""
"""
...
@@ -39,7 +39,7 @@ class RandomStreams(object):
...
@@ -39,7 +39,7 @@ class RandomStreams(object):
"""
"""
def
updates
(
self
):
def
updates
(
self
):
return
list
(
self
.
random_state_variabl
es
)
return
list
(
self
.
state_updat
es
)
def
__init__
(
self
,
seed
=
None
):
def
__init__
(
self
,
seed
=
None
):
"""
"""
...
@@ -49,7 +49,7 @@ class RandomStreams(object):
...
@@ -49,7 +49,7 @@ class RandomStreams(object):
`RandomStreamsInstance.__init__` for more details.
`RandomStreamsInstance.__init__` for more details.
"""
"""
super
(
RandomStreams
,
self
)
.
__init__
()
super
(
RandomStreams
,
self
)
.
__init__
()
self
.
random_state_variabl
es
=
[]
self
.
state_updat
es
=
[]
self
.
default_instance_seed
=
seed
self
.
default_instance_seed
=
seed
self
.
gen_seedgen
=
numpy
.
random
.
RandomState
(
seed
)
self
.
gen_seedgen
=
numpy
.
random
.
RandomState
(
seed
)
...
@@ -67,7 +67,7 @@ class RandomStreams(object):
...
@@ -67,7 +67,7 @@ class RandomStreams(object):
seed
=
self
.
default_instance_seed
seed
=
self
.
default_instance_seed
seedgen
=
numpy
.
random
.
RandomState
(
seed
)
seedgen
=
numpy
.
random
.
RandomState
(
seed
)
for
old_r
,
new_r
in
self
.
random_state_variabl
es
:
for
old_r
,
new_r
in
self
.
state_updat
es
:
old_r_seed
=
seedgen
.
randint
(
2
**
30
)
old_r_seed
=
seedgen
.
randint
(
2
**
30
)
old_r
.
value
=
numpy
.
random
.
RandomState
(
int
(
old_r_seed
))
old_r
.
value
=
numpy
.
random
.
RandomState
(
int
(
old_r_seed
))
...
@@ -119,7 +119,8 @@ class RandomStreams(object):
...
@@ -119,7 +119,8 @@ class RandomStreams(object):
random_state_variable
=
shared
(
numpy
.
random
.
RandomState
(
seed
))
random_state_variable
=
shared
(
numpy
.
random
.
RandomState
(
seed
))
new_r
,
out
=
op
(
random_state_variable
,
*
args
,
**
kwargs
)
new_r
,
out
=
op
(
random_state_variable
,
*
args
,
**
kwargs
)
out
.
rng
=
random_state_variable
out
.
rng
=
random_state_variable
self
.
random_state_variables
.
append
((
random_state_variable
,
new_r
))
out
.
update
=
(
random_state_variable
,
new_r
)
self
.
state_updates
.
append
(
out
.
update
)
return
out
return
out
def
binomial
(
self
,
*
args
,
**
kwargs
):
def
binomial
(
self
,
*
args
,
**
kwargs
):
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论