のんびりしているエンジニアの日記

ソフトウェアなどのエンジニア的な何かを書きます。

Python Theanoの使い方(自動微分:Grad、関数:Function,乱数:RandomStream)

Sponsored Links

こんにちわ
お元気ですか?私は元気です。

さて、本日はTheanoについて

Theanoとは?

Deep Learningを実装するために作られたPythonのライブラリなのかな…
色々計算するのに便利です。

特徴

①科学技術計算ライブラリNumpyの使用(numpy.ndarray)
GPUの使用(計算速度の向上)
③自動微分システムが搭載されてる(便利!)
④なんか関数作れるよ

インストール

sudo pip install theano

How to Use

import

import numpy

import theano
import theano.tensor as T
from theano.tensor.shared_randomstreams import RandomStreams

変数の作り方

x = dscalar()
y = dvector()
z = dmatrix()

x = lscalar()
y = lvector()
z = lmatrix()

関数の名前はd = double l = long
もしくは値(scalar)、ベクトル(vector)、行列(matrix)で決まります。
これをシンボルというそうです。
これを元にこれから関数を作ってみましょう。

function

単純なfunctionの利用
x = T.lscalar("x")
y = x*2
f = theano.function([x],y)
#f = 3 * 2
print f(3) #6`

yにx * 2の式が入っています
(xはobject)つまり、yを出力しても数字が出てきません
f = theano.function([x],y)は与える引数のシンボルを入れていたらいいと思います。

f(3)にてy = x * 2のうち、x に 3を代入し実際の計算した値を出力しています(今回は6ですね)

givensの活用

theano.functionではgivenと呼ばれる引数を渡せます。
givenでは与えたシンボルから計算し、それを値として置き換えるようなことをしています。
言葉では意味不明なので、実際に例を見てみましょう。

x = T.dscalar()
y = T.dscalar()
c = T.dscalar()

#ff = (2 * 10.0) * 2 + 5.0 = 45.0
ff = theano.function([c], x*2+y, givens=[(x, c*10.0), (y,5.0)])
print ff(2) #45.0

実際の動作ですが、cに2を渡し、x = 2 * 10.0、y = 5.0としています。
そのため実際の計算では (2 * 10.0) * 2 + 5.0 = 45.0となります。

自動微分

先程からtheano.functionの式は微分ができます。凄いですね…
むしろこれが便利だから利用している人はきっと多いはず。

z = (x+2*y)**2
gx = T.grad(z,x) #微分するとdz/dx =2(x+2*y) ,gxにその式が入る
fz = theano.function([x,y],z) #functionを生成 #25.0
fgx = theano.function([x,y],gx) #functionを生成 #10
print fz(1,2) #25.0
print fgx(1,2) #10

T.gradを利用すると微分ができます。
T.grad(z,x) = zをxで微分、もちろん yでも同じことができます。

Shared(共有変数)

なんかすごい

x = T.dscalar('x')
b = theano.shared(1)
f = theano.function([x],b*x)
print f(2) #2.0
b.get_value()
b.set_value(3)
print f(2) #6.0

式を構成した後に、変数にしていない部分をこの共有変数を変更することによって切り替えることができます凄い。
今回の場合、f = b * xの式があり、変数として入れるのはxのシンボルです。
しかし、bを変更したい場合にb.set_value()で変更することによって変更することができ、funcitonにも反映することができます。

1 * 2 → 3 * 2へ式が今回は変わってますね。

update

まずは簡単な例から
c = theano.shared(0)
f = theano.function([],c,updates = {c:c+1})
print f
print f() #0
print f() #1
print f() #2

関数を実行する時にupdatesに登録してある辞書にもとづいて
共有変数を変更してくれます。
勾配法を利用する方には素晴らしいですね。

勾配法
x = T.dvector("x")
c = theano.shared(0.)
y = T.sum((x-c)**2)
gc = T.grad(y,c) #偏微分
d2 = theano.function([x],y,updates={c:c-0.05*gc})

