標籤:

Theano (1)

Palo Alto的早晨好冷。。再加上沒有太陽,所以就不想出門了。不想把這個叫做「學習筆記」,因為實在有太多學習筆記,看多了就覺得很煩。但是如果叫做Tutorial(教程),又必須到達把人教會的地步為止,所以只好寫個偉大的Theano當做標題,就當做是Theano中讓人感到驚奇的地方了吧(我還算是Python新手,對Cython,Numpy,Scipy等等還不夠熟悉,所以對我來講很驚異的事情,不一定對高手來講很驚奇,所以這點請見諒)。

各種知識點來自於More Examples(官方指南的某頁)和一本暫時還沒開賣的書,是Manning出版社的MEAP系列,叫做《Fundamentals of Deep Learning》(深度學習基礎),希望以後國內能有所翻譯。

這不是教程,這不是教程,這不是教程,所以在對Theano一點知識都沒有的情況下,請不要閱讀這玩意。這是一篇變相吐槽文。

包含知識點:

Shared Variable 共享變數

Given 函數對象的其中一個參數

Borrowing 租賃(指針)

= Shared Variable =

共享變數。《深度學習基礎》書里說這玩意是(Stateful function)有狀態方程的必備物。這種說了等於沒說的東西其實還是不提的好。實際上共享變數基本上算是值會變化的變數,尤其是能讓人手動調整其變化的變數。所有在

theano.function(updates=((a, b), (c,d)))

updates裡面的變數,都必須是共享變數。比較常見的「共享」變數包括機器學習演算法中的權重(weights),或者需要學到的參數(比如回歸中的beta值等等)

w = theano.shared(numpy.random.randn(700), name="w") b = theano.shared(0., name="b")train = theano.function(inputs=[x, y], outputs=[prediction, xent], updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))

= Givens =

這是在theano.function()中的一個參數(Parameter),和update很像,也是接受一個Pair,一組變數,當然也可以是一個key-value map(數值鍵)。從某種意義上來講——至少官方指南是這樣說得,given可以用來保持共享變數的狀態不變,來動態替換共享變數——好奇葩的用途。

state = shared(0)inc = T.iscalar(inc)fn_of_state = state * 2 + incfoo = T.scalar(dtype=state.dtype)skip_shared = function([inc, foo], fn_of_state, givens=[(state, foo)])

就這樣,每次將foo替換state,所以如果執行

skip_shared(1, 3)

我們會自然的得到7([foo=3] * 2 + [inc=1] = 7)。然後如果我們查看state的值:state.get_value(),我們會發現值一直為0。現在讓我們來試試官方指南沒有進行的嘗試,如果我將上面的簡單代碼改成如下,什麼會發生呢?

skip_shared = function([inc, foo], fn_of_state, updates=[(state, state + inc)], givens=[(state, foo)])

如果在這裡加上updates條件,state變數在一次執行後會變成什麼呢?答案是4。為什麼?因為整個state變數的值被foo替換了,包括在updates中,state = state + inc,實際變為了state = foo + inc。而且state的值將會一直為4,不會改變。是不是挺有趣的?(但是一點實際作用都木有)

好歹還有《深度學習基礎》圖書來拯救。這本書提供了一個比較有用的用法:

state = shared(0)query = T.dvector(query)W = T.dvector("W") # model parameterresult = T.dot(W, query) > 0sentiment = function(inputs=[query], outputs=result, updates=[(state, state + 1)], givens={ W: np.array([1, -2, 3, -0.5, 1]) })

這是什麼意思呢?把given作為一個賦值器,傳入不變的常量,這樣讀者就不用自己傳入了。該書聲明如此賦值能讓Theano對graph structure(圖結構)進行優化,但我還沒能進行驗證:)說不定以後驗證了再來補完這一節。

小記:關於不改變變數,no_default_updates=False 可以關閉對變數的自動更新,但這一般是針對隨機變數的。方程會自動更新所有變數(在完成一次執行後),除了那些有特殊標記的變數,或者在updates=中的變數。

= Borrowing =

這是Theano裡面第一個讓我吃驚的概念,這彷彿讓我看到了「指針」這樣的存在——雖然對於Python來講,估計都是Pass-by-reference。官方的教程厚顏無恥的在最基礎的部分各種使用borrow,看得我這個初學者是一愣一愣的。於是仔細研究了一下,發現這玩意還真的比較有趣。

一共有三種Borrow模式,前兩種我稍有探索,最後一種只是在這裡提及一下,以後有機會再補充。

== Borrowing When Creating Shared Variable ==

在創造共享變數的時候實現Borrow。

import numpy, theanonp_array = numpy.ones(2, dtype=float32)s_default = theano.shared(np_array)s_false = theano.shared(np_array, borrow=False)s_true = theano.shared(np_array, borrow=True)

其實真心就是指針杠杠的。當創造一個共享變數,開啟Borrow模式,任何在np_array上進行的操作就會影響到s_true共享變數了。

== Borrowing When Accessing Value of Shared Variables ==

v_false = s.get_value(borrow=False) v_true = s.get_value(borrow=True)v_internal = s.get_value(borrow=True, return_internal_type=True)

在這裡,官方指南講了一堆,實際上就是一點,當你讀取共享變數值的時候(很多時候是在某theano function已經改變值了後,如果不開啟borrow,Theano會另外創建一個變數,將原本值拷貝給那個變數,然後給你——簡直是勞民傷財啊,估計就是怕程序員亂搞吧。所以傳入一個borrow=True,告訴Theano不必大費周章,會提高很多運行速度。

聰明的中國程序員們一定會想,既然能拿出在內部的變數,能否進行更改呢?好想法,但是因為Theano也會在GPU上跑,所以如果創造的演算法依賴對共享變數的取出更改操作,那麼該演算法就不能在GPU上跑了。

最後一個return_internal_type=True,是強制(保證一定)返回Theano內部的變數,並不一定是你傳進去變數的數據類型。但經過一些嘗試,只要不在GPU上跑,就算是開啟了return_internal_type=True,返回來的也和傳進去的值相同:)

== Borrowing When Constructing Function Objects ==

這算是很無聊但是比較有趣的一節了。強調的是,在創建函數時,應該儘可能的開啟Borrow模式,來提升運算速度。

x = theano.tensor.matrix()y = 2 * xf = theano.function([theano.In(x, borrow=True)], theano.Out(y, borrow=True))

官方指南介紹的很長,但簡單來講,這玩意也是給GPU提速用的,開啟之後,提速15倍左右(有測試)。使用的條件是,如果你傳入後就不再用x變數了,就該開啟傳入,當你返回一個很大的y值(占記憶量很大),而你只需要讀取一次的情況下,開啟borrow也能讓速度大幅提升。

寫了這麼多,本來承諾不寫機器學習的內容,只寫我稍微比較了解的Scala或者自然語言處理。但正在學Theano嘛,不寫不好玩。。。所以各種請見諒。(這篇文章會再更新一兩節,直到我想寫第二篇系列文為止)


推薦閱讀:

打開機器學習的黑盒——卷積神經網路原理介紹
Python基礎_103.數據結構與演算法_查找
《大演算:機器學習的終極演演算法將如何改變我們的未來,創造新紀元的文明》

TAG:機器學習 |