1. 程式人生 > >Theano中文翻譯教程(二). 基礎騙之 More Examples

Theano中文翻譯教程(二). 基礎騙之 More Examples

>>> 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])
當我們執行function 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.]])]

注: 在這裡定義輸入變數時我們用的是T.dmatrices(),它可以同時定義多個矩陣變數,而前文T.dmatrix()一次只能定義一個矩陣變數。

對函式的輸入引數設定預設值

假設我們想要定義一個這樣的函式,可以算出兩個數的和,但是如果你只給第一個變數賦值,第二個變數預設值為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 這個類,可以設定你定義函式的某個引數的預設值。顯而易見,我們定義變數y的預設值為1。即如果你不給y傳傳入值,則y的值自動取為1;如果你給y傳入值,則y的取值為你所傳入的。 和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)
注:經測試 f(33, w=1, y=0), f(33, w_by_name=1, 0), f(33, y=1, 1)均是錯誤的 這裡我一知半解,意思大概就是 第一個錯誤:我們用'w_by_name'覆蓋了'w',函式不識別w。 第二和三個錯誤:因為我們定義了兩個關鍵詞y和w_by_name,當你的輸入變數有關鍵詞時,它的後面必須也是關鍵詞,因此f(33, y=1, w_by_name=1)和f(33, w_by_name=1, y=0)是正確的 詳情請看Theano庫中的Function

共享變數

給函式一個內部變數是也可行的,讓我們來做一個累加器:在開始時,累加器的狀態(值)設為0,每次迴圈累加器的值都會因為給定的輸入變數而增加。 首先,我們先定義一個累加器。它加上輸入變數並傳給內部狀態,然後返回舊的內部狀態。
>>> from theano import shared
>>> state = shared(0)
>>> inc = T.iscalar('inc')
>>> accumulator = function([inc], state, updates=[(state, state+inc)])
這段程式碼包含了幾個新的概念。shared函式構建了一個所謂的共享變數,而這個變數的值可以在多個函式中共享。如同 dmatrices() 的功能一樣,只不過這個共享變數包含了一一個可以被很多函式共享的內部值。通過shared() 所定義的變數可以被修改.get_value()和列印.set_value。 這段程式碼中另一個新的概念就是 function 函式中的 updates 引數, 這個引數必須被賦予 (共享變數, 新的表示式)這樣的形式。意思就是,每當這個函式執行,共享變數的值值都會通過定義的新的表示式而進行更新。因此我們的累加器才能夠成功執行。來讓我們試一下吧!
>>> print(state.get_value())
0
>>> accumulator(1)
array(0)
>>> print(state.get_value())
1
>>> accumulator(300)
array(1)
>>> print(state.get_value())
301
當然,共享變數的值可以被重新定義,利用 .set_value() >>> state.set_value(-1)
>>> accumulator(3)
array(-1)
>>> print(state.get_value())
2
正如我們在前面所提到的,你可以定義不止一個函式來共享同一個共享變數,這些函式都可以更新它的值
>>> decrementor = function([inc], state, updates=[(state, state-inc)])
>>> decrementor(2)
array(2)
>>> print(state.get_value())
0
你可能會想這樣的共享機制有什麼用,你可以用一個新的表示式返回上述同樣的結果。這種機制可以使你的程式碼簡潔,不過更主要的是可以提高效率。共享變數在適當的演算法上上(例如低階矩陣的更新)可以運算的非常快。除此之外,Theano可以更好地控制共享變數的分配,是提高GPU效能的一個很重要的方面。 有些時候當你用共享變數計算完某個式子後,卻不想要這個值。這種情況下,你可以用 function 中的 givens 引數。
>>> 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 引數可以用來替代任何變數,不一定是共享變數,可以是常數也可以是表示式 因此實際操作中,我們可以利用 givens 來用同一型別和長度的不同表示式替換你的表示式的某一項 (筆者一直無法實現這幾個操作)

隨機數

在Theano中一般是先用各種符號完成表示式,然後再去編譯表示式得到函式。在Numpy中用偽隨機數雖然簡單但是顯然是不直觀的。 我們一般是先定義隨機變數,然後再把隨機變數放入 Theano 的計算中來增加隨機性。Theano會為每一個隨機變數分配一個隨機數生成器,什麼時候需要什麼時候再用。我們稱這種隨機數列為隨機流,而隨機流的核心就是共享變數。

簡單的例子

這是一個簡單的例子,初始程式碼如下
from theano.tensor.shared_randomstreams import RandomStreams
from theano import function
srng = RandomStreams(seed=234)
rv_u = srng.uniform((2,2))<pre name="code" class="python"><span style="font-family: Arial, Helvetica, sans-serif;">rv_n = srng.normal((2,2))</span>
f = function([], rv_u)g = function([], rv_n, no_default_updates=True) #Not updating rv_n.rngnearly_zeros = function([], rv_u + rv_u - 2 * rv_u) 在這裡,'rv_u'代表著一個2x2的隨機流矩陣,裡面的數是從均勻分佈中取得的。同樣'rv_n'也代表著一個2x2的隨機流矩陣,裡面的數是從正態分佈中取得的。這些分佈在 RandomStreams中就被定義好了,在低層次上raw random。這樣的隨機數只能用在CPU上,GPU版本請戳這裡 現在我們可以開始使用了, 如果我們呼叫 f(), 我們得到均勻分佈的隨機數,內部的隨機數生成器可以幫我們自動更新,因此每次呼叫都會得到不同的隨機數
>>> f_val0 = f()
>>> f_val1 = f()  #different numbers from f_val0
當我們給function函式增加一個輸入引數no_default_updates = True時,例如函式g,這樣每次呼叫函式就不會更改隨機數的值,兩次呼叫將返回同樣的值
>>> g_val0 = g()  # different numbers from f_val0 and f_val1
>>> g_val1 = g()  # same numbers as g_val0!
很重要的一點就是在單獨的函式中,每個隨機變數最多隻會被呼叫一次,因此在 nearly_zeros函式中,即使該隨機變數被呼叫了3次,還是會得到一個非常接近0的數(除非有時因為舍入誤差)。
>>> nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)

種子流

隨機變數的種子可以被統一指定(上一節)或者單獨指定。通過 .rng.set_value 可以把rv_u分配隨機種子的任務交給變數rng_val
>>> 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
一般來說,我們定義完隨機變數後,先用上一節的方法為所有隨機變數的種子設定一個暫時的初值,然後如果有需要,再對個別的隨機變數設定其自己的種子值

在函式之間共享種子

如同共享變數一樣,隨機變數的隨機數生成器也可以在不同的函式間共享。因此 nearly_zeros 函式就可以更新 f 函式的隨機數生成器的狀態
>>> 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圖之間複製隨機狀態

有些情況下,使用者希望把所有隨機數生成器的‘狀態’從一個 theano圖到另一個 theano圖,比如你想要用一個模型的狀態去初始化另一個模型的狀態。對theano.tensor.shared_randomstreams.RandomStreams和我們可以通過拷貝 state_updates 引數去實現。 每一次從隨機流物件得到隨機變數,一個元組就會被增加到 state_updates 的列表中。第一個元素是共享變數,代表著隨機數生成器的狀態;第二個元素代表著theano圖,對應著隨機數生成過程(例如 RandomFunction{uniform}.0)
下面是“隨機狀態“從一個函式轉化到另一個函式的例子。
>>> 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])

一個例子:邏輯迴歸

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.matrix("x")
y = T.vector("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]))


本文翻譯自:http://deeplearning.net/software/theano/tutorial/

並對有些文字進行了適當的刪改