Обратный вызов Tensorflow как пользовательский метри c для CTC - PullRequest
1 голос
/ 18 февраля 2020

В попытке получить больше метрик во время обучения моей модели (написано в TensorFlow версии 2.1.0), таких как частота ошибок в символах (CER) и частота ошибок в словах (WER), я создал обратный вызов для передачи на подбор функция моей модели. Он способен генерировать CER и WER в конце эпохи. Это мой второй выбор, так как я хотел создать для этого Custom Metri c, но вы можете использовать функциональность Keras Backend только для пользовательских метрик. Кто-нибудь есть какие-либо советы о том, как преобразовать обратный вызов ниже в Custom Metri c (который затем может быть рассчитан во время обучения на основе проверки и / или данных обучения)?

Некоторые препятствия, с которыми я столкнулся:

  • Не удалось преобразовать результат K.ctc_decode в разреженный тензор
  • Как рассчитать расстояние, например расстояние редактирования, с помощью бэкэнда Keras?
class Metrics(tf.keras.callbacks.Callback):
    def __init__(self, valid_data, steps):
        """
        valid_data is a TFRecordDataset with batches of 100 elements per batch, shuffled and repeated infinitely. 
        steps defines the amount of batches per epoch
        """
        super(Metrics, self).__init__()
        self.valid_data = valid_data
        self.steps = steps

    def on_train_begin(self, logs={}):
        self.cer = []
        self.wer = []

    def on_epoch_end(self, epoch, logs={}):

        imgs = []
        labels = []
        for idx, (img, label) in enumerate(self.valid_data.as_numpy_iterator()):
            if idx >= self.steps:
                break
            imgs.append(img)
            labels.extend(label)

        imgs = np.array(imgs)
        labels = np.array(labels)

        out = self.model.predict((batch for batch in imgs))        
        input_length = len(max(out, key=len))

        out = np.asarray(out)
        out_len = np.asarray([input_length for _ in range(len(out))])

        decode, log = K.ctc_decode(out,
                                    out_len,
                                    greedy=True)

        decode = [[[int(p) for p in x if p != -1] for x in y] for y in decode][0]

        for (pred, lab) in zip(decode, labels):

            dist = editdistance.eval(pred, lab)
            self.cer.append(dist / (max(len(pred), len(lab))))
            self.wer.append(not np.array_equal(pred, lab))


        print("Mean CER: {}".format(np.mean([self.cer], axis=1)[0]))
        print("Mean WER: {}".format(np.mean([self.wer], axis=1)[0]))
...