Python深度学习11——Keras实现共享层模型(多输入多输出)

 参考书目:陈允杰.TensorFlow与Keras——Python深度学习应用实战.北京:中国水利水电出版社,2021

本系列基本不讲数学原理,只从代码角度去让读者们利用最简洁的Python代码实现深度学习方法。


Keras框架虽然很简单,但是封装得太好了,自定义的自由度不够高,其搭建神经网络像搭建积木一样容易,却难以更改自己想要的积木的形状和位置。好在其神经网络层可以当成函数调用,这就保证了Keras还是具有一定的自定义能力,可以面向对象编程,下面进行一定的神经网络中间层的张量形状的获取,还有怎么实现共享模型,做到多输入和输出。


取得神经网络层的信息

定义好模型后,我们可以显示神经网络每层的名称和输出张量。如果训练完了还可以显示神经网络的权重。

先导入包

from keras.models import Sequential
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

定义模型

# 定义模型
model = Sequential()
model.add(Conv2D(16, kernel_size=(5, 5), padding="same",input_shape=(28, 28, 1), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, kernel_size=(5, 5), padding="same",activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128, activation="relu"))
model.add(Dropout(0.5))
model.add(Dense(10, activation="softmax"))
model.summary()   # 显示模型摘要信息

 查看有多少层

# 显示各神经层
print("神经层数: ", len(model.layers))
for i in range(len(model.layers)):
    print(i, model.layers[i].name)

 

print("每一层的输入张量 ")  
for i in range(len(model.layers)):
    print(i, model.layers[i].input)  

 

print("每一层的输出张量: ")    
for i in range(len(model.layers)):
    print(i, model.layers[i].output)  

#显示各层的权重形状
for i in range(len(model.layers)):
    print(i, model.layers[i].name, ":")
    weights = model.layers[i].get_weights()
    for j in range(len(weights)):
        print("==>", j, weights[j].shape)

可以读取的模型,查看其训练的权重

model = Sequential()
model = load_model("imdb_gru.h5")
model.summary()   #  显示模型摘要信息
# 编译模型 
model.compile(loss="binary_crossentropy", optimizer="rmsprop",  metrics=["accuracy"])
# 显示GRU层的权重形状 
print(2, model.layers[2].name, ":")
weights = model.layers[2].get_weights()
for i in range(len(weights)):
    print("==>", i,weights[i].shape)

 

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')

 


使用Functional API进行搭建

以前Kears搭建模型都是上面那种,类似搭积木,下面使用函数的形式去搭建。

搭建这样一个网络

 

# 定义模型
mnist_input = Input(shape=(28, 28, 1), 
                    name="input")
conv1 = Conv2D(16, kernel_size=(5, 5), padding="same",
               activation="relu", name="conv1")(mnist_input)
pool1 = MaxPooling2D(pool_size=(2, 2),
                     name="pool1")(conv1)
conv2 = Conv2D(32, kernel_size=(5, 5), padding="same",
               activation="relu", name="conv2")(pool1)
pool2 = MaxPooling2D(pool_size=(2, 2),
                     name="pool2")(conv2)
drop1 = Dropout(0.5, name="drop1")(pool2)
flat = Flatten(name="flat")(drop1)
hidden1 = Dense(128, activation="relu", name="hidden1")(flat)
drop2 = Dropout(0.5, name="drop2")(hidden1)
output = Dense(10, activation="softmax",
               name="output")(drop2)
model = Model(inputs=mnist_input, outputs=output)
model.summary()   # 显示模型摘要信息

或者搭建这样一个LSTM网络

 

# 定义模型
imdb_input = Input(shape=(100,), dtype="int32",
                   name="imdb_input")
embed = Embedding(top_words, 32, input_length=max_words,
                    name="embed")(imdb_input)
drop1 = Dropout(0.25, name="drop1")(embed)
lstm = LSTM(32, name="lstm")(drop1)
drop2 = Dropout(0.25, name="drop2")(lstm)
output = Dense(1, activation="sigmoid", 
               name="output")(drop2)
model = Model(inputs=imdb_input, outputs=output)
model.summary()   #显示模型摘要信息

共享层模型

前面的模型都是序列模型,即一层一层的搭建,但是有的网络可以多层一起搭建,例如下面这个模型,然后代码如下:

 

from keras.models import Model
from keras.layers import Input, Dense, Flatten, Conv2D, MaxPooling2D
from keras.layers.merge import concatenate

