TensorFlow神经网络中间层的可视化
- TensorFlow神经网络中间层的可视化
-
- [1. 训练网络并保存为.h5文件](#1. 训练网络并保存为.h5文件)
- [2. 通过.h5文件导入网络](#2. 通过.h5文件导入网络)
- [3. 可视化网络中间层结果](#3. 可视化网络中间层结果)
TensorFlow神经网络中间层的可视化
1. 训练网络并保存为.h5文件
我们使用AlexNet为例,任务是手写数字识别,训练集使用手写数字集(mnist)。
网络的结构(我们使用的是28x28的黑白图):
网络搭建和训练的代码
python
# 最终版
import os.path
import tensorflow as tf
import matplotlib.pyplot as plt
import cv2
# 画出训练过程的准确率和损失值的图像
def plotTrainHistory(history, train, val):
plt.plot(history[train])
plt.plot(history[val])
plt.title('Train History')
plt.xlabel('Epoch')
plt.ylabel(train)
plt.legend(['train', 'validation'], loc = 'upper left')
plt.show()
(xTrain, yTrain), (xTest, yTest) = tf.keras.datasets.mnist.load_data()
xTrain = tf.expand_dims(xTrain, axis = 3)
xTest = tf.expand_dims(xTest, axis = 3)
print(f"训练集数据大小:{xTrain.shape}")
print(f"训练集标签大小:{yTrain.shape}")
print(f"测试集数据大小:{xTest.shape}")
print(f"测试集标签大小:{yTest.shape}")
# 归一化
xTrainNormalize = tf.cast(xTrain, tf.float32) / 255
xTestNormalize = tf.cast(xTest, tf.float32) / 255
# 数据独热编码
yTrainOneHot = tf.keras.utils.to_categorical(yTrain)
yTestOneHot = tf.keras.utils.to_categorical(yTest)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(
filters = 96, kernel_size = 11, strides = 4, input_shape = (28, 28, 1),
padding = 'SAME', activation = tf.keras.activations.relu
),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.MaxPool2D(pool_size = 3, strides = 2, padding = 'SAME'),
tf.keras.layers.Conv2D(
filters = 256, kernel_size = 5, strides = 1,
padding = 'SAME', activation = tf.keras.activations.relu
),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.MaxPool2D(pool_size = 3, strides = 2, padding = 'SAME'),
tf.keras.layers.Conv2D(
filters = 384, kernel_size = 3, strides = 1,
padding = 'SAME', activation = tf.keras.activations.relu
),
tf.keras.layers.Conv2D(
filters = 384, kernel_size = 3, strides = 1,
padding = 'SAME', activation = tf.keras.activations.relu
),
tf.keras.layers.Conv2D(
filters = 256, kernel_size = 3, strides = 1,
padding = 'SAME', activation = tf.keras.activations.relu
),
tf.keras.layers.MaxPool2D(pool_size = 3, strides = 2, padding = 'SAME'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(4096, activation = tf.keras.activations.relu),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(4096, activation = tf.keras.activations.relu),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(10, activation = tf.keras.activations.softmax)
])
weightsPath = './AlexNetModel/'
callback = tf.keras.callbacks.ModelCheckpoint(
filepath = weightsPath,
save_best_only = True,
save_weights_only = True,
verbose = 1
)
model.compile(
loss = tf.keras.losses.CategoricalCrossentropy(),
optimizer = tf.keras.optimizers.Adam(),
metrics = ['accuracy']
)
model.summary()
# 不存在就训练模型
print('参数文件不存在,即将训练模型')
modelTrain = model.fit(
xTrainNormalize, yTrainOneHot, validation_split = 0.2,
epochs = 20, batch_size = 300, verbose = 1, callbacks = [callback]
)
model.save("./model.h5")
plotTrainHistory(modelTrain.history, 'loss', 'val_loss')
plotTrainHistory(modelTrain.history, 'accuracy', 'val_accuracy')
2. 通过.h5文件导入网络
把刚才训练得到的模型重新读取,并且重新加载数据集
python
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
def plot_images(images, number, path, title, gray = False):
plt.figure()
plt.title(title)
order = 1
for i in range(0, number):
plt.subplot(3, 3, order)
if gray:
plt.imshow(images[:, :, 0, i], cmap = 'gray')
else:
plt.imshow(images[:, :, 0, i])
plt.colorbar()
order = order + 1
plt.savefig("./{}.png".format(path))
plt.show()
if __name__ == '__main__':
weightsPath = './AlexNetModel/'
(xTrain, yTrain), (xTest, yTest) = tf.keras.datasets.mnist.load_data()
xTrain = tf.expand_dims(xTrain, axis = 3)
xTest = tf.expand_dims(xTest, axis = 3)
# print(f"训练集数据大小:{xTrain.shape}")
# print(f"训练集标签大小:{yTrain.shape}")
# print(f"测试集数据大小:{xTest.shape}")
# print(f"测试集标签大小:{yTest.shape}")
# 归一化
xTrainNormalize = tf.cast(xTrain, tf.float32) / 255
xTestNormalize = tf.cast(xTest, tf.float32) / 255
# 数据独热编码
yTrainOneHot = tf.keras.utils.to_categorical(yTrain)
yTestOneHot = tf.keras.utils.to_categorical(yTest)
model = tf.keras.models.load_model("model.h5")
model.summary()
print('Layer Number', len(model.layers))
sample = xTrainNormalize[0]
plt.imshow(sample)
plt.colorbar()
plt.savefig('./train.png')
3. 可视化网络中间层结果
测试的数字,5
(1)索引取层可视化
model.layers 中存放着这个神经网络的全部层,它是一个list类型变量
AlexNet一共16层(卷积层、全连接层、池化层等都算入),全部存储在里面
python
model = tf.keras.models.load_model("model.h5")
print('Layer Number', len(model.layers))
可视化的时候我们取出一部分层,然后来预测,预测结果就是取出来这部分层的结果,因此就看到了中间层的结果
python
output = tf.keras.models.Sequential([
tf.keras.layers.InputLayer(input_shape = (28, 28, 1)),
model.layers[0],
model.layers[1],
model.layers[2],
]).predict(sample)
print('output.shape', output.shape)
plot_images(output, 9, '5_Conv2D_BN_MP_1', str(output.shape))
查看三层的结果,即Conv2D+BN+MaxPool,结果是 (28, 4, 1, 96),这里画出前9个
把这96个叠加在一起的结果
python
t = output[:, :, 0, 0]
for i in range(1, output.shape[3]):
t = t + output[:, :, 0, i]
plt.imshow(t)
plt.colorbar()
plt.savefig('./5_Conv2D_BN_MP_1_All.png')
下面的代码是画出神经网络三个中间层的结果
python
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
def plot_images(images, number, path, title, gray = False):
plt.figure()
plt.title(title)
order = 1
for i in range(0, number):
plt.subplot(3, 3, order)
if gray:
plt.imshow(images[:, :, 0, i], cmap = 'gray')
else:
plt.imshow(images[:, :, 0, i])
plt.colorbar()
order = order + 1
plt.savefig("./{}.png".format(path))
plt.show()
if __name__ == '__main__':
weightsPath = './AlexNetModel/'
(xTrain, yTrain), (xTest, yTest) = tf.keras.datasets.mnist.load_data()
xTrain = tf.expand_dims(xTrain, axis = 3)
xTest = tf.expand_dims(xTest, axis = 3)
# print(f"训练集数据大小:{xTrain.shape}")
# print(f"训练集标签大小:{yTrain.shape}")
# print(f"测试集数据大小:{xTest.shape}")
# print(f"测试集标签大小:{yTest.shape}")
# 归一化
xTrainNormalize = tf.cast(xTrain, tf.float32) / 255
xTestNormalize = tf.cast(xTest, tf.float32) / 255
# 数据独热编码
yTrainOneHot = tf.keras.utils.to_categorical(yTrain)
yTestOneHot = tf.keras.utils.to_categorical(yTest)
model = tf.keras.models.load_model("model.h5")
model.summary()
print('Layer Number', len(model.layers))
sample = xTrainNormalize[0]
plt.imshow(sample)
plt.colorbar()
plt.savefig('./train.png')
output = tf.keras.models.Sequential([
tf.keras.layers.InputLayer(input_shape = (28, 28, 1)),
model.layers[0],
model.layers[1],
model.layers[2],
]).predict(sample)
print('output.shape', output.shape)
plot_images(output, 9, '5_Conv2D_BN_MP_1', str(output.shape))
t = output[:, :, 0, 0]
for i in range(1, output.shape[3]):
t = t + output[:, :, 0, i]
plt.imshow(t)
plt.colorbar()
plt.savefig('./5_Conv2D_BN_MP_1_All.png')
output = tf.keras.models.Sequential([
tf.keras.layers.InputLayer(input_shape=(28, 28, 1)),
model.layers[0],
model.layers[1],
model.layers[2],
model.layers[3],
model.layers[4],
model.layers[5],
]).predict(sample)
print('output.shape', output.shape)
plot_images(output, 9, '5_Conv2D_BN_MP_2', str(output.shape))
t = output[:, :, 0, 0]
for i in range(1, output.shape[3]):
t = t + output[:, :, 0, i]
plt.imshow(t)
plt.colorbar()
plt.savefig('./5_Conv2D_BN_MP_2_All.png')
output = tf.keras.models.Sequential([
tf.keras.layers.InputLayer(input_shape=(28, 28, 1)),
model.layers[0],
model.layers[1],
model.layers[2],
model.layers[3],
model.layers[4],
model.layers[5],
model.layers[6],
model.layers[7],
model.layers[8],
model.layers[9],
]).predict(sample)
print('output.shape', output.shape)
plot_images(output, 9, '5_Conv2D_3_MP', str(output.shape))
t = output[:, :, 0, 0]
for i in range(1, output.shape[3]):
t = t + output[:, :, 0, i]
plt.imshow(t)
plt.colorbar()
plt.savefig('./5_Conv2D_3_MP_All.png')
0和5的结果
(2)通过名字取层可视化
模型的**summary()**成员函数可以查看网络每一层名字和参数情况
python
model.summary()
博客中使用的AlexNet每一层名字和参数情况
通过名字来取中间层,并且预测得到中间层可视化结果
如果我们要看这个池化层的结果,这样写代码
python
model = tf.keras.models.load_model("../model.h5")
model.summary()
sample = xTrainNormalize[0]
plt.imshow(sample)
plt.colorbar()
plt.savefig('./train.png')
output = tf.keras.models.Model(
inputs=model.get_layer('conv2d').input,
outputs=model.get_layer('max_pooling2d').output
).predict(sample)
通过get_layer获取指定名字的层
inputs指定输入层,outputs指定输出层
每一层的名字可以在创建的时候使用name参数指定
python
...
tf.keras.layers.Conv2D(
filters = 96, kernel_size = 11, strides = 4, input_shape = (28, 28, 1),
padding = 'SAME', activation = tf.keras.activations.relu, name = 'Conv2D_1'
),
...
每一层的名字红色框框出
下面是例子:
python
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
def plot_images(images, number, path, title, gray = False):
plt.figure()
plt.title(title)
order = 1
for i in range(0, number):
plt.subplot(3, 3, order)
if gray:
plt.imshow(images[:, :, 0, i], cmap = 'gray')
else:
plt.imshow(images[:, :, 0, i])
plt.colorbar()
order = order + 1
plt.savefig("./{}.png".format(path))
plt.show()
if __name__ == '__main__':
(xTrain, yTrain), (xTest, yTest) = tf.keras.datasets.mnist.load_data()
xTrain = tf.expand_dims(xTrain, axis = 3)
xTest = tf.expand_dims(xTest, axis = 3)
# 归一化
xTrainNormalize = tf.cast(xTrain, tf.float32) / 255
xTestNormalize = tf.cast(xTest, tf.float32) / 255
# 数据独热编码
yTrainOneHot = tf.keras.utils.to_categorical(yTrain)
yTestOneHot = tf.keras.utils.to_categorical(yTest)
model = tf.keras.models.load_model("../model.h5")
model.summary()
sample = xTrainNormalize[0]
plt.imshow(sample)
plt.colorbar()
plt.savefig('./train.png')
output = tf.keras.models.Model(
inputs=model.get_layer('conv2d').input,
outputs=model.get_layer('max_pooling2d').output
).predict(sample)
# output = tf.keras.models.Sequential([
# tf.keras.layers.InputLayer(input_shape = (28, 28, 1)),
# model.layers[0],
# model.layers[1],
# model.layers[2],
# ]).predict(sample)
print('output.shape', output.shape)
# plot_images(output, 9, '5_Conv2D_BN_MP_1', str(output.shape))