#python #tensorflow #deep-learning #loss-function #image-recognition
Вопрос:
Я выполнял задание по распознаванию и обнаружил, что глубокое обучение на основе метрик может сыграть решающую роль в процессе обучения. Я видел функции потерь, такие как arcface, cosface и многие другие функции потерь. В их реализации TensorFlow эти функции потерь были реализованы как последний слой в модели, и во время компиляции этой модели используется какая-то другая функция потерь, например, в данном случае Разреженная категориальная кроссэнтропийная потеря.
class ArcMarginProduct(tf.keras.layers.Layer): def __init__(self, n_classes, s=30, m=0.50, easy_margin=False, ls_eps=0.0, **kwargs): super(ArcMarginProduct, self).__init__(**kwargs) self.n_classes = n_classes self.s = s self.m = m self.ls_eps = ls_eps self.easy_margin = easy_margin self.cos_m = tf.math.cos(m) self.sin_m = tf.math.sin(m) self.th = tf.math.cos(math.pi - m) self.mm = tf.math.sin(math.pi - m) * m def get_config(self): config = super().get_config().copy() config.update({ 'n_classes': self.n_classes, 's': self.s, 'm': self.m, 'ls_eps': self.ls_eps, 'easy_margin': self.easy_margin, }) return config def build(self, input_shape): super(ArcMarginProduct, self).build(input_shape[0]) self.W = self.add_weight( name='W', shape=(int(input_shape[0][-1]), self.n_classes), initializer='glorot_uniform', dtype='float32', trainable=True, regularizer=None) def call(self, inputs): X, y = inputs y = tf.cast(y, dtype=tf.int32) cosine = tf.matmul( tf.math.l2_normalize(X, axis=1), tf.math.l2_normalize(self.W, axis=0) ) sine = tf.math.sqrt(1.0 - tf.math.pow(cosine, 2)) phi = cosine * self.cos_m - sine * self.sin_m if self.easy_margin: phi = tf.where(cosine gt; 0, phi, cosine) else: phi = tf.where(cosine gt; self.th, phi, cosine - self.mm) one_hot = tf.cast( tf.one_hot(y, depth=self.n_classes), dtype=cosine.dtype ) if self.ls_eps gt; 0: one_hot = (1 - self.ls_eps) * one_hot self.ls_eps / self.n_classes output = (one_hot * phi) ((1.0 - one_hot) * cosine) output *= self.s return output E FNS = [efn.EfficientNetB0, efn.EfficientNetB1, efn.EfficientNetB2, efn.EfficientNetB3, efn.EfficientNetB4, efn.EfficientNetB5, efn.EfficientNetB6, efn.EfficientNetB7] def freeze_BN(model): # Unfreeze layers while leaving BatchNorm layers frozen for layer in model.layers: if not isinstance(layer, tf.keras.layers.BatchNormalization): layer.trainable = True else: layer.trainable = False # Function to create our EfficientNetB3 model def get_model(): with strategy.scope(): margin = ArcMarginProduct( n_classes = N_CLASSES, s = 30, m = 0.5, name='head/arc_margin', dtype='float32' ) inp = tf.keras.layers.Input(shape = (*IMAGE_SIZE, 3), name = 'inp1') label = tf.keras.layers.Input(shape = (), name = 'inp2') x = EFNS[EFF_NET](weights = 'imagenet', include_top = False)(inp) x = tf.keras.layers.GlobalAveragePooling2D()(x) x = margin([x, label]) output = tf.keras.layers.Softmax(dtype='float32')(x) model = tf.keras.models.Model(inputs = [inp, label], outputs = [output]) opt = tf.keras.optimizers.Adam(learning_rate = LR) if FREEZE_BATCH_NORM: freeze_BN(model) model.compile( optimizer = opt, loss = [tf.keras.losses.SparseCategoricalCrossentropy()], metrics = [tf.keras.metrics.SparseCategoricalAccuracy()] ) return model get_model().summary()
Помимо уровня, подобного реализации функций потерь, я нашел другую реализацию, основанную на пользовательских функциях потерь TensorFlow
class ArcFaceLoss(tf.keras.losses.Loss) : # m:margin # s:magnification # loss_func:Original loss function tf.keras.losses.CategoricalCrossentropy(from_logits = True)Such def __init__(self, loss_func, m = 0.5, s = 30, name = "arcface_loss", **kwargs) : self.loss_func = loss_func self.margin = m self.s = s self.enable = True super(ArcFaceLoss, self).__init__(name = name, **kwargs) def call(self, y_true, y_pred): # y_pred is cos(θ) #Sin for the addition theorem(θ)To calculate sine = tf.keras.backend.sqrt(1.0 - tf.keras.backend.square(y_pred)) phi = y_pred * self.cos_m - sine * self.sin_m # cos(θ m)Addition theorem phi = tf.where(y_pred gt; 0, phi, y_pred) #As it is when facing the day after tomorrow #Correct answer class:cos(θ m)Other classes:cosθ logits = (y_true * phi) ((1.0 - y_true) * y_pred) #Call the original loss function return self.loss_func(y_true, logits * self.s) #Evaluation function for ArcFace class ArcFaceAccuracy(tf.keras.metrics.Mean) : def __init__(self, metrics_func, s = 30, name = "arcface_accuracy", dtype = None) : self.metrics_func = metrics_func self.s = s super(ArcFaceAccuracy, self).__init__(name, dtype) def update_state(self, y_true, y_pred, sample_weight = None) : output = tf.nn.softmax(y_pred * self.s) matches = self.metrics_func(y_true, output) return super(ArcFaceAccuracy, self).update_state(matches, sample_weight = sample_weight)
Теперь я не понимаю, какая реализация правильна, если обе они являются правильными реализациями, то почему мы используем функцию потерь в качестве слоя в модели и какую реализацию эффективно использовать при работе с большими данными