SSD損失分為兩部分,類別損失和回歸框位置損失
其中,類別損失采用softmax損失,回顧框損失采用l1——smooth損失。
1. softmax損失:
def _softmax_loss(self, y_true, y_pred): y_pred = tf.maximum(y_pred, 1e-7) softmax_loss = -tf.reduce_sum(y_true * tf.math.log(y_pred), axis=-1) return softmax_loss
SSD類別部分的網絡輸出維度為(batch_size, 8732, num_classes),並經過softmax激活函數,轉化為概率。
softmax_loss = -tf.reduce_sum(y_true * tf.math.log(y_pred), axis=-1)
概率取-log,與對應真實值位置乘積求和, 維度為(batch_size, 8732)
2. l1_soomth 損失
def _l1_smooth_loss(self, y_true, y_pred): abs_loss = tf.abs(y_true - y_pred) sq_loss = 0.5 * (y_true - y_pred)**2 l1_loss = tf.where(tf.less(abs_loss, 1.0), sq_loss, abs_loss - 0.5) return tf.reduce_sum(l1_loss, -1)
SSD回歸框偏差部份輸出維度為(batch_size, 8732, 4),分別求l1_loss 和 l2_loss,將二者結合,
l1_loss = tf.where(tf.less(abs_loss, 1.0), sq_loss, abs_loss - 0.5)
return tf.reduce_sum(l1_loss, -1)
維度為(batch_size, 8732)。
3. 計算類別和回歸框總損失
3.1 正樣本:
正樣本的損失分為類別損失和回歸損失兩種:
類別損失:(batch_size, )
pos_conf_loss = tf.reduce_sum(conf_loss * y_true[:, :, -8], axis=1)
回歸損失:(batch_size, )
pos_loc_loss = tf.reduce_sum(loc_loss * y_true[:, :, -8],axis=1)
3.2 負樣本
負樣本的損失只有類別損失:
首先如何確定負樣本,如果選取所有的負樣本,則會引起類別不平衡的問題,所以選取部分負樣本(正樣本數量的3倍)
num_neg = tf.minimum(3 * num_pos, 8732 - num_pos)
# 求平均每個圖片要取多少個負樣本
num_neg_batch = tf.reduce_mean(tf.boolean_mask(num_neg,
tf.greater(num_neg, 0)))
num_neg_batch = tf.cast(num_neg_batch,tf.int32)
如果是選取部分負樣本,選取哪些呢?選取不該有預測結果的框,求他們的最大置信度
max_confs = tf.reduce_max(y_pred[:, :, confs_start:confs_end], axis=2) # 5:25 (不包括背景的20個類別)
# 取top_k個置信度,作為負樣本
_, indices = tf.nn.top_k(max_confs * (1 - y_true[:, :, -8]),
k=num_neg_batch)
抽取相應位置的conf_loss
neg_conf_loss = tf.gather(tf.reshape(conf_loss, [-1]),
full_indices)
neg_conf_loss = tf.reshape(neg_conf_loss,
[batch_size, num_neg_batch])
neg_conf_loss = tf.reduce_sum(neg_conf_loss, axis=1)
3.3 總損失
total_loss = tf.reduce_sum(pos_conf_loss) + tf.reduce_sum(neg_conf_loss)
total_loss /= tf.reduce_sum(num_pos)
total_loss += tf.reduce_sum(self.alpha * pos_loc_loss) / tf.reduce_sum(num_pos)