7.2.2 更多示例
譯者:Python 文檔協(xié)作翻譯小組柏靶,原文:More Examples弃理。
本文以 CC BY-NC-SA 4.0 協(xié)議發(fā)布,轉(zhuǎn)載請保留作者署名和文章出處屎蜓。
Python 文檔協(xié)作翻譯小組人手緊缺案铺,有興趣的朋友可以加入我們,完全公益性質(zhì)梆靖。交流群:467338606控汉。
現(xiàn)在開始,通過瀏覽庫的Basic Tensor Functionality這一部分返吻,開始更加系統(tǒng)地熟悉Theano的基本對象和操作是非常明智的姑子。
隨著教程的展開,你還應(yīng)該逐漸熟悉庫的其他相關(guān)領(lǐng)域以及文檔入口頁面的相關(guān)主題测僵。
Logistic函數(shù)
這里是另一個簡單的例子街佑,雖然比將兩個數(shù)字加在一起更復(fù)雜一點。讓我們說捍靠,你想計算logistic曲線沐旨,它由下式給出:
![s(x) = \frac{1}{1 + e^{-x}}](http://upload-images.jianshu.io/upload_images/118142-c139ee6e04cddedd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
logistic函數(shù)的圖,其中x在x軸上榨婆,s(x)在y軸上磁携。
如果你想對雙精度矩陣上的每個元素計算這個函數(shù),這表示你想將這個函數(shù)應(yīng)用到矩陣的每個元素上良风。
嗯谊迄,你是這樣做的:
>>> import theano
>>> import theano.tensor as T
>>> x = T.dmatrix('x')
>>> s = 1 / (1 + T.exp(-x))
>>> logistic = theano.function([x], s)
>>> logistic([[0, 1], [-1, -2]])
array([[ 0.5 , 0.73105858],
[ 0.26894142, 0.11920292]])
在每個元素上執(zhí)行l(wèi)ogistic的原因是因為它的所有運算 —— 除法、加法烟央、冪和除法 —— 本身是單個元素的操作统诺。
下面是這種情況:
![s(x) = \frac{1}{1 + e^{-x}} = \frac{1 + \tanh(x/2)}{2}](http://upload-images.jianshu.io/upload_images/118142-1bad24045abd4930.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
我們可以驗證這個另外一種形式是否產(chǎn)生相同的值:
>>> s2 = (1 + T.tanh(x / 2)) / 2
>>> logistic2 = theano.function([x], s2)
>>> logistic2([[0, 1], [-1, -2]])
array([[ 0.5 , 0.73105858],
[ 0.26894142, 0.11920292]])
同時計算多個值
Theano支持多輸出功能。例如疑俭,我們可以同時計算兩個矩陣a和b之間每個元素的差粮呢、差的絕對值和平方差:
>>> a, b = T.dmatrices('a', 'b')
>>> diff = a - b
>>> abs_diff = abs(diff)
>>> diff_squared = diff**2
>>> f = theano.function([a, b], [diff, abs_diff, diff_squared])
注意
dmatrices
產(chǎn)生與你提供的名稱一樣多的輸出。它是分配符號變量的一個快捷方式,我們將在教程中經(jīng)常使用它啄寡。
當(dāng)我們使用函數(shù)f豪硅,它返回三個變量(為了可讀性,輸出被重新格式化了):
>>> f([[1, 1], [1, 1]], [[0, 1], [2, 3]])
[array([[ 1., 0.],
[-1., -2.]]), array([[ 1., 0.],
[ 1., 2.]]), array([[ 1., 0.],
[ 1., 4.]])]
為參數(shù)設(shè)置默認(rèn)值
假設(shè)你想定義一個函數(shù)將兩個數(shù)字相加这难,但是你只提供一個數(shù)字舟误,另一個輸入假設(shè)為1。你可以這樣做:
>>> from theano import In
>>> from theano import function
>>> x, y = T.dscalars('x', 'y')
>>> z = x + y
>>> f = function([x, In(y, value=1)], z)
>>> f(33)
array(34.0)
>>> f(33, 2)
array(35.0)
這里使用In類姻乓,它允許你更詳細(xì)地指定你的函數(shù)的參數(shù)的屬性嵌溢。這里,通過創(chuàng)建value
字段設(shè)置為1的In
實例蹋岩,為y賦予默認(rèn)值1赖草。
具有默認(rèn)值的輸入必須遵循沒有默認(rèn)值的輸入(類似Python的函數(shù))〖舾觯可以有多個具有默認(rèn)值的輸入秧骑。這些參數(shù)可以按位置或名稱設(shè)置,和在標(biāo)準(zhǔn)Python中一樣:
>>> x, y, w = T.dscalars('x', 'y', 'w')
>>> z = (x + y) * w
>>> f = function([x, In(y, value=1), In(w, value=2, name='w_by_name')], z)
>>> f(33)
array(68.0)
>>> f(33, 2)
array(70.0)
>>> f(33, 0, 1)
array(33.0)
>>> f(33, w_by_name=1)
array(34.0)
>>> f(33, w_by_name=1, y=0)
array(33.0)
注意
In
不知道作為參數(shù)傳遞的局部變量y和w的名稱扣囊。符號變量對象具有名稱屬性(在上面的示例中由dscalars
設(shè)置)和它們是我們構(gòu)建的函數(shù)中的關(guān)鍵字參數(shù)的名稱乎折。這是In(y, value = 1)
中工作的機(jī)制侵歇。在In(w, value=2, name='w_by_name')
的情況下骂澄。我們用一個這個函數(shù)使用的名稱來覆蓋符號變量的name屬性探越。
你可能想查看庫中的Function以獲取更多詳細(xì)信息婉称。
使用共享變量
還可以利用內(nèi)部狀態(tài)生成一個函數(shù)。例如邪蛔,假設(shè)我們想要一個累加器:在開始溃蔫,狀態(tài)被初始化為零健提。然后,在每次函數(shù)調(diào)用時伟叛,狀態(tài)通過函數(shù)的參數(shù)增加私痹。
首先我們定義累加器函數(shù)。它將其參數(shù)添加到內(nèi)部狀態(tài)痪伦,并返回舊的狀態(tài)值侄榴。
>>> from theano import shared
>>> state = shared(0)
>>> inc = T.iscalar('inc')
>>> accumulator = function([inc], state, updates=[(state, state+inc)])
這段代碼引入了一些新的概念。shared
函數(shù)構(gòu)造所謂的共享變量网沾。它們是符號變量和非符號變量的混合,其值可以在多個函數(shù)之間共享蕊爵。共享變量就像dmatrices(...)
返回的對象一樣可以在符號表達(dá)式中使用辉哥,但它們還有一個內(nèi)部值,定義在所有使用這個符號變量的函數(shù)中的值。它被稱為共享變量??醋旦,因為它的值在許多函數(shù)之間共享恒水。該值可以通過.get_value()
和.set_value()
方法訪問和修改。我們會很快回來饲齐。
該代碼中的另一個新東西是function
的updates
參數(shù)钉凌。updates
必須提供形式為(共享變量,新表達(dá)式)對的一個列表捂人。它也可以是一個字典御雕,其鍵是共享變量,值是新的表達(dá)式滥搭。無論哪種方式酸纲,它意味著“每當(dāng)這個函數(shù)運行時,它將用相應(yīng)表達(dá)式的結(jié)果替換每個共享變量的.value
”瑟匆。上面闽坡,我們的累加器用狀態(tài)和增量總和取代state
的值。
讓我們試試吧愁溜!
>>> print(state.get_value())
0
>>> accumulator(1)
array(0)
>>> print(state.get_value())
1
>>> accumulator(300)
array(1)
>>> print(state.get_value())
301
可以重置狀態(tài)疾嗅。只需使用.set_value()
方法:
>>> state.set_value(-1)
>>> accumulator(3)
array(-1)
>>> print(state.get_value())
2
如上所述,你可以定義多個函數(shù)來使用相同的共享變量冕象。這些函數(shù)都可以更新該值代承。
>>> decrementor = function([inc], state, updates=[(state, state-inc)])
>>> decrementor(2)
array(2)
>>> print(state.get_value())
0
你可能想知道為什么存在更新機(jī)制。你總是可以通過返回新的表達(dá)式交惯,并在NumPy中照常使用它們來實現(xiàn)類似的結(jié)果次泽。更新機(jī)制可以是語法方便,但是它主要是為了效率席爽。有時可以使用就地算法(例如低秩矩陣更新)更快地完成對共享變量的更新意荤。此外,Theano對分配變量的位置和方式有更多的控制只锻,這是在GPU上獲得良好性能的重要因素之一玖像。
可能會發(fā)生這種情況,你使用共享變量表達(dá)了某個公式齐饮,但你不想使用它的值捐寥。在這種情況下,你可以使用function
的givens
參數(shù)為一個特定函數(shù)替換圖中的特定節(jié)點祖驱。
>>> fn_of_state = state * 2 + inc
>>> # The type of foo must match the shared variable we are replacing
>>> # with the ``givens``
>>> foo = T.scalar(dtype=state.dtype)
>>> skip_shared = function([inc, foo], fn_of_state, givens=[(state, foo)])
>>> skip_shared(1, 3) # we're using 3 for the state, not state.value
array(7)
>>> print(state.get_value()) # old state still there, but we didn't use it
0
givens
參數(shù)可用于替換任何符號變量握恳,而不僅僅是共享變量。一般情況下捺僻,你可以替換常量和表達(dá)式乡洼。但要小心崇裁,不要讓givens
替換引入的表達(dá)式是共同依賴的,替換的順序沒有定義束昵,所以替換必須以任何順序工作拔稳。
在實踐中,考慮givens
的一個好方法是允許你用一個不同的表達(dá)式替換你的公式的任何部分锹雏,這個表達(dá)式的計算結(jié)果是一個相同形狀和dtype的張量巴比。
注意
Theano共享變量broadcast模式對于每個維度默認(rèn)為False。共享變量大小可以隨時間改變礁遵,所以我們不能使用形狀來找到broadcastable的模式轻绞。如果你想要一個不同的模式,只要將它作為參數(shù)傳遞theano.shared(..., broadcastable=(True, False))
復(fù)制函數(shù)
Theano函數(shù)可以被復(fù)制榛丢,這對于創(chuàng)建類似的函數(shù)铲球,但是使用不同的共享變量或更新是有用的。這是使用function
對象的copy()
方法完成的晰赞。復(fù)制的是原始函數(shù)的優(yōu)化圖稼病,因此編譯只需要執(zhí)行一次。
讓我們從上面定義的累加器開始:
>>> import theano
>>> import theano.tensor as T
>>> state = theano.shared(0)
>>> inc = T.iscalar('inc')
>>> accumulator = theano.function([inc], state, updates=[(state, state+inc)])
我們可以使用它像往常一樣增加狀態(tài):
>>> accumulator(10)
array(0)
>>> print(state.get_value())
10
我們可以使用copy()
創(chuàng)建一個類似的累加器掖鱼,但使用自己的內(nèi)部狀態(tài)使用swap
參數(shù)然走,它是一個要交換的共享變量的字典:
>>> new_state = theano.shared(0)
>>> new_accumulator = accumulator.copy(swap={state:new_state})
>>> new_accumulator(100)
[array(0)]
>>> print(new_state.get_value())
100
第一個函數(shù)的狀態(tài)保持不變:
>>> print(state.get_value())
10
我們現(xiàn)在使用delete_updates
參數(shù)創(chuàng)建一個刪除更新的副本,默認(rèn)情況下戏挡,該參數(shù)設(shè)置為False
:
>>> null_accumulator = accumulator.copy(delete_updates=True)
如預(yù)期芍瑞,共享狀態(tài)不再更新:
>>> null_accumulator(9000)
[array(10)]
>>> print(state.get_value())
10
使用隨機(jī)數(shù)
因為在Theano中你首先將一切用符號表示并在之后編譯這個表達(dá)式以獲得函數(shù),所以使用偽隨機(jī)數(shù)字不是像在NumPy中那么直接褐墅,雖然也不太復(fù)雜拆檬。
將隨機(jī)性放到Theano的計算中的考慮方式是將隨機(jī)變量放在你的圖中。Theano將為每個這樣的變量分配一個NumPy RandomStream對象(一個隨機(jī)數(shù)生成器)妥凳,并根據(jù)需要繪制它竟贯。我們將這種隨機(jī)數(shù)序列稱為隨機(jī)流。隨機(jī)流的核心是它們的共享變量逝钥,因此在這里也可以對共享變量進(jìn)行觀察屑那。Theanos的隨機(jī)對象在RandomStreams中定義和實現(xiàn),底層在RandomStreamsBase中定義和實現(xiàn)艘款。
簡要示例
這里有一個簡單的例子持际。起始代碼是:
from theano.tensor.shared_randomstreams import RandomStreams
from theano import function
srng = RandomStreams(seed=234)
rv_u = srng.uniform((2,2))
rv_n = srng.normal((2,2))
f = function([], rv_u)
g = function([], rv_n, no_default_updates=True) #Not updating rv_n.rng
nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)
這里,'rv_u'表示來自均勻分布的2×2矩陣的隨機(jī)流哗咆。同樣蜘欲,'rv_n'表示來自正態(tài)分布的2×2矩陣的隨機(jī)流。分布的實現(xiàn)在RandomStreams
中定義晌柬,底層在raw_random中定義芒填。它們只在CPU上工作呜叫。有關(guān)GPU版本空繁,請參見其他實現(xiàn)殿衰。
現(xiàn)在讓我們使用這些對象。隨機(jī)數(shù)發(fā)生器的內(nèi)部狀態(tài)是自動更新的盛泡,所以我們每次都得到不同的隨機(jī)數(shù)闷祥。
>>> f_val0 = f()
>>> f_val1 = f() #different numbers from f_val0
當(dāng)我們向function
添加額外參數(shù)no_default_updates=True
(如在g中)時,隨機(jī)數(shù)生成器狀態(tài)不受調(diào)用返回函數(shù)影響傲诵。因此凯砍,例如,多次調(diào)用g將返回相同的數(shù)字拴竹。
>>> g_val0 = g() # different numbers from f_val0 and f_val1
>>> g_val1 = g() # same numbers as g_val0!
一個重要的提醒是悟衩,在函數(shù)的每次執(zhí)行期間最多繪制一個隨機(jī)變量。因此栓拜,即使rv_u隨機(jī)變量在輸出表達(dá)式中出現(xiàn)三次座泳,almost_zeros函數(shù)保證返回大約為0(舍入誤差除外)。
>>> nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)
種子流
隨機(jī)變量可以使用單獨的種子或使用共同的種子幕与。
你可以使用.rng.set_value()
挑势,通過播種或分配.rng
屬性來播種一個隨機(jī)變量。
>>> rng_val = rv_u.rng.get_value(borrow=True) # Get the rng for rv_u
>>> rng_val.seed(89234) # seeds the generator
>>> rv_u.rng.set_value(rng_val, borrow=True) # Assign back seeded rng
你也可以通過RandomStreams
對象的seed
方法對該對象分配的全部隨機(jī)變量設(shè)置種子啦鸣。該種子將用于設(shè)置臨時隨機(jī)數(shù)發(fā)生器的種子潮饱,這個零時隨機(jī)數(shù)發(fā)生器隨后將為每個隨機(jī)變量生成種子。
>>> srng.seed(902340) # seeds rv_u and rv_n with different seeds each
函數(shù)之間共享流
與通常的共享變量一樣诫给,用于隨機(jī)變量的隨機(jī)數(shù)發(fā)生器在函數(shù)之間是共同的香拉。因此,我們的almost_zeros函數(shù)將更新函數(shù)f中使用的生成器的狀態(tài)中狂。
例如:
>>> state_after_v0 = rv_u.rng.get_value().get_state()
>>> nearly_zeros() # this affects rv_u's generator
array([[ 0., 0.],
[ 0., 0.]])
>>> v1 = f()
>>> rng = rv_u.rng.get_value(borrow=True)
>>> rng.set_state(state_after_v0)
>>> rv_u.rng.set_value(rng, borrow=True)
>>> v2 = f() # v2 != v1
>>> v3 = f() # v3 == v1
在Theano圖之間復(fù)制隨機(jī)狀態(tài)
在一些使用情況下凫碌,用戶可能想要將與給定的theano圖(例如,具有下面的編譯函數(shù)f1的g1)相關(guān)聯(lián)的所有隨機(jī)數(shù)發(fā)生器的“狀態(tài)”轉(zhuǎn)移到第二個圖形(例如具有函數(shù)f2的g2)吃型。這中情況例如证鸥,如果你試圖從之前的一個序列化的模型的參數(shù)初始化模型的狀態(tài)。對于theano.tensor.shared_randomstreams.RandomStreams
和theano.sandbox.rng_mrg.MRG_RandomStreams
勤晚,可以通過復(fù)制state_updates
參數(shù)的元素來實現(xiàn)枉层。
每當(dāng)從RandomStreams對象中繪制隨機(jī)變量時,就會將元組添加到state_updates
列表中赐写。第一個元素是一個共享變量鸟蜡,它表示與此特定變量??相關(guān)聯(lián)的隨機(jī)數(shù)生成器的狀態(tài),而第二個元素表示與隨機(jī)數(shù)生成過程對應(yīng)的theano圖(即RandomFunction {uniform} .0)挺邀。
下面示出了如何將“隨機(jī)狀態(tài)”從一個theano函數(shù)傳遞到另一個函數(shù)的示例揉忘。
>>> from __future__ import print_function
>>> import theano
>>> import numpy
>>> import theano.tensor as T
>>> from theano.sandbox.rng_mrg import MRG_RandomStreams
>>> from theano.tensor.shared_randomstreams import RandomStreams
>>> class Graph():
... def __init__(self, seed=123):
... self.rng = RandomStreams(seed)
... self.y = self.rng.uniform(size=(1,))
>>> g1 = Graph(seed=123)
>>> f1 = theano.function([], g1.y)
>>> g2 = Graph(seed=987)
>>> f2 = theano.function([], g2.y)
>>> # By default, the two functions are out of sync.
>>> f1()
array([ 0.72803009])
>>> f2()
array([ 0.55056769])
>>> def copy_random_state(g1, g2):
... if isinstance(g1.rng, MRG_RandomStreams):
... g2.rng.rstate = g1.rng.rstate
... for (su1, su2) in zip(g1.rng.state_updates, g2.rng.state_updates):
... su2[0].set_value(su1[0].get_value())
>>> # We now copy the state of the theano random number generators.
>>> copy_random_state(g1, g2)
>>> f1()
array([ 0.59044123])
>>> f2()
array([ 0.59044123])
其他隨機(jī)分布
其他實現(xiàn)
還有2個基于MRG31k3p和CURAND
的實現(xiàn)。RandomStream只在CPU上工作泣矛,MRG31k3p在CPU和GPU上工作疲眷。CURAND只在GPU上工作。
注意
使用MRG版本很容易您朽,你只需要更改import為:
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
簡要示例
這里有一個簡單的例子狂丝。起始代碼是:
from theano.tensor.shared_randomstreams import RandomStreams
from theano import function
srng = RandomStreams(seed=234)
rv_u = srng.uniform((2,2))
rv_n = srng.normal((2,2))
f = function([], rv_u)
g = function([], rv_n, no_default_updates=True) #Not updating rv_n.rng
nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)
這里,'rv_u'表示來自均勻分布的2×2矩陣的隨機(jī)流哗总。同樣几颜,'rv_n'表示來自正態(tài)分布的2×2矩陣的隨機(jī)流。分布的實現(xiàn)在RandomStreams
中定義讯屈,底層在raw_random中定義蛋哭。它們只在CPU上工作。有關(guān)GPU版本涮母,請參見其他實現(xiàn)谆趾。
現(xiàn)在讓我們使用這些對象。隨機(jī)數(shù)發(fā)生器的內(nèi)部狀態(tài)是自動更新的哈蝇,所以我們每次都得到不同的隨機(jī)數(shù)棺妓。
>>> f_val0 = f()
>>> f_val1 = f() #different numbers from f_val0
當(dāng)我們向function
添加額外參數(shù)no_default_updates=True
(如在g中)時,隨機(jī)數(shù)生成器狀態(tài)不受調(diào)用返回函數(shù)影響炮赦。因此怜跑,例如,多次調(diào)用g將返回相同的數(shù)字吠勘。
>>> g_val0 = g() # different numbers from f_val0 and f_val1
>>> g_val1 = g() # same numbers as g_val0!
一個重要的提醒是性芬,在函數(shù)的每次執(zhí)行期間最多繪制一個隨機(jī)變量。因此剧防,即使rv_u隨機(jī)變量在輸出表達(dá)式中出現(xiàn)三次植锉,almost_zeros函數(shù)保證返回大約為0(舍入誤差除外)。
>>> nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)
種子流
隨機(jī)變量可以使用單獨的種子或使用共同的種子峭拘。
你可以使用.rng.set_value()
俊庇,通過播種或分配.rng
屬性來播種一個隨機(jī)變量。
>>> rng_val = rv_u.rng.get_value(borrow=True) # Get the rng for rv_u
>>> rng_val.seed(89234) # seeds the generator
>>> rv_u.rng.set_value(rng_val, borrow=True) # Assign back seeded rng
你也可以通過RandomStreams
對象的seed
方法對該對象分配的全部隨機(jī)變量設(shè)置種子鸡挠。該種子將用于設(shè)置臨時隨機(jī)數(shù)發(fā)生器的種子辉饱,這個零時隨機(jī)數(shù)發(fā)生器隨后將為每個隨機(jī)變量生成種子。
>>> srng.seed(902340) # seeds rv_u and rv_n with different seeds each
函數(shù)之間共享流
與通常的共享變量一樣拣展,用于隨機(jī)變量的隨機(jī)數(shù)發(fā)生器在函數(shù)之間是共同的彭沼。因此,我們的almost_zeros函數(shù)將更新函數(shù)f中使用的生成器的狀態(tài)备埃。
例如:
>>> state_after_v0 = rv_u.rng.get_value().get_state()
>>> nearly_zeros() # this affects rv_u's generator
array([[ 0., 0.],
[ 0., 0.]])
>>> v1 = f()
>>> rng = rv_u.rng.get_value(borrow=True)
>>> rng.set_state(state_after_v0)
>>> rv_u.rng.set_value(rng, borrow=True)
>>> v2 = f() # v2 != v1
>>> v3 = f() # v3 == v1
在Theano圖之間復(fù)制隨機(jī)狀態(tài)
在一些使用情況下姓惑,用戶可能想要將與給定的theano圖(例如褐奴,具有下面的編譯函數(shù)f1的g1)相關(guān)聯(lián)的所有隨機(jī)數(shù)發(fā)生器的“狀態(tài)”轉(zhuǎn)移到第二個圖形(例如具有函數(shù)f2的g2)。這中情況例如于毙,如果你試圖從之前的一個序列化的模型的參數(shù)初始化模型的狀態(tài)敦冬。對于theano.tensor.shared_randomstreams.RandomStreams
和theano.sandbox.rng_mrg.MRG_RandomStreams
,可以通過復(fù)制state_updates
參數(shù)的元素來實現(xiàn)望众。
每當(dāng)從RandomStreams對象中繪制隨機(jī)變量時匪补,就會將元組添加到state_updates
列表中。第一個元素是一個共享變量烂翰,它表示與此特定變量??相關(guān)聯(lián)的隨機(jī)數(shù)生成器的狀態(tài),而第二個元素表示與隨機(jī)數(shù)生成過程對應(yīng)的theano圖(即RandomFunction {uniform} .0)蚤氏。
下面示出了如何將“隨機(jī)狀態(tài)”從一個theano函數(shù)傳遞到另一個函數(shù)的示例甘耿。
>>> from __future__ import print_function
>>> import theano
>>> import numpy
>>> import theano.tensor as T
>>> from theano.sandbox.rng_mrg import MRG_RandomStreams
>>> from theano.tensor.shared_randomstreams import RandomStreams
>>> class Graph():
... def __init__(self, seed=123):
... self.rng = RandomStreams(seed)
... self.y = self.rng.uniform(size=(1,))
>>> g1 = Graph(seed=123)
>>> f1 = theano.function([], g1.y)
>>> g2 = Graph(seed=987)
>>> f2 = theano.function([], g2.y)
>>> # By default, the two functions are out of sync.
>>> f1()
array([ 0.72803009])
>>> f2()
array([ 0.55056769])
>>> def copy_random_state(g1, g2):
... if isinstance(g1.rng, MRG_RandomStreams):
... g2.rng.rstate = g1.rng.rstate
... for (su1, su2) in zip(g1.rng.state_updates, g2.rng.state_updates):
... su2[0].set_value(su1[0].get_value())
>>> # We now copy the state of the theano random number generators.
>>> copy_random_state(g1, g2)
>>> f1()
array([ 0.59044123])
>>> f2()
array([ 0.59044123])
其他隨機(jī)分布
其他實現(xiàn)
還有2個基于MRG31k3p和CURAND
的實現(xiàn)竿滨。RandomStream只在CPU上工作佳恬,MRG31k3p在CPU和GPU上工作。CURAND只在GPU上工作于游。
注意
使用MRG版本很容易毁葱,你只需要更改import為:
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
真實示例:Logistic回歸
前面的內(nèi)容體現(xiàn)在下面這個更現(xiàn)實的例子中。它將被重復(fù)使用贰剥。
import numpy
import theano
import theano.tensor as T
rng = numpy.random
N = 400 # training sample size
feats = 784 # number of input variables
# generate a dataset: D = (input_values, target_class)
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
training_steps = 10000
# Declare Theano symbolic variables
x = T.dmatrix("x")
y = T.dvector("y")
# initialize the weight vector w randomly
#
# this and the following bias variable b
# are shared so they keep their values
# between training iterations (updates)
w = theano.shared(rng.randn(feats), name="w")
# initialize the bias term
b = theano.shared(0., name="b")
print("Initial model:")
print(w.get_value())
print(b.get_value())
# Construct Theano expression graph
p_1 = 1 / (1 + T.exp(-T.dot(x, w) - b)) # Probability that target = 1
prediction = p_1 > 0.5 # The prediction thresholded
xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1) # Cross-entropy loss function
cost = xent.mean() + 0.01 * (w ** 2).sum()# The cost to minimize
gw, gb = T.grad(cost, [w, b]) # Compute the gradient of the cost
# w.r.t weight vector w and
# bias term b
# (we shall return to this in a
# following section of this tutorial)
# Compile
train = theano.function(
inputs=[x,y],
outputs=[prediction, xent],
updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))
predict = theano.function(inputs=[x], outputs=prediction)
# Train
for i in range(training_steps):
pred, err = train(D[0], D[1])
print("Final model:")
print(w.get_value())
print(b.get_value())
print("target values for D:")
print(D[1])
print("prediction on D:")
print(predict(D[0]))