异或问题:
import numpy as np
from keras.models import Sequential # Kera的基础模型类
from keras.layers import Dense, Activation # Dense是神经元的全连接层
from keras.optimizers import SGD # 随机梯度下降,Keras中还有一些其他优化器
# Our examples for an exclusive OR.
x_train = np.array([[0, 0],
[0, 1],
[1, 0],
[1, 1]]) # x_train是二维特征向量表示的训练样本列表
y_train = np.array([[0],
[1],
[1],
[0]]) # y_train是每个特征向量样本对应的目标输出值
model = Sequential()
num_neurons = 10 # 全连接隐藏层包含10个神经元
model.add(Dense(num_neurons, input_dim=2)) # input_dim仅在第一层中使用,后面的其他层会自动计算前一层输出的形状,这个例子中输入的XOR样本是二维特征向量,因此input_dim设置为2
model.add(Activation('tanh'))
model.add(Dense(1)) # 输出层包含一个神经元,输出结果是二分类值(0或1)
model.add(Activation('sigmoid'))
model.summary()
10个神经元,每个神经元有3个权重,其中有两个是输入向量的权重(输入向量中的每个值对应一个权重),还有一个是偏置对应的权重,所以一共有30个权重需要学习。输出层中有10个权重,分别与第一层的10个神经元一一对应,再加上1个偏置权重,所以该层共有11个权重。
sgd = SGD(lr=0.1)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
SGD是之前导入的随机梯度下降优化器,模型用它来最小化误差或者损失。lr
是学习速率,与每个权重的误差的导数结合使用,数值越大模型的学习速度越快,但可能会使模型无法找到全局极小值,数值越小越精确,但会增加训练时间,并使模型更容易陷入局部极小值。损失函数本身也定义为一个参数,在这里用的是binary_crossentropy
。metrics
参数是训练过程中输出流的选项列表。用compile
方法进行编译,此时还未开始训练模型,只对权重进行了初始化,大家也可以尝试一下用这个随机初始状态来预测,当然得到的结果只是随机猜测:
model.predict(x_train)
[[ 0.5 ]
[ 0.43494844]
[ 0.50295198]
[ 0.42517585]]
predict
方法将给出最后一层的原始输出,在这个例子中是由sigmoid
函数生成的。
之后再没什么好写的了,但是这里还没有关于答案的任何知识,它只是对输入使用了随机权重。接下来可以试着进行训练。
model.fit(x_train, y_train, epochs=100) # 从这里开始训练模型
在第一次训练时网络可能不会收敛。第一次编译可能以随机分布的参数结束,导致难以或者不能得到全局极小值。如果遇到这种情况,可以用相同的参数再次调用model.fit
,或者添加更多训练周期,看看网络能否收敛。或者也可以用不同的随机起始点来重新初始化网络,然后再次尝试fit
。如果使用后面这种方法,请确保没有设置随机种子,否则只会不断重复同样的实验结果。
model.predict_classes(x_train)
model.predict(x_train)
在这个经过训练的模型上再次调用predict
(和predict_classes
)会产生更好的结果。它在这个小数据集上获得了 100%的精确度。当然,精确率并不是评估预测模型的最佳标准,但对这个小例子来说完全可以说明问题。接下来展示了如何保存这个异或模型:
import h5py
model_structure = model.to_json() # 用Keras的辅助方法将网络结构导出为JSON blob类型以备后用
with open("basic_model.json", "w") as json_file:
json_file.write(model_structure)
model.save_weights("basic_weights.h5") # 训练好的权重必须被单独保存。第一部分只保存网络结构。在后面重新加载网络结构时必须对其重新实例化