逻辑异或问题的成功解决,可以带给我们一定的信心,但是毕竟只有4个样本,还不能发挥出双层神经网络的真正能力。下面让我们一起来解决问题二,复杂的二分类问题。

代码实现

主过程代码

  1. if __name__ == '__main__':
  2. ......
  3. n_input = dataReader.num_feature
  4. n_hidden = 2
  5. n_output = 1
  6. eta, batch_size, max_epoch = 0.1, 5, 10000
  7. eps = 0.08
  8. hp = HyperParameters2(n_input, n_hidden, n_output, eta, max_epoch, batch_size, eps, NetType.BinaryClassifier, InitialMethod.Xavier)
  9. net = NeuralNet2(hp, "Arc_221")
  10. net.train(dataReader, 5, True)
  11. net.ShowTrainingTrace()

此处的代码有几个需要强调的细节:

  • n_input = dataReader.num_feature,值为2,而且必须为2,因为只有两个特征值
  • n_hidden=2,这是人为设置的隐层神经元数量,可以是大于2的任何整数
  • eps精度=0.08是后验知识,笔者通过测试得到的停止条件,用于方便案例讲解
  • 网络类型是NetType.BinaryClassifier,指明是二分类网络

运行结果

经过快速的迭代,训练完毕后,会显示损失函数曲线和准确率曲线如图10-15。

实现双弧形二分类 - 图1

蓝色的线条是小批量训练样本的曲线,波动相对较大,不必理会,因为批量小势必会造成波动。红色曲线是验证集的走势,可以看到二者的走势很理想,经过一小段时间的磨合后,从第200个epoch开始,两条曲线都突然找到了突破的方向,然后只用了50个epoch,就迅速达到指定精度。

同时在控制台会打印一些信息,最后几行如下:

  1. ......
  2. epoch=259, total_iteration=18719
  3. loss_train=0.092687, accuracy_train=1.000000
  4. loss_valid=0.074073, accuracy_valid=1.000000
  5. W= [[ 8.88189429 6.09089509]
  6. [-7.45706681 5.07004428]]
  7. B= [[ 1.99109895 -7.46281087]]
  8. W= [[-9.98653838]
  9. [11.04185384]]
  10. B= [[3.92199463]]
  11. testing...
  12. 1.0

一共用了260个epoch,达到了指定的loss精度(0.08)时停止迭代。看测试集的情况,准确度1.0,即100%分类正确。

代码位置

原代码位置:ch10, Level3

个人代码:DoubleArcClassifier**

keras实现

  1. from HelperClass2.DataReader_2_0 import *
  2. from keras.models import Sequential
  3. from keras.layers import Dense
  4. import matplotlib.pyplot as plt
  5. import os
  6. os.environ['KMP_DUPLICATE_LIB_OK']='True'
  7. def load_data():
  8. train_data_name = "../data/ch10.train.npz"
  9. test_data_name = "../data/ch10.test.npz"
  10. dataReader = DataReader_2_0(train_data_name, test_data_name)
  11. dataReader.ReadData()
  12. dataReader.NormalizeX()
  13. dataReader.Shuffle()
  14. dataReader.GenerateValidationSet()
  15. x_train, y_train = dataReader.XTrain, dataReader.YTrain
  16. x_test, y_test = dataReader.XTest, dataReader.YTest
  17. x_val, y_val = dataReader.XDev, dataReader.YDev
  18. return x_train, y_train, x_test, y_test, x_val, y_val
  19. def build_model():
  20. model = Sequential()
  21. model.add(Dense(2, activation='sigmoid', input_shape=(2, )))
  22. model.add(Dense(1, activation='sigmoid'))
  23. model.compile(optimizer='Adam',
  24. loss='binary_crossentropy',
  25. metrics=['accuracy'])
  26. return model
  27. #画出训练过程中训练和验证的精度与损失
  28. def draw_train_history(history):
  29. plt.figure(1)
  30. # summarize history for accuracy
  31. plt.subplot(211)
  32. plt.plot(history.history['accuracy'])
  33. plt.plot(history.history['val_accuracy'])
  34. plt.title('model accuracy')
  35. plt.ylabel('accuracy')
  36. plt.xlabel('epoch')
  37. plt.legend(['train', 'validation'], loc='upper left')
  38. # summarize history for loss
  39. plt.subplot(212)
  40. plt.plot(history.history['loss'])
  41. plt.plot(history.history['val_loss'])
  42. plt.title('model loss')
  43. plt.ylabel('loss')
  44. plt.xlabel('epoch')
  45. plt.legend(['train', 'validation'], loc='upper left')
  46. plt.show()
  47. if __name__ == '__main__':
  48. x_train, y_train, x_test, y_test, x_val, y_val = load_data()
  49. model = build_model()
  50. history = model.fit(x_train, y_train, epochs=500, batch_size=5, validation_data=(x_val, y_val))
  51. draw_train_history(history)
  52. loss, accuracy = model.evaluate(x_test, y_test)
  53. print("test loss: {}, test accuracy: {}".format(loss, accuracy))
  54. weights = model.get_weights()
  55. print("weights: ", weights)

模型输出

  1. test loss: 0.3726512098312378, test accuracy: 0.8199999928474426
  2. weights: [array([[-0.06496473, 0.02829591],
  3. [-4.5003347 , 4.043444 ]], dtype=float32), array([ 2.66075 , -2.1573546], dtype=float32), array([[-5.7543817],
  4. [ 4.9798098]], dtype=float32), array([0.25002602], dtype=float32)]

训练损失以及准确率曲线

实现双弧形二分类 - 图2