#定义模型
shared_input = Input(shape=(64, 64, 1))
# 第1个共享输入层的卷积和池化层
conv1 = Conv2D(32, kernel_size=3, activation="relu")(shared_input)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
flat1 = Flatten()(pool1)
# 第2个共享输入层的卷积和池化层
conv2 = Conv2D(16, kernel_size=5, activation="relu")(shared_input)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
flat2 = Flatten()(pool2)
#合并 2 个共享输入层的卷积和池化层
merge = concatenate([flat1, flat2])
hidden1 = Dense(10, activation="relu")(merge)
output = Dense(1, activation="sigmoid")(hidden1)
model = Model(inputs=shared_input, outputs=output)
model.summary()   #  显示模型摘要信息
from keras.utils import plot_model

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

也可以不对称,两边随便弄几层,例如这样的

from keras.models import Model
from keras.layers import Input, Dense, LSTM
from keras.layers.merge import concatenate

#定义模型
model_input = Input(shape=(100, 1))
lstm = LSTM(32)(model_input)
# 第 1 个共享特征提取层的解释层
extract1 = Dense(16, activation="relu")(lstm)
# 第 2 个共享特征提取层的解释层
dense1 = Dense(16, activation="relu")(lstm)
dense2 = Dense(32, activation="relu")(dense1)
extract2 = Dense(16, activation='relu')(dense2)
# 合并 2 个共享特征提取层的解释层
merge = concatenate([extract1, extract2])
output = Dense(1, activation="sigmoid")(merge)
model = Model(inputs=model_input, outputs=output)
model.summary()   #显示模型摘要信息

 


多输入和输出模型

更加复杂的模型,有多对输入数据,例如图片有彩色和灰白,销售量有季节、温度、折扣、成本等很多因素影响。这就涉及到需要多输入和输出了。下面构建一个对彩色和灰白图片一起输入的模型:

多输入模型为

from keras.models import Model
from keras.layers import Input, Dense, Flatten, Conv2D, MaxPooling2D
from keras.layers.merge import concatenate

# 定义模型
# 第 1 个灰度图片输入
input1 = Input(shape=(28, 28, 1))
conv11 = Conv2D(16, (3,3), activation="relu")(input1)
pool11 = MaxPooling2D(pool_size=(2,2))(conv11)
conv12 = Conv2D(32, (3,3), activation="relu")(pool11)
pool12 = MaxPooling2D(pool_size=(2,2))(conv12)
flat1 = Flatten()(pool12)
# 第 2 个彩色图片输入
input2 = Input(shape=(28, 28, 3))
conv21 = Conv2D(16, (3,3), activation="relu")(input2)
pool21 = MaxPooling2D(pool_size=(2,2))(conv21)
conv22 = Conv2D(32, (3,3), activation="relu")(pool21)
pool22 = MaxPooling2D(pool_size=(2,2))(conv22)
flat2 = Flatten()(pool22)
# 合并 2 个输入
merge = concatenate([flat1, flat2])
dense1 = Dense(512, activation="relu")(merge)
dense2 = Dense(128, activation="relu")(dense1)
dense3 = Dense(32, activation="relu")(dense2)
output = Dense(10, activation="softmax")(dense3)
# 定义多输入模型
model = Model(inputs=[input1, input2], outputs=output)
model.summary()   # 显示模型摘要信息

 多输出模型为:

 

from keras.models import Model
from keras.layers import Dense, Input
 
#  定义模型
model_input = Input(shape = (784,))
dense1 = Dense(512, activation="relu")(model_input)
dense2 = Dense(128, activation="relu")(dense1)
dense3 = Dense(32, activation ="relu")(dense2)
# 第 1 个分类输出
output = Dense(10, activation="softmax")(dense3)
# 第 2 个自编码器输出
up_dense1 = Dense(128, activation="relu")(dense3)
up_dense2 = Dense(512, activation="relu")(up_dense1)
decoded_outputs = Dense(784)(up_dense2)
# 定义多输出模型
model = Model(model_input, [output, decoded_outputs])
model.summary()   # 显示模型摘要信息

 mnist案例

使用手写数字数据集做上面两个模型的案例。

多输入

由于手写数字集没有彩色,那就改为两个黑白输入(这个案例里面这样做对精度没啥提升作用….只是演示)

from keras.models import Model
from keras.layers import Input, Dense, Flatten, Conv2D, MaxPooling2D
from keras.layers.merge import concatenate
from keras.datasets import mnist
from tensorflow.keras.utils import to_categorical

