我也打了这个,添加到 tensorflow github 问题中,在 tf 2.7 和 tf-nightly 中尝试过,仍然看到错误,所以提出了新的 keras 问题:https://github.com/keras-team/keras/issues/15818。
解决方法不会解决所有用例 - 它限制了嵌入活动,而不是整个嵌入矩阵。我确实有一个使用 keras 回调的解决方法 - 但我发现它减慢了训练速度 - 我相信回调适用于无法在 GPU 上运行的 numpy 数组 - 但如果有用,这里是方法
import numpy as np
import tensorflow as tf
class ConstrainEmbeddings(tf.keras.callbacks.Callback):
def __init__(self, min_norm, emb, eps=1e-9):
super(ConstrainEmbeddings, self).__init__()
self.min_norm = min_norm
self.emb = emb
self.eps = eps
def on_batch_begin(self, *args, **kwargs):
W = self.emb.get_weights()[0]
norms = tf.maximum(self.eps, tf.norm(W, axis=1))
delta = tf.expand_dims(tf.math.divide(self.min_norm, norms) - 1.0, 1)
deltaW = tf.math.multiply(W, delta)
constrainedW = W + tf.expand_dims(tf.cast(norms < self.min_norm, dtype=tf.float32), 1) * deltaW
self.emb.set_weights([constrainedW])
def constrain_embeddings(use_keras):
N = 10
batch_size = 5
data = {
'X': np.random.randint(0, 10, N),
'Y': np.random.randint(0, 2, N)
}
def get_labels(features):
labels = features.pop('Y')
return features, labels
dset = tf.data.Dataset.from_tensor_slices(data).map(get_labels).batch(batch_size)
inp = tf.keras.Input(shape=(1,), name='X', dtype='int64')
constraint = tf.keras.constraints.MaxNorm(max_value=0.1) if use_keras else None
emb = tf.keras.layers.Embedding(
10, 3, input_length=1,
embeddings_initializer=tf.keras.initializers.RandomUniform(minval=-1.0, maxval=1.0),
embeddings_constraint=constraint
)
emb_out = emb(inp)
out = tf.keras.layers.Dense(1)(emb_out)
model = tf.keras.Model(inputs=inp, outputs=out)
model.compile(optimizer='adam', loss=tf.keras.losses.binary_crossentropy)
callbacks = [ConstrainEmbeddings(.3, emb)] if not use_keras else []
model.fit(dset, epochs=10, callbacks=callbacks)
if __name__ == '__main__':
print("tensorflow git version: ", tf.version.GIT_VERSION)
constrain_embeddings(use_keras=False)