第二節,基礎知識之更多的例子
阿新 • • 發佈:2018-03-28
表達式 form 偽隨機 CP ... 表示 同一時間 ner state
先聲明:theano模塊的內容大都是參考來源於網上,並親手實踐復現一遍,也有部分內容是自己補充
本文會列出所參考文章,如有版權問題,請聯系我,我會及時刪除
# -*- coding: utf-8 -*- """ Created on Fri Mar 23 16:53:19 2018 @author: zy """ ‘‘‘ Theano2.1.3-基礎知識之更多的例子 http://www.cnblogs.com/shouhuxianjian/p/4594517.html ‘‘‘ import theano.tensor as T import theano ‘‘‘ 現在,是時候開始系統的熟悉theano的基礎對象和操作了,可以通過瀏覽庫的部分來詳細的了解 Basic Tensor Functionality. 隨著這個教程的深入,你可以逐漸的讓自己熟悉庫的其他相關的部分和文檔入口頁面的其他相關的主題了。 Basic Tensor Functionality:http://deeplearning.net/software/theano/library/tensor/basic.html#libdoc-basic-tensor‘‘‘ ‘‘‘ 一、Logistic函數 ‘‘‘ ‘‘‘ 這是一個簡單的例子:雖然回比兩個數值相加要難一些。假設你想要設計一個邏輯曲線,首先得到一個如下的式子 s(x) = 1/(1+exp(-x)) 你需要在doubles矩陣上逐元素(elementwise)的計算這個函數,也就是說你想要在矩陣的每個獨立的元素上都是用這個函數 代碼如下 ‘‘‘ import numpy as np x = T.dmatrix(‘x‘) s = 1/(1+T.exp(-x)) logistic = theano.function([x],s) inpt = np.array([[0,1],[-1,-2]],dtype=‘float64‘) print(logistic(inpt)) #[[ 0.5 0.73105858],[ 0.26894142 0.11920292]] ‘‘‘ 需要逐元素計算是因為它的操作:除法、加法、指數和減法,都是逐元素的操作。在該情況下也是: s(x) = 1/(1+exp(-x)) = (1+tanh(x/2))/2 我們可以驗證從這個可代替的式子上得到的結果是一樣的 ‘‘‘ s2 = (1 + T.tanh(x/2))/2 logistic2 = theano.function([x],s2) print(logistic2(inpt)) #[[ 0.5 0.73105858],[ 0.26894142 0.11920292]]‘‘‘ 二、在同一時間對多個操作進行運算 ‘‘‘ ‘‘‘ Theano支持函數有著多於一個的輸出。例如,我們可以在同一時刻計算兩個矩陣a和b 之間的逐元素(elementwise )的差, 絕對值的差,平方值的差: ‘‘‘ a,b =T.dmatrices(‘a‘,‘b‘) diff = a-b abs_diff = T.abs_(a-b) diff_squared = T.square(a-b) f = theano.function([a,b],[diff,abs_diff,diff_squared]) #note:dmatrices 生成提供的名字一樣數量的輸出。這是一個用來分配符號變量的快捷方式,在本教程中會經常用到。 #當我們使用函數f 時,它返回三個變量(輸出的時候會為了更好的可讀性而被重新格式): r1 = f([[1,1],[1,1]],[[0,1],[2,3]]) print(r1) #[array([[ 1., 0.], # [-1., -2.]]), array([[ 1., 0.], # [ 1., 2.]]), array([[ 1., 0.], # [ 1., 4.]])] ‘‘‘ 三、對參數設置默認值 ‘‘‘ ‘‘‘ 假設你想要定義一個相加兩個數的函數,如果你定義完之後,在調用的時候,只提供了一個參數,那麽另一個輸入可以假設默認 為1,可以如下所示: ‘‘‘ from theano import Param x,y = T.dscalars(‘x‘,‘y‘) z = x+y f = theano.function([x,Param(y,default=1)],z) print(f(33)) #34.0 print(f(33,2)) #35.0 ‘‘‘ 使用的 Param 參數允許你指定你函數的參數有著更詳細的值。這裏我們通過創建一個Param實例來將y設置其默認值為1。 有著默認值的輸入必須在沒有默認值的輸入的後面(和python的函數一樣的順序)可以對多個輸入進行設置默認值。 這些參數可以通過位置或者名稱來進行設定,就像標準的python中一樣: ‘‘‘ x, y, w = T.dscalars(‘x‘, ‘y‘, ‘w‘) z = (x + y) * w f = theano.function([x, Param(y, default=1), Param(w, default=2, name=‘w_by_name‘)], z) #對符號變量w名字重命名 print(f(33)) #68.0 print(f(33,2)) #70.0 print(f(33,0,1)) #33.0 print(f(33,w_by_name=1,y=0)) #33.0 ‘‘‘ note:Param 不知道作為參數傳入的局部變量y和w的名稱。這些符號變量對象都有name屬性(和上面例子一樣通過dscalars來設置) ,這些是我們構建的函數中的關鍵參數的名稱。這就是 Param(y, default=1)中的工作機制。在Param(w, default=2, name=‘w_by_name‘) 的情況下 ,我們用在這個函數中使用過的名字來覆蓋符號變量的名字屬性。 你可以看看庫中的 Function 來更詳細的了解。 function:http://deeplearning.net/software/theano/library/compile/function.html#usingfunction ‘‘‘ ‘‘‘ 四、使用共享變量 ‘‘‘ ‘‘‘ 同樣的也可以讓函數有一個內部狀態。例如,我們想要在開始就設置一個累加器,先初始化為0。那麽,在每次的函數調用, 該狀態就 會被函數的參數遞增的。首先定義一個accumulator 函數。然後將參數增加到內部狀態上,然後返回增加之前的狀態值。 ‘‘‘ state = theano.shared(0) inc = T.iscalar(‘inc‘) accumulator = theano.function([inc],state,updates=[(state,state+inc)]) ‘‘‘ 該代碼引入了一些新的概念。 shared 函數構建所謂的 shared variables。這些都是混合符號和非符號變量,他們的值可以在多個 函數中共享,就像是由dmatrices(...)返回的對象一樣,不過他們同樣有著一個內部值,這個值是通過這個在所有函數中使用的符號 變量定義的。被稱作共享變量是因為它的值在許多函數之間共享的。該值可以被 .get_value() 和 .set_value() 方法所訪問和修改。 該代碼中另一個新事物就是function. updates的參數 updates 必須被以(shared-variable, new expression)這種對形式的列表 所賦值。它同樣可以是一個字典,其中的鍵是共享變量而值是新表達式。。不管怎麽說,它表示“不論什麽時候運行,它會將.value的 每個共享變量替換成對應的表達式的結果” 。也就是說,我們的累加器會用狀態state的和以及遞增數來替換狀態state的值。 shared variables:http://deeplearning.net/software/theano/library/compile/shared.html#libdoc-compile-shared ‘‘‘ print(state.get_value()) #0 print(accumulator(1)) #0 print(state.get_value()) #1 state.set_value(-1) print(accumulator(3)) #-1 print(state.get_value()) #2 #正如上面說的,你可以定義超過一個函數來使用相同的共享變量。這些函數都能夠更新這個值。 decrementor = theano.function([inc], state, updates=[(state, state-inc)]) print(decrementor(2)) #2 print(state.get_value()) #0 ‘‘‘ 你也許會驚訝為什麽這個更新機制會存在。你總可以通過返回一個新的表達式來得到一個相似的結果,然後在NumPy裏面使用它們。 該更新機制是一個語法上的方便,不過在這裏主要是因為效率問題。對共享變量的更新有時候可以使用in-place算法更快的完成 (了例如: low-rank矩陣更新).。同樣的,theano有著更多有關在哪和如何來分配共享權重的函數,這些都是在需要使用在 GPU上很重要的組成部分. 有時候你想要使用一個共享變量來表示一些公式,卻不想要使用它們的值。在這種情況下,你可以使用function函數的givens 的參數,這個用來代替這種情況下graph中的特定的節點。 ‘‘‘ 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 = theano.function([inc, foo], fn_of_state, givens=[(state, foo)]) #使用foo變量替代state共享變量的值,並不更改state的值 print(skip_shared(1, 3)) # we‘re using 3 for the state, not state.value 3*2+1 = 7 print(state.get_value()) # old state still there, but we didn‘t use it 0 ‘‘‘ givens 參數可以用來代替任何符號變量,不只是共享變量。你還可以用來代替常量、表達式。不過要註意,不要讓由givens替 換的表達式之間有著相互依賴關系,替換的順序是沒法保證的,所以替換之後是有可能以任意順序來執行的。 在實際中,有關使用givens的一個好的方法就是替換公式的任何部分的時候使用的是不同的表達式,只不過該表達式有著相同 shape和dtype的張量而已。 note:Theano 共享變量的廣播模式默認情況下對於每個維度來說都是False。共享變量的size可以隨著時間變化,所以我們 沒法使用shape來找到可廣播的模式。如果你想要一個不同的模式,只要將它像參數一樣傳遞 theano.shared(..., broadcastable=(True, False))。 ‘‘‘ ‘‘‘ 五、使用隨機數 ‘‘‘ ‘‘‘ 因為在theano中,你首先會將任何事情進行符號化,然後編譯這個表達式來得到函數,然後使用偽隨機數不是和Numpy中一樣簡單的,當然也不會太復雜。 將隨機放入theano的計算中就是將隨機變量放到你的graph中。theano將會對每個這樣的變量分配一個 NumPy RandomStream 對象 (一個隨機生成器) ,然後必要的時候提取出來。我們稱這類隨機數序列為a random stream. 隨機流的核心也是共享變量,所以 對共享變量的觀察在這裏也是一樣的。theano的隨機對象的定義和實現在 RandomStreams 更低的版本,也就是其父類RandomStreamsBase. RandomStreams:http://deeplearning.net/software/theano/library/tensor/shared_randomstreams.html#libdoc-tensor-shared-randomstreams RandomStreamsBase:http://deeplearning.net/software/theano/library/tensor/raw_random.html#libdoc-tensor-raw-random ‘‘‘ from theano.tensor.shared_randomstreams import RandomStreams srng = RandomStreams(seed = 234) #創建一個隨機生成器 rv_u = srng.uniform((2,2)) #表示一個從均勻分布中提取2*2的矩陣的隨機流 rv_n = srng.normal((2,2)) #表示一個從標準正太分布中提取的2*2矩陣的一個隨機流。 f= theano.function([],rv_u) g = theano.function([], rv_n, no_default_updates=True) #Not updating rv_n.rng nearly_zeros = theano.function([],rv_u+rv_u - 2*rv_u) #現在讓我們來使用這些對象。如果我們調用 f(),我們就得到了均勻隨機數。 隨機數生成器的內部狀態是自動進行更新的,所以 #我們在每個時間上得到的是不同的隨機數: f_val0 = f() f_val1 = f() #different numbers from f_val0 print(f_val0) #[[ 0.12672381 0.97091597] # [ 0.13989098 0.88754827]] print(f_val1) #[[ 0.31971416 0.47584376] # [ 0.24129163 0.42046082]] #當我們增加額外的參數 no_default_updates=True 到 function (as in g),那麽隨機數生成器狀態不會受到返回函數調用的影響。 #所以,例如,調用g 函數多次,而返回的是同樣的數值: g_val0 = g() # different numbers from f_val0 and f_val1 g_val1 = g() # same numbers as g_val0! print(g_val0) #[[ 0.37328446 -0.65746671] # [-0.36302373 -0.97484624]] print(g_val1) #[[ 0.37328446 -0.65746671] # [-0.36302373 -0.97484624]] print(nearly_zeros()) #[[ 0. 0.] # [ 0. 0.]] #一個重要的備註是隨機變量在任何單一函數執行中最多被提取一次。所以,即使 rv_u 隨機變量在輸出表達式中出現了三次, #nearly_zero函數可以保證返回的值可以逼近0 (除了舍入導致的錯誤): #nearly_zeros = function([], rv_u + rv_u - 2 * rv_u) ‘‘‘ 隨機變量可以被獨立或集體的被傳入種子。你可以只對隨機變量通過seeding或者使用.rng.set_value()的.rng 屬性來指定傳入種子: ‘‘‘ 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方法來分配種子。該種子將會被用來傳遞給一個臨時隨機數生成器, #然後對每個隨機變量生成種子。 srng.seed(902340) # seeds rv_u and rv_n with different seeds each ‘‘‘ 在函數之間共享流 ‘‘‘ #和通常的共享變量一樣,用於隨機變量的隨機數生成器都是函數中常見的。所以我們的nearly_zeros 函數將會使用上面介紹的函數 # f 來更新生成器的狀態。例如: state_after_v0 = rv_u.rng.get_value().get_state() nearly_zeros() # this affects rv_u‘s generator 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 graphs之間復制隨機狀態 ‘‘‘ ‘‘‘ 在一些使用的情況中,用戶有可能想要將所有隨機數生成器的“state”從一個給定的theano graph (例如, g1,和下面編譯的函數f1一起的) 到 另一個 graph (例如 g2,和函數f2一起的).。如果你想要從之前模型的pickled版本的參數中初始化模型的state,那麽這個問題就會出現。 theano.tensor.shared_randomstreams.RandomStreams 和 theano.sandbox.rng_mrg.MRG_RandomStreams 可以通過復制state_updates 參數的元素來獲得 每次從一個RandomStreams對象中得到一個隨機變量,一個元組就會被添入到 state_updates 列表中。第一個元素就是一個共享變量,用來 表示與這個具體的變量相關聯的隨機數生成器的狀態,第二個元素用來表示對應於隨機數生成過程(即RandomFunction{uniform}.0)的theano graph。 一個關於如何“random states”可以從一個theano function遷移到另一個的例子如下: ‘‘‘ import theano from theano.sandbox.rng_mrg import MRG_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) print (‘By default, the two functions are out of sync.‘) print (‘f1() returns ‘, f1() ) print (‘f2() returns ‘, f2() ) 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()) print (‘We now copy the state of the theano random number generators.‘ ) copy_random_state(g1, g2) print (‘f1() returns ‘, f1() ) print (‘f2() returns ‘, f2() ) ‘‘‘ 會有如下的輸出: By default, the two functions are out of sync. f1() returns [ 0.72803009] f2() returns [ 0.55056769] # We now copy the state of the theano random number generators. f1() returns [ 0.59044123] f2() returns [ 0.59044123] ‘‘‘ ‘‘‘ 其他隨機分布 other distributions implemented. http://deeplearning.net/software/theano/library/tensor/raw_random.html#libdoc-tensor-raw-random ‘‘‘ ‘‘‘ 其他實現 這裏有2個基於 CURAND 和 MRG31k3p.的兩個實現。該RandomStream 只工作在CPU上, 而 MRG31k3p 既能在CPU 上也能在GPU上。CURAND 只工作在 GPU上。 http://deeplearning.net/software/theano/library/sandbox/cuda/op.html#module-theano.sandbox.cuda.rng_curand http://deeplearning.net/software/theano/library/sandbox/rng_mrg.html#libdoc-rng-mrg ‘‘‘ ‘‘‘ 六、邏輯回歸案例 ‘‘‘ rng = np.random N=400 #實例個數 feats = 784 #特征個數 #隨機生成訓練集數據 #numpy.random.randn(d0, d1, …, dn)是從標準正態分布中返回一個或多個樣本值。 #numpy.random.rand(d0, d1, …, dn)的隨機樣本位於[0, 1)中。 #rng.randint(size=N,low=0,high=2) 生成0或者1的類別 D = [np.asarray(rng.randn(N,feats),dtype=‘float32‘) ,np.asarray(rng.randint(size=N,low=0,high=2),dtype=‘float32‘)] #叠代次數 training_steps = 10000 #聲明theano符號變量 x = T.matrix(‘x‘) #float32 y = T.vector(‘y‘) #float32 w = theano.shared(np.asarray(rng.randn(feats),dtype=‘float32‘),name = ‘w‘) #float32 print(w.type) b = theano.shared(np.float32(0.0),name = ‘b‘) #float32 類型最好一致 print(b.type) print(‘Initial model‘) #print(w.get_value(),b.get_value()) #定義代價函數,預測函數表達式 p_1 = 1/(1 + T.exp(-T.dot(x,w)-b)) #目標為1的概率 prediction = p_1 > 0.5 #預測閾值 >0.5 預測類別為1 否則為0 xent = -y*T.log(p_1) - (1-y)*T.log(1-p_1) #交叉熵代價函數 維數為:實例個數*1 cost = xent.mean() + 0.01*(w**2).sum() #加入正則項 求平均 gw,gb = T.grad(cost,[w,b]) #定義編譯函數 #訓練函數 train = theano.function( inputs = [x,y], outputs = [prediction,xent], updates=[(w,w-0.1*gw),(b,b-0.1*gb)]) #預測函數 predict = theano.function([x],prediction) #準確率 acc = T.mean(T.eq(T.cast(y,‘bool‘) ,prediction)) accuracy = theano.function([x,y],acc) for i in range(training_steps): pred,err=train(D[0],D[1]) print(‘Final Model‘) print(w.get_value(),b.get_value()) print (‘target values for D:‘, D[1]) print (‘prediction on D:‘, predict(D[0])) print(‘accuracy:‘,accuracy(D[0],D[1]))
第二節,基礎知識之更多的例子