Есть нейронная сеть для распознавания текста с капчи. Если вся капча имеет одинаковую длину, то сеть обучается и распознает текст со 100% результатом. Но с переменной длиной сеть уже не обучается и соответственно не распознает текст. Что я только не пробовал ничего не помогает. Код не весь, а только важные моменты:
char_to_num = keras.layers.StringLookup(vocabulary=chars, invert=False)
blank_char_index = len(char_to_num.get_vocabulary())
encoded_labels = keras.preprocessing.sequence.pad_sequences(
encoded_labels, maxlen=max_label_length, padding='post', value=blank_char_index
)
# CTC loss
class CTCLayer(keras.layers.Layer):
def __init__(self, name=None):
super().__init__(name=name)
def call(self, y_true, y_pred):
# Количество примеров в батче
batch_len = tf.cast(tf.shape(y_true)[0], dtype=tf.int32)
# Длина последовательности предсказаний (временные шаги)
input_length = tf.cast(tf.shape(y_pred)[1], dtype=tf.int32)
# Создаем тензоры длин для всего батча
input_length = input_length * tf.ones(shape=(batch_len, 1), dtype=tf.int32)
# Длина целевой текстовой метки
label_length = tf.math.reduce_sum(tf.cast(tf.math.not_equal(y_true, blank_char_index), tf.int32), axis=1, keepdims=True)
loss = keras.backend.ctc_batch_cost(y_true, y_pred, input_length, label_length)
self.add_loss(loss)
return y_pred
# Входной слой
image_input_layer = keras.layers.Input(shape=(image_width, image_height, 1), name="image_input_layer", dtype=tf.float32)
label_input_layer = keras.layers.Input(shape=(max_label_length,), name="label_input_layer", dtype=tf.int32)
# Слой CNN (извлечение признаков)
x = keras.layers.Conv2D(32, (3, 3), activation="relu", kernel_initializer="he_normal", padding="same")(image_input_layer)
x = keras.layers.MaxPooling2D((2, 2))(x)
x = keras.layers.Conv2D(64, (3, 3), activation="relu", kernel_initializer="he_normal", padding="same")(x)
x = keras.layers.MaxPooling2D((2, 2))(x)
# Преобразование в последовательность для RNN
new_rnn_shape = ((image_width // 4), (image_height // 4) * 64)
x = keras.layers.Reshape(target_shape=new_rnn_shape)(x)
x = keras.layers.Dense(64, activation="relu")(x)
x = keras.layers.Dropout(0.2)(x)
# Слой RNN (обработка последовательности)
x = keras.layers.Bidirectional(keras.layers.LSTM(128, return_sequences=True, dropout=0.25))(x)
x = keras.layers.Bidirectional(keras.layers.LSTM(64, return_sequences=True, dropout=0.25))(x)
# Выходной слой
output_layer = keras.layers.Dense(blank_char_index + 1, activation="softmax", name="output_layer")(x)
# CTC loss
ctc_loss_output = CTCLayer(name="ctc_loss_output")(label_input_layer, output_layer)
# Модель
model = keras.models.Model(inputs=[image_input_layer, label_input_layer], outputs=ctc_loss_output)
model.compile(optimizer=keras.optimizers.Adam())
model.summary()