Пользовательские функции потерь Tensorflow

#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)   

Теперь я не понимаю, какая реализация правильна, если обе они являются правильными реализациями, то почему мы используем функцию потерь в качестве слоя в модели и какую реализацию эффективно использовать при работе с большими данными