# 定义模型
# 第 1 个灰度图片输入
input1 = Input(shape=(28, 28, 1))
conv11 = Conv2D(16, (3,3), activation="relu")(input1)
pool11 = MaxPooling2D(pool_size=(2,2))(conv11)
conv12 = Conv2D(32, (3,3), activation="relu")(pool11)
pool12 = MaxPooling2D(pool_size=(2,2))(conv12)
flat1 = Flatten()(pool12)
# 第 2 个彩色图片输入
input2 = Input(shape=(28, 28, 1))
conv21 = Conv2D(16, (3,3), activation="relu")(input2)
pool21 = MaxPooling2D(pool_size=(2,2))(conv21)
conv22 = Conv2D(32, (3,3), activation="relu")(pool21)
pool22 = MaxPooling2D(pool_size=(2,2))(conv22)
flat2 = Flatten()(pool22)
# 合并 2 个输入
merge = concatenate([flat1, flat2])
dense1 = Dense(512, activation="relu")(merge)
dense2 = Dense(128, activation="relu")(dense1)
dense3 = Dense(32, activation="relu")(dense2)
output = Dense(10, activation="softmax")(dense3)
# 定义多输入模型
model = Model(inputs=[input1, input2], outputs=output)
model.summary()   # 显示模型摘要信息

 

import numpy as np
# 指定乱数种子
seed = 7
np.random.seed(seed)
# 载入数据集
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
# 将图片转换成 4D 张量  
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype("float32")
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype("float32")
# 因为是固定范围, 所以执行正规化, 从 0-255 至 0-1  
X_train = X_train / 255
X_test = X_test / 255
# One-hot编码
Y_train = to_categorical(Y_train)
Y_test = to_categorical(Y_test)

#编译模型
model.compile(loss="categorical_crossentropy", optimizer="adam",metrics=["accuracy"])

#  训练模型
history = model.fit([X_train,X_train], Y_train,validation_split=0.2,
                    epochs=10, batch_size=128, verbose=2)

model.evaluate([X_test,X_test],Y_test)

 

 

多输出

from keras.models import Sequential
from keras.models import load_model
# 建立Keras的Sequential模型
model = Sequential()
model = load_model("mnist.h5")
model.summary()   # 显示模型摘要信息
# 编译模型
model.compile(loss="categorical_crossentropy", optimizer="adam",metrics=["accuracy"])

#  使用 Model 建立 前4层的 Conv2D 和 MaxPooling 层
# 此模型是 1 个输入, 和 4 个输出
layer_outputs = [layer.output for layer in model.layers[:4]]
model_test = Model(inputs=model.input, outputs=layer_outputs)

outputs = model_test.predict(X_train[1].reshape(1,28,28,1))
# 取得第1个 Conv2D 的输出
output = outputs[0]
output.shape

import matplotlib.pyplot as plt
#绘出第1个 Conv2D 层的输出
plt.figure(figsize=(10,8))
for i in range(0,16):
    plt.subplot(4,4,i+1)
    plt.imshow(output[0,:,:,i], cmap="gray")
    plt.axis("off")

 

 

#  取得第1个 MaxPooling 的输出
output = outputs[1]
# 绘出第1个 MaxPooling 层的输出
plt.figure(figsize=(10,8))
for i in range(0,16):
    plt.subplot(4,4,i+1)
    plt.imshow(output[0,:,:,i], cmap="gray")
    plt.axis("off")

 

 

# 取得第2个 Conv2D 的输出
output = outputs[2]
# 绘出第2个 Conv2D 层的输出
plt.figure(figsize=(10,8))
for i in range(0,32):
    plt.subplot(6,6,i+1)
    plt.imshow(output[0,:,:,i], cmap="gray")
    plt.axis("off")

 

 

# 取得第2个 MaxPooling 的输出
output = outputs[3]
# 绘出第2个 MaxPooling 层的输出
plt.figure(figsize=(10,8))
for i in range(0,32):
    plt.subplot(6,6,i+1)
    plt.imshow(output[0,:,:,i], cmap="gray")
    plt.axis("off") 
    

 这个多输出模型是将每一步的中间层都输出了,可以查看模型学到了什么。算是模型中间层的可视化

来源:阡之尘埃

物联沃分享整理
物联沃-IOTWORD物联网 » Python深度学习11——Keras实现共享层模型(多输入多输出)

发表评论