>source

언밸런스 데이터 셋의 이미지 분류에 CNN을 사용합니다. 나는 tensorflow 백엔드에 완전히 새로운 사람입니다. 멀티 클래스 문제가 아니며 (멀티 레이블이 아님) 16 클래스가 있습니다. 클래스는 하나의 핫 인코딩입니다.

각 시대 (F1, Precision 및 Recall)에 대한 MACRO 메트릭을 계산하고 싶습니다.

매크로 측정 항목을 인쇄하는 코드를 찾았지만 유효성 검사 세트에서만 작동합니다. 보낸 사람 : https ://medium.com/@thongonary/how-to-compute-f1-score-for-each-epoch-in-keras-a1acd17715a2

class Metrics(Callback):
 def on_train_begin(self, logs={}):
  self.val_f1s = []
  self.val_recalls = []
  self.val_precisions = []
 def on_epoch_end(self, epoch, logs={}):
  val_predict = (np.asarray(self.model.predict(self.validation_data[0]))).round()
  val_targ = self.validation_data[1]
  _val_f1 = f1_score(val_targ, val_predict,average='macro')
  _val_recall = recall_score(val_targ, val_predict,average='macro')
  _val_precision = precision_score(val_targ, val_predict,average='macro')
  self.val_f1s.append(_val_f1)
  self.val_recalls.append(_val_recall)
  self.val_precisions.append(_val_precision)
  print (" — val_f1: %f — val_precision: %f — val_recall %f" % (_val_f1, _val_precision, _val_recall))
  return
metrics = Metrics()

이 코드가 실제로 사용 중인지 확실하지 않습니다

val_predict = (np.asarray(self.model.predict(self.validation_data[0]))).round()

멀티 클래스 분류의 경우 ROUND로 인해 오류가 발생할 수 있습니까?

그리고이 코드를 사용하여 훈련 세트에 대한 지표 (나에게 중요한 지표이므로 리콜 만) (모델. 컴퓨 트에서 사용되므로 검증 세트에 대해서도 계산) 코드는 케 라스에서 불러 오기위한 사용자 지정 매크로


def recall(y_true,y_pred):
     true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
     possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
     return  true_positives / (possible_positives + K.epsilon())
def unweightedRecall(y_true, y_pred):
    return (recall(y_true[:,0],y_pred[:,0]) + recall(y_true[:,1],y_pred[:,1])+recall(y_true[:,2],y_pred[:,2]) + recall(y_true[:,3],y_pred[:,3])
            +recall(y_true[:,4],y_pred[:,4]) + recall(y_true[:,5],y_pred[:,5])
            +recall(y_true[:,6],y_pred[:,6]) + recall(y_true[:,7],y_pred[:,7])
            +recall(y_true[:,8],y_pred[:,8]) + recall(y_true[:,9],y_pred[:,9])
            +recall(y_true[:,10],y_pred[:,10]) + recall(y_true[:,11],y_pred[:,11])
            +recall(y_true[:,12],y_pred[:,12]) + recall(y_true[:,13],y_pred[:,13])
            +recall(y_true[:,14],y_pred[:,14]) + recall(y_true[:,15],y_pred[:,15]))/16.    



나와 함께 내 모델을 실행

model.compile(optimizer="adam", loss="categorical_crossentropy",metrics=[unweightedRecall,"accuracy"])   #model compilation with unweightedRecall metrics
train =model.fit_generator(image_gen.flow(train_X, train_label, batch_size=64),epochs=100,verbose=1,validation_data=(valid_X, valid_label),class_weight=class_weights,callbacks=[metrics],steps_per_epoch=len(train_X)/64)  #run the model


유효 매크로 리콜은 두 가지 코드와 다릅니다.

즉 (val_unweightedRecallval_recall으로 표시)

Epoch 10/100
19/18 [===============================] - 13s 703ms/step - loss: 1.5167 - unweightedRecall: 0.1269 - acc: 0.5295 - val_loss: 1.5339 - val_unweightedRecall: 0.1272 - val_acc: 0.5519
 — val_f1: 0.168833 — val_precision: 0.197502 — val_recall 0.15636


두 개의 다른 코드로 매크로 검증 리콜에 다른 가치를 갖는 이유는 무엇입니까?

보너스 질문: 이미 시도한 사람들의 경우 관심있는 측정 항목 (예 : 리콜) 또는 가중치가있는 범주 형 교차 엔트로피를 기반으로 맞춤 손실을 사용하는 것이 실제로 동일한 결과를 산출 할 가치가 있습니까?


  • 답변 # 1

    두 질문에 모두 반대 순서로 대답하겠습니다 :

    리콜을 커스텀 손실의 기초로 사용할 수는 없습니다 : 볼록하지 않습니다! 리콜 또는 정밀도 또는 f1을 손실로 사용할 수없는 이유를 완전히 이해하지 못하는 경우 손실의 역할을 확인하는 데 시간을 내십시오 (결국 모델에서 큰 매개 변수 임).

    실제로, 라운드는 이진 문제를위한 것입니다. 그들이 말했듯이, 그것이 당신이 아니라면 그것은 다른 것입니다. 그러나 귀하의 경우에는 잘못되었습니다. 코드를 던져 보자 :

    val_predict = (np.asarray(self.model.predict(self.validation_data[0]))).round()
    
    
    그는 내부에서 데이터를 가져 와서 (self.validation_data [0;]) 숫자 (1 개 뉴런을 출력으로)를 예측합니다. 따라서 그는 1이 될 확률을 계산합니다.이 확률이 0.5를 초과하면 라운드는 1로 변환하고, 아래에 있으면 0으로 변환합니다. 어떤 경우에는 어떤 클래스도 예측하지 못할 것입니다. 이 실수에 따라 나머지도 잘못되었습니다.

    이제 해결책입니다. 모든 단계에서 평균 리콜을 계산하려고합니다. 그건 그렇고, "하지만 유효성 검사 세트에서만 작동합니다". 예, 의도 된 것입니다. 기차가 아닌 모델의 유효성을 검사하기 위해 유효성 검사를 사용합니다. 그렇지 않으면 부정 행위입니다.

    따라서 리콜은 모든 긍정에서 참 긍정과 같습니다. 그렇게하자!

    def recall(y_true, y_pred):
         recall = 0
         pred = K.argmax(y_pred)
         true = K.argmax(y_true)
         for i in range(16):
             p = K.cast(K.equal(pred,i),'int32')
             t = K.cast(K.equal(true,i),'int32')
             # Compute the true positive
             common = K.sum(K.dot(K.reshape(t,(1,-1)),K.reshape(p,(-1,1))))
             # divide by all positives in t
             recall += common/ (K.sum(t) + K.epsilon)
         return recall/16
    
    

    모든 클래스에 대한 평균 리콜을 제공합니다. 모든 수업의 가치를 인쇄 할 수 있습니다.

    질문이 있으면 알려주세요!

    바이너리 리콜의 구현에 대해서는 코드가 적용되는이 질문을 참조하십시오.

  • 이전 Azure BackOp를 사용하는 Azure DevOps의 Terraform
  • 다음 laravel - 두 개체의 값이 동일