Ich arbeite an einem semantischen Segmentierungsproblem, bei dem ich eine Eingabe x (CT-Bild) für ein Deep-Learning-Modell der Form (batch_size,1,256,256) und eine Ausgabe der Form (batch_size,2,256,256) wobei der erste Kanal eine Ausgabemaske (Knochenmaske) und der zweite Kanal eine zweite Ausgabemaske (Läsionsmaske) darstellt. Ich verwende eine kombinierte Verlustfunktion für jede Kanalausgabe, die eine Kombination aus gewichtetem BCE und Soft-Dice-Verlust ist, die sich beide auf die Vordergrundpixel konzentrieren:
class Custom_Loss(tf.keras.losses.Loss):
def __init__(self,w1 = 0.3, w2 = 0.7 , w3 = 0.4, w4 = 0.6, w5 = 1.6 , reduction="sum_over_batch_size" ):
"""
w1 : weight for the bone loss contribution to the total loss.
w2 : Weight for the lession loss contribution to the total loss.
w3 : Weight for the soft dice loss contribution to the combined loss.
w4 : Weight for the BCE contribution to the combined loss.
w5: Weight for the foreground pixels in the BCE loss
"""
self.w1 = w1
self.w2 = w2
self.w3 = w3
self.w4 = w4
self.w5 = w5
self.reduction = reduction
super().__init__(reduction = reduction)
def bce(self,y_true, y_pred):
epsilon = 1e-8 # Add small epsilon to avoid log(0)
# Compute the total number of pixels
N = y_true.shape[1] * y_true.shape[2]
# Compute the BCE loss per image
bce_loss = (-1 / N) * tf.reduce_sum((self.w5 *y_true * tf.math.log(y_pred + epsilon)) + ((1 - y_true) * tf.math.log(1 - y_pred + epsilon)),axis = (1,2))
# Average the loss over the batch
#bce_loss = tf.reduce_mean(bce_loss)
return bce_loss
def soft_dice_loss(self,y_true, y_pred):
epsilon = 1e-8 # Add small epsilon to avoid division by zero
# Calculate the numerator and denominator
numerator_dice_coef= 2 * tf.reduce_sum(y_true * y_pred, axis=(1, 2)) + epsilon
den_dice_coef = (tf.reduce_sum(y_true * y_true, axis=(1, 2))) + (tf.reduce_sum(y_pred * y_pred, axis=(1, 2))) + epsilon
# Dice coefficient per image in the batch
dice_coef = numerator_dice_coef / den_dice_coef
# Average Dice coefficient over the batch
#mean_dice_coef = tf.reduce_mean(dice_coef)
return 1 - dice_coef
def combined_loss(self, y_true, y_pred):
loss = (self.w3 * self.soft_dice_loss(y_true, y_pred) ) + (self.w4 * self.bce(y_true, y_pred))
return loss
def call(self, y_true, y_pred):
bone_pred = y_pred [:,0,:,:]
lesion_pred = y_pred [:,1,:,:]
bone_ground_truth = y_true [:,0,:,:]
lesion_ground_truth = y_true [:,1,:,:]
#loss = (self.w1 * self.combined_loss(bone_ground_truth, bone_pred ) ) + (self.w2 * self.combined_loss(lession_ground_truth, lession_pred) )
# Compute combined loss for bone and lesion masks
bone_loss = self.combined_loss(bone_ground_truth, bone_pred) # Shape: (batch_size,)
lesion_loss = self.combined_loss(lesion_ground_truth, lesion_pred) # Shape: (batch_size,)
# Total loss per sample
# Use tf.multiply for weighted sum
weighted_bone_loss = tf.multiply(self.w1, bone_loss) # Shape: (batch_size,)
weighted_lesion_loss = tf.multiply(self.w2, lesion_loss) # Shape: (batch_size,)
# Add weighted losses
total_loss = weighted_bone_loss + weighted_lesion_loss # Shape: (batch_size,)
# Store loss components for logging
#self.last_bone_loss = tf.reduce_mean(bone_loss)
#self.last_lesion_loss = tf.reduce_mean(lesion_loss)
return total_loss
Ich folge der Keras-Dokumentation, in der die Aufruffunktion den Verlust pro Probe zurückgibt. Jetzt habe ich einen benutzerdefinierten Rückruf geschrieben, um die Validierungsverlustkomponenten (für jede Maske, jeden Knochen und jede Läsion) sowie den Gesamtverlust wie folgt zu protokollieren:
# Callback for logging loss components at the end of each epoch for the validation data
class LossLoggerCallback(tf.keras.callbacks.Callback):
def __init__(self, loss_fn, validation_data):
"""
Callback to log loss components for validation data at the end of each epoch.
Args:
loss_fn: Custom loss function (instance of `CustomLoss`).
validation_data: Validation dataset (can be a tf.data.Dataset).
"""
super().__init__()
self.loss_fn = loss_fn
self.validation_data = validation_data
def on_epoch_end(self, epoch, logs=None):
# Initialize lists to accumulate losses
total_losses = []
bone_losses = []
lesion_losses = []
# Initialize a counter to keep track of the total number of samples
total_samples = 0
# Iterate over all batches in the validation data
for x_val, y_val in self.validation_data:
batch_size = x_val.shape[0] # Get the batch size
# Make predictions
y_pred = self.model.predict(x_val, verbose=0)
# Extract bone and lesion predictions and ground truths
bone_pred = y_pred[:, 0, :, :]
lesion_pred = y_pred[:, 1, :, :]
bone_gt = y_val[:, 0, :, :]
lesion_gt = y_val[:, 1, :, :]
# Compute combined loss for bone and lesion (this gives a batch-wise loss)
bone_loss = self.loss_fn.combined_loss(bone_gt, bone_pred) # Shape: (batch_size,)
lesion_loss = self.loss_fn.combined_loss(lesion_gt, lesion_pred) # Shape: (batch_size,)
# Apply weighting as in `call`
weighted_bone_loss = tf.multiply(self.loss_fn.w1, bone_loss) # Shape: (batch_size,)
weighted_lesion_loss = tf.multiply(self.loss_fn.w2, lesion_loss) # Shape: (batch_size,)
# Total loss per sample in the batch
total_loss = weighted_bone_loss + weighted_lesion_loss # Shape: (batch_size,)
# Accumulate batch-wise losses for averaging later
total_losses.extend(total_loss.numpy()) # Add individual losses per sample
bone_losses.extend(bone_loss.numpy()) # Add individual bone losses
lesion_losses.extend(lesion_loss.numpy()) # Add individual lesion losses
# Update total number of samples processed
total_samples += batch_size
# Compute the mean loss across the entire validation dataset
mean_bone_loss = np.sum(bone_losses) / total_samples
mean_lesion_loss = np.sum(lesion_losses) / total_samples
mean_total_loss = np.sum(total_losses) / total_samples
# Print the results for the current epoch
print(f"Epoch {epoch + 1}: Validation Bone Loss = {mean_bone_loss:.4f}, "
f"Validation Lesion Loss = {mean_lesion_loss:.4f}, "
f"Validation Total Loss = {mean_total_loss:.4f}")
Die verwendete Batch-Größe beträgt 4, daher ist die Form eines Batches in der Validierung (4,2, 256,256) für y und für x (4,1,256,256). ) . Wie Sie in der benutzerdefinierten Verlustklasse sehen, verwende ich die Reduzierung sum_over_batch_size. Wenn ich das Modell in einer Multi-GPU-Umgebung trainiere:
Epoch 1/100
237/237 ━━━━━━━━━━━━━━━━━━━━ 0s 1s/step - io_u: 0.1837 - loss: 272.1821
Epoch 1: val_io_u improved from -inf to 0.00000, saving model to /kaggle/working/best_model.keras
Epoch 1: Validation Bone Loss = 0.6672, Validation Lesion Loss = 0.6553, Validation Total Loss = 0.6589
237/237 ━━━━━━━━━━━━━━━━━━━━ 443s 1s/step - io_u: 0.1842 - loss: 271.8742 - val_io_u: 0.0000e+00 - val_loss: 83.1071
Epoch 2/100
237/237 ━━━━━━━━━━━━━━━━━━━━ 0s 1s/step - io_u: 0.3941 - loss: 56.6352
Epoch 2: val_io_u did not improve from 0.00000
Epoch 2: Validation Bone Loss = 0.5375, Validation Lesion Loss = 0.5063, Validation Total Loss = 0.5157
237/237 ━━━━━━━━━━━━━━━━━━━━ 339s 1s/step - io_u: 0.3941 - loss: 56.5627 - val_io_u: 0.0000e+00 - val_loss: 19.8229
Warum der vom Rückruf zurückgegebene Validierungs-Gesamtverlust nicht dem von Keras zurückgegebenen val_loss entspricht. Ich glaube, ich habe ein Missverständnis darüber, wie Keras den Verlust mithilfe der Reduzierung sum_over_batch_size berechnet. Ich möchte, dass der vom Rückruf zurückgegebene Verlust mit dem von Keras berechneten identisch ist.
Ich arbeite an einem semantischen Segmentierungsproblem, bei dem ich eine Eingabe x (CT-Bild) für ein Deep-Learning-Modell der Form (batch_size,1,256,256) und eine Ausgabe der Form (batch_size,2,256,256) wobei der erste Kanal eine Ausgabemaske (Knochenmaske) und der zweite Kanal eine zweite Ausgabemaske (Läsionsmaske) darstellt. Ich verwende eine kombinierte Verlustfunktion für jede Kanalausgabe, die eine Kombination aus gewichtetem BCE und Soft-Dice-Verlust ist, die sich beide auf die Vordergrundpixel konzentrieren: [code]class Custom_Loss(tf.keras.losses.Loss): def __init__(self,w1 = 0.3, w2 = 0.7 , w3 = 0.4, w4 = 0.6, w5 = 1.6 , reduction="sum_over_batch_size" ): """ w1 : weight for the bone loss contribution to the total loss.
w2 : Weight for the lession loss contribution to the total loss.
w3 : Weight for the soft dice loss contribution to the combined loss.
w4 : Weight for the BCE contribution to the combined loss.
w5: Weight for the foreground pixels in the BCE loss
# Total loss per sample # Use tf.multiply for weighted sum weighted_bone_loss = tf.multiply(self.w1, bone_loss) # Shape: (batch_size,) weighted_lesion_loss = tf.multiply(self.w2, lesion_loss) # Shape: (batch_size,) # Add weighted losses total_loss = weighted_bone_loss + weighted_lesion_loss # Shape: (batch_size,)
# Store loss components for logging #self.last_bone_loss = tf.reduce_mean(bone_loss) #self.last_lesion_loss = tf.reduce_mean(lesion_loss)
return total_loss [/code] Ich folge der Keras-Dokumentation, in der die Aufruffunktion den Verlust pro Probe zurückgibt. Jetzt habe ich einen benutzerdefinierten Rückruf geschrieben, um die Validierungsverlustkomponenten (für jede Maske, jeden Knochen und jede Läsion) sowie den Gesamtverlust wie folgt zu protokollieren: [code]# Callback for logging loss components at the end of each epoch for the validation data class LossLoggerCallback(tf.keras.callbacks.Callback): def __init__(self, loss_fn, validation_data): """ Callback to log loss components for validation data at the end of each epoch.
Args: loss_fn: Custom loss function (instance of `CustomLoss`). validation_data: Validation dataset (can be a tf.data.Dataset). """ super().__init__() self.loss_fn = loss_fn self.validation_data = validation_data
# Compute combined loss for bone and lesion (this gives a batch-wise loss) bone_loss = self.loss_fn.combined_loss(bone_gt, bone_pred) # Shape: (batch_size,) lesion_loss = self.loss_fn.combined_loss(lesion_gt, lesion_pred) # Shape: (batch_size,)
# Apply weighting as in `call` weighted_bone_loss = tf.multiply(self.loss_fn.w1, bone_loss) # Shape: (batch_size,) weighted_lesion_loss = tf.multiply(self.loss_fn.w2, lesion_loss) # Shape: (batch_size,)
# Total loss per sample in the batch total_loss = weighted_bone_loss + weighted_lesion_loss # Shape: (batch_size,)
# Accumulate batch-wise losses for averaging later total_losses.extend(total_loss.numpy()) # Add individual losses per sample bone_losses.extend(bone_loss.numpy()) # Add individual bone losses lesion_losses.extend(lesion_loss.numpy()) # Add individual lesion losses
# Update total number of samples processed total_samples += batch_size
# Compute the mean loss across the entire validation dataset mean_bone_loss = np.sum(bone_losses) / total_samples mean_lesion_loss = np.sum(lesion_losses) / total_samples mean_total_loss = np.sum(total_losses) / total_samples
# Print the results for the current epoch print(f"Epoch {epoch + 1}: Validation Bone Loss = {mean_bone_loss:.4f}, " f"Validation Lesion Loss = {mean_lesion_loss:.4f}, " f"Validation Total Loss = {mean_total_loss:.4f}")
[/code] Die verwendete Batch-Größe beträgt 4, daher ist die Form eines Batches in der Validierung (4,2, 256,256) für y und für x (4,1,256,256). ) . Wie Sie in der benutzerdefinierten Verlustklasse sehen, verwende ich die Reduzierung sum_over_batch_size. Wenn ich das Modell in einer Multi-GPU-Umgebung trainiere: [code] with strategy.scope(): loss_fn = Custom_Loss() # Initialize the model model= create_model() model.compile(optimizer=Adam(learning_rate=1e-4,beta_1 = 0.999, beta_2 = 0.999), loss= loss_fn, metrics=[IoU] ) val_loss_logger = LossLoggerCallback(loss_fn, validation_data=val_dataset) es = EarlyStopping(monitor='val_io_u', mode='max', verbose=1, patience=40) mc = ModelCheckpoint('/kaggle/working/best_model.keras', monitor='val_io_u', mode='max', verbose=1, save_best_only=True) # Train the model
history = model.fit(x = train_dataset, batch_size= batch_size, validation_data = val_dataset, epochs= epochs, steps_per_epoch= steps_per_epoch, callbacks=[es,mc,val_loss_logger]) [/code] Ich bekomme: [code]Epoch 1/100 237/237 ━━━━━━━━━━━━━━━━━━━━ 0s 1s/step - io_u: 0.1837 - loss: 272.1821 Epoch 1: val_io_u improved from -inf to 0.00000, saving model to /kaggle/working/best_model.keras Epoch 1: Validation Bone Loss = 0.6672, Validation Lesion Loss = 0.6553, Validation Total Loss = 0.6589 237/237 ━━━━━━━━━━━━━━━━━━━━ 443s 1s/step - io_u: 0.1842 - loss: 271.8742 - val_io_u: 0.0000e+00 - val_loss: 83.1071 Epoch 2/100 237/237 ━━━━━━━━━━━━━━━━━━━━ 0s 1s/step - io_u: 0.3941 - loss: 56.6352 Epoch 2: val_io_u did not improve from 0.00000 Epoch 2: Validation Bone Loss = 0.5375, Validation Lesion Loss = 0.5063, Validation Total Loss = 0.5157 237/237 ━━━━━━━━━━━━━━━━━━━━ 339s 1s/step - io_u: 0.3941 - loss: 56.5627 - val_io_u: 0.0000e+00 - val_loss: 19.8229
[/code] Warum der vom Rückruf zurückgegebene Validierungs-Gesamtverlust nicht dem von Keras zurückgegebenen val_loss entspricht. Ich glaube, ich habe ein Missverständnis darüber, wie Keras den Verlust mithilfe der Reduzierung sum_over_batch_size berechnet. Ich möchte, dass der vom Rückruf zurückgegebene Verlust mit dem von Keras berechneten identisch ist.
Ich benutze Keras und Tensorflow, um eine einfache Multilayer-Perzeptron (MLP) für eine Regressionsaufgabe zu trainieren, bei der ich den Mittelwert-Quadrat-Fehler (MSE) als Verlustfunktion verwende....
Das JDK 21-Dokument über virtuelle Threads (im Folgenden „VT“)
(
ist ziemlich klar über einen synchronisierten Block, der dazu führt, dass ein Thread angeheftet wird, oder über native Methoden, oder...
Ich habe Probleme bei der Verwendung von Tensorflow 2 in VS Code. Der Code wird problemlos ausgeführt, die Fehler hängen nur mit Pylint im VS-Code zusammen.
Zum Beispiel gibt dieser Import aus...
Ich verwende TensorFlow 1.15.0 im Docker-Container und habe Probleme beim Importieren von Keras-Submodulen.
from tensorflow import keras
import tensorflow.keras.backend as K
from...