在深度学习领域,Keras是一个广受欢迎且易于使用的构建深度学习模型的库。它支持多种常见的层类型,如输入层、全连接层、卷积层、转置卷积层、重塑层、归一化层、随机失活层、展平层以及激活层等。然而,有时我们可能需要对数据执行现有层无法实现的操作,这时Lambda层就派上用场了。本文将详细介绍如何在Keras中使用Lambda层来构建、保存和加载模型。
在Keras中有三种构建模型的API:顺序API(Sequential API)、函数式API(Functional API)和模型子类化API(Model Subclassing API)。本文重点关注函数式API。
以MNIST数据集图像识别任务为例,构建模型需堆叠各种层。首先是输入层,使用tensorflow.keras.layers.Input()
类创建,需指定shape
参数,MNIST图像大小为28x28,即784,因此shape=(784)
。如下:
input_layer = tensorflow.keras.layers.Input(shape=(784), name="input_layer")
接下来是全连接层,使用Dense
类创建,通过units
参数指定神经元数量,并连接到输入层:
dense_layer_1 = tensorflow.keras.layers.Dense(units=500, name="dense_layer_1")(input_layer)
然后添加激活层,这里使用ReLU激活函数:
activ_layer_1 = tensorflow.keras.layers.ReLU(name="activ_layer_1")(dense_layer_1)
按照类似方式继续添加全连接层和激活层:
dense_layer_2 = tensorflow.keras.layers.Dense(units=250, name="dense_layer_2")(activ_layer_1)
activ_layer_2 = tensorflow.keras.layers.ReLU(name="relu_layer_2")(dense_layer_2)
dense_layer_3 = tensorflow.keras.layers.Dense(units=20, name="dense_layer_3")(activ_layer_2)
activ_layer_3 = tensorflow.keras.layers.ReLU(name="relu_layer_3")(dense_layer_3)
由于MNIST数据集有10个类别,最后一个全连接层的units
设为10:
dense_layer_4 = tensorflow.keras.layers.Dense(units=10, name="dense_layer_4")(activ_layer_3)
为得到每个类别的分数,添加Softmax层:
output_layer = tensorflow.keras.layers.Softmax(name="output_layer")(dense_layer_4)
此时各层已连接,但模型尚未创建,使用Model
类构建模型,传入输入层和输出层:
model = tensorflow.keras.models.Model(input_layer, output_layer, name="model")
在加载数据集和训练模型前,需使用compile()
方法编译模型:
model.compile(optimizer=tensorflow.keras.optimizers.Adam(lr=0.0005), loss="categorical_crossentropy")
使用model.summary()
可查看模型架构概述。准备数据集时,从keras.datasets
模块加载MNIST数据,将数据类型转换为float64
并归一化,再重塑为784维向量。由于使用categorical_crossentropy
损失函数,需对标签进行独热编码,最后使用fit()
方法训练模型。
假设在dense_layer_3
层后,想对张量执行添加固定值2的操作,现有层无法实现,可通过Lambda层解决。
先定义执行该操作的函数:
def custom_layer(tensor):
return tensor + 2
然后使用Lambda
类创建Lambda层,传入定义的函数,并连接到dense_layer_3
:
lambda_layer = tensorflow.keras.layers.Lambda(custom_layer, name="lambda_layer")(dense_layer_3)
为查看Lambda层前后张量的变化,可创建两个新模型before_lambda_model
和after_lambda_model
,分别返回Lambda层前和Lambda层的输出。训练主模型后,使用predict()
方法查看两个新模型的输出,可看到Lambda层操作的结果。
若想执行依赖于dense_layer_3
和relu_layer_3
两层的操作,需向Lambda层传递两个张量。通过创建包含这两个张量的列表实现:
lambda_layer = tensorflow.keras.layers.Lambda(custom_layer, name="lambda_layer")([dense_layer_3, activ_layer_3])
在自定义函数中获取并处理这些张量,例如将两层相加:
def custom_layer(tensor):
tensor1 = tensor[0]
tensor2 = tensor[1]
return tensor1 + tensor2
同样可创建相关模型查看各层输出。
保存模型可使用save()
方法:
model.save("model.h5")
加载模型使用load_model()
方法:
loaded_model = tensorflow.keras.models.load_model("model.h5")
但加载包含Lambda层的模型时,可能会遇到SystemError: unknown opcode
错误,可能原因是构建和使用模型的Python版本不同。
解决此问题,不采用上述保存模型的方式,而是使用save_weights()
方法仅保存模型权重。模型架构通过代码重新创建,因为将模型架构保存为JSON文件再加载仍会报错。
保存模型权重:
model.save_weights('model_weights.h5')
重新创建模型架构:
input_layer = tensorflow.keras.layers.Input(shape=(784), name="input_layer")
dense_layer_1 = tensorflow.keras.layers.Dense(units=500, name="dense_layer_1")(input_layer)
activ_layer_1 = tensorflow.keras.layers.ReLU(name="relu_layer_1")(dense_layer_1)
dense_layer_2 = tensorflow.keras.layers.Dense(units=250, name="dense_layer_2")(activ_layer_1)
activ_layer_2 = tensorflow.keras.layers.ReLU(name="relu_layer_2")(dense_layer_2)
dense_layer_3 = tensorflow.keras.layers.Dense(units=20, name="dense_layer_3")(activ_layer_2)
activ_layer_3 = tensorflow.keras.layers.ReLU(name="relu_layer_3")(dense_layer_3)
def custom_layer(tensor):
tensor1 = tensor[0]
tensor2 = tensor[1]
epsilon = tensorflow.keras.backend.random_normal(shape=tensorflow.keras.backend.shape(tensor1), mean=0.0, stddev=1.0)
random_sample = tensor1 + tensorflow.keras.backend.exp(tensor2/2) * epsilon
return random_sample
lambda_layer = tensorflow.keras.layers.Lambda(custom_layer, name="lambda_layer")([dense_layer_3, activ_layer_3])
dense_layer_4 = tensorflow.keras.layers.Dense(units=10, name="dense_layer_4")(lambda_layer)
after_lambda_model = tensorflow.keras.models.Model(input_layer, dense_layer_4, name="after_lambda_model")
output_layer = tensorflow.keras.layers.Softmax(name="output_layer")(dense_layer_4)
model = tensorflow.keras.models.Model(input_layer, output_layer, name="model")
model.compile(optimizer=tensorflow.keras.optimizers.Adam(lr=0.0005), loss="categorical_crossentropy")
最后使用load_weights()
方法加载权重:
model.load_weights('model_weights.h5')
通过本文介绍,我们了解了如何在Keras中使用Lambda层创建自定义操作,以及如何解决加载包含Lambda层模型时可能遇到的问题,希望能帮助读者在深度学习模型构建中更灵活地运用Keras。