Распознавание проверочного кода TensorFlow

задняя часть Python NumPy TensorFlow

В этом разделе мы будем использовать TensorFlow для реализации модели глубокого обучения, которая используется для реализации процесса распознавания кода проверки. Код проверки, который мы идентифицируем здесь, представляет собой графический код проверки. Во-первых, мы будем использовать отмеченные данные для обучения модель, а затем используйте модель для реализации идентификации этого кода подтверждения.

код верификации

Во-первых, давайте посмотрим, как выглядит проверочный код. Здесь мы используем библиотеку капчи Python для ее генерации. Эта библиотека не установлена ​​по умолчанию, поэтому нам нужно сначала установить эту библиотеку. Кроме того, нам также нужно установить библиотеку подушек и используйте pip3 Просто:

1
pip3 install captcha pillow

После установки мы можем использовать следующий код для создания простого графического кода подтверждения:
12345678from captcha.image import ImageCaptchafrom PIL import Image text = '1234'image = ImageCaptcha()captcha = image.generate(text)captcha_image = Image.open(captcha)captcha_image.show()

После запуска выскочит картинка, а результат такой:

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

предварительная обработка

Предварительная обработка данных должна быть выполнена перед обучением.Теперь мы сначала определяем текстовое содержимое генерируемого проверочного кода, что эквивалентно наличию метки, а затем мы используем его для генерации проверочного кода, а затем мы можем получить ввод data is x. Здесь мы сначала определяем наш входной словарь. Поскольку словарь прописных и строчных букв и цифр относительно велик, представьте, что мы используем проверочный код, содержащий прописные и строчные буквы и цифры, а проверочный код состоит из четырех символов, тогда всего возможных комбинаций (26 + 26 + 10) ^ 4 = 14776336 комбинаций, это число немного велико для обучения, поэтому давайте упростим его здесь и будем использовать для обучения только чисто цифровые проверочные коды, так что количество комбинаций становится 10 ^ 4 = 10000 видов, очевидно, намного меньше.

Итак, здесь мы сначала определяем словарь и его переменную длины:
123VOCAB = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']CAPTCHA_LENGTH = 4VOCAB_LENGTH = len(VOCAB)

Здесь VOCAB — это содержание словаря, то есть 10 цифр от 0 до 9, количество символов в проверочном коде, то есть CAPTCHA_LENGTH равно 4, а длина словаря — это длина VOCAB, то есть 10.

Затем мы определяем метод для генерации данных кода подтверждения, Процесс аналогичен описанному выше, за исключением того, что здесь мы преобразуем возвращенные данные в массив в форме Numpy:

123456789101112131415from PIL import Imagefrom captcha.image import ImageCaptchaimport numpy as np def generate_captcha(captcha_text):    """    get captcha text and np array    :param captcha_text: source text    :return: captcha image and array    """    image = ImageCaptcha()    captcha = image.generate(captcha_text)    captcha_image = Image.open(captcha)    captcha_array = np.array(captcha_image)    return captcha_array

Вызывая этот метод таким образом, мы можем получить массив Numpy.Это фактически преобразование проверочного кода в RGB каждого пикселя.Попробуем этот метод:
12captcha = generate_captcha('1234')print(captcha, captcha.shape)

Содержание следующее:

123456789[[[239 244 244]  [239 244 244]  [239 244 244]  ...,   ...,   [239 244 244]  [239 244 244]  [239 244 244]]] (60, 160, 3)

Вы можете видеть, что его форма (60,160,3), что на самом деле означает, что высота изображения капчи равна 60, ширина 160, и это капча 60 × 160 пикселей, Каждый пиксель имеет значение RGB, поэтому последнее измерение - это значение RGB пикселя.

Далее нам нужно определить метку.Поскольку нам нужно использовать модель глубокого обучения для обучения, лучше всего использовать One-Hot кодирование для наших данных метки здесь, то есть, если текст проверочного кода 1234, то словарь Позиция индекса должна быть установлена ​​​​на 1, а общая длина равна 40. Мы используем программу для реализации взаимного преобразования между кодировкой One-Hot и текстом:

12345678910111213141516171819202122232425262728def text2vec(text):    """    text to one-hot vector    :param text: source text    :return: np array    """    if len(text) > CAPTCHA_LENGTH:        return False    vector = np.zeros(CAPTCHA_LENGTH * VOCAB_LENGTH)    for i, c in enumerate(text):        index = i * VOCAB_LENGTH + VOCAB.index(c)        vector[index] = 1    return vector  def vec2text(vector):    """    vector to captcha text    :param vector: np array    :return: text    """    if not isinstance(vector, np.ndarray):        vector = np.asarray(vector)    vector = np.reshape(vector, [CAPTCHA_LENGTH, -1])    text = ''    for item in vector:        text += VOCAB[np.argmax(item)]    return text

Здесь метод text2vec() предназначен для преобразования реального текста в кодировку One-Hot, а метод vec2text() — для преобразования кодировки One-Hot обратно в реальный текст.

Например, вызываем вот эти два метода, мы конвертируем текст 1234 в кодировку One-Hot, а потом возвращаем обратно:

123vector = text2vec('1234')text = vec2text(vector)print(vector, text)

Результаты приведены ниже:

1234[ 0.  1.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  0.  0.  0.  0.  0.]1234

Таким образом, мы можем реализовать взаимную конвертацию текста в кодировку One-Hot.

Затем мы можем создать пакет данных.Данные x – это пустой массив кода подтверждения, а данные y – это горячее кодирование текста кода подтверждения. Сгенерированное содержимое выглядит следующим образом:
1234567891011121314151617181920212223242526272829303132333435363738import randomfrom os.path import join, existsimport pickleimport numpy as npfrom os import makedirs DATA_LENGTH = 10000DATA_PATH = 'data' def get_random_text():    text = ''    for i in range(CAPTCHA_LENGTH):        text += random.choice(VOCAB)    return text def generate_data():    print('Generating Data...')    data_x, data_y = [], []     # generate data x and y    for i in range(DATA_LENGTH):        text = get_random_text()        # get captcha array        captcha_array = generate_captcha(text)        # get vector        vector = text2vec(text)        data_x.append(captcha_array)        data_y.append(vector)     # write data to pickle    if not exists(DATA_PATH):        makedirs(DATA_PATH)     x = np.asarray(data_x, np.float32)    y = np.asarray(data_y, np.float32)    with open(join(DATA_PATH, 'data.pkl'), 'wb') as f:        pickle.dump(x, f)        pickle.dump(y, f)

Здесь мы определяем метод get_random_text(), который может случайным образом генерировать текст кода проверки, а затем использовать случайно сгенерированный текст для генерации соответствующих данных x, y, а затем мы записываем данные в файл рассола, так что операция предварительной обработки выполнен.

Построить модель

После того, как у нас есть данные, давайте начнем строить модель.Здесь мы все еще используем метод train_test_split() для разделения данных на три части: обучающий набор, набор для разработки и набор для проверки:
1234567with open('data.pkl', 'rb') as f:    data_x = pickle.load(f)    data_y = pickle.load(f)    return standardize(data_x), data_y train_x, test_x, train_y, test_y = train_test_split(data_x, data_y, test_size=0.4, random_state=40)dev_x, test_x, dev_y, test_y, = train_test_split(test_x, test_y, test_size=0.5, random_state=40)

Затем мы создаем три объекта набора данных, используя три набора данных:

123456789# train and dev datasettrain_dataset = tf.data.Dataset.from_tensor_slices((train_x, train_y)).shuffle(10000)train_dataset = train_dataset.batch(FLAGS.train_batch_size) dev_dataset = tf.data.Dataset.from_tensor_slices((dev_x, dev_y))dev_dataset = dev_dataset.batch(FLAGS.dev_batch_size) test_dataset = tf.data.Dataset.from_tensor_slices((test_x, test_y))test_dataset = test_dataset.batch(FLAGS.test_batch_size)

Затем инициализируйте итератор и привяжите его к этому набору данных:

12345# a reinitializable iteratoriterator = tf.data.Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes)train_initializer = iterator.make_initializer(train_dataset)dev_initializer = iterator.make_initializer(dev_dataset)test_initializer = iterator.make_initializer(test_dataset)

Следующая часть является ключевой частью.Здесь мы используем трехслойную свертку и двухуровневую полносвязную сеть для построения.Чтобы упростить метод записи, мы напрямую используем модуль слоя TensorFlow:
1234567891011121314151617# input Layerwith tf.variable_scope('inputs'):    # x.shape = [-1, 60, 160, 3]    x, y_label = iterator.get_next()keep_prob = tf.placeholder(tf.float32, [])y = tf.cast(x, tf.float32)# 3 CNN layersfor _ in range(3):    y = tf.layers.conv2d(y, filters=32, kernel_size=3, padding='same', activation=tf.nn.relu)    y = tf.layers.max_pooling2d(y, pool_size=2, strides=2, padding='same')    # y = tf.layers.dropout(y, rate=keep_prob) # 2 dense layersy = tf.layers.flatten(y)y = tf.layers.dense(y, 1024, activation=tf.nn.relu)y = tf.layers.dropout(y, rate=keep_prob)y = tf.layers.dense(y, VOCAB_LENGTH)

Здесь размер ядра свертки равен 3, заполнение использует режим SAME, а функция активации использует relu.

После преобразования полносвязной сети форма y становится [batch_size, n_classes]. Наша метка состоит из CAPTCHA_LENGTH One-Hot векторов. Здесь мы хотим использовать перекрестную энтропию для расчета, но перекрестная энтропия рассчитывается At на этот раз сумма элементов последнего измерения вектора параметров метки должна быть равна 1, иначе возникнут проблемы при вычислении градиента. Подробнее см. в официальной документации TensorFlow:
https://www.tensorflow.org/api_docs/python/tf/nn/


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

Но текущий параметр метки представляет собой комбинацию векторов One-Hot CAPTCHA_LENGTH, поэтому сумма каждого элемента здесь равна CAPTCHA_LENGTH, поэтому нам нужно изменить его форму, чтобы гарантировать, что каждый элемент в последнем измерении равен 1:

1
2
y_reshape = tf.reshape(y, [-1, VOCAB_LENGTH])
y_label_reshape = tf.reshape(y_label, [-1, VOCAB_LENGTH])

Таким образом, мы можем гарантировать, что последнее измерение имеет длину VOCAB_LENGTH, и это вектор One-Hot, поэтому сумма элементов должна быть равна 1.

Тогда сумма убытка вычисляется просто отлично:
1234567# losscross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(logits=y_reshape, labels=y_label_reshape))# accuracymax_index_predict = tf.argmax(y_reshape, axis=-1)max_index_label = tf.argmax(y_label_reshape, axis=-1)correct_predict = tf.equal(max_index_predict, max_index_label)accuracy = tf.reduce_mean(tf.cast(correct_predict, tf.float32))

Затем вы можете выполнить следующее обучение:

12345678910111213141516171819# traintrain_op = tf.train.RMSPropOptimizer(FLAGS.learning_rate).minimize(cross_entropy, global_step=global_step)for epoch in range(FLAGS.epoch_num):    tf.train.global_step(sess, global_step_tensor=global_step)    # train    sess.run(train_initializer)    for step in range(int(train_steps)):        loss, acc, gstep, _ = sess.run([cross_entropy, accuracy, global_step, train_op],                                       feed_dict={keep_prob: FLAGS.keep_prob})        # print log        if step % FLAGS.steps_per_print == 0:            print('Global Step', gstep, 'Step', step, 'Train Loss', loss, 'Accuracy', acc)     if epoch % FLAGS.epochs_per_dev == 0:        # dev        sess.run(dev_initializer)        for step in range(int(dev_steps)):            if step % FLAGS.steps_per_print == 0:                print('Dev Accuracy', sess.run(accuracy, feed_dict={keep_prob: 1}), 'Step', step)

Здесь мы сначала инициализируем train_initializer, привязываем итератор к набору данных train, а затем выполняем train_op, получаем результаты loss, acc, gstep и т. д. и выводим их.

тренироваться

Запустив тренировочный процесс, результаты будут примерно такими:
12345678910...Dev Accuracy 0.9580078 Step 0Dev Accuracy 0.9472656 Step 2Dev Accuracy 0.9501953 Step 4Dev Accuracy 0.9658203 Step 6Global Step 3243 Step 0 Train Loss 1.1920928e-06 Accuracy 1.0Global Step 3245 Step 2 Train Loss 1.5497207e-06 Accuracy 1.0Global Step 3247 Step 4 Train Loss 1.1920928e-06 Accuracy 1.0Global Step 3249 Step 6 Train Loss 1.7881392e-06 Accuracy 1.0...

Уровень точности набора проверки составляет более 95%.

контрольная работа

В процессе обучения мы также можем сохранять модель каждые несколько Эпох:
123# save modelif epoch % FLAGS.epochs_per_save == 0:    saver.save(sess, FLAGS.checkpoint_dir, global_step=gstep)

Конечно, вы также можете сохранить модель с высочайшей точностью на проверочном наборе.

При проверке мы можем обновить модель, а затем проверить:

1234567891011# load modelckpt = tf.train.get_checkpoint_state('ckpt')if ckpt:    saver.restore(sess, ckpt.model_checkpoint_path)    print('Restore from', ckpt.model_checkpoint_path)    sess.run(test_initializer)    for step in range(int(test_steps)):        if step % FLAGS.steps_per_print == 0:            print('Test Accuracy', sess.run(accuracy, feed_dict={keep_prob: 1}), 'Step', step)else:    print('No Model Found')

После проверки точность в основном такая же.

Если вы хотите выполнить новый вывод, вы можете заменить test_x.

Эпилог

Выше приведен процесс использования TensorFlow для идентификации кода подтверждения. Код см. в разделе:


Этот ресурс был впервые опубликован в личном блоге Цуй Цинцай Цзин Ми:Практическое руководство по разработке веб-краулера на Python3 | Цзин Ми

Если вы хотите узнать больше информации о поисковых роботах, обратите внимание на мой личный публичный аккаунт WeChat: Coder of Attack.

WeChat.QQ.com/Day/5 Это радость VE Z…(автоматическое распознавание QR-кода)