Theano 學習筆記(一)
為什么要定義共享變量?
定義共享變量的原因在於GPU的使用,如果不定義共享的話,那么當GPU調用這些變量時,遇到一次就要調用一次,這樣就會花費大量時間在數據存取上,導致使用GPU代碼運行很慢,甚至比僅用CPU還慢。共享變量的類型必須為floatX
因為GPU要求在floatX上操作,所以所有的共享變量都要聲明為floatX類型
- shared_x = theano.shared(numpy.asarray(data_x, dtype=theano.config.floatX))
-
- self.A = theano.shared(name = "A", value = E.astype(theano.config.floatX))
創建tensor variables
在創建變量時可以給變量命名,命名能夠加快debugging的過程,所有的構造器中都有name參數供命名,下面三種創建變量的方式都是創建一個整型的標量,命名為‘myvar’
- x = scalar('myvar',dtype='int32')
- x = iscalar('myvar')
- x = TensorType(dtype = 'int32', broadcastable=())('myvar')
典型構造器
- theano.tensor.scalar(name=None,dtype=config.floatX)
- theano.tensor.vector(name=None,dtype=config.floatX)
- theano.tensor.row(name=None, dtype=config.floatX)
- theano.tensor.col(name=None,dtype=config.floatX)
- theano.tensor.matrix(name=None,dtype=config.floatX)
- theano.tensor.tensor3(name=None,dtype=config.floatX) #3D張量
- theano.tensot.tensor4(name=None,dtype=config.floatX) #4D張量
導入的命名空間 from theano.tensor import *
創建新的Tensor Type
- dtensor5 = TensorType('float64',(False,)*5)
- x=dtensor5()
- z=dtensor5('z')
-
Theano requires that the inputs to all expressions be Variable instances, so Theano automatically wraps them in a TensorConstant. Thus, when you use a numpy ndarray or a python number together with TensorVariable instances in arithmetic expressions, the result is a TensorVariable.
-
broadcastable
這個東西是一個布爾有元素組成的元組,比如[False,True,False]等
broadcastable 一方面指定了類型的大小,另一方面也指定了那個維度上size只能為1(True,表示對應維度上長度只能為1,matlab: size(A,broadcasrable(i)==True)=1)
- [] scalar
- [True] 1D scalar (vector of length 1)
- [True, True] 2D scalar (1x1 matrix)
- [False] vector
- [False, False] matrix
- [False] * n nD tensor
- [True, False] row (1xN matrix)
- [False, True] column (Mx1 matrix)
- [False, True, False] A Mx1xP tensor (a)
- [True, False, False] A 1xNxP tensor (b)
- [False, False, False] A MxNxP tensor (pattern of a + b)
For dimensions in which broadcasting is False, the length of this dimension can be 1 or more.
For dimension in which broadcasting is True, the length of this dimension must be 1.
另外,broadcastable,顧名思義,與傳播運算有關,當兩個維度不同的參數進行元素運算時,broadcastable pattern 可以通過在tuple的左側填充True,湊齊維度。
比如 a vector's pattern [False],可以擴展成 [True, False]; a matrix pattern [False,False]可以擴展成 [True, False,False]
然后對應的True維度上就可以broad了
這樣學起來實在是太慢了。。。。。。。。。。。
總覺得python亂,還是讀代碼吧,邊讀邊學。。。
- import theano
- import theano.tensor as T
- x=T.matrix('x')
- s=1/(1+t.exp(-x))
- logistic = theano.function([x],s)
- logistic([[1,2,3],[4,3,0.5]])
結果

學到的點:
聲明符號變量x,名稱為'x',這個我們也說了主要是為了GPU調度方便
+,-,*,/,包括exp等函數都是元素操作的
logistic相當於一個函數句柄,這個函數的輸入是x,輸出是s, x到s的關系根據前面定義可得
- import theano
- import theano.tensor as T
- a,b=T.matrices('a','b')
- diff = a-b
- abs_diff = abs(diff)
- diff_squared = diff**2
- f = theano.function([a,b],[diff,abs_diff,diff_squared])
點:
theano 可以定義多輸入多輸出,類似的matlab代碼
- function [diff,abs_diff,diff_squared]=f(a,b)
- ...
- end
matrices 是同時聲明參數個數個變量,類似的還有scalars,vectors等
- f([[1,2,3],[2,1,1]])
輸出結果

可以看到輸出的是個tuple,正對應輸出指定變量
- import theano
- import theano.tensor as T
- from theano import In
- x,y = T.scalars('x','y')
- z=x+y
- f= theano.function([x,In(y,value=1)],z)
- f(2)
- f(2,5)
輸出結果

新知識點:
In 這個類能夠更詳細的指定函數的參數,比如默認值。 函數中給定默認值的參數應該放在沒給定默認值參數的后面,c++也這樣。
In 還能夠重新給參數命名,這樣就能夠使函數輸入,假設2-4個輸入是有默認值的,但我2,3想使用默認值,第4個不想使用默認值時,不用對2,3賦值了,比如
- x,y,w= T.scalars('x','y','w')
- z=(x+y)*w
- f=T.function([x,In(y,value=1),In(w,value=2,name='w_byname')],z)
那么f(33,1,5)和f(33,w_by_name=5)結果時一樣的
這里為什么w已經有名字'w'了,還要再定義名字呢?
主要是由於In並不知道局部變量x,y,w的名字,函數輸入參數其實就是一個字典,keyword是scalar默認的姓名屬性,這里In是重寫了參數的keyword
- from theano import shared
- from theano import In
- import theano
- import theano.tensor as T
- state = shared(0)
- inc = T.scalar('inc')
- accumular = function([inc],state,update=[(state,state+inc)])
新知識點:
shared 這個函數聲明的是一個符號和變量的結合體,也就說他直接賦值了,內部有一定的值參與運算。另外之所以稱為shared是因為這個量是可以多個函數共享的,有點像c++里面的靜態變量,在一個函數里面修改了這個量,后面使用這個量的函數就是在新的值上運算了。
shared變量可以通過.set_value()和.get_value()設置和讀取狀態值updates是一個list量,他的元素是(shared_variable,new expression)對,有點像字典,每次對keyword對應的值更新,注意
這里是先返回的state,再進行的state=state+inc,看下面的代碼結果

- >>> 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
知識點:
這個蠻有意思的,就是說我現在有個函數,函數里面的計算牽涉到state變量,但是我不想使用state當前的值,那么我就可以使用function的givens參數另一個值暫且替代state
看上面這個代碼,我使用state表示的fn_of_state,但是計算時不想使用當前state的值,而是使用3,於是使用givens令新變量foo替代state占的位置,所以得到的結果fn_of_state=foo*2+inc=7
而state.get_value()值仍然為state的原先值,這里是0這里的givens不僅僅可以適用於shared,還可以適用於任意的symbolic variable,要注意的是在givens的list里面替代的量要相互獨立,要不然就不知道怎么替代了
shared變量默認的是broadcastable=False,所以要想使用broadcasrable pattern,需要特別指定,如
theano.shared(...,broadcastable=(True,False))
1