Kayıp işlevinde GradientTape hesaplama belirginliği
Cümleleri sınıflandırmak ve belirginlik kullanarak sınıflandırma için açıklama sağlamak için bir LSTM ağı oluşturmaya çalışıyorum . Bu ağ, gerçek sınıftan y_true
ve hangi kelimelere dikkat etmemesi gerektiğini Z
(ikili maske) öğrenmelidir .
Bu makale , kayıp fonksiyonumuzu bulmamız için bize ilham verdi. İşte kayıp fonksiyonumun nasıl görünmesini istediğim:

Coût de classification
çevirir classification_loss
ve Coût d'explication (saillance)
üzere saliency_loss
aşağıdaki kod (giriş wrt çıkış gradyanı ile aynıdır) . Bunu, arka uç olarak Tensorflow ile Keras'ta özel bir Model ile uygulamaya çalıştım:
loss_tracker = metrics.Mean(name="loss")
classification_loss_tracker = metrics.Mean(name="classification_loss")
saliency_loss_tracker = metrics.Mean(name="saliency_loss")
accuracy_tracker = metrics.CategoricalAccuracy(name="accuracy")
class CustomSequentialModel(Sequential):
def _train_test_step(self, data, training):
# Unpack the data
X = data[0]["X"]
Z = data[0]["Z"] # binary mask (1 for important words)
y_true = data[1]
# gradient tape requires "float32" instead of "int32"
# X.shape = (None, MAX_SEQUENCE_LENGTH, EMBEDDING_DIM)
X = tf.cast(X, tf.float32)
# Persitent=True because we call the `gradient` more than once
with GradientTape(persistent=True) as tape:
# The tape will record everything that happens to X
# for automatic differentiation later on (used to compute saliency)
tape.watch(X)
# Forward pass
y_pred = self(X, training=training)
# (1) Compute the classification_loss
classification_loss = K.mean(
categorical_crossentropy(y_true, y_pred)
)
# (2) Compute the saliency loss
# (2.1) Compute the gradient of output wrt the maximum probability
log_prediction_proba = K.log(K.max(y_pred))
# (2.2) Compute the gradient of the output wrt the input
# saliency.shape is (None, MAX_SEQUENCE_LENGTH, None)
# why isn't it (None, MAX_SEQUENCE_LENGTH, EMBEDDING_DIM) ?!
saliency = tape.gradient(log_prediction_proba, X)
# (2.3) Sum along the embedding dimension
saliency = K.sum(saliency, axis=2)
# (2.4) Sum with the binary mask
saliency_loss = K.sum(K.square(saliency)*(1-Z))
# => ValueError: No gradients provided for any variable
loss = classification_loss + saliency_loss
trainable_vars = self.trainable_variables
# ValueError caused by the '+ saliency_loss'
gradients = tape.gradient(loss, trainable_vars)
del tape # garbage collection
if training:
# Update weights
self.optimizer.apply_gradients(zip(gradients, trainable_vars))
# Update metrics
saliency_loss_tracker.update_state(saliency_loss)
classification_loss_tracker.update_state(classification_loss)
loss_tracker.update_state(loss)
accuracy_tracker.update_state(y_true, y_pred)
# Return a dict mapping metric names to current value
return {m.name: m.result() for m in self.metrics}
def train_step(self, data):
return self._train_test_step(data, True)
def test_step(self, data):
return self._train_test_step(data, False)
@property
def metrics(self):
return [
loss_tracker,
classification_loss_tracker,
saliency_loss_tracker,
accuracy_tracker
]
Ben hesaplamak için yönetmek classification_loss
yanı sıra saliency_loss
ve bir skaler değer elde. Ancak bu işe yarar: tape.gradient(classification_loss, trainable_vars)
ama bu işe yaramaztape.gradient(classification_loss + saliency_loss, trainable_vars)
ve atmazValueError: No gradients provided for any variable
.
Yanıtlar
Teyp bağlamının dışında (ilk gradient
aramadan sonra ) hesaplamalar yapıyorsunuz ve ardından daha fazla gradyan almaya çalışıyorsunuz. Bu çalışmıyor; farklılaştırmak için tüm işlemlerin bağlam yöneticisi içinde gerçekleştirilmesi gerekir. Kodunuzu iki iç içe bant kullanarak aşağıdaki şekilde yeniden yapılandırmanızı öneririm:
with GradientTape() as loss_tape:
with GradientTape() as saliency_tape:
# The tape will record everything that happens to X
# for automatic differentiation later on (used to compute saliency)
saliency_tape.watch(X)
# Forward pass
y_pred = self(X, training=training)
# (2) Compute the saliency loss
# (2.1) Compute the gradient of output wrt the maximum probability
log_prediction_proba = K.log(K.max(y_pred))
# (2.2) Compute the gradient of the output wrt the input
# saliency.shape is (None, MAX_SEQUENCE_LENGTH, None)
# why isn't it (None, MAX_SEQUENCE_LENGTH, EMBEDDING_DIM) ?!
saliency = saliency_tape.gradient(log_prediction_proba, X)
# (2.3) Sum along the embedding dimension
saliency = K.sum(saliency, axis=2)
# (2.4) Sum with the binary mask
saliency_loss = K.sum(K.square(saliency)*(1-Z))
# (1) Compute the classification_loss
classification_loss = K.mean(
categorical_crossentropy(y_true, y_pred)
)
loss = classification_loss + saliency_loss
trainable_vars = self.trainable_variables
gradients = loss_tape.gradient(loss, trainable_vars)
Şimdi, göze çarpan girdiyi oluşturan gradyanları hesaplamaktan sorumlu bir kasetimiz var. Biz başka bu işlemleri izler ve daha sonra degrade eğimi hesaplayabilir etrafında bandı (yani gradyan belirginlik arasında). Bu bant aynı zamanda sınıflandırma kaybı için gradyanları hesaplar. Sınıflandırma kaybını dış bant bağlamında taşıdım çünkü iç bant buna ihtiyaç duymuyor. Ayrıca, iki kaybın toplamının bile dış bandın bağlamı içinde olduğuna dikkat edin - her şeyin orada olması gerekir, aksi takdirde hesaplama grafiği kaybolur / eksiktir ve gradyanlar hesaplanamaz.
Süslemek için deneyin train_step()
ile@tf.function