基于keras库训练BP神经网络的实例

本文详细介绍了使用Keras库训练BP神经网络的过程,包括数据集准备、数据标准化、模型搭建、参数调整等内容,并通过实例展示了如何优化隐层节点数和迭代次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面

最近学习了深度学习中最基础的一种神经网络——BP神经网络。经过数学推导之后,我的感悟:

1.BP神经网络是一种对人脑神经网络的一种抽象化的“仿生”。我们知道,人的大脑中有成千上万的神经元,这些神经元本身不复杂,但神经元之间错综复杂的连接使得人脑可以迅速处理信息和学习等。BP神经网络中每个节点都好比一个“神经元”,当INPUT(类比激励)超过一定阈值时,经激活函数计算的OUTPUT达到较高水平(类比神经元兴奋),向输出层传导。

2.BP神经网络本质上是以网络输出与实际输出的误差为评估函数(它是各层权重和偏倚的函数),以各层权重和偏倚为自变量,采用梯度下降法,通过不断迭代改变各层权重和偏倚(也就是训练网络的过程),最终实现误差最小的一种前馈型神经网络。

3.在推导的过程中要多次用到复合函数求导法则。我推导时使用的激励函数是sigmoid函数,它的导数与函数本身有关系,利用这点可以化简结果。

学习了BP神经网络的原理后,我使用python的keras库来训练一个BP神经网络的实例

1.数据集准备

下表由雇员数据库的训练数据组成。数据已泛化,例如,age “31–35"表示年龄在31~ 35之间。对于给定的行,count表示department, status, age和salary在该行具有给定值的元组数。设status是类标号属性。

pic0

1.1数据集生成

import numpy as np
import matplotlib.pyplot as plt
data=np.array([[0,0,2,4,30],
      [0,1,1,0,40],
     [0,1,2,1,40],
     [1,1,0,4,20],
     [1,0,2,5,5],
     [1,1,1,4,3],
     [1,0,4,5,3],
     [2,0,3,4,10],
     [2,1,2,3,4],
     [3,0,5,2,4],
     [3,1,1,0,6]])
data
array([[ 0,  0,  2,  4, 30],
       [ 0,  1,  1,  0, 40],
       [ 0,  1,  2,  1, 40],
       [ 1,  1,  0,  4, 20],
       [ 1,  0,  2,  5,  5],
       [ 1,  1,  1,  4,  3],
       [ 1,  0,  4,  5,  3],
       [ 2,  0,  3,  4, 10],
       [ 2,  1,  2,  3,  4],
       [ 3,  0,  5,  2,  4],
       [ 3,  1,  1,  0,  6]])
#生成训练集和目标
X_train,y_train = data[:,[0,2,3,4]],data[:,1]
X_train
array([[ 0,  2,  4, 30],
       [ 0,  1,  0, 40],
       [ 0,  2,  1, 40],
       [ 1,  0,  4, 20],
       [ 1,  2,  5,  5],
       [ 1,  1,  4,  3],
       [ 1,  4,  5,  3],
       [ 2,  3,  4, 10],
       [ 2,  2,  3,  4],
       [ 3,  5,  2,  4],
       [ 3,  1,  0,  6]])
y_train
array([0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1])

1.2数据标准化

#定义数据处理函数
def stand(a):
    a = a.astype(float)
    max1 = a.max()
    min1 = a.min()
    range1 = max1 - min1
    if range1 == 0:
        return [0]*len(a)
    else:
        for i in range(len(a)):
            a[i] = (a[i] - min1)/range1
        return a    
X_train = X_train.astype(float)
for i in range(len(X_train[0])):
    X_train[:,i] = stand(X_train[:,i])
#标准化后的训练集
X_train
array([[0.        , 0.4       , 0.8       , 0.72972973],
       [0.        , 0.2       , 0.        , 1.        ],
       [0.        , 0.4       , 0.2       , 1.        ],
       [0.33333333, 0.        , 0.8       , 0.45945946],
       [0.33333333, 0.4       , 1.        , 0.05405405],
       [0.33333333, 0.2       , 0.8       , 0.        ],
       [0.33333333, 0.8       , 1.        , 0.        ],
       [0.66666667, 0.6       , 0.8       , 0.18918919],
       [0.66666667, 0.4       , 0.6       , 0.02702703],
       [1.        , 1.        , 0.4       , 0.02702703],
       [1.        , 0.2       , 0.        , 0.08108108]])

