目录
- 1、Keras:
- 2、Sequential模型:
- 2.1、建立Sequential模型:model=tf.keras.Sequential()
- 2.2、添加层:model.add(tf.keras.layers.层)
- 2.3、查看摘要:model.summary()
- 2.4、配置训练方法:model.compile(loss,optimizer,metrics)
- 2.4.1、损失函数:
- 2.4.2、优化器:
- 2.4.3、metrics评价指标
- 2.4.4、其他(tf.keras.metrics.评价方法)
- 3、训练模型
- 3.1、model.fit
- 3.2、手写数字识别的训练模型
- 3.3、评估模型:model.evaluate(test_set_x,test_set_y,batch_size,verbose)
- 3.4、使用模型进行预测:model.predict
- 3.5、保存模型参数:save_weights、save
- 3.6、保存整个模型.save(...)
- 3.7、加载
- 4、Sequential实现手写数字识别
- 4.1、设计神经网络
- 4.2、配置训练方法:
- 4.3、评估模型
- 4.4、保存模型
- 4.5、使用模型预测测试集中前4个数据
- 4.6、重新加载整个模型(对应于save()方法)
1、Keras:
由Python编写的开源人工神经网络库;面向对象,完全模块化;支持神经网络和深度学习的主流算法;
它只是一个库,计算引擎可以指定是TensorFlow、CNTK、Theano等,因此可以
- 独立安装Keras库,在安装Keras后如果没有检测到TensorFlow,那么会自动地以依赖项的形式自动安装TensorFlow
- 也可以直接安装TensorFlow,tf.keras会作为子模块被自动安装
2、Sequential模型:
是一种神经网络框架(像一个容器),只有一组输入和一组输出,各个层按照先后顺序堆叠
2.1、建立Sequential模型:model=tf.keras.Sequential()
model=tf.keras.Sequential()
model #它是keras中的Sequential对象,目前来说是一个空的容器
Out[5]: <tensorflow.python.keras.engine.sequential.Sequential at 0x23e451fc7f0>
2.2、添加层:model.add(tf.keras.layers.层)
layers比如有全连接层(Dense)、卷积层、池化层…
tf.keras.layers.Dense( #Dense表示
inputs #输入该网络层的数据,表示这个层中神经元的个数
activation #激活函数,字符串形式给出:'relu','softmax','sigmoid','tanh'
input_shape #输入数据的形状,全连接神经网络的第一层接收来自输入层的数据,必须要指明数据,后面的层接收前一层的输出,不用定义输入数据形状
)
2.3、查看摘要:model.summary()
查看网络的结构和参数信息
例如:创建下图三层神经网络(模型参数分别有40、36、15个),输入层4节点,隐含层1有8节点,隐含层2有4节点,输出层3节点
import tensorflow as tf
model=tf.keras.Sequential()
#下面一行代码:隐含层1共8节点,激活函数为relu函数,输入数据shape=(4,)
model.add(tf.keras.layers.Dense(8,activation="relu",input_shape=(4,)))
model.add(tf.keras.layers.Dense(4,activation="relu"))
model.add(tf.keras.layers.Dense(3,activation="softmax"))
model.summary() #使用model.summary查看摘要信息
#输出:
Model: "sequential_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 8) 40 #Dense表示全连接,(None, 8)是输出的形状,有40个参数
_________________________________________________________________
dense_1 (Dense) (None, 4) 36 #dense_1后面的数字1是系统自动加上的
_________________________________________________________________
dense_2 (Dense) (None, 3) 15
=================================================================
Total params: 91
Trainable params: 91
Non-trainable params: 0
_________________________________________________________________
也可以创建Sequential模型时定义多层:(建议用上面的方法,更加清晰)
model=tf.keras.Sequential([
tf.keras.layers.Dense(8,activation="relu",input_shape=(4,)),
tf.keras.layers.Dense(4,activation="relu"),
tf.keras.layers.Dense(3,activation="softmax")])
2.4、配置训练方法:model.compile(loss,optimizer,metrics)
loss:损失函数,optimizer:优化器,metrics:模型训练时我们希望输出的评测指标
2.4.1、损失函数:
可以以字符串形式和函数形式(可以有2种函数形式)给出
函数类型 | 字符串形式 | 函数形式 |
---|---|---|
均方差损失函数 | ‘mse’ | tf.keras.losses.mean_squared_error() |
多分类交叉熵损失函数 | ‘categorical_crossentropy’ ‘sparse_categorical_crossentropy’ | tf.keras.losses.categorical_crossentropy(from_logits=False) tf.keras.losses.sparse_categorical_crossentropy(from_logits=False) |
二分类交叉熵损失函数 | 'binary_crossentropy | tf.keras.losses.binary_crossentropy() |
注意:
- 表格中多分类交叉熵损失函数的标签值采用独热编码用第一行,当采用自然顺序码表示时用第二行;
- from_logits=False表示神经网络在输出前已经使用softmax函数,将预测结果变换为概率分布,所有输出值之和为1(前面所做的都是有转化为概率的)
- 二分类交叉熵损失函数就是逻辑回归时使用的,与激活函数sigmoid搭配使用,实现二分类任务
2.4.2、优化器:
Ir:学习率 momentum:动量
字符串形式 | 函数形式 |
---|---|
‘sgd’ | tf.keras.optimizers.SGD(lr,momentum) |
‘adagrad’ | tf.keras.optimizers.Adagrad(Ir) |
‘adadelta’ | tf.keras.optimizers.Adadelta(Ir) |
‘adam’ | tf.keras.optimizers.Adam(lr,beta_1=0.9,beta_2=0.999) |
注意:tensorflow1.x中也提供了优化器:tf.train.optimizer,但tensorflow2.0+中建议使用tf.keras.optimizer(否则可能会有命名冲突等问题)
2.4.3、metrics评价指标
metrics指定训练模型时使用的评价指标,可以使用keras模型性能评估函数、自定义性能评估函数。
其中,keras中预定义的“准确率函数”(tf.keras.metrics.函数名):
标签值:数值 预测值:数值 | ‘accuracy’ | tf.keras.metrics.Accuracy() | |
---|---|---|---|
二分类 | 标签值:数值 预测值:概率 | ‘binary_accuracy’ | tf.keras.metrics.binary_accuracy(threshold=0.5) tf.keras.metrics.BinaryAccuracy(threshold=0.5) |
多分类 | 标签值:独热编码 预测值:独热编码 | ‘categorical_accuracy’ | tf.keras.metrics.categorical_accuracy() tf.keras.metrics.CategoricalAccuracy() |
多分类 | 标签值:数值 预测值:独热编码 | ‘sparse_categorical_accuracy’ | tf.keras.metrics.sparse_categorical_accuracy() tf.keras.metrics.SparseCategoricalAccuracy() |
多分类 | k种标签标签值:数值 预测值:独热编码 | ‘top_k_categorical_accuracy’ | tf.keras.metrics.top_k_categorical_accuracy() tf.keras.metrics.TopKCategoricalAccuracy() |
多分类 | k种标签标签值:数值 预测值:独热编码 | ‘sparse_top_k_categorical_accuracy’ | tf.keras.metrics.sparse_top_k_categorical_accuracy() tf.keras.metrics.SparseTopKCategoricalAccuracy() |
注:
- “数值”就是标量值
- 二分类中的“threshold”表示阈值。例如threshold=0.5时,表示预测值大于0.5为1,小于0.5为0。若标签值为{0, 1, 1, 0},预测值为{0.3, 0.7, 0.6, 0.9},则准确率为75%(前3个预测正确)
- 列表最后2行的“k种标签”,若k=3,则表示预测值概率排名前三的类别中只要有一个和标签值一致就预测正确。
2.4.4、其他(tf.keras.metrics.评价方法)
AUC | BinaryCrossentropy(二元交叉熵) | MeanAbsoluteError |
---|---|---|
SUM(求和) | CategoricalCrossentropy | MeanAbsolutePercentageError |
Mean(均值) | SparseCategoricalCrossentropy | MeanRelativeError |
Precision | Hinge | MeanSquareError |
CategoricalHinge |
- 其他预设定的评价标准可以参考:https://tensorflow.google.cn/versions/r2.0/api_docs/python/tf/keras/metrics
import tensorflow as tf
model=tf.keras.Sequential()
#配置训练方法:model.compile(),当鸢尾花数据集的标签值用数值表示时(即是0&1)
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1), #优化器采用随机梯度下降法,学习率lr=0.1
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),#损失函数:稀疏交叉熵损失函数,False为默认值可以不写
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()]) #稀疏交叉熵准确率,注意要有[],中括号中可以有多个评价函数,用逗号隔开
#当鸢尾花数据集的标签值用独热编码,那么将后2参数改为:
#loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False)
#metrics=[tf.keras.metrics.CategoricalAccuracy()]
#手写数字识别数据集Mnist
model2=tf.keras.Sequential()
model2.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['sparse_categorical_accuracy'])
3、训练模型
3.1、model.fit
model.fit(训练集的输入特征,训练集的标签,
batch_size=批量大小,
epochs=迭代次数,
shuffle=是否每轮训练之前打乱数据, #默认True
validation_data=(测试集的输入特征,测试集的标签), #直接给出测试集数据,
validation_split=从训练集划分多少比例给测试集, #取值0~1*100%
validation_freq=测试频率, #每隔多少轮训练使用测试集并输出一次评测指标,默认1
verbose=日志显示形式)
注意:执行顺序是先validation_split划分数据集,然后shuffle打乱参数,因此若数据本身有序,要先打乱数据再进行第一轮训练。
validation_data和validation_split是二选一的,如果同时给出,则只执行前者
verbose取值: verbose=0:不在标准输出流输出
verbose=1:输出进度条记录
verbose=2:每个epoch输出一行记录
各参数的默认值:
model.fit(x=None,y=None,batch_size=32,epochs=1,shuffle=True,validation_data=None,
validation_split=0.0,validation_freq=1,verbose=1)
3.2、手写数字识别的训练模型
#批量大小batch_size=64,训练5轮,测试数据的比例为0.2(训练集48000条数据,测试集12000条),测试频率validation_freq=1(默认),
model.fit(X_train,y_train,batch_size=64,epochs=5,validation_split=0.2) #如果validation_split=0.0那么就只有训练集没有测试集
#输出:测试频率validation_freq默认为1,每轮训练后都显示训练指标(在model.compile(metrics=[])设定的)
Epoch 1/5 #下一行的0.0520和0.9848是训练集的损失和准确率,0.0918和0.9721是测试集的损失和准确率
750/750 [==============================] - 2s 2ms/step - loss: 0.0520 - sparse_categorical_accuracy: 0.9848 - val_loss: 0.0918 - val_sparse_categorical_accuracy: 0.9721
Epoch 2/5
750/750 [==============================] - 2s 2ms/step - loss: 0.0418 - sparse_categorical_accuracy: 0.9880 - val_loss: 0.0879 - val_sparse_categorical_accuracy: 0.9732
Epoch 3/5
750/750 [==============================] - 2s 2ms/step - loss: 0.0338 - sparse_categorical_accuracy: 0.9907 - val_loss: 0.0955 - val_sparse_categorical_accuracy: 0.9721
Epoch 4/5
750/750 [==============================] - 2s 2ms/step - loss: 0.0278 - sparse_categorical_accuracy: 0.9921 - val_loss: 0.0796 - val_sparse_categorical_accuracy: 0.9768
Epoch 5/5
750/750 [==============================] - 2s 2ms/step - loss: 0.0222 - sparse_categorical_accuracy: 0.9942 - val_loss: 0.0852 - val_sparse_categorical_accuracy: 0.9758
Out[3]: <tensorflow.python.keras.callbacks.History at 0x2089484ac40> #fit返回一个History对象,该对象记录了整个训练过程中的性能指标变化情况
model.metrics_names #性能评价指标(函数)可以这样子查看,这里是损失和稀疏分类准确率,
Out[4]: ['loss', 'sparse_categorical_accuracy'] #损失是默认指标,不用再compile方法中显式说明
history=model.fit(X_train,y_train,batch_size=64,epochs=5,validation_split=0.2)
type(history)
Out[6]: tensorflow.python.keras.callbacks.History
history.history
Out[7]: #history的history属性是一个字典,4个关键字,分别是训练集和测试集上的损失和准确率,每个关键字的值是一个列表,是每轮训练的结果
{'loss': [0.018985189497470856,
0.014733679592609406,
0.01280575804412365,
0.011680101044476032,
0.00846030842512846],
'sparse_categorical_accuracy': [0.9948124885559082,
0.9963541626930237,
0.9968541860580444,
0.9971041679382324,
0.9983333349227905],
'val_loss': [0.08265149593353271,
0.09434033930301666,
0.09341054409742355,
0.09228695929050446,
0.09402573853731155],
'val_sparse_categorical_accuracy': [0.9772499799728394,
0.9754166603088379,
0.9754166603088379,
0.9768333435058594,
0.9768333435058594]}
3.3、评估模型:model.evaluate(test_set_x,test_set_y,batch_size,verbose)
batch_size:批量大小,verbose:输出信息的方式(见上面函数fit()说明)
model.evaluate(X_test,y_test,verbose=2)
313/313 - 0s - loss: 0.0812 - sparse_categorical_accuracy: 0.9745 #损失和准确率
Out[10]: [0.08119513094425201, 0.9745000004768372]
3.4、使用模型进行预测:model.predict
model.predict(x,batch_size,verbose) #根据batch_size分批量预测数据
In [41]: model.predict(X_test[0:3]) #要和输入训练集的属性一致:1、归一化后的属性;2、是一个3维张量
Out[41]: #返回值是一个2维数组,第一维度元素对应各个样本,第二维度是某样本对应各个标签的概率值,可以用np.argmax查看最大值下标
array([[1.24529450e-07, 2.53378785e-09, 2.86495761e-05, 1.30367815e-03,
1.10695474e-10, 6.58034310e-07, 1.65426561e-11, 9.98663902e-01,
3.28517558e-07, 2.63686820e-06],
[5.17673072e-07, 5.53406135e-04, 9.99354422e-01, 2.06063087e-05,
8.16944385e-13, 1.42126032e-06, 7.46596470e-06, 2.53397095e-11,
6.20424471e-05, 8.87795566e-12],
[3.26827940e-05, 9.94493604e-01, 1.19115051e-03, 1.25147795e-04,
1.63687553e-04, 2.60076649e-05, 7.57008092e-05, 3.00905458e-03,
8.65864626e-04, 1.69854065e-05]], dtype=float32)
In [42]: np.argmax(model.predict(tf.expand_dims(X_test[0],axis=0))) #查看第一个元素的值,X_test[0]是二维张量需要在轴0上增加一维
Out[42]: 7
3.5、保存模型参数:save_weights、save
model.save_weights(filepath, #指定文件路径,默认为当前路径
overwrite=True, #表示当指定文件已经存在时,是否覆盖已经存在的文件
save_format=None)
模型参数可以保存为:
- HDF5格式(分层数据格式,Hierarchical Data Format):
- 需要设定:文件名后缀为.hs或.keras,且save_format=None。
- HDF5格式是一种二进制的文件格式,可以看做是一个包含group(类似于文件夹,其下面可以创建子文件夹和数据)、dataset(具体的数据)的容器
- 效率高,常用作保存大量数据(图片,数组)
- SavedModel格式
- 若没有指定为HDF5格式,则默认保存为此格式。建议显示设置save_format=‘tf’
- 它是TensorFlow特有序列化文件格式,这种格式保存参数信息不是保存在一个文件中,而是保存在多个文件中,打开工作目录:checkpoint是检查点文件保存模型的相关信息;data文件保存所有的可训练变量(就是模型参数的值);index文件保存变量关键字和值之间的对应关系
- 若overwrite=True,且文件已经存在就会提示是否覆盖:[WARNING] mnist_weights.index already exists - overwrite?
3.6、保存整个模型.save(…)
可以保存:神经网络的结构、模型参数、配置信息(优化器,损失函数等)、优化器状态
- filepath有2种格式:HDF5格式、SavedModel(可参见上面的save_weights()方法)
model.save(filepath,
overwrite=True,
include_optimizer=True, #是否存储当前优化器的状态,有时候需要暂时关机明天再继续训练,就需要这个为True
save_format=None)
这个方法保存后,打开工作目录,有一个文件夹,其包含2个文件夹(assets保存一些辅助资源文件、variables保存模型参数)和一个文件(saved_model.pb保存计算图):
3.7、加载
- 加载模型参数(对应于save_weights()方法):model.load_weights(filepath) #仅仅替代了model.fit()方法
该方法仅仅保存了神经网络的模型参数,在使用前需要首先定义一个完全相同的神经网络模型 - 加载模型(对应于save()方法):tf.keras.models.load_model()
4、Sequential实现手写数字识别
4.1、设计神经网络
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
mnist=tf.keras.datasets.mnist
#ndarray数组:train_x.shape=(60000, 28, 28),train_y.shape=(60000,),test_x.shape=(10000, 28, 28),test_y.shape=(10000,)
(train_x,train_y),(test_x,test_y)=mnist.load_data()
# X_train=train_x.reshsape((60000,28*28)) #将60000*28*28改为60000*784,
# X_test=test_x.reshape((10000,28*28)) #这2行可省去,在后面创建神经网络是用tf.keras.layers.Flatten()代替
X_train,X_test=tf.cast(train_x/255.0,tf.float32),tf.cast(test_x/255.0,tf.float32) #归一化
y_train,y_test=tf.cast(train_y,tf.int16),tf.cast(test_y,tf.int16)
#建立模型
model=tf.keras.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=(28,28))) #flatten层不进行计算,只是把输入的数据拉直,变为一维数组
model.add(tf.keras.layers.Dense(128,activation='relu')) #隐含层,全连接层,128节点,激活函数:relu
model.add(tf.keras.layers.Dense(10,activation='softmax')) #隐含层,全连接层,10节点,激活函数softmax
model.summary() #查看网络结构和参数信息
#输出:
Model: "sequential_5"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten_5 (Flatten) (None, 784) 0
_________________________________________________________________
dense_10 (Dense) (None, 128) 100480
_________________________________________________________________
dense_11 (Dense) (None, 10) 1290
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
_________________________________________________________________
4.2、配置训练方法:
#配置训练方法:
model.compile(optimizer='adam', #优化器:adam,不用设计adam算法中的参数,因为keras中已经使用常用的公开参数作为默认值
loss='sparse_categorical_crossentropy', #损失函数:稀疏交叉熵损失函数
metrics=['sparse_categorical_accuracy']) #准确率:稀疏准确率分布函数(标签值:0~9,预测值:概率分布)
#训练模型,每次训练的结果不一样的,若已经存在模型则直接加载模型,此时模型参数将和之前结果一样
model.fit(X_train,y_train,batch_size=64,epochs=5,validation_split=0.2) #加载模型:model.save_weights('mnist_weights.h5')
#输出:
Epoch 1/5
750/750 [==============================] - 2s 3ms/step - loss: 0.3325 - sparse_categorical_accuracy: 0.9072 - val_loss: 0.1857 - val_sparse_categorical_accuracy: 0.9482
Epoch 2/5
750/750 [==============================] - 2s 3ms/step - loss: 0.1518 - sparse_categorical_accuracy: 0.9555 - val_loss: 0.1282 - val_sparse_categorical_accuracy: 0.9647
Epoch 3/5
750/750 [==============================] - 2s 3ms/step - loss: 0.1064 - sparse_categorical_accuracy: 0.9681 - val_loss: 0.1103 - val_sparse_categorical_accuracy: 0.9677
Epoch 4/5
750/750 [==============================] - 2s 3ms/step - loss: 0.0803 - sparse_categorical_accuracy: 0.9764 - val_loss: 0.1014 - val_sparse_categorical_accuracy: 0.9695
Epoch 5/5
750/750 [==============================] - 2s 2ms/step - loss: 0.0637 - sparse_categorical_accuracy: 0.9810 - val_loss: 0.0932 - val_sparse_categorical_accuracy: 0.9720
4.3、评估模型
#评估模型,这里是损失和准确率
In [50]:
...: model.evaluate(X_test,y_test,verbose=2)
313/313 - 0s - loss: 0.0869 - sparse_categorical_accuracy: 0.9733
Out[50]: [0.08692450821399689, 0.9732999801635742]
4.4、保存模型
model.save_weights('mnist_weights.h5') #保存模型的参数
#model.save('mnist_model.h5') #保存模型
4.5、使用模型预测测试集中前4个数据
#使用模型
y_pred=np.argmax(model.predict(X_test[0:4]),axis=1)
for i in range(4):
plt.subplot(1,4,i+1)
plt.axis("off")
plt.imshow(test_x[i],cmap='gray')
plt.title('y='+str(test_y[i])+"\ny_pred="+str(y_pred[i]))
plt.show()
In [58]: model.predict(X_test[0:4])
Out[58]:
array([[1.0333792e-06, 1.7836443e-09, 3.7520505e-05, 2.2237692e-03,
8.4596380e-10, 3.6472747e-07, 4.6298947e-11, 9.9771035e-01,
3.2618391e-06, 2.3784525e-05],
[4.3476388e-07, 6.9682335e-04, 9.9892431e-01, 3.0969214e-04,
1.7906347e-12, 1.0973981e-05, 1.4038921e-05, 2.8779685e-11,
4.3727505e-05, 1.3733418e-11],
[1.4807856e-06, 9.9750793e-01, 7.4583240e-04, 9.0791560e-05,
1.2258282e-04, 8.2332235e-06, 2.0272743e-04, 8.5284153e-04,
4.1387818e-04, 5.3609900e-05],
[9.9927765e-01, 4.4347512e-08, 8.4634876e-06, 3.8136254e-06,
1.9439985e-05, 3.5597732e-05, 6.4988859e-04, 4.1058142e-06,
8.5573371e-09, 1.0365890e-06]], dtype=float32)
随机取4个样本预测:
for i in range(4):
num=np.random.randint(1,10000)
y_pred=np.argmax(model.predict(tf.expand_dims(X_test[num],axis=0)))
plt.subplot(1,4,i+1)
plt.axis("off")
plt.imshow(test_x[num],cmap='gray')
plt.title('y='+str(test_y[num])+"\ny_pred="+str(y_pred))
plt.show()
4.6、重新加载整个模型(对应于save()方法)
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
mnist=tf.keras.datasets.mnist
#ndarray数组:train_x.shape=(60000, 28, 28),train_y.shape=(60000,),test_x.shape=(10000, 28, 28),test_y.shape=(10000,)
(train_x,train_y),(test_x,test_y)=mnist.load_data()
X_train,X_test=tf.cast(train_x/255.0,tf.float32),tf.cast(test_x/255.0,tf.float32) #归一化
y_train,y_test=tf.cast(train_y,tf.int16),tf.cast(test_y,tf.int16)
model=tf.keras.models.load_model('mnist_model.h5')
#测试模型,参数和上一次完全一样
In [9]: model.evaluate(X_test,y_test,verbose=2)
313/313 - 0s - loss: 0.0889 - sparse_categorical_accuracy: 0.9718
Out[9]: [0.08891819417476654, 0.9718000292778015]