我正在尝试为 Keras 定制 LoRA 实现,但在尝试让我的方法发挥作用时遇到了一些麻烦。我在 Google Collab 中使用 Keras 3.4.1。
首先,我尝试了这个 Stack Overflow 帖子中解释的解决方案,当我使用 VGG16 时它对我有用。然而,我正在尝试提出一个适用于功能模型的解决方案,而不仅仅是适用于 VGG16 等顺序模型。
因此,我尝试做类似于这个 Keras 教程中解释的事情,但它对我不起作用。首先,我创建没有最后一层的模型,禁用其训练并打印其摘要:
vgg16_lora = tf.keras.applications.vgg16.VGG16(weights="imagenet", input_shape=(224, 224, 3))
vgg16_lora.trainable = False
lora_model = tf.keras.Model(inputs=vgg16_lora.inputs, outputs=vgg16_lora.layers[-2].output)
lora_model.summary()
然后我尝试添加 LoRA 层,如下所示:
import math
class LoraLayer(tf.keras.Layer):
def __init__(self, original_layer, rank=8, trainable=False, **kwargs):
original_layer_config = original_layer.get_config()
name = original_layer_config["name"]
kwargs.pop('name', None)
super().__init__(name=name, trainable=trainable, **kwargs)
self.original_layer = original_layer
self.original_layer.trainable = False
self.A = tf.keras.layers.Dense(units=rank, use_bias=False, kernel_initializer=tf.keras.initializers.VarianceScaling(scale=math.sqrt(5), mode="fan_in", distribution="uniform"), trainable=trainable, name="lora_A")
self.B = tf.keras.layers.Dense(units=original_layer.output.shape[-1], kernel_initializer="zeros", trainable=trainable, name="lora_B")
def call(self, inputs):
original_outputs = self.original_layer(inputs)
lora_outputs = self.B(self.A(inputs))
return original_outputs + lora_outputs
lora_model._tracker.unlock()
lora_model.layers[-2] = LoraLayer(lora_model.layers[-2], rank=8, trainable=False)
lora_model._tracker.lock()
lora_model.summary()
我使用这段代码的目的是用 LoRA 本身替换倒数第二层。然而,根据模型的摘要,这种情况并没有发生:
最后一层仍然是密集层,可训练参数的数量完全没有变化。
我的实施过程中是否做错了什么?也许它与这个问题中解释的内容有关,并且在 Keras 中基本上不可能做到这一点,或者我是否缺少一些中间步骤来使其工作?
最后,我也尝试过这个解决方案,但代码对我不起作用(它失败说 Node 对象没有属性
outbound_layer
)
如有任何帮助,我们将不胜感激🙏
我不确定这是否可行,但一个简单的解决方案可能是简单地循环原始模型的各层:
new_model = keras.Sequantial()
for i, layer in enumerate(lora_model.layers):
if i == len(lora_model.layers) - 2:
new_model.add(LoraLayer(...))
else:
new_model.add(layer)