2.创建bp神经网络

#导入相关库
from keras.models import Sequential
from keras.layers import Dense, Activation
Using TensorFlow backend.
#生成Sequential 顺序模型
model = Sequential()

#创建两个layer
layer1 = Dense(2, input_shape=(4,),activation='sigmoid')
layer2 = Dense(1,activation='sigmoid')

#使用 .add() 来堆叠模型
#现在模型会以尺寸为 (*, 4) 的数组作为输入,其输出数组的尺寸为 (*, 2)
model.add(layer1)
#在第一层之后,就不再需要指定输入的尺寸了
model.add(layer2)

#使用 .compile() 来配置学习过程
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
WARNING:tensorflow:From E:\anaconda\anaconda1\lib\site-packages\tensorflow\python\ops\resource_variable_ops.py:435: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
#查看隐层的初始权重和偏倚
layer1.get_weights()
[array([[-0.47375464, -0.5235982 ],
        [-0.38250756, -0.74181414],
        [-0.2465694 ,  0.55842113],
        [ 0.11825562, -0.3772707 ]], dtype=float32),
 array([0., 0.], dtype=float32)]
#查看输出层的初始权重和偏倚
layer2.get_weights()
[array([[ 0.09723485],
        [-0.49100333]], dtype=float32), array([0.], dtype=float32)]

3.先模拟一下梯度下降法的原理

X0 = np.array([[0.        , 0.4       , 0.8       , 0.72972973]])
y0 = np.array([[0]])
#未训练前先看看输出的结果
model.predict(X0, batch_size=1)
array([[0.45316178]], dtype=float32)
#只用这个样本迭代model一次
model.fit(X0, y0, epochs=1, batch_size=1)
WARNING:tensorflow:From E:\anaconda\anaconda1\lib\site-packages\tensorflow\python\ops\math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.cast instead.
Epoch 1/1
1/1 [==============================] - 0s 177ms/step - loss: 0.6036 - accuracy: 1.0000

<keras.callbacks.callbacks.History at 0x1ab3c6be408>
#查看隐层的此时的权重和偏倚
layer1.get_weights()
[array([[-0.47375464, -0.5235982 ],
        [-0.38566962, -0.73865193],
        [-0.24973156,  0.5615834 ],
        [ 0.11509346, -0.37410843]], dtype=float32),
 array([-0.00316219,  0.00316226], dtype=float32)]
#查看输出层的此时的权重和偏倚
layer2.get_weights()
[array([[ 0.09407257],
        [-0.4941656 ]], dtype=float32), array([-0.00316228], dtype=float32)]
#再看看更新后输出的结果
model.predict(X0, batch_size=1)
array([[0.4513354]], dtype=float32)

可以发现此时隐层和输出层的权重和偏倚已经更新(符合用S型激励函数所推导的更新公式),在更新后输出结果由0.45316178变为0.4513354,向着真实值0接近

4.正式训练模型

# 训练模型,以 11个样本为一个 batch 进行迭代,迭代10000次
model.fit(X_train, y_train, epochs=10000, batch_size=11)
#输出最终的损失值和评估值
loss_and_metrics = model.evaluate(X_train, y_train, batch_size=11)
print("loss is",loss_and_metrics[0])
print("metrics is",loss_and_metrics[1])
11/11 [==============================] - 0s 4ms/step
loss is 0.0003669886791612953
metrics is 1.0
#查看隐层的最终的权重和偏倚
layer1.get_weights()
[array([[  1.6629684,  -1.1666613],
        [-10.349615 ,   9.213103 ],
        [ -8.158486 ,   7.631497 ],
        [ -1.920792 ,   1.9880017]], dtype=float32),
 array([ 9.8020735, -9.160663 ], dtype=float32)]
#查看输出层的最终的权重和偏倚
layer2.get_weights()
[array([[ 10.038265],
        [-10.15324 ]], dtype=float32), array([0.28461477], dtype=float32)]
#查看最终收敛后输出的结果
y_predict = model.predict(X_train, batch_size=11)
y_predict
array([[4.1028857e-04],
       [9.9996442e-01],
       [9.9965948e-01],
       [9.9988532e-01],
       [6.3014030e-04],
       [9.9921250e-01],
       [5.5342913e-05],
       [4.4330955e-04],
       [9.9929118e-01],
       [4.7654950e-04],
       [9.9996698e-01]], dtype=float32)

可以看出,输出的结果与真实值之间非常接近,说明模型对这个数据集训练效果较好(但本训练集数据较少且可能存在过拟合情况)

5.初步调参

思考:
1.一开始选择隐层的节点时选择了两个结点,是不是最优选择?
2.迭代次数选择10000是不是最优选择呢?

5.1最优隐层节点数的调整

#将隐层结点设为3个,其余不变
model2 = Sequential()
model2.add(Dense(3, input_shape=(4,),activation='sigmoid'))
model2.add(Dense(1,activation='sigmoid'))
model2.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model2.fit(X_train, y_train, epochs=10000, batch_size=11)
loss_and_metrics2 = model2.evaluate(X_train, y_train, batch_size=11)
print("loss is",loss_and_metrics2[0])
print("metrics is",loss_and_metrics2[1])
loss is 6.332933480734937e-06
metrics is 1.0
#将隐层结点设为4个,其余不变
model3 = Sequential()
model3.add(Dense(4, input_shape=(4,),activation='sigmoid'))
model3.add(Dense(1,activation='sigmoid'))
model3.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model3.fit(X_train, y_train, epochs=10000, batch_size=11)
loss_and_metrics3 = model3.evaluate(X_train, y_train, batch_size=11)
print("loss is",loss_and_metrics3[0])
print("metrics is",loss_and_metrics3[1])
loss is 5.404044145507214e-07
metrics is 1.0
#绘图
plt.plot([2,3,4],[loss_and_metrics[0],loss_and_metrics2[0],loss_and_metrics3[0]])
plt.xlabel("number of hidden layer nodes")
plt.ylabel("the final loss")
plt.show()

pic1

由图像可知,隐层选择三个节点的效果应该最好,既避免了空间浪费也保证了精度

5.2最优迭代次数的调整

#选择隐层3个节点,将迭代次数调整为5000次,其余不变
model4 = Sequential()
model4.add(Dense(3, input_shape=(4,),activation='sigmoid'))
model4.add(Dense(1,activation='sigmoid'))
model4.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model4.fit(X_train, y_train, epochs=5000, batch_size=11)
loss_and_metrics4 = model4.evaluate(X_train, y_train, batch_size=11)
print("loss is",loss_and_metrics4[0])
print("metrics is",loss_and_metrics4[1])
loss is 0.01632225513458252
metrics is 1.0
#选择隐层3个节点,将迭代次数调整为15000次,其余不变
model5 = Sequential()
model5.add(Dense(3, input_shape=(4,),activation='sigmoid'))
model5.add(Dense(1,activation='sigmoid'))
model5.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model5.fit(X_train, y_train, epochs=15000, batch_size=11)
loss_and_metrics5 = model5.evaluate(X_train, y_train, batch_size=11)
print("loss is",loss_and_metrics5[0])
print("metrics is",loss_and_metrics5[1])
loss is 1.373911260316163e-07
metrics is 1.0
#绘图
plt.plot([5000,10000,15000],[loss_and_metrics4[0],loss_and_metrics2[0],loss_and_metrics5[0]])
plt.xlabel("number of epochs")
plt.ylabel("the final loss")
plt.show()

pic2

由图像可知,迭代次数选择10000次附近的效果应该较好,如果想要得到更优的epochs可以在10000附近进一步搜索

6.问题解决汇总

 1.运行keras时报错:cudaGetDevice() failed. Status: CUDA driver version is insufficient for CUDA

解决方法:cuda与显卡驱动不匹配,或者使用anaconda安装tensorflow时cudnn、tensorflow-gpu和cudatoolkit版本不匹配。可以降低cudnn和tensorflow-gpu等的版本与显卡驱动匹配。
链接:CUDA工具包和兼容的驱动程序版本
链接:tensorflow-gpu与cuda、cudnn匹配版本

2.numpy数组标准化时全部变为整数,而不是0-1之间的浮点数

解决方法:numpy数组的dtype为int,应该使用array = array.astype(float)将整型数组变为浮点型数组后,再存储标准化后的数据

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值