大家好,本文从0到1详细讲解两种基于Keras的建模方法:
通过本文你将学到下面10个实用的知识点,快速掌握基于Kera搭建神经网络模型的流程:
- # 导入数据集
- from keras.datasets import cifar10
-
- (train_images, train_labels), (test_images, test_labels) = cifar10.load_data()
-
- train_images.shape, test_images.shape, train_labels.shape, test_labels.shape
-
Out[1]:
- ((50000, 32, 32, 3), (10000, 32, 32, 3), (50000, 1), (10000, 1))
-
可以看到cifar服装图片数据集存在50000个训练样本,10000个测试样本;数据集是四维的。
神经网络中一般输入较小的数值,需要对数据进行缩放:
- # 将像素的值标准化至0到1
- train_images, test_images = train_images / 255.0, test_images / 255.0
-
同时对标签labels进行one-hot编码:
- # 标签编码
- from keras.utils.np_utils import to_categorical
-
- one_hot_train_labels = to_categorical(train_labels)
- one_hot_test_labels = to_categorical(test_labels)
-
搭建基于Sequential的网络模型:
- import tensorflow as tf
- from keras.models import Sequential
- from keras.layers import Dense,Flatten,Conv2D,MaxPooling2D,Dropout,Activation,ZeroPadding2D
- from tensorflow.keras import datasets, layers, models
-
- # Sequential模型实例化
- model = Sequential()
- # 卷积层1
- model.add(Conv2D(filters = 32, # filters个数
- kernel_size = (3,3), # 卷积核大小
- padding="same", # 边界填充方式
- input_shape=(32,32,3), # 输入数据shape
- activation="relu" # 激活函数
- ))
- # Dropout层1
- model.add(Dropout(0.25)) # dropout比例
- # 最大池化层1
- model.add(MaxPooling2D(pool_size=(2,2)))
- # 卷积层2
- model.add(Conv2D(64, kernel_size=(3,3), padding="same",activation="relu"))
- # 最大池化层2
- model.add(MaxPooling2D(pool_size=(2,2)))
- # Dropout层2
- model.add(Dropout(0.2)) # dropout比例
- # 拉直层
- model.add(Flatten())
- # 密集连接层
- model.add(Dense(128,activation="relu"))
- # Dropout层3
- model.add(Dropout(0.25))
-
- # 输出层:10表示的最终数据的分类数目
- model.add(Dense(10, activation="softmax")) # 多分类使用softmax激活函数
-
在多分类问题的最后全连接层中,激活函数使用softmax函数;它输出的是每个分类的概率值,且它们的概率之和为;取最大的概率所在的类。
查看所搭建的网络层的基本信息:
In [5]:
- len(model.layers) # 总层数
-
Out[5]:
- 10
-
In [6]:
- for i in range(len(model.layers)):
- print(f'第 {i + 1} 层网络名称:{model.layers[i].name}')
- 第 1 层网络名称:conv2d
- 第 2 层网络名称:dropout
- 第 3 层网络名称:max_pooling2d
- 第 4 层网络名称:conv2d_1
- 第 5 层网络名称:max_pooling2d_1
- 第 6 层网络名称:dropout_1
- 第 7 层网络名称:flatten
- 第 8 层网络名称:dense
- 第 9 层网络名称:dropout_2
- 第 10 层网络名称:dense_1
-
In [7]:
- for i in range(len(model.layers)):
- print(f'第 {i + 1} 层网络shape:{model.layers[i].input.shape}')
- 第 1 层网络shape:(None, 32, 32, 3)
- 第 2 层网络shape:(None, 32, 32, 32)
- 第 3 层网络shape:(None, 32, 32, 32)
- 第 4 层网络shape:(None, 16, 16, 32)
- 第 5 层网络shape:(None, 16, 16, 64)
- 第 6 层网络shape:(None, 8, 8, 64)
- 第 7 层网络shape:(None, 8, 8, 64)
- 第 8 层网络shape:(None, 4096)
- 第 9 层网络shape:(None, 128)
- 第 10 层网络shape:(None, 128)
-
In [8]:
- for i in range(len(model.layers)):
- print(i, model.layers[i].name, ":") # 每层的名称
- weights = model.layers[i].get_weights() # 获取每层的权重
- print(f'第{i}的权重层数: {len(weights)}')
- for j in range(len(weights)): # 每个网络的每层权重数
- print("====>",j, weights[j].shape)
- 0 conv2d :
- 第0的权重层数: 2
- ====> 0 (3, 3, 3, 32)
- ====> 1 (32,)
- 1 dropout :
- 第1的权重层数: 0
- 2 max_pooling2d :
- 第2的权重层数: 0
- 3 conv2d_1 :
- 第3的权重层数: 2
- ====> 0 (3, 3, 32, 64)
- ====> 1 (64,)
- 4 max_pooling2d_1 :
- 第4的权重层数: 0
- 5 dropout_1 :
- 第5的权重层数: 0
- 6 flatten :
- 第6的权重层数: 0
- 7 dense :
- 第7的权重层数: 2
- ====> 0 (4096, 128)
- ====> 1 (128,)
- 8 dropout_2 :
- 第8的权重层数: 0
- 9 dense_1 :
- 第9的权重层数: 2
- ====> 0 (128, 10)
- ====> 1 (10,)
-
In [9]:
- # 同时显示网络层名称、input和output
-
- for i in range(len(model.layers)):
- print(i, model.layers[i].name)
- print(i, model.layers[i].input)
- print(i, model.layers[i].output)
- print("\n")
-
In [10]:
- model.summary() # 显示模型信息
- Model: "sequential"
- _________________________________________________________________
- Layer (type) Output Shape Param #
- =================================================================
- conv2d (Conv2D) (None, 32, 32, 32) 896
-
- dropout (Dropout) (None, 32, 32, 32) 0
-
- max_pooling2d (MaxPooling2D (None, 16, 16, 32) 0
- )
-
- conv2d_1 (Conv2D) (None, 16, 16, 64) 18496
-
- max_pooling2d_1 (MaxPooling (None, 8, 8, 64) 0
- 2D)
-
- dropout_1 (Dropout) (None, 8, 8, 64) 0
-
- flatten (Flatten) (None, 4096) 0
-
- dense (Dense) (None, 128) 524416
-
- dropout_2 (Dropout) (None, 128) 0
-
- dense_1 (Dense) (None, 10) 1290
-
- =================================================================
- Total params: 545,098
- Trainable params: 545,098
- Non-trainable params: 0
- _________________________________________________________________
-
网络编译的时候通常需要指定3个参数:
In [11]:
- model.compile(optimizer='rmsprop', # 优化器
- loss='categorical_crossentropy', # 多分类交叉熵categorical_crossentropy
- metrics=['accuracy'] # 评价指标
- )
-
在使用TensorBoard的时候需要
In [12]:
- # 后面tensorborad使用需要
-
- tf_callback = tf.keras.callbacks.TensorBoard(log_dir="./logs") # 指定log_dir路径
-
存放路径为当前路径下的logs文件夹下
- history = model.fit(train_images, # x
- one_hot_train_labels, # y
- epochs=20, # 训练轮次
- batch_size=1024, # 每次训练使用样本小批量
- validation_split=0.2, # 验证集比例
- callbacks=[tf_callback], # 回调函数
- verbose=1 # 是否显示训练详细信息,1-显示 0-不显示
- # validation_data=[x_val,y_val] # 验证集的数据
- )
-
当verbose=1的时候会显示每轮训练的具体信息:
主要是针对精度和损失值的可视化
In [14]:
- history_data = history.history # 字典形式
-
- for keys in history_data:
- print(keys)
- loss
- accuracy
- val_loss
- val_accuracy
-
In [15]:
- loss = history_data["loss"]
- val_loss = history_data["val_loss"]
-
- # 原文 acc = history_data["acc]
- acc = history_data["accuracy"] # 改动:精度acc使用全称accuracy
- val_acc = history_data["val_accuracy"]
-
In [16]:
- # 1、损失loss
-
- import matplotlib.pyplot as plt
- %matplotlib inline
-
- epochs = range(1, len(loss) + 1) # 作为横轴
-
- plt.plot(epochs, loss, "bo", label="Training Loss")
- plt.plot(epochs, val_loss, "b", label="Validation Loss")
- plt.xlabel("Epochs")
- plt.ylabel("Loss")
- plt.legend()
- plt.title("Training and Validation Loss")
- plt.show()
-
- # 2、精度acc
-
- plt.plot(epochs, acc, "bo", label="Training Acc")
- plt.plot(epochs, val_acc, "b", label="Validation Acc")
- plt.xlabel("Epochs")
- plt.ylabel("Acc")
- plt.legend()
- plt.title("Training and Validation Acc")
- plt.show()
-
首次使用的时候需要先加载两个环境:
In [18]:
- %load_ext tensorboard
-
In [19]:
- %tensorboard --logdir logs
-
然后在notebook页面中会直接显示Tensorboard:
除此之外,你也可以通过localhost:6006到本地网页查看:
显示的内容就是每轮的loss和acc
上面的网络模型是基于Sequential;下面对比构建出基于函数式API的等效模型:
- from keras.models import Model
-
- from keras.layers import Input
- from keras.layers import Dense
- from keras.layers import Flatten
- from keras.layers import Conv2D
- from keras.layers import MaxPooling2D
- from keras.layers import Dropout
- from keras.layers import Activation
- from keras.layers import ZeroPadding1D
-
- # 第一步:实例化输入层
- cifar_input = Input(shape=(32,32,3),
- name="input")
-
- # 第二步:中间层的不断传递
- conv1 = Conv2D(32,
- kernel_size=(3,3),
- padding="same",
- activation="relu",
- name="conv1")(cifar_input)
-
- drop1 = Dropout(0.25, name="drop1")(conv1)
- maxpool1 = MaxPooling2D(pool_size=(2,2), name="maxpool1")(drop1)
- conv2 = Conv2D(64,
- kernel_size=(3,3),
- padding="same",
- activation="relu",
- name="conv2")(maxpool1)
-
- maxpool2 = MaxPooling2D(pool_size=(2,2), name="maxpool2")(conv2)
- drop2 = Dropout(0.25, name="drop2")(maxpool2)
-
- flatten = Flatten(name="flatten")(drop2)
- dense1 = Dense(128, activation="relu")(flatten)
- drop3 = Dropout(0.25, name="drop3")(dense1)
-
- # 第三步:输出层
- output = Dense(10, activation="softmax")(drop3)
-
- # 第四步:实例化Model类:传入输入和输出信息
- model = Model(inputs=cifar_input, outputs=output)
- model.summary()
-
-
打印出来的效果:
- Model: "model"
- _________________________________________________________________
- Layer (type) Output Shape Param #
- =================================================================
- input (InputLayer) [(None, 32, 32, 3)] 0
-
- conv1 (Conv2D) (None, 32, 32, 32) 896
-
- drop1 (Dropout) (None, 32, 32, 32) 0
-
- maxpool1 (MaxPooling2D) (None, 16, 16, 32) 0
-
- conv2 (Conv2D) (None, 16, 16, 64) 18496
-
- maxpool2 (MaxPooling2D) (None, 8, 8, 64) 0
-
- drop2 (Dropout) (None, 8, 8, 64) 0
-
- flatten (Flatten) (None, 4096) 0
-
- dense_2 (Dense) (None, 128) 524416
-
- drop3 (Dropout) (None, 128) 0
-
- dense_3 (Dense) (None, 10) 1290
-
- =================================================================
- Total params: 545,098
- Trainable params: 545,098
- Non-trainable params: 0
- _________________________________________________________________
-
-
通过keras自带的plot_model能够绘制出当前模型的框架。
首先需要安装两个库:pydot 和 graphviz。其中graphviz的安装可能你会遇到些困难;特别是在windows系统下,希望你有耐心解决。
- pip install pydot
- pip install graphviz
-
安装完成之后在命令行输入dot -version出现下面的界面则表示安装成功:
然后就可以绘图了:
- from keras.utils.vis_utils import plot_model
-
- plot_model(model, to_file="model_graph.png", show_shapes=True)
-