在 theano 中学会定义矩阵 matrix 和功能 function 是一个比较重要的事, 我们在这里简单的提及了一下在 theano 将要运用到的东西.
theano 和 tensorflow 类似,都是基于建立神经网络每个组件,在组件联系起来,数据放入组件,得到结果。
首先, 我们这次需要加载 theano 和 numpy 两个模块, 并且使用 theano 来创建 function.
import numpy as np import theano.tensor as T from theano import function 定义X和Y两个常量 (scalar),把结构建立好之后,把结构放在function,在把数据放在function。
# basic
x = T.dscalar('x') # 建立 x 的容器
y = T.dscalar('y') # 建立 y 的容器
z = x+y # 建立方程
# 使用 function 定义 theano 的方程,
# 将输入值 x, y 放在 [] 里, 输出值 z 放在后面
f = function([x, y], z)
print(f(2,3)) # 将确切的 x, y 值放入方程中
# 5.0
使用 theano 中 的 pp (pretty-print)
能够打印出原始方程:
from theano import pp
print(pp(z))
# (x + y)
定义矩阵,以及利用矩阵做相关运算:
x = T.dmatrix('x') # 矩阵 x 的容器
y = T.dmatrix('y') # 矩阵 y 的容器
z = x + y # 定义矩阵加法
f = function([x, y], z) # 定义方程
print(f(
np.arange(12).reshape((3,4)),
10*np.ones((3,4))
)
)
"""
[[ 10. 11. 12. 13.]
[ 14. 15. 16. 17.]
[ 18. 19. 20. 21.]]
"""
例如,以下的两行代码,就表示了一个具有两层神经元的神经网络:
# to define the layer like this:
l1 = Layer(inputs, 1, 10, T.nnet.relu)
l2 = Layer(l1.outputs, 10, 1, None)
其中,第一层网络我们命名为l1, 输入变量为inputs, 输入为1维,输出为10维,也就是说l, 含有10个神经元或节点; 激活函数为theano.tensor.nnet.relu函数, 当然我们也可以针对不同的问题选用别的函数, 例如theano.tensor.nnet.nnet.sigmoid。
第二层网络的输入是第一层网络的输出l1.outputs, 所以输入的维度是10,输出是1维,激活函数我们采用one,也就是说我们采用默认的线形激活函数, l2层含有1个神经元,也就是网络的输出神经元。
以上的代码,描述并构建了一个1-10-1的神经网络(inputs-l1-l2)。
接下来我们来具体的实现Layer类的代码:
class Layer(object):
def __init__(self, inputs, in_size, out_size, activation_function=None):
self.W = theano.shared(np.random.normal(0, 1, (in_size, out_size)))
self.b = theano.shared(np.zeros((out_size, )) + 0.1)
self.Wx_plus_b = T.dot(inputs, self.W) + self.b
self.activation_function = activation_function
if activation_function is None:
self.outputs = self.Wx_plus_b
else:
self.outputs = self.activation_function(self.Wx_plus_b)
这段代码中,我们最关心的就是这个类的构造函数
def __init__(self, inputs, in_size, out_size, activation_function=None)
和之前的例子一致,我们采用了相同的输入变量名。
接着,我们定义了W,b来代表该神经网络层的输入权值和偏置值,我们把W初始化为 由符合均值为0, 方差为1高斯分布的随机变量值组成的in_size-by-out_size的矩阵; b初始化为值为0.1的out_put-by-1的向量。 (当然,我们也可以采用不同的初始化方法,这里我们暂时不讨论初始化权值对最终神经网络训练的影响)。
self.W = theano.shared(np.random.normal(0, 1, (in_size, out_size)))
self.b = theano.shared(np.zeros((out_size, )) + 0.1)
首先我们要计算所有神经元的输入矩阵, 也就是输入inputs与输入权值W的点乘(dot product)在加上偏置值b:
self.Wx_plus_b = T.dot(inputs, self.W) + self.b
然后,我们需要根据我们构造神经层指定的激活函数类型activation_function,来计算神经层的输出向量。 这里我们假设如果activation_function是None, 那就是该层神经元采用线形输出;如果是其他Theano的激活函数,就把Wx_plus_b作为该层激活函数的输入,同时函数的输出即为神经层的输出:
self.activation_function = activation_function
if activation_function is None:
self.outputs = self.Wx_plus_b
else:
self.outputs = self.activation_function(self.Wx_plus_b)
我们就成功的定义了神经网络的最最重要的结构–神经层Layer。
引入需要使用的Python包:
import numpy as np
import theano
import theano.tensor as T
先定义一个功能,用来计算分类问题的准确率,即预测的类别中有多少是和实际类别一样的,计算出百分比。
def compute_accuracy(y_target, y_predict):
correct_prediction = np.equal(y_predict, y_target)
accuracy = np.sum(correct_prediction)/len(correct_prediction)
return accuracy
用 randn
随机生成数据集。 D 中的 input_values
是 400 个样本,784 个feature
。 target_class
是有两类,0 和 1。 要做的是,用神经网络训练数据学习哪些输入对应 0,哪些对应 1.
rng = np.random
N = 400 # training 数据个数
feats = 784 # input 的 feature 数
# 生成随机数: D = (input_values, target_class)
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
接下来,定义神经网络。
先定义一个大的图片,编辑好图片的小部件,再把训练数据集放到图片中去自动地训练。
定义 x 和 y,相当于 placeholder。
# 定义 x y 容器
x = T.dmatrix("x")
y = T.dvector("y")
初始化 weights 和 bias。 有多少 features 就生成多少个 weights, 今天只是用最基本的 input 和 output 层的神经网络,如果想用 hidden layer 可以参考上一节课的例子。
# 初始化 weights and biases
W = theano.shared(rng.randn(feats), name="w")
b = theano.shared(0., name="b")
定义激活函数,交叉熵。 p_1 是用 sigmoid 求的概率,输入越小,则概率值越接近 0,越大则越接近 1,等于 0 则值为 0.5. p_1 > 0.5 时,预测值为 True,即为 1。 然后计算针对每个 sample 的交叉熵 xent。 再计算整批数据的 cost,为了减小 overfitting,这里加入了 L1-正则化。 接下来可以计算 weights 和 bias 的梯度 gW, gb。
p_1 = T.nnet.sigmoid(T.dot(x, W) + b) # sigmoid 激励函数
prediction = p_1 > 0.5
xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1) # 交叉熵
# xent 也可以使用下面这个达到一样的效果
# xent = T.nnet.binary_crossentropy(p_1, y)
cost = xent.mean() + 0.01 * (W ** 2).sum() # l2 正则化
gW, gb = T.grad(cost, [W, b])
学习率需要小于 1. 接下来定义两个函数 train 和 predict,方法和上一节课的类似。 outputs 可以输出两个 prediction 和交叉熵损失的平均值 xent.mean。
learning_rate = 0.1
train = theano.function(
inputs=[x, y],
outputs=[prediction, xent.mean()],
updates=((W, W - learning_rate * gW), (b, b - learning_rate * gb)))
predict = theano.function(inputs=[x], outputs=prediction)
接下来训练模型。 用训练集的 feature 和 target 训练模型,输出预测值和损失 pred, err。 每 50 步打印一次损失和准确率。
# Training
for i in range(500):
pred, err = train(D[0], D[1])
if i % 50 == 0:
print('cost:', err)
print("accuracy:", compute_accuracy(D[1], predict(D[0])))
最后打印出预测值与实际值进行比较。
print("target values for D:")
print(D[1])
print("prediction on D:")
print(predict(D[0]))
"""
cost: 11.677533008109728
accuracy: 0.52
cost: 6.1946164642562636
accuracy: 0.6175
cost: 3.012375762498935
accuracy: 0.725
cost: 1.3340537876600198
accuracy: 0.8275
cost: 0.4690120202455575
accuracy: 0.9075
...
target values for D:
[1 1 0 1 0 1 0 1 1 1 1 1 .....]
prediction on D:
[1 1 0 1 0 1 0 1 1 1 1 1 .....]
"""