神经网络的模型可以参考 UFLDL 的教程,这里不做过多描述。
http://ufldl.stanford.edu/wiki/index.php/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C
In [1]:
import theano
import theano.tensor as T
import numpy as np
from load import mnist
Using gpu device 1: Tesla K10.G2.8GB (CNMeM is disabled)
我们在这里使用一个简单的三层神经网络:输入 - 隐层 - 输出。
对于网络的激活函数,隐层用 sigmoid
函数,输出层用 softmax
函数,其模型如下:
$$ \begin{aligned} h & = \sigma (W_h X) \ o & = \text{softmax} (W_o h) \end{aligned} $$In [2]:
def model(X, w_h, w_o):
"""
input:
X: input data
w_h: hidden unit weights
w_o: output unit weights
output:
Y: probability of y given x
"""
# 隐层
h = T.nnet.sigmoid(T.dot(X, w_h))
# 输出层
pyx = T.nnet.softmax(T.dot(h, w_o))
return pyx
使用随机梯度下降的方法进行训练:
In [3]:
def sgd(cost, params, lr=0.05):
"""
input:
cost: cost function
params: parameters
lr: learning rate
output:
update rules
"""
grads = T.grad(cost=cost, wrt=params)
updates = []
for p, g in zip(params, grads):
updates.append([p, p - g * lr])
return updates
对于 MNIST
手写数字的问题,我们使用一个 784 × 625 × 10
即输入层大小为 784
,隐层大小为 625
,输出层大小为 10
的神经网络来模拟,最后的输出表示数字为 0
到 9
的概率。
为了对权重进行更新,我们需要将权重设为 shared 变量:
In [4]:
def floatX(X):
return np.asarray(X, dtype=theano.config.floatX)
def init_weights(shape):
return theano.shared(floatX(np.random.randn(*shape) * 0.01))
因此变量初始化为:
In [5]:
X = T.matrix()
Y = T.matrix()
w_h = init_weights((784, 625))
w_o = init_weights((625, 10))
模型输出为:
In [6]:
py_x = model(X, w_h, w_o)
预测的结果为:
In [7]:
y_x = T.argmax(py_x, axis=1)
模型的误差函数为:
In [8]:
cost = T.mean(T.nnet.categorical_crossentropy(py_x, Y))
更新规则为:
In [9]:
updates = sgd(cost, [w_h, w_o])
定义训练和预测的函数:
In [10]:
train = theano.function(inputs=[X, Y], outputs=cost, updates=updates, allow_input_downcast=True)
predict = theano.function(inputs=[X], outputs=y_x, allow_input_downcast=True)
训练:
导入 MNIST 数据:
In [11]:
trX, teX, trY, teY = mnist(onehot=True)
训练 100 轮,正确率为 0.956:
In [12]:
for i in range(100):
for start, end in zip(range(0, len(trX), 128), range(128, len(trX), 128)):
cost = train(trX[start:end], trY[start:end])
print "{0:03d}".format(i), np.mean(np.argmax(teY, axis=1) == predict(teX))
000 0.7028
001 0.8285
002 0.8673
003 0.883
004 0.89
005 0.895
006 0.8984
007 0.9017
008 0.9047
009 0.907
010 0.9089
011 0.9105
012 0.9127
013 0.914
014 0.9152
015 0.9159
016 0.9169
017 0.9173
018 0.918
019 0.9185
020 0.919
021 0.9197
022 0.9201
023 0.9205
024 0.9206
025 0.9212
026 0.9219
027 0.9228
028 0.9228
029 0.9229
030 0.9236
031 0.9244
032 0.925
033 0.9255
034 0.9263
035 0.927
036 0.9274
037 0.9278
038 0.928
039 0.9284
040 0.9289
041 0.9294
042 0.9298
043 0.9302
044 0.9311
045 0.932
046 0.9325
047 0.9332
048 0.934
049 0.9347
050 0.9354
051 0.9358
052 0.9365
053 0.9372
054 0.9377
055 0.9385
056 0.9395
057 0.9399
058 0.9405
059 0.9411
060 0.9416
061 0.9422
062 0.9427
063 0.9429
064 0.9431
065 0.9438
066 0.9444
067 0.9446
068 0.9449
069 0.9453
070 0.9458
071 0.9462
072 0.9469
073 0.9475
074 0.9474
075 0.9476
076 0.948
077 0.949
078 0.9497
079 0.95
080 0.9503
081 0.9507
082 0.9507
083 0.9515
084 0.9519
085 0.9521
086 0.9523
087 0.9529
088 0.9536
089 0.9538
090 0.9542
091 0.9545
092 0.9544
093 0.9546
094 0.9547
095 0.9549
096 0.9552
097 0.9554
098 0.9557
099 0.9562