for i in xrange(3):
	print d2([1,2,3,4,5])
	print c.get_value()
55.0
1.5
21.25
2.25
12.8125
2.625

勾配法によって値が小さくなるように変化すること、そして共有変数cの値が変化していってることがわかります。
c:c-0.05*gcの0.05は学習係数です。

乱数(RandomStream)

最後に乱数の生成です。基本的にはnumpyのrandomの使い方と同じです。

numpy_rng = numpy.random.RandomState(89677)
theanoRng = RandomStreams(numpy_rng.randint(2 ** 30))
	
#2項分布
fbino = theanoRng.binomial(size=(1,3))
funi = theanoRng.uniform(size=(3,2))
#関数化
f1 = theano.function([],fbino)
f2 = theano.function([],funi)
#とりあえず使う
print f1()
print f2()

functionから読み出せば、使えます。

気が向いたらロジスティック回帰とかDenoising Auto Encoderのソースコードの解説でもやりたいと思います。
数学をやる時間がないんだけど大丈夫かなぁ

参考文献

http://qiita.com/mokemokechicken/items/3fbf6af714c1f66f99e9
ソースコードを参考にさせて頂きました。(というかちょっとしか変えてない…)
http://deeplearning.net/tutorial/

ソースコード全文

#coding:utf-8
import numpy

import theano
import theano.tensor as T
from theano.tensor.shared_randomstreams import RandomStreams

"""
Functionメソッドについて
実行しているコードの箇所
"""
def functionTest():
	"""
	Functionメソッドについて
	実行しているコードの箇所
	"""
	x = T.lscalar("x")
	y = x*2
	"""Function オーソドックス"""
	#f = 3 * 2
	f = theano.function([x],y)
	print f(3) #6`


	"""Function Given込"""
	x = T.dscalar()
	y = T.dscalar()
	c = T.dscalar()

	#ff = (2 * 10.0) * 2 + 5.0 = 45.0
	ff = theano.function([c], x*2+y, givens=[(x, c*10.0), (y,5.0)])
	print ff(2) #45.0


	"""自動微分"""
	z = (x+2*y)**2
	gx = T.grad(z,x) #微分するとdz/dx =2(x+2*y) gxにその式が入る
	fz = theano.function([x,y],z) #functionを生成
	fgx = theano.function([x,y],gx) #functionを生成
	print fz(1,2)
	print fgx(1,2)

"""
共有変数部分のテスト
Shared
"""
def sharedTest():
	x = T.dscalar('x')
	b = theano.shared(1)
	f = theano.function([x],b*x)
	print f(2)
	b.get_value()
	b.set_value(3)
	print f(2)

"""
Updateの利用方法
これをうまく使うと勾配法を実装できる。
"""

def updateTest():
	""" 簡単なUpdate文の使い方 """
	c = theano.shared(0)
	f = theano.function([],c,updates = {c:c+1})
	print f
	print f()
	print f()
	print f()

	x = T.dvector("x")
	c = theano.shared(0.)
	y = T.sum((x-c)**2)
	gc = T.grad(y,c)
	d2 = theano.function([x],y,updates={c:c-0.05*gc})

	for i in xrange(3):
		print d2([1,2,3,4,5])
		print c.get_value()

def testRandomStream():
	"""Numpy Random"""
	numpy_rng = numpy.random.RandomState(89677)
	theanoRng = RandomStreams(numpy_rng.randint(2 ** 30))
	
	#2項分布
	fbino = theanoRng.binomial(size=(1,3))
	funi = theanoRng.uniform(size=(3,2))
	#関数化
	f1 = theano.function([],fbino)
	f2 = theano.function([],funi)
	#とりあえず使う
	print f1()
	print f2()

if __name__ == '__main__':
	functionTest()
	sharedTest()
	updateTest()
	testRandomStream()