[Aprendizaje profundo] Reconocimiento de Captcha basado en red neuronal convolucional

Dirección del evento: Desafío de aprendizaje de 21 días de CSDN

prefacio

El entorno no se repetirá aquí. Es consistente con el entorno en el [Deep Learning] Weather Recognition Training Text Based on Convolutional Neural Networks. Si la configuración sigue sin tener éxito, consulte la configuración detallada del paquete al final de este artículo.

Comprender el conjunto de datos captcha

Contiene 1070 imágenes de código de verificación escritas a mano. Y use el código de verificación normal como el nombre de la imagen. Entonces, en la etapa posterior, debe dividir manualmente el conjunto de prueba y el conjunto de validación, y debe extraer manualmente los códigos de verificación en todos los nombres de las imágenes.
inserte la descripción de la imagen aquí

Descargar el conjunto de datos weather_photos

Puede enviarme un mensaje privado (porque el conjunto de datos ya se cargó en csdn, por lo que no se puede volver a cargar)

Ya sea para usar entrenamiento de CPU o entrenamiento de GPU

En términos generales, si tiene una buena tarjeta gráfica (GPU), use la GPU para entrenar porque es rápida , por lo que debe descargar el paquete tensorflow-gpu en consecuencia. Si su tarjeta gráfica es mala o no tiene fondos suficientes para comenzar con una buena tarjeta gráfica, puede usar la capacitación CUP.

la diferencia

(1) La CPU se utiliza principalmente para operaciones en serie, mientras que la GPU es para operaciones paralelas masivas. Debido a la gran cantidad de muestras y la gran cantidad de parámetros en el aprendizaje profundo, el papel de la GPU es acelerar las operaciones de red.

(2) También es posible calcular la red neuronal mediante la CPU, y la red neuronal calculada también es muy efectiva en aplicaciones prácticas, pero la velocidad será muy lenta. En la actualidad, las operaciones de GPU se centran principalmente en la multiplicación y convolución de matrices, y otras operaciones lógicas no son tan rápidas como las CPU.

Entrenar con CPU

# 使用cpu训练
import os

os.environ["CUDA_VISIBLE_DEVICES"] = "-1"

El modelo de CPU no se muestra cuando se entrena con CPU.
inserte la descripción de la imagen aquí

Entrenamiento con GPU

gpus = tf.config.list_physical_devices("GPU")

if gpus:
    gpu0 = gpus[0]  # 如果有多个GPU,仅使用第0个GPU
    tf.config.experimental.set_memory_growth(gpu0, True)  # 设置GPU显存用量按需使用
    tf.config.set_visible_devices([gpu0], "GPU")

Al usar el entrenamiento de GPU, se mostrará el modelo de GPU correspondiente.
inserte la descripción de la imagen aquí

apoyo chino

Utilice import matplotlib.pyplot as pltla biblioteca de importación, . plt es una biblioteca que significa dibujar. La configuración en la biblioteca es fija, pero a veces queremos modificar los parámetros de configuración de plt para satisfacer las necesidades de dibujo.
Se puede plt.rcParams['配置参数']=[修改值]modificar, rcParams (ejecutar parámetros de configuración) ejecutar parámetros de configuración.

plt.rcParams['font.sans-serif'] = ['SimHei'] #运行配置参数中的字体(font)为黑体(SimHei)
plt.rcParams['axes.unicode_minus'] = False #运行配置参数总的轴(axes)正常显示正负号(minus)

Datos de importacion

Aquí vemos que la semilla aleatoria de numpy y la semilla aleatoria de tf se establecen en valores fijos, para que los resultados del entrenamiento sean lo más estables posible. Aquí, la ruta donde el conjunto de datos se almacena localmente se proporciona a la variable data_dir.

import matplotlib.pyplot as plt
import PIL

# 设置随机种子尽可能使结果可以重现
import numpy as np

np.random.seed(1)

# 设置随机种子尽可能使结果可以重现
tf.random.set_seed(1)

from tensorflow import keras
from tensorflow.keras import layers, models

import pathlib

data_dir = "E:\\PythonProject\\day6\\data\\captcha\\"
data_dir = pathlib.Path(data_dir)

# 提取所有照片的路径
all_image_paths = list(data_dir.glob('*'))
all_image_paths = [str(path) for path in all_image_paths]

# 打乱数据  因为文件默认按照文件名的字母排序,所以需要打乱顺序
random.shuffle(all_image_paths)

# 获取数据标签  通过拆分图片名称的后缀见所有的验证码字符串提取出来
# 验证码长度是5位,且都已.png结尾 然后进行拆分
all_label_names = [path.split("\\")[5].split(".")[0] for path in all_image_paths]

Ver volumen de datos

image_count = len(all_image_paths)
print("图片总数为:", image_count)

mostrar algunas fotos

Dibuja las primeras 20 hojas, 5 en cada fila para un total de cuatro líneas.

from matplotlib import pyplot as plt

plt.figure(figsize=(10, 5))

for i in range(20):
    plt.subplot(4, 5, i + 1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)

    # 显示图片
    images = plt.imread(all_image_paths[i])
    plt.imshow(images)
    # 显示标签
    plt.xlabel(all_label_names[i])

plt.show()

Trazar el resultado:
inserte la descripción de la imagen aquí

preprocesamiento

Establecer etiquetas manualmente

Diseñe una matriz para almacenar todos los números y caracteres que aparecen en el código de verificación.

number = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
            'v', 'w', 'x', 'y', 'z']
char_set = number + alphabet
char_set_len = len(char_set)
label_name_len = len(all_label_names[0])

def text2vec(text):
    vector = np.zeros([label_name_len, char_set_len])
    for i, c in enumerate(text):
        idx = char_set.index(c)
        vector[i][idx] = 1.0
    return vector


all_labels = [text2vec(i) for i in all_label_names]

Puede ser un poco confuso mirar el código directamente. La siguiente imagen es el efecto final, que es equivalente a una matriz tridimensional. La primera dimensión representa cada imagen, la segunda dimensión representa múltiples conjuntos de caracteres y la tercera dimensión representa lo que debe ser el código de verificación de cada persona Caracteres, si lo hay es 0 en la posición correspondiente, si no es 0.
inserte la descripción de la imagen aquí

Procesamiento en escala de grises

Escala de grises, en el modelo RGB, si R=G=B, el color representa un color en escala de grises, y el valor de R=G=B se denomina valor de escala de grises. Por lo tanto, cada píxel de la imagen en escala de grises solo necesita un almacenamiento de bytes en escala de grises. valores (también conocidos como valores de intensidad, valores de brillo), y el rango de escala de grises es 0-255. La fórmula es la siguiente:
inserte la descripción de la imagen aquí

método promedio

Se obtiene una imagen en escala de grises promediando las luminancias de tres componentes en la imagen en color. Este artículo utiliza las fotos procesadas por el método promedio.
inserte la descripción de la imagen aquí
La siguiente figura está en escala de grises por el método de promedio. La izquierda es la imagen original y la derecha es la imagen en escala de grises.
inserte la descripción de la imagen aquí

método de promedio ponderado

Este método es un método para estimar la dirección probable de este valor en el futuro en función del valor observado durante un cierto período de tiempo en el pasado.
inserte la descripción de la imagen aquí
La siguiente figura está en escala de grises por el método de promedio. La izquierda es la imagen original y la derecha es la imagen en escala de grises.
inserte la descripción de la imagen aquí

cvtColor

La función API cvtColor de OpenCV también puede lograr el procesamiento en escala de grises. La siguiente figura está en escala de grises por el método de promedio. La izquierda es la imagen original y la derecha es la imagen en escala de grises.
inserte la descripción de la imagen aquí

Descargar datos

Aquí se utiliza el método from_tensor_slices. Esta función es una de las funciones centrales del conjunto de datos Su función es dividir los datos dados, como tuplas, listas y tensores. La extensión del corte comienza desde la dimensión más exterior. Si hay varias funciones para combinar, entonces un corte es para cortar los datos de la dimensión más externa de cada combinación y dividirlos en grupos.

AUTOTUNE = tf.data.experimental.AUTOTUNE

path_ds  = tf.data.Dataset.from_tensor_slices(all_image_paths)
image_ds = path_ds.map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE)
label_ds = tf.data.Dataset.from_tensor_slices(all_labels)

image_label_ds = tf.data.Dataset.zip((image_ds, label_ds))

# 拆分数据集 将前1000个作为训练集 剩余的作为测试集
train_ds = image_label_ds.take(1000) 
val_ds   = image_label_ds.skip(1000)  

Configurar el conjunto de datos (acelerar)

shuffle(): Esta función ordena aleatoriamente todos los elementos de la lista. A veces, nuestras tareas muestrearán aleatoriamente ciertos números de un conjunto de datos. Por ejemplo, hay 10 líneas en un texto y debemos seleccionar aleatoriamente las primeras 5.
prefetch(): la captación previa es el contenido de la memoria de captación previa, el programador le dice a la CPU qué contenido se puede usar inmediatamente y la CPU realiza una captación previa para la optimización.

BATCH_SIZE = 16
train_ds = train_ds.batch(BATCH_SIZE)
train_ds = train_ds.prefetch(buffer_size=AUTOTUNE)

val_ds = val_ds.batch(BATCH_SIZE)
val_ds = val_ds.prefetch(buffer_size=AUTOTUNE)

Construir un modelo CNN

El modelo aquí es más o menos el mismo que los anteriores, por lo que no lo presentaré demasiado.

from tensorflow.keras import datasets, layers, models

model = models.Sequential([
    
    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(50, 200, 1)),
    layers.MaxPooling2D((2, 2)),                   
    layers.Conv2D(64, (3, 3), activation='relu'),  
    layers.MaxPooling2D((2, 2)),                   
    
    layers.Flatten(),                              
    layers.Dense(1000, activation='relu'),         
    
    layers.Dense(label_name_len * char_set_len),
    layers.Reshape([label_name_len, char_set_len]),
    layers.Softmax()                               
])

model.summary()  # 打印网络结构

estructura de red

Un total de 10 capas, incluida la capa de entrada.
inserte la descripción de la imagen aquí

cantidad de parámetro

El número total de parámetros es 33M, y la cantidad de parámetros es mayor, pero el conjunto de datos no es muy grande. Se recomienda entrenamiento GPU.

Total params: 33,991,996
Trainable params: 33,991,996
Non-trainable params: 0

entrenar al modelo

Entrena al modelo durante 10 épocas.

# 设置优化器
model.compile(optimizer="adam",
              loss='categorical_crossentropy',
              metrics=['accuracy'])

epochs = 10

history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=epochs
)

Resultados del entrenamiento: después de 10 rondas, la tasa correcta del conjunto de prueba es solo del 78,57 %, lo que demuestra que todavía hay mucho espacio para la optimización.
inserte la descripción de la imagen aquí

Evaluación del modelo

Los datos del modelo entrenado se convierten en una tabla de curvas, lo cual es conveniente para la optimización posterior del modelo, ya sea que se ajuste en exceso o en forma insuficiente o que necesite expandir los datos, etc.

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)

plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

resultado de la operación:
inserte la descripción de la imagen aquí

predecir

Aquí realizamos un efecto de preprocesamiento en el modelo entrenado. Las siguientes seis imágenes se utilizan como ejemplo para la prueba.

def vec2text(vec):
    text = []
    for i, c in enumerate(vec):
        text.append(char_set[c])
    return "".join(text)


plt.figure(figsize=(8, 8))

for images, labels in val_ds.take(1):
    for i in range(6):
        ax = plt.subplot(5, 2, i + 1)

        # 显示图片
        image = tf.reshape(images, [16, 50, 200])
        plt.imshow(image[i])

        # 需要给图片增加一个维度
        img_array = tf.expand_dims(images[i], 0)

        # 使用模型预测验证码
        predictions = model.predict(img_array)
        plt.title(vec2text(np.argmax(predictions, axis=2)[0]))

        plt.axis("off")

plt.show()

Se puede ver que la tasa de error sigue siendo bastante alta y que el modelo debe mejorarse aún más.
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_45254369/article/details/126329361
Recomendado
Clasificación