Как определить последние слои модели для обучения передаче?

#tensorflow #deep-learning #ocr #transfer-learning #pre-trained-model

#tensorflow #глубокое обучение #ocr #передача-обучение #предварительно обученная модель

Вопрос:

прежде всего: я новичок в глубоком обучении и Tensorflow, поэтому извините за глупые вопросы. Может быть, кто-нибудь может помочь мне получить больше понимания и ясности. Я работаю над проектом OCR, где у меня есть только 4000 помеченных изображений с пунктирным шрифтом и белым фоном. Я решил использовать этот код для решения задачи: https://github.com/Pay20Y/FOTS_TF

Я использовал предварительно обученную модель для набора данных Synthtext и продолжил обучение с моим собственным набором данных, но результаты были не такими хорошими. Я думаю, что одна из проблем может заключаться в том, что количество классов моего пользовательского набора данных меньше, чем количество классов предварительно обученной модели. Я читал об обучении передаче, где вы обучаете только последние слои, а затем вы можете использовать другое количество классов, но я не знаю, как это сделать. Итак, чтобы быть более точным, я не знаю, как определить последние слои графика?

Вот код построения графика:

     def cnn(self, rois):
        with tf.variable_scope("recog/cnn"):
            conv1 = slim.conv2d(rois, 64, 3, stride=1, padding='SAME', activation_fn=tf.nn.relu, normalizer_fn=None)
            conv1 = slim.conv2d(conv1, 64, 3, stride=1, padding='SAME', activation_fn=tf.nn.relu, normalizer_fn=None)
            pool1 = slim.max_pool2d(conv1, [2, 1], stride=[2, 1])
            conv2 = slim.conv2d(pool1, 128, 3, stride=1, padding='SAME', activation_fn=tf.nn.relu, normalizer_fn=None)
            conv2 = slim.conv2d(conv2, 128, 3, stride=1, padding='SAME', activation_fn=tf.nn.relu, normalizer_fn=None)
            pool2 = slim.max_pool2d(conv2, [2, 1], stride=[2, 1])
            conv3 = slim.conv2d(pool2, 256, 3, stride=1, padding='SAME', activation_fn=tf.nn.relu, normalizer_fn=None)
            conv3 = slim.conv2d(conv3, 256, 3, stride=1, padding='SAME', activation_fn=tf.nn.relu, normalizer_fn=None)
            pool3 = slim.max_pool2d(conv3, [2, 1], stride=[2, 1])
            return pool3
    

    def bilstm(self, input_feature, seq_len):
        with tf.variable_scope("recog/rnn"):
            lstm_fw_cell = rnn.LSTMCell(self.rnn_hidden_num)
            lstm_fw_cell = tf.nn.rnn_cell.DropoutWrapper(lstm_fw_cell, input_keep_prob=self.keepProb, output_keep_prob=self.keepProb)
            lstm_bw_cell = rnn.LSTMCell(self.rnn_hidden_num)
            lstm_bw_cell = tf.nn.rnn_cell.DropoutWrapper(lstm_bw_cell, input_keep_prob=self.keepProb, output_keep_prob=self.keepProb)
            # infer_output, _ = tf.nn.bidirectional_dynamic_rnn(lstm_fw_cell, lstm_bw_cell, input_feature, seq_len, dtype=tf.float32)
            # infer_output, _ = tf.nn.bidirectional_dynamic_rnn(lstm_fw_cell, lstm_bw_cell, input_feature, sequence_length=seq_len, time_major=True, dtype=tf.float32)
            infer_output, _ = tf.nn.bidirectional_dynamic_rnn(lstm_fw_cell, lstm_bw_cell, input_feature, sequence_length=seq_len, dtype=tf.float32)
            # stack_lstm_layer, _, _ = rnn.stack_bidirectional_dynamic_rnn(lstm_fw_cell, lstm_bw_cell, input_feature, dtype=tf.float32)
            infer_output = tf.concat(infer_output, axis=-1)
            return infer_output
            # return stack_lstm_layer

    def build_graph(self, rois, seq_len):
        num_rois = tf.shape(rois)[0]

        cnn_feature = self.cnn(rois) # N * 1 * W * C
        print cnn_feature

        cnn_feature = tf.reshape(cnn_feature, [nums, -1, 256]) # squeeze B x W x C
        cnn_feature = tf.squeeze(cnn_feature, axis=1) # N * W * C
        reshape_cnn_feature = tf.transpose(cnn_feature, (1, 0, 2))
        reshape_cnn_feature = cnn_feature

        # print "final cnn: ", reshape_cnn_feature.shape

        lstm_output = self.bilstm(reshape_cnn_feature, seq_len) # N * T * 2H

        # print "lstm_output: ", lstm_output

        logits = tf.reshape(lstm_output, [-1, self.rnn_hidden_num * 2]) # (N * T) * 2H
        
        W = tf.Variable(tf.truncated_normal([self.rnn_hidden_num * 2, self.num_classes], stddev=0.1), name="W")
        b = tf.Variable(tf.constant(0., shape=[self.num_classes]), name="b")

        logits = tf.matmul(logits, W)   b # (N * T) * Class

        logits = tf.reshape(logits, [num_rois, -1, self.num_classes])
        logits = tf.reshape(logits, [nums, -1, self.num_classes])
        logits = tf.reshape(logits, [num_rois, -1, self.num_classes])
        
        logits = tf.transpose(logits, (1, 0, 2))

        return logits
  

Я не знаю, разумно ли проводить обучение передаче?
Есть ли еще другой способ использовать предварительно обученную модель и выполнить точную настройку в моем собственном наборе данных, но с другим количеством классов символов?
Я действительно не понимаю, как решить эту задачу и что попытаться улучшить результаты. Я уже пробовал обучать с нуля без предварительно обученной модели, но модель переобучается.

Комментарии:

1. вы пробовали разные модели для решения вашей проблемы распознавания?

2. что вы имеете в виду под разными моделями? Вы имеете в виду разные предварительно обученные модели?

3. Как вы сказали, вы не получили лучшего результата, используя эту модель, так почему бы не использовать модель SOTA (т. Е. ABCNet). К вашему сведению, для проблемы распознавания текста вам не нужно обучать последний слой или что-то в этом роде (в отличие от проблемы компьютерного зрения в целом); просто инициализируйте с предварительно подготовленными весами и запустите с несколькими эпохами. AFAIK, вы не можете переобучить только последний слой модели распознавания.

4. Последний уровень любой модели распознавания текста — это, по сути, ветвь распознавания для распознавания текста. Это сочетается с ветвью обнаружения. Чтобы точно настроить определенный тип текста, вам необходимо потренироваться на наборе данных synth-text и точно настроить целевой набор данных.

5. Теперь, когда выбранная модель уже обучена синтезаторному тексту и настроена на эталонный набор данных (т. Е. total-text, icdar и т. Д.), Мы можем взять их предварительно обученный вес и инициализировать его для нашей задачи или нашего конкретного набора данных.