Fork me on GitHub

从0实现基于Keras的两种建模

从0到1实现2种Keras建模网络

本文介绍两种基于Keras的建模方法:

  • 基于Sequential的建模;快速方便,易上手
  • 基于函数式API的建模;易于扩展,灵活性强

主要知识点

通过本文你将学到下面9个实用的知识点,掌握基于Kera搭建神经网络模型的流程:

  1. 如何导入keras的内置数据集
  2. keras如何实现one-hot编码
  3. 如何定义keras的Sequential模型,包含卷积层、池化层、Dropout层等
  4. 如何各个层基本信息,比如层的名称、权重、形状等
  5. 模型的编译、训练
  6. 如何将模型的精度和准确率指标进行可视化
  7. 如何使用TensorFlow的Tensorboard进行可视化
  8. 如何搭建基于函数式API的keras模型
  9. 如何将网络结构图进行可视化

导入内置数据集

1
2
3
4
5
6
# 导入数据集
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]:

1
((50000, 32, 32, 3), (10000, 32, 32, 3), (50000, 1), (10000, 1))

可以看到cifar服装图片数据集存在50000个训练样本,10000个测试样本;数据集是四维的。

数据缩放和标签编码

神经网络中一般输入较小的数值,需要对数据进行缩放:

1
2
# 将像素的值标准化至0到1
train_images, test_images = train_images / 255.0, test_images / 255.0

同时对标签labels进行one-hot编码:

1
2
3
4
5
# 标签编码
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网络模型

搭建基于Sequential的网络模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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]:

1
len(model.layers)  # 总层数

Out[5]:

1
10

每层网络名

In [6]:

1
2
3
4
5
6
7
8
9
10
11
12
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]:

1
2
3
4
5
6
7
8
9
10
11
12
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]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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]:

1
2
3
4
5
6
7
# 同时显示网络层名称、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]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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个参数:

  • 优化器optimizer
  • 损失函数loss
  • 评价指标metrics

In [11]:

1
2
3
4
model.compile(optimizer='rmsprop',  # 优化器
loss='categorical_crossentropy', # 多分类交叉熵categorical_crossentropy
metrics=['accuracy'] # 评价指标
)

回调函数

在使用TensorBoard的时候需要

In [12]:

1
2
3
# 后面tensorborad使用需要

tf_callback = tf.keras.callbacks.TensorBoard(log_dir="./logs") # 指定log_dir路径

存放路径为当前路径下的logs文件夹下

训练模型

1
2
3
4
5
6
7
8
9
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]:

1
2
3
4
5
6
7
8
history_data = history.history  #  字典形式

for keys in history_data:
print(keys)
loss
accuracy
val_loss
val_accuracy

In [15]:

1
2
3
4
5
6
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
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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()

1
2
3
4
5
6
7
8
9
# 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()

tensorboard使用

首次使用的时候需要加载两个环境:

In [18]:

1
%load_ext tensorboard

In [19]:

1
%tensorboard --logdir logs

然后面notebook页面会直接显示Tensorboard:

显示的内容就是每轮的loss和acc。除此之外,你也可以通过localhost:6006到本地网页查看:

构建函数式模型

上面的模型是基于Sequention;下面对比构建出基于函数式API的等效模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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()

打印出来的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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能够绘制出当前模型的框架。

首先需要安装两个库:graphviz可能你会遇到些困难;特别是在windows系统下,希望你有耐心解决。

1
2
pip install pydot
pip install graphviz

安装完成之后在命令行输入dot -version出现下面的界面则表示安装成功:

然后就可以绘图了:

1
2
3
from keras.utils.vis_utils import plot_model

plot_model(model, to_file="model_graph.png", show_shapes=True)

本文标题:从0实现基于Keras的两种建模

发布时间:2022年12月08日 - 22:12

原始链接:http://www.renpeter.cn/2022/12/08/%E4%BB%8E0%E5%AE%9E%E7%8E%B0%E5%9F%BA%E4%BA%8EKeras%E7%9A%84%E4%B8%A4%E7%A7%8D%E5%BB%BA%E6%A8%A1.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Coffee or Tea