Visión por computadora: práctica de aprendizaje profundo de Flying Paddle: principios y práctica del algoritmo de clasificación de imágenes

Teoría básica:

La clasificación de imágenes es la primera tarea en la que el aprendizaje profundo ha logrado resultados revolucionarios en el campo de la visión. Este capítulo presenta primero el historial de desarrollo y los indicadores de evaluación de la tarea de clasificación de imágenes. Luego se introducen desde tres perspectivas los tres modelos que juegan un papel importante en el campo de la clasificación de imágenes. El primero es un modelo basado en redes residuales. Este capítulo se centra en ResNet, DenseNet y DPN. El segundo es un modelo basado en las ideas de Transformer. Este capítulo se centra en los modelos ViT y Swin-Transformer. El tercer tipo es un modelo liviano para dispositivos móviles. Este capítulo se centra en MobileNet y PP-LCNet. Finalmente, este capítulo completa un proyecto de clasificación de melocotones utilizando Flying Paddle Framework. Después de estudiar este capítulo, espero que los lectores puedan dominar los siguientes puntos de conocimiento:

  1. Comprender la historia del desarrollo de la clasificación de imágenes;
  2. Dominar las características de los modelos basados ​​en ideas residuales;
  3. Dominar las características de los modelos basados ​​en ideas de Transformer;
  4. Domine las características de los modelos de red ligeros.

La tarea de clasificación de imágenes es la primera tarea de visión por computadora que utiliza métodos de aprendizaje profundo. Muchas arquitecturas de red clásicas se aplicaron por primera vez a las tareas de clasificación de imágenes, por lo que el modelo de red de aprendizaje profundo en la clasificación de imágenes puede considerarse como la piedra angular de otras tareas de visión por computadora.

Los primeros métodos de clasificación de imágenes describían principalmente la imagen completa extrayendo características manualmente y luego usaban un clasificador para determinar la categoría de la imagen. Por lo tanto, el núcleo de la clasificación de imágenes radica en clasificar las características, y cómo extraer las características de la imagen es crucial. Las características subyacentes contienen una gran cantidad de ruido redundante. Para mejorar la solidez de la expresión de características, se debe utilizar un algoritmo de transformación de características para codificar las características subyacentes, lo que se denomina codificación de características. Después de la codificación de características, generalmente se somete a restricciones de características espaciales, también llamadas agregación de características. Específicamente, solo se toma el valor máximo o el valor promedio de cada característica dentro de un rango espacial, de modo que se pueda obtener una expresión de característica con cierta invariancia de característica.


Después de la extracción de características subyacentes, la codificación de características y la agregación de características, la imagen se puede expresar como una descripción de vector de dimensión fija y la imagen se puede clasificar clasificando el vector de características mediante un clasificador.
SVM basado en el método del kernel es el clasificador más utilizado entre los métodos tradicionales y funciona muy bien en tareas tradicionales de clasificación de imágenes. Los métodos de clasificación de imágenes tradicionales son efectivos para algunos escenarios de clasificación de imágenes simples y obvios. Sin embargo, debido a la complejidad de la situación real, los métodos de clasificación tradicionales no pueden lograr resultados de clasificación satisfactorios cuando se enfrentan a escenas complejas. Esto se debe a que los métodos tradicionales de extracción manual de características utilizados en el método de clasificación no se pueden describir de manera completa y precisa las características de la imagen, y las características extraídas manualmente no pueden hacer frente a problemas como visualización múltiple, ángulos múltiples, iluminación y oclusión diferentes del mismo objeto y morfología múltiple.
 

La transformación de CNN a Transformer es similar al cambio de centrarse en lo local a especializarse en lo global. Está más en línea con las características visuales humanas (los humanos son buenos para capturar rápidamente características globales), CNN es bueno para extraer localmente pequeños y información precisa, pero tiene la desventaja de una capacidad de extracción insuficiente. Transformer se basa en el modelado global de larga distancia y no presta atención a la información local, por lo que pierde las características de CNN, como la invariancia de traducción y la invariancia de inversión, lo que conducirá a la desventajas de capturar información redundante y mayores requisitos de datos.


En conjunto, los métodos de aprendizaje profundo han pasado por el proceso de desarrollo de MLP simple, CNN, Transformer, MLP complejo y otros modelos en problemas de clasificación de imágenes. Estos modelos tienen sus propias características: la convolución solo contiene conexiones locales, por lo que el cálculo es eficiente; la autoatención usa pesos dinámicos, por lo que la capacidad del modelo es mayor y también tiene un campo receptivo global; MLP también tiene un campo receptivo global. pero no se utilizan pesos dinámicos. Se puede ver que la convolución y la autoatención tienen características complementarias, la convolución tiene la mejor capacidad de generalización y Transformer tiene la mayor capacidad de modelo entre las tres arquitecturas. La convolución es la mejor opción para diseñar modelos livianos, pero se debe considerar Transformer al diseñar modelos grandes. Por lo tanto, puede considerar el uso de modelado local convolucional para ayudar a mejorar el rendimiento de Transformer y MLP. Teniendo en cuenta las características de la estructura anterior, las conexiones escasas ayudan a mejorar el rendimiento de la generalización, mientras que los pesos dinámicos y los campos receptivos globales ayudan a mejorar la capacidad del modelo. Por lo tanto, constantemente surgen métodos innovadores en las tareas de clasificación de imágenes, lo que proporciona un espacio de aplicación más amplio para la visión por computadora.

Nombre del experimento: Construcción y entrenamiento de un modelo de clasificación de melocotones.

1. Objetivos experimentales

Este experimento explica principalmente: Utilice el marco de aprendizaje profundo paddlepaddle para construir un modelo de clasificación de melocotón y completar todo el proceso de capacitación y prueba.

Después de completar este experimento, las habilidades que podrás dominar incluyen:

  • Dominar el uso del marco de aprendizaje profundo paddlepaddle;
  • Domine cómo utilizar el marco de aprendizaje profundo paddlepaddle para construir un modelo de clasificación de duraznos;
  • Domine cómo completar el proceso de trabajo de aprendizaje profundo, como la capacitación, evaluación, guardado y predicción de modelos;

2. Introducción a los antecedentes experimentales

La clasificación de imágenes es la base de la visión por computadora y otras tareas informáticas complejas. Con el desarrollo de la tecnología de aprendizaje profundo, han nacido muchos algoritmos excelentes de clasificación de imágenes. Para esta clasificación de melocotones, usaremos el algoritmo típico representado por resnet .

3. Introducción al proceso general de uso del marco de paddlepaddle.

Hoy, paddlepaddle ha lanzado la versión 2.0. En la versión 2.0, se ha lanzado una API de alto nivel, lo que hace que el código sea más simple y fácil de programar.

Actualmente, la API de alto nivel de Flying Paddle consta de cinco módulos, a saber, carga de datos, construcción de modelos, entrenamiento de modelos, visualización de modelos y uso de alto nivel. Como se muestra abajo:

 

Es muy fácil utilizar el marco paddlepaddle para realizar proyectos de aprendizaje profundo. Puede completar el proyecto de aprendizaje profundo siguiendo el proceso general (la siguiente figura muestra el proceso general de implementación del proyecto). El proceso incluye principalmente cinco pasos principales: procesamiento de datos, diseño del modelo, configuración de capacitación, proceso de capacitación y almacenamiento del modelo. En la etapa de procesamiento de datos, se trata principalmente de obtener datos que estén casi disponibles para el modelo, incluida la recopilación y el preprocesamiento de datos locales o de red. La etapa de diseño del modelo es la construcción de modelos más discutida en proyectos de aprendizaje profundo. La clave en esta etapa es el diseño y la implementación de la estructura de la red. Flying Paddle Framework ha preparado una gran cantidad de bibliotecas de modelos verificadas industrialmente y modelos previamente entrenados para desarrolladores para facilitar el desarrollo o utilizarlo directamente. En la fase de configuración del entrenamiento, los desarrolladores deben establecer parámetros como el tipo de optimizador y la atenuación de la tasa de aprendizaje, y también deben especificar si usar GPU o CPU para completar los cálculos. La etapa del proceso de capacitación es la etapa en la que el marco realmente ejecuta el proceso de cálculo. En esta etapa, el marco de la paleta voladora completa continuamente el proceso de propagación hacia adelante, propagación hacia atrás y descenso de gradiente. El último paso es guardar el modelo. Cuando el modelo alcanza indicadores predeterminados o alcanza un número predeterminado de tiempos de entrenamiento, los desarrolladores pueden guardar el modelo "entrenado" para el próximo entrenamiento o implementación.

Uso del marco paddlepaddle para el proceso de proyectos de aprendizaje profundo

4. Contenido del experimento

4.1 Introducción a los conjuntos de datos

El conjunto de datos que utilizamos en este experimento son cuatro tipos de melocotones, estos melocotones se dividen en cuatro carpetas y el nombre de cada carpeta corresponde a un tipo de melocotón.

conjunto de datos de durazno

 

Observando con nuestros propios ojos, parece que estos melocotones se dividen en cuatro categorías según tamaño y color, ¿es realmente así? Después de completar este experimento, el modelo de aprendizaje profundo podrá juzgar por sí mismo en qué se basa la clasificación.

Para este experimento, se ha proporcionado un conjunto de datos para todos, que se almacena en la  carpeta "data/enhancement/"  . Las imágenes están divididas en 2 carpetas, una es el conjunto de entrenamiento y la otra es el conjunto de prueba. Hay 4 categorías en cada carpeta: R0, B1, M2, S3. El conjunto de datos de clasificación de duraznos original contiene dos carpetas: "train" y "test".
Cada carpeta contiene: "B1", "M2", "R0" y "S3".
Conjunto de entrenamiento:
    train_B1: 1601 imágenes
    train_M2: 1800 imágenes
    train_R0: 1601 imágenes
    train_S3: 1635 imágenes
Conjunto de prueba:
    test_B1: 16 imágenes
    test_M2: 18 imágenes
    test_R0: 18 imágenes
    test_S3: 15 imágenes

# Descompresión de datos. Si ya lo ha descomprimido una vez, comente este código.
# !descomprimir /home/aistudio/data/data103593/data.zip - d /home/aistudio/data/enhancement_data/
Introducción al archivo experimental

La estructura de archivos de este experimento es la siguiente:

El código y el conjunto de datos para este experimento se han preparado para todos. La estructura del directorio se muestra a continuación:

La estructura de archivos de este experimento.


 

4.2 Importar las bibliotecas necesarias para los experimentos.

En el primer paso del experimento, necesita importar bibliotecas relevantes, las más importantes son las siguientes:

  • os: el módulo OS proporciona un método muy rico para procesar archivos y directorios.
  • sys: el módulo sys proporciona una serie de variables y funciones relacionadas con el entorno de ejecución de Python.
  • Shutil: módulo para copiar archivos.
  • Numpy: Numpy es una biblioteca de extensión del lenguaje Python que admite una gran cantidad de operaciones matriciales y de matrices dimensionales. Además, también proporciona una gran cantidad de bibliotecas de funciones matemáticas para operaciones de matrices.
  • aleatorio: el módulo aleatorio en Python se utiliza para generar números aleatorios.
  • paddle.vision.datasets: este módulo contiene funciones relacionadas con la carga de datos, por ejemplo, se puede utilizar para cargar conjuntos de datos de uso común, como mnist.
  • paddle.vision.transforms: este módulo contiene funciones para convertir imágenes, como convertir imágenes en formato HWC en tensores de entrada en modo CHW. También incluye el método de preprocesamiento de imágenes del marco de la paleta voladora, que puede completar rápidamente el preprocesamiento de imágenes comunes, como ajustar el tono, el contraste, el tamaño de la imagen, etc.;
  • paddle.io.Dataset: este módulo incluye el método de carga de datos del marco de paleta, que puede completar la carga por lotes y la carga asincrónica de datos con "un clic".
#os: el módulo OS proporciona un método muy rico para procesar archivos y directorios.
#sys: el módulo sys proporciona una serie de variables y funciones relacionadas con el entorno de ejecución de Python.
#shutil: módulo para copiar archivos 
#numpy: Numpy es  una biblioteca de extensión del lenguaje Python que admite una gran cantidad de operaciones matriciales y de matrices dimensionales. Además, también proporciona una gran cantidad de bibliotecas de funciones matemáticas para operaciones de matrices.
#random: el módulo aleatorio en Python se utiliza para generar números aleatorios.
#paddle.vision.datasets: este módulo contiene funciones relacionadas con la carga de datos, por ejemplo, se puede utilizar para cargar conjuntos de datos de uso común, como mnist.
#paddle.vision.transforms: este módulo contiene funciones para convertir imágenes, como convertir imágenes en formato HWC en tensores de entrada en modo CHW. También incluye el método de preprocesamiento de imágenes del marco de la paleta voladora, que puede completar rápidamente el preprocesamiento de imágenes comunes, como ajustar el tono, el contraste, el tamaño de la imagen, etc.;
# paddle.io.Dataset: el módulo superior incluye el método de carga de datos Paddle Framework, que puede completar la carga por lotes y la carga asincrónica de datos con "un clic".
importarnos  _
 sistema de importación
importar  Shuil
importar  numpy  como  np
importar  paleta
importar  aleatoriamente
desde  paddle.io  importar  conjunto de datos, DataLoader
desde  paddle.vision.datasets  importar  DatasetFolder, ImageFolder
desde  paddle.vision  la importación  se transforma  como  T

4.3 Preparación del conjunto de datos

Para este experimento, se ha proporcionado un conjunto de datos para todos, que se almacena en la  carpeta "data/enhancement/"  .

El preprocesamiento de datos para este experimento incluye:

1. Generar archivo txt
2. Dividir el conjunto de entrenamiento y el conjunto de validación

4.3.1 Generar archivo de texto

¿Por qué generar archivos txt? Vemos que en el conjunto de datos, cada carpeta corresponde a una categoría, pero no hay un archivo txt para especificar la etiqueta, por lo que primero debemos generar un archivo txt;

Para que el código sea claro y conciso, configuramos parámetros como la ruta del conjunto de datos en una variable global train_parameters . La explicación es la siguiente:

  • 'train_data_dir' es el conjunto de entrenamiento original mejorado proporcionado;
  • 'test_image_dir' es el conjunto de prueba original proporcionado;
  • 'train_image_dir' y 'eval_image_dir' son el conjunto de entrenamiento real y el conjunto de validación generado al dividir el conjunto de entrenamiento original.
  • 'train_list_dir' y 'test_list_dir' son las rutas del archivo txt generado
  • Carpeta 'saved_model' donde se almacenan los resultados del entrenamiento
'''
Configuración de parámetros:
'train_data_dir' es el conjunto de entrenamiento original mejorado proporcionado;
'test_image_dir' es el conjunto de prueba original proporcionado;
'train_image_dir' y 'eval_image_dir' son el conjunto de entrenamiento real y el conjunto de validación generado al dividir el conjunto de entrenamiento original.
'train_list_dir' y 'test_list_dir' son las rutas del archivo txt generado
Carpeta 'saved_model' donde se almacenan los resultados del entrenamiento
'''
parámetros_tren = {          
    'train_image_dir' './data/splitted_training_data/train_images' ,
    'eval_image_dir' './data/splitted_training_data/eval_images' ,
    'test_image_dir' './data/enhancement_data/test' ,
    'train_data_dir' : './data/enhancement_data/train' ,
    'train_list_dir' : './data/enhancement_data/train.txt' ,
    'test_list_dir' : './data/enhancement_data/test.txt' ,  
    'modelo_salvado' : './modelo_salvado/'
}
#4 etiquetas de categoría del conjunto de datos
etiquetas = [ 'R0' 'B1' 'M2' 'S3' ]
etiquetas.sort()
#Prepárese para generar un archivo txt con el nombre del archivo del conjunto de entrenamiento y el nombre de la etiqueta
write_file_name = train_parameters[  'train_list_dir' ]
#Abra el archivo write_file_name en modo de escritura
con  open (write_file_name,  "w" como  write_file:
    #Ingrese diferentes etiquetas de clasificación por separado
    para  etiqueta  en  etiquetas:
        #Crea una lista vacía para guardar nombres de imágenes
        lista_archivo = [] 
        # Se utiliza para buscar todas las imágenes bajo la ruta de esta etiqueta.
        train_txt_dir = train_parameters[  'train_data_dir' ]+ '/' +etiqueta+ '/'     
        para  nombre_archivo  en  os.listdir(train_txt_dir):
            nombre_directorio = etiqueta        
            línea_temp = nombre_directorio +  '/'  + nombre_archivo +  '\t'  + etiqueta +  '\n'     # Ejemplo:"B1/101.png B1"
            write_file.write(temp_line)
    
#Prepárese para generar archivos txt con nombres de archivos de conjuntos de prueba y nombres de etiquetas
write_file_name = train_parameters[  'test_list_dir' ]
#Abra el archivo write_file_name en modo de escritura
con  open (write_file_name,  "w" como  write_file:
    #Ingrese diferentes etiquetas de clasificación por separado
    for label in labels:
        #建立空列表,用于保存图片名
        file_list = [] 
        #用于找到该标签路径下的所有图片.
        train_txt_dir = train_parameters[ 'test_image_dir']+'/'+label+'/'     
        for file_name in os.listdir(train_txt_dir):
            dir_name = label        
            temp_line = dir_name + '/' + file_name + '\t' + label + '\n'    # 例如:"B1/101.png B1"
            write_file.write(temp_line)

以上步骤操作完之后,就会在 data/enhancement_data/目录下生成 train.txt test.txt两个文件。


 
4.3.2 划分训练集和验证集
  • 我们已经有了训练集、测试集;最好还要把训练集再次拆分,从训练集中拆分出来一个验证集。
  • 这样,我们训练的时候,就可以用验证集来验证我们的模型训练效果,通过实时的观察训练效果,便于我们及时的调参。
#Determine si la carpeta splitted_training_data existe, si no existe, cree una nueva.
si  no es  os.path.exists ( 'datos/splitted_training_data' ):
    os.makedirs( 'datos/splitted_training_data' )
#Defina una función para dividir el conjunto de entrenamiento y el conjunto de validación
def  crear_tren_eval():
    '''
    Dividir el conjunto de entrenamiento y el conjunto de validación
    '''
    train_dir = train_parameters[ 'train_image_dir' ]
    eval_dir = train_parameters[ 'eval_image_dir' ]
    train_list_path = train_parameters[ 'train_list_dir' ]  
    train_data_dir = train_parameters[  'train_data_dir'
    
    print ( 'creación de imágenes de entrenamiento y evaluación' )
    #Si la carpeta no existe, crea la carpeta correspondiente
    si  no  os.path.exists (train_dir):
        os.mkdir(tren_dir)
    si  no  os.path.exists (eval_dir):
        os.mkdir(eval_dir) 
    #Abre el archivo txt y divide los datos.
    nombre_archivo = ruta_lista_tren
    f =  abrir (nombre_archivo,  'r'
    #Leer datos fila por fila
    líneas = f.readlines()
    f.cerrar()
        
    para  i  en  rango ( len (líneas)):
        #Divida cada línea de datos en 2 partes según espacios y tome el nombre de la ruta y el nombre del archivo de imagen de la primera parte, por ejemplo: R0/1.png
        img_path = líneas[i].split( '\t' )[ 0
        #Obtén la etiqueta de la segunda parte, por ejemplo: R0
        etiqueta_clase = líneas[i].split( '\t' )[ 1 ].strip( '\n' )
        # Tome una de cada 8 fotografías como datos de verificación y las demás se utilizan para entrenamiento.
        si  yo %  8  ==  0 :
            #Combinar nombres de directorios y archivos en una sola ruta
            eval_target_dir = os.path.join(eval_dir , class_label) 
            # Combine la ruta total del archivo y el nombre del archivo de la imagen actual. De hecho, obtendrá el nombre de la imagen en la carpeta donde se encuentra la imagen del conjunto de entrenamiento.   
            eval_img_path = os.path.join(train_dat a_dir, img_path)
            si  no  os.path.exists (eval_target_dir):
                    os.mkdir(eval_target_dir)  
            #Copie la imagen a la carpeta con la etiqueta especificada en el conjunto de verificación      
            Shutil.copy(eval_img_path, eval_target _dir) 
        más :           
            train_target_dir = os.path.join(train_dir , class_label)                                 
            train_img_path = os.path.join(train_da ta_dir, img_path)
            si  no  os.path.exists (train_target_dir):
                os.mkdir(train_target_dir)
            Shutil.copy(train_img_path, train_targ y_dir) 
    print  ( '¡Se completó la división del conjunto de entrenamiento y el conjunto de validación!' )
# Cree un conjunto de datos. Si ya lo ha hecho, comente el código.
crear_tren_eval()
 ¡Se ha completado la creación de imágenes de entrenamiento y evaluación para dividir el conjunto de entrenamiento y el conjunto de validación!

Después de ejecutar el código anterior, se completa la división del conjunto de entrenamiento y el conjunto de validación. Divídalo y colóquelo en el directorio ./data/splitted_training_data/:


 

4.5 Clase de conjunto de datos personalizado

Paddle Framework ha convertido algunos de nuestros conjuntos de datos de uso común en API, que están abiertas a los usuarios. Las API correspondientes son paddle.vision.datasets y paddle.text.datasets. Cuando lo usamos, podemos llamar directamente a estas API para descargar y usar el conjunto de datos. Estos conjuntos de datos integrados incluyen:

  • Conjuntos de datos relacionados con la visión: ['DatasetFolder', 'ImageFolder', 'MNIST', 'FashionMNIST', 'Flowers', 'Cifar10', 'Cifar100', 'VOC2012']
  • Conjuntos de datos relacionados con el lenguaje natural: ['Conll05st', 'Imdb', 'Imikolov', 'Movielens', 'UCIHousing', 'WMT14', 'WMT16']

Sin embargo, en escenarios de uso reales, a menudo necesitamos utilizar nuestros propios conjuntos de datos. Por ejemplo, en este experimento utilizamos nuestro propio conjunto de datos de melocotón.

Paddle proporciona a los usuarios la clase base paddle.io.Dataset, lo que les permite implementar rápidamente la definición de conjuntos de datos a través de la integración de clases.

El método de carga de PaddlePaddle para conjuntos de datos es utilizar uniformemente Dataset (definición de conjunto de datos) + DataLoader (carga de conjunto de datos multiproceso).

Definición de conjunto de datos-Conjunto de datos
  • Primero definimos el conjunto de datos;
  • La definición del conjunto de datos implementa principalmente una nueva clase de conjunto de datos, heredando la clase principal paddle.io.Dataset;
  • Luego implemente los siguientes dos métodos abstractos en la clase principal, "__getitem__" y "__len__":


 
clase  PeachDataset(Conjunto de datos):
    """
    Paso 1: heredar la clase paddle.io.Dataset
    """
    def  __init__ ( self , modo= 'tren' ):
        """
        Paso 2: implementar el constructor, definir el método de lectura de datos y dividir los conjuntos de datos de entrenamiento, verificación y prueba.
        """
        súper (PeachDataset,  self ). __inicio__ ()
        train_image_dir = train_parameters[ 'train_image_dir' ] #Ruta del conjunto de entrenamiento
        eval_image_dir = train_parameters[ 'eval_image_dir' ]
        test_image_dir = train_parameters[ 'test_image_dir' ]        
        
        ''' ''' 
        #transformar función de mejora de datos, aquí solo se transforma el método de apertura de la imagen            
        #Aquí, use Transpose() para cambiar el método de apertura de la imagen (ancho, alto,  número de canales) al método de lectura PaddlePaddle (número de canales, ancho, alto)
        media = [ 127,5 127,5 127,5 # Normalización, media
        std = [ 127.5 127.5 127.5 # Normalización, diferencia de etiqueta 
        transform_train = T.Compose([T.ColorJitter ( 0.4 0.4 0.4 0.4 )
                                     ,T.Resize(tamaño e=( 224 , 224 )) 
                                     ,T.Transponer( )
                                     ,T.Normalizar( media, estándar)
                                    ])
        transform_eval = T.Compose([T.Resize(tamaño= ( 224 , 224 )) 
                                    ,T.Transponer()
                                    ,T.Normalizar(media , estándar)
                                    ])
        transform_test = T.Compose([T.Resize(tamaño= ( 224 , 224 )) 
                                    ,T.Transponer()
                                    ,T.Normalizar(media , estándar)
                                    ])
        
        '''         
        # 参考API: https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/Overview_cn.html#about-transforms
        #Aquí, use Transpose() para cambiar el método de apertura de la imagen (ancho, alto,  número de canales) al método de lectura PaddlePaddle (número de canales, ancho, alto)
        # ColorJitter ajusta aleatoriamente el brillo, el contraste, la saturación y el tono de una imagen.
        # hflip Voltea la imagen de entrada horizontalmente.        
        #Normalizar la normalización. media = [127,5, 127,5,  127,5], estándar = [127,5, 127,5, 127,5]
        # RandomHorizontalFlip realiza un giro horizontal de la imagen según la probabilidad.
        # RandomVerticalFlip Realiza un giro vertical de la imagen según la probabilidad.
        media = [127.5, 127.5, 127.5] # Normalización, media
        std = [127.5, 127.5, 127.5] # Normalización, diferencia de etiqueta 
        transform_train = T.Compose([T.Resize(tamaño =(224,224)), 
                                     T.Transponer() ,                                
                                     T.ColorJitter (0,4, 0,4, 0,4, 0,4),
                                     T.RandomHoriz ontalFlip(prob=0.5,),
                                     T.RandomVerti calFlip(prob=0.5,),
                                     T.Normalizar(media , estándar)])
        transform_eval = T.Compose([T.Resize(tamaño= (224,224)), T.Transpose()])
        transform_test = T.Compose([T.Resize(tamaño= (224,224)), T.Transpose()])
        ''' 
        #Fei Paddle recomienda usar paddle.io.DataLoader  para completar la carga de datos y generar un iterador que pueda cargar datos.
        #API instalada  :https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/io/DataLoader_cn.html#cn-api-fluid-io-dataloader
        #Carga el conjunto de entrenamiento, train_data_folder es un iterador
        参考API: https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/datasets/DatasetFolder_cn.html#datasetfolder
        train_data_folder = Carpeta del conjunto de datos (train_im age_dir, transform=transform_train)
        #Carga el conjunto de validación, eval_data_folder es un iterador
        eval_data_folder = Carpeta del conjunto de datos (eval_image e_dir, transform=transform_eval)
        #Cargue el conjunto de prueba, test_data_folder es un iterador
        test_data_folder = DatasetFolder(test_imag e_dir, transform=transform_test)
        self .modo = modo
        si  self .mode ==  'entrenar' :
            self .data = carpeta_datos_tren
        elif  self .modo ==  'eval' :
            self .data = eval_data_folder
        elif  self .modo ==  'prueba' :
            self .data = carpeta_datos_prueba
    #Devolver datos y etiquetas correspondientes durante cada iteración
    def  __getitem__( self , índice):
        """
        Paso 3: implementar el método __getitem__, definir cómo obtener datos al especificar el índice y devolver un solo dato (datos de entrenamiento, etiqueta correspondiente)
        """
        datos = np.array( self .data[index][ 0 ]).astype( 'float32' )
        etiqueta = np.array([ self .data[index][ 1 ]]).astype( 'int64' )
        datos de retorno  , etiqueta
    # Devuelve el número total de todo el conjunto de datos.
    def  __len__( yo ):
        """
        Paso 4: implementar el método __len__ y devolver el número total de conjuntos de datos
        """
        devolver  len ( self .data)
#Utilice la clase personalizada PeachDataset para cargar su propio conjunto de datos
train_dataset = PeachDataset (modo = 'tren' )
val_dataset = PeachDataset (modo = 'eval' )
test_dataset = PeachDataset (modo = 'prueba' )
Carga de conjunto de datos-DataLoader

DataLoader devuelve un iterador. Cada elemento de los datos devueltos por el iterador es un tensor. El método de llamada es el siguiente:

class paddle.io.DataLoader(dataset, feed_list=None, places=None, return_list=False, batch_sampler=None, batch_size=1, shuffle=False, drop_last=False, collate_fn=None, num_workers=0, use_buffer_reader=True, use_shared_memory=True, timeout=0, worker_init_fn=None) 

DataLoader itera un conjunto de datos determinado una vez (el orden lo proporciona Batch_sampler).
DataLoader admite modos de carga de datos de proceso único y multiproceso . Cuando num_workers es mayor que 0, se utilizará el modo multiproceso para cargar datos de forma asincrónica.

Introducción detallada https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/io/DataLoader_cn.html

El siguiente código muestra cómo utilizar DataLoader

# Código de muestra del cargador de datos
#Cargar biblioteca
importar  cv2  como  cv  #Usar OpenCV
print ( "el número de versión de opencv es:"  + cv.__version__)  #Ver número de versión
# De hecho, esta biblioteca de clases debe instalarse antes de usar OpenCV, pero debido a que se usa AI-Studio  , el sistema ya está preinstalado para los desarrolladores: opencv-python 4.1.1.26       
desde  matplotlib  importe  pyplot  como  plt  #Dibuje en esta página
%matplotlib en línea 
# Construir un cargador de datos
test_loader = Cargador de datos(test_dataset,
                    tamaño_lote = 2 ,
                    barajar = Verdadero ,
                    drop_last= Verdadero ,
                    núm_trabajadores= 2 )
El número de versión de opencv es: 4.1.1 
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/__init__.py:107: Advertencia de desuso: uso o importación del ABC desde 'colecciones' en lugar de desde 'collections.abc' está en desuso y en 3.8 dejará de funcionar  desde la importación de colecciones MutableMapping  /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/rcsetup.py:20: Advertencia de desuso: uso o importación el ABC de 'colecciones' en lugar de 'collections.abc' está obsoleto y en 3.8 dejará de funcionar  desde la importación de colecciones Iterable, Mapping /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/colors.py:53: Advertencia de desuso: uso o importación del ABC desde 'colecciones' en lugar de desde 'collections.abc' está en desuso y en 3.8 dejará de funcionar  desde la importación de colecciones.
# Utilice DataLoader para recorrer el conjunto de datos
para  mini_batch  en  test_loader():  # Obtener mini_batch de DataLoader 
    print ( "El tipo de mini_batch es: "  +  str ( tipo (mini_batch)))
    pic_list = mini_batch[ 0 #Datos de imagen
    lista_etiqueta = mini_lote[ 1 #etiqueta
    print ( "El tamaño de mini_batch es: "  +  str ( len (pic_list)))
    # Convierta la visualización de la imagen al formato numpy y establezca los números internos en tipos enteros
    pic_1 = lista_pic[ 0 ]
    pic_2 = lista_pic[ 1 ]
    arr1 = np.asarray(pic_1, dtype=np.float64) 
    imprimir (arr1.forma)
    arr2 = np.asarray(pic_2, dtype=np.float64)    
    imprimir (arr2.forma)
    break  #Dado que este es un ejemplo, solo se saca el primer mini_batch
    
El tipo de mini_batch es: <clase 'lista'>  El tamaño de mini_batch es: 2  (3, 224, 224)  (3, 224, 224)
# Mostrar los datos de la imagen obtenida.
r = arreglo1[ 0 ]
g = arreglo1[ 1 ]
b = arreglo1[ 2 ]
img = cv.merge([r,g,b])
plt.imshow(img)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/cbook/__init__.py:2349: Advertencia de desuso: usar o importar el ABC de 'colecciones' en lugar de 'colecciones'. abc' está en desuso y en 3.8 dejará de funcionar  si isinstance(obj, collections.Iterator):  /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/cbook/__init__ .py:2366: Advertencia de desuso: el uso o la importación de ABC desde 'colecciones' en lugar de 'collections.abc' está en desuso, y en 3.8 dejará de funcionar y devolverá la  lista (datos) si es una instancia (datos, colecciones.MappingView) más datos  Recortar los datos de entrada al rango válido para imshow con datos RGB ([0..1] para flotantes o [0..255] para enteros).
<matplotlib.image.AxesImage en 0x7fb4678d8350>

Como se muestra en la imagen de arriba, la imagen obtenida en este momento no es como se ve la imagen original. Esto se debe a que en la clase PeachDataset, el método de transformación se usa en los datos de la imagen, es decir, se realizan algunos cambios en la imagen. Para ilustrar este punto, se puede utilizar el siguiente método a modo de comparación.

La siguiente imagen muestra los cambios que se han producido:

Para comparación y explicación, modifique el código en la clase PeachDataset y agregue un símbolo de comentario. El código es el siguiente: El
propósito de esto es cambiar el tamaño de la imagen y cumplir con los requisitos de paddle, y evitar cambios de datos causados por normalización.

transform_test = T.Compose([ T.Resize(size=(224,224)) ,T.Transpose() #,T.Normalize(mean, std) ]) 

Después de modificar el código, abra los comentarios del código a continuación, reinicie el ejecutor y haga clic en "Ejecutar -> Ejecutar las celdas actualmente seleccionadas y anteriores" en la esquina superior derecha.

Puede ver las imágenes en el conjunto de datos original, como se muestra a continuación:

Después de ver los datos, no olvide abrir los comentarios en la clase PeachDataset. y agregue comentarios al código a continuación.

'''
# Mostrar los datos de la imagen obtenida.
arr1 = arr1 / 255 # Cambia cada píxel entre 0-1
r = arreglo1[0]
g = arreglo1[1]
b = arreglo1[2]
img = cv.merge([r,g,b])
plt.imshow(img)
'''

4.6 Construir un modelo de clasificación

A continuación, crearemos un modelo de clasificación de imágenes que se puede utilizar para clasificar el conjunto de datos de melocotón.

¿Cómo construir un modelo de clasificación?

  • Podemos construir modelos de red DNN, modelos de red CNN u otros modelos de red de acuerdo con nuestras propias ideas, pero esto requiere que nuestra capacidad de investigación de algoritmos sea muy alta;
  • Podemos usar modelos de red clásicos y maduros, como VGG, ResNet, etc., usar el marco paddle para construir estos modelos para nuestro uso.

En este experimento, utilizamos la red residual de 50 capas ResNet como nuestro modelo de clasificación.

Además, en este experimento, para aumentar el efecto de nuestro modelo, todavía utilizamos el método de aprendizaje por transferencia. Entonces, ¿por qué utilizar el aprendizaje por transferencia? ¿Cómo utilizar el aprendizaje por transferencia?

4.6.1 Transferir aprendizaje

En el desarrollo de ingeniería real, pocas personas entrenan una red neuronal completa desde cero.

¿Por qué?

Debido a que nuestros conjuntos de datos generalmente no son muy grandes, la capacidad de generalización del modelo entrenado a menudo no es sólida. Y la formación requiere mucho tiempo.

¿Cómo hacerlo?

Un método común es encontrar un gran conjunto de datos públicos (como ImageNet, que contiene 1,2 millones de imágenes y 1000 categorías) y primero entrenar un modelo de red neuronal A en este conjunto de datos (este A generalmente ha sido entrenado por otros), luego use esta A como punto de partida, ajústela y luego entrene nuestro propio conjunto de datos. Esta A también se denomina  "modelo de preentrenamiento" .

Este es   un método de  aprendizaje por transferencia , también llamado ajuste fino .

Entonces, ¿cuál es la base teórica del ajuste fino? Es decir: ¿por qué podemos realizar ajustes en función de modelos entrenados por otros? Esto requiere un análisis de los principios estructurales de las redes neuronales convolucionales.

  • Para redes convolucionales: las primeras capas aprenden características generales, como los bordes de las imágenes; a medida que las capas de red se profundizan, las redes posteriores se centran más en aprender características específicas, como partes del cuerpo, caras y otras características combinadas.
  • Generalmente se considera que la capa final completamente conectada captura información relevante para resolver la tarea correspondiente. Por ejemplo, la capa completamente conectada de AlexNet puede indicar a qué categoría de 1000 categorías de objetos pertenecen las características extraídas.
  • Por ejemplo, en el proceso de reconocimiento facial, varias capas primarias de convolución extraerán características generales como líneas rectas y curvas; varias capas intermedias de convolución aprenderán más partes específicas como ojos y narices, y las convoluciones de alto nivel pueden aprender características combinadas. Por lo tanto, se considera que se trata de una imagen de rostro. -Esta característica de la red neuronal convolucional es la base teórica de nuestro ajuste fino.

Algunos estudiantes pueden preguntar: ¿Por qué no simplemente utilizamos el modelo entrenado por otros en un gran conjunto de datos (como ImageNet), pero también lo ajustamos?

  • 因为别人训练好的模型,可能并不是完全适用于我们自己的任务。可能别人的网络能做比我们的任务更多的事情;可能别人的网络比较复杂,我们的任务比较简单。 -举一个例子,假如我们想训练一个猫狗图像二分类的网络,我们首先会想到直接使用别人在 ImageNet上训练好的网络模型。但是 ImageNet 有 1000 个类别,而我们只需要2 个类别。此时,就需要针对我们自己的任务,来进行微调了,比如可以固定原始网络的相关层,修改网络的输出层,以使结果更符合我们的需要。

在PaddlePaddle2.0中,使用预训练模型只需要设定模型参数pretained=True。

4.6.2 搭建模型

使用飞桨,很便利的一点是:飞桨框架内置了许多模型,真正的一行代码实现深度学习模型。

目前,飞桨框架内置的模型都是CV领域的模型,在paddle.vision.models目录下,具体包含如下的模型:

飞桨框架内置模型: ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152', 'VGG', 'vgg11', 'vgg13', 'vgg16', 'vgg19', 'MobileNetV1', 'mobilenet_v1', 'MobileNetV2', 'mobilenet_v2', 'LeNet']

比如我们本次使用的resnet50,就已经有内置模型了。


 
# 使用内置的模型,这边可以选择多种不同网络,这里选了resnet50网络
#pretrained (bool,可选) - 是否加载在imagenet数据集上的预训练权重
modelo = paddle.vision.models.resnet18 (preentrenado = Verdadero , num_classes = 4 )    
#Pruebe diferentes estructuras de red: MobileNetV2
Documento de referencia de MobileNetV2: https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/models/MobileNetV2_cn.html
# modelo = paddle.vision.models.mobilenet_v2(preentrenado =True, num_classes=4)    
#Utilice paddle.Model para completar la encapsulación del modelo y combinar la estructura de la red en una clase que pueda utilizar rápidamente API de alto nivel para entrenamiento y predicción.
modelo = paleta.Modelo(modelo)
100%|██████████| 69183/69183 [00:01<00:00, 47292.60it/s]  /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py: 1301: Advertencia del usuario: omita la carga de fc.weight. fc.weight recibe una forma [512, 1000], pero la forma esperada es [512, 4].  advertencias.warn(("Omitir carga para {}. ".format(key) + str(err)))  /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/ fluid/dygraph/layers.py:1301: Advertencia del usuario: omita la carga de fc.bias. fc.bias recibe una forma [1000], pero la forma esperada es [4].  advertencias.warn(("Omitir carga para {}. ".format(key) + str(err)))

Utilice model.summary para observar las condiciones de la red

Documentación de referencia: https://github.com/PaddlePaddle/Paddle/blob/release/2.1/python/paddle/hapi/model.py#L883

Existe una ligera diferencia entre la documentación de la API y el código real.

# 以下为源代码 def summary(self, input_size=None, dtype=None): """Prints a string summary of the network. Args: input_size (tuple|InputSpec|list[tuple|InputSpec], optional): size of input tensor. if not set, input_size will get from ``self._inputs`` if network only have one input, input_size can be tuple or InputSpec. if model have multiple input, input_size must be a list which contain every input's shape. Default: None. dtypes (str, optional): if dtypes is None, 'float32' will be used, Default: None. Returns: Dict: a summary of the network including total params and total trainable params. Examples: .. code-block:: python import paddle from paddle.static import InputSpec input = InputSpec([None, 1, 28, 28], 'float32', 'image') label = InputSpec([None, 1], 'int64', 'label') model = paddle.Model(paddle.vision.models.LeNet(), input, label) optim = paddle.optimizer.Adam( learning_rate=0.001, parameters=model.parameters()) model.prepare( optim, paddle.nn.CrossEntropyLoss()) params_info = model.summary() print(params_info) """ assert (input_size is not None or self._inputs is not None ), "'input_size' or 'self._input' must be set" if input_size is not None: _input_size = input_size else: _input_size = self._inputs return summary(self.network, _input_size, dtype) 

parámetro:

  • input_size (tupla|InputSpec|list): el tamaño del tensor de entrada. Si la red tiene solo una entrada, entonces este valor debe establecerse en tupla o InputSpec. Si el modelo tiene múltiples entradas. Luego, el valor debe establecerse en list[tuple|InputSpec], incluida la forma de cada entrada. Si no se establece este valor, se utilizará self._inputs como entrada. Valor predeterminado: Ninguno.
  • dtypes (cadena, opcional): tipo de datos del tensor de entrada; si no se proporciona, se usa float32 de forma predeterminada. Valor predeterminado: Ninguno.

Devuelve: diccionario. Contiene el tamaño de todos los parámetros de la red y el tamaño de todos los parámetros entrenables.

# Utilice el resumen para observar la información de la red.
model.summary(input_size=( 1 3 224 224 ), dtype= 'float32'
-------------------------------------------------- -----------------------  Capa (tipo) Forma de entrada Forma de salida Parám #  =========== ==================================================== ==================  Conv2D-1 [[1, 3, 224, 224]] [1, 64, 112, 112] 9,408  BatchNorm2D-1 [[1, 64 , 112, 112]] [1, 64, 112, 112] 256  ReLU-1 [[1, 64, 112, 112]] [1, 64, 112, 112] 0  MaxPool2D-1 [[1, 64, 112 , 112]] [1, 64, 56, 56] 0  Conv2D-2 [[1, 64, 56, 56]] [1, 64, 56, 56] 36,864  BatchNorm2D-2 [[1, 64, 56, 56 ]] [1, 64, 56, 56] 256  ReLU-2 [[1, 64, 56, 56 ]] [1, 64, 56, 56] 0  Conv2D-3 [[1, 64, 56, 56]] [1, 64, 56, 56] 36.864 BatchNorm2D  -3 [[1, 64, 56, 56]] [1, 64, 56, 56] 256  BasicBlock- 1 [[1, 64, 56, 56]] [1, 64, 56, 56] 0  Conv2D-4 [[1, 64, 56, 56]] [1, 64, 56, 56] 36.864 BatchNorm2D  -4 [ [1, 64, 56, 56]] [1, 64, 56, 56] 256  ReLU-3 [[1, 64, 56, 56]] [1, 64, 56, 56] 0  Conv2D-5 [[1 , 64, 56, 56]] [1, 64, 56, 56] 36.864  BatchNorm2D-5 [[1, 64 , 56, 56]] [1, 64, 56, 56] 256  BasicBlock-2 [[1, 64, 56, 56]] [1, 64, 56, 56] 0  Conv2D-7 [[1, 64 , 56, 56]] [1, 128, 28, 28] 73,728  BatchNorm2D-7 [[1, 128, 28, 28]] [1, 128, 28, 28] 512 ReLU-4 [[1, 128, 28, 28]] [1, 128, 28, 28]  0  Conv2D- 8 [[1, 128, 28, 28]] [1, 128, 28, 28] 147.456  BatchNorm2D-8 [[1, 128, 28, 28]] [1, 128, 28, 28] 512  Conv2D-6 [ [1, 64, 56, 56]] [1, 128, 28, 28] 8.192  BatchNorm2D-6 [[1, 128, 28, 28]] [1, 128, 28, 28] 512  BasicBlock-3 [[1 , 64, 56, 56]] [1, 128, 28, 28] 0  ReLU-5 [[1, 128 , 28, 28]] [1, 128, 28, 28] 0 
     Conv2D-9        [[1, 128, 28, 28]]    [1, 128, 28, 28]       147,456     BatchNorm2D-9 [[1, 128, 28, 28]] [1, 128, 28, 28] 512 Conv2D-10 [[1, 128, 28, 28]] [1, 128, 28, 28]  147,456  BatchNorm2D- 10 [[1, 128, 28, 28]] [1, 128, 28, 28] 512  BasicBlock-4 [[1, 128, 28, 28]] [1, 128, 28, 28] 0 Conv2D  -12 [ [1, 128, 28, 28]] [1, 256, 14, 14] 294.912  BatchNorm2D-12 [[1, 256, 14, 14]] [1, 256, 14, 14] 1.024  ReLU-6 [[1 , 256, 14, 14]] [1, 256, 14, 14] 0  Conv2D-13 [[1, 256, 14, 14]] [1, 256, 14, 14] 589.824  BatchNorm2D-13 [[1, 256 , 14, 14]] [1, 256, 14, 14] 1,024  Conv2D-11 [[1, 128, 28, 28]] [1, 256, 14, 14] 32.768  BatchNorm2D-11 [[1, 256 , 14, 14]] [1, 256, 14, 14] 1,024  BasicBlock-5 [[1, 128, 28, 28]] [1, 256, 14, 14] 0  Conv2D- 14 [[1, 256, 14, 14]] [1, 256, 14, 14] 589.824  BatchNorm2D-14 [[1, 256, 14, 14]] [1, 256, 14, 14] 1.024  ReLU-7 [ [1, 256, 14, 14]] [1, 256, 14, 14] 0  Conv2D-15 [[1, 256, 14, 14]] [1, 256, 14, 14] 589.824  BatchNorm2D-15 [[1 , 256, 14, 14]] [1, 256, 14, 14] 1.024  BasicBlock-6 [[1, 256, 14, 14]] [1, 256, 14, 14] 0 Conv2D-17  [[1, 256 , 14, 14]] [1, 512, 7, 7] 1,179,648  BatchNorm2D-17 [[1, 512, 7, 7]] [1, 512, 7, 7] 2,048  ReLU-9 [[1, 512 , 7, 7]] [1, 512, 7, 7] 0 
      ReLU-8          [[1, 512, 7, 7]]      [1, 512, 7, 7]           0        Conv2D-18 [[1, 512, 7, 7]] [1, 512, 7, 7] 2,359,296  BatchNorm2D-18 [[1, 512, 7, 7]] [1, 512, 7, 7] 2,048  Conv2D- 16 [[1, 256, 14, 14]] [1, 512, 7, 7] 131,072  BatchNorm2D-16 [[1, 512, 7, 7]] [1, 512, 7, 7] 2,048  BasicBlock-7 [ [1, 256, 14, 14]] [1, 512, 7, 7] 0  Conv2D-19 [[1, 512, 7, 7]] [1, 512, 7, 7] 2,359,296  BatchNorm2D-19 [[1 , 512, 7, 7]] [1, 512, 7, 7] 2,048  BatchNorm2D-20 [[1, 512 , 7, 7]] [1, 512, 7, 7] 2,048  Conv2D-20 [[1, 512, 7, 7]] [1, 512, 7, 7] 2,359,296  Tamaño total estimado (MB): 100,30 BasicBlock-8 [[1, 512, 7, 7]] [1, 512, 7, 7] 0  AdaptiveAvgPool2D-1 [[1, 512, 7, 7]] [1, 512, 1, 1] 0  Lineal- 1 [[1, 512]] [1, 4] 2,052  ===================================== ===========================================  Parámetros totales: 11,188,164  Parámetros entrenables: 11.168.964  Parámetros no entrenables: 19.200  ------------------------------------------- ------------------------------------  Tamaño de entrada (MB): 0,57  Tamaño de paso hacia adelante/atrás (MB ): 57.04  Tamaño de parámetros (MB): 42.68  ---------------------------------------- ---------------------------------------

{'total_params': 11188164, 'trainable_params': 11168964}
# Llame al módulo VisualDL de Paddle y guarde la información en el directorio.
#log_dir (str): la ruta donde se guarda el registro de salida.
devolución de llamada = paddle.callbacks.VisualDL (log_dir = 'visualdl_log_dir' )

4.6.3 Configuración de entrenamiento

Configuración del optimizador

Después de encapsular el modelo con paddle.Model, debe configurar el modelo antes del entrenamiento. Utilice la interfaz Model.prepare para realizar preparativos de configuración avanzados para el entrenamiento, incluida la configuración del optimizador del modelo, el método de cálculo de pérdidas, el método de cálculo de precisión, etc.

 
  • El parámetro de tasa de aprendizaje (learning_rate) es importante.
  • Si la tasa de precisión fluctúa durante el proceso de capacitación, de mayor a menor, puede intentar reducir la tasa de aprendizaje.
#Utilice la interfaz Model.prepare para configurar y prepararse para la capacitación con anticipación, incluida la configuración del optimizador del modelo, el método de cálculo de pérdidas, el método de cálculo de precisión, etc.
# Documentación de la API del optimizador:  https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/optimizer/Overview_cn.html#paddle-optimizer
# Estrategia de disminución de la tasa de aprendizaje
# Documentación API de la estrategia de disminución de la tasa de aprendizaje  : https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/optimizer/Overview_cn.html#about-lr
planificador_StepDecay = paddle.optimizer.lr.StepDeca y (tasa de aprendizaje = 0,1 , tamaño de paso = 50 , gamma = 0,9 , detallado = Falso )
planificador_PiezasDecay = paddle.optimizer.lr.Pie cewiseDecay (límites = [ 100 1000 4000 5000 6000 ], valores = [ 0,1 0,5 0,01 0,005 ], detallado = Falso )
# Intente utilizar SGD, métodos Momentum
sgd = paleta.optimizador.SGD(
                learning_rate=scheduler_StepDecay, 
                parámetros=modelo.parámetros())
adán = paddle.optimizador.Adam( 
                tasa_de_aprendizaje= 0.01 #Ajustar parámetros
                parámetros=modelo.parámetros())
model.prepare(optimizador= adán,  # adán
              pérdida=paddle.nn.CrossEntropyLoss(),
              métricas=paddle.metric.Accuracy())
Configuración de recursos informáticos

Establezca los recursos informáticos específicos utilizados para este cálculo.
Primero, puede ver los dispositivos informáticos que está utilizando actualmente. (Este paso no es necesario).
Luego, configure el dispositivo informático utilizado para esta capacitación.

# Verifique el dispositivo informático actual
dispositivo = paleta.dispositivo.get_device()
imprimir (dispositivo)
# Utilice el entrenamiento de GPU
dispositivo = paddle.set_device( 'gpu' # o 'cpu'
imprimir (dispositivo)

4.6.4 Modelo de entrenamiento

Después de completar los preparativos preliminares para el entrenamiento del modelo, llamamos formalmente a la interfaz fit() para iniciar el proceso de entrenamiento. Necesitamos especificar al menos los siguientes tres parámetros clave: conjunto de datos de entrenamiento, rondas de entrenamiento y tamaño del lote de datos de entrenamiento único.


 

Descripción del tiempo de entrenamiento:

  • Ejecutar 10 épocas en la CPU lleva aproximadamente 1,5 horas;
  • Ejecutar 10 épocas en la GPU lleva unos 30 minutos;
# documentación de API de ajuste:  https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/Model_cn.html#fit-train-data-none-eval-data-none-batch-size-1 -epochs-1-eval-freq-1-log-freq-10-save-dir-none-save-freq-1-verbose-2-drop-last-false-shuffle-true-num-workers-0-callbacks -ninguno
# Inicie el entrenamiento del modelo, especifique el conjunto de datos de entrenamiento, configure las rondas de entrenamiento, establezca el tamaño del lote para cada cálculo del conjunto de datos y establezca el formato de registro
#epochs: número total de épocas de entrenamiento
#batch_size: número de muestras en un lote
#Si se le solicita memoria insuficiente, puede intentar reducir el tamaño del lote
#verbose: visualización del registro, 0 significa no generar información de registro en el flujo de salida estándar, 1 significa generar registros de la barra de progreso, 2 significa generar una línea de registros para cada época; 1 significa generar registros de la barra de progreso, 2 significa generar una línea de registros para cada época.
modelo.fit(train_dataset,
          conjunto_datosval,
          épocas = 1 ,
          tamaño_lote = 2 ,
          devoluciones de llamada = devolución de llamada,
          detallado = 1 )
El valor de pérdida impreso en el registro es el paso actual y la métrica es el valor promedio de los pasos anteriores.  Época 1/1
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:77: Advertencia de desuso: usar o importar el ABC de 'colecciones' en lugar de ' collections.abc' está en desuso y en 3.8 dejará de funcionar  return (isinstance(seq, collections.Sequence) y  /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/ nn/layer/norm.py:641: Advertencia del usuario: Cuando entrenamos, ahora siempre realizamos un seguimiento de la media y la varianza globales.  "Cuando entrenamos, ahora siempre realizamos un seguimiento de la media y la varianza globales.")
paso 2904/2904 [==============================] - pérdida: 0,0549 - acc: 0,5786 - 62 ms/paso  Inicio de evaluación ...  paso 415/415 [==============================] - pérdida: 0.0867 - acc: 0.7819 - 23ms/ paso  Evaluar muestras: 830

4.6.5 Evaluación y preservación del modelo

Una vez completado el entrenamiento del modelo, obtenemos un modelo entrenado, pero aún debemos evaluar en detalle qué tan efectivo es este modelo.

¿Qué es la evaluación de modelos?

  • La evaluación del modelo en realidad significa: usar los datos de prueba que reservamos en el modelo resultante para hacer predicciones reales y verificar en función de las etiquetas para ver cómo se desempeña el modelo en el conjunto de prueba.
  • La implementación del código de evaluación del modelo también es muy simple en la API de alto nivel. Después de definir de antemano el conjunto de datos para la evaluación, podemos usar la interfaz model.evaluate para evaluar el modelo entrenado; una vez completada la operación, preparar Se utilizará la interfaz Configurar pérdida y métrica para calcular y devolver indicadores relacionados.

Indicadores de evaluación para este experimento:

En este experimento, el índice de evaluación que utilizamos es  precisión, o acc para abreviar.

Estudiantes, comparen entre sí, ¿cómo son los resultados de la evaluación de su modelo? ¿Cuál es el valor de su cuenta?

Si se realiza una mejora razonable de los datos en este experimento, la precisión puede ser muy alta. Trabaje duro para aumentar el valor de acc por encima del 90 %.

#Evaluación del modelo
#Puede utilizar la interfaz model.evaluate para evaluar el modelo entrenado; una vez completada la operación, los  indicadores relevantes se calcularán y devolverán de acuerdo con la pérdida y la métrica configuradas en la interfaz de preparación.
#Documento de referencia del indicador de evaluación  : https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/Model_cn.html#evaluate-eval-data-batch-size-1-log-freq-10- detallado-2-núm-trabajadores-0-devoluciones de llamada-ninguno
model.evaluate(test_dataset, detallado= 1 )
Inicio de evaluación...  paso 67/67 [==============================] - pérdida: 0.0052 - acc: 0.7910 - 13 ms/paso  Muestras de evaluación: 67
{'pérdida': [0.0051732725], 'cuenta': 0.7910447761194029}
#Guardar modelo
model.save( './saved_model/saved_model' )   # guardar para entrenamiento

4.6.6 Predicción del modelo

En los pasos anteriores, hemos completado el entrenamiento del modelo, la evaluación del modelo y el guardado del modelo; si el modelo funciona bien después de la evaluación, se puede utilizar. Podemos utilizar este modelo guardado para hacer predicciones.

¿Cómo hacer predicciones de modelos?

  • La interfaz model.predict se proporciona en la API de alto nivel de Flying Paddle para facilitar a los usuarios la predicción del modelo entrenado;
  • Solo necesitamos colocar los "datos predichos + modelo guardado" en la interfaz model.predict para el cálculo, y la interfaz devolverá los resultados de predicción calculados por el modelo, completando así nuestra tarea.
#modelo predictivo
resultados = modelo.predict(test_dataset)
Predecir comienzo...  paso 67/67 [==============================] - 12 ms/paso  Predecir muestras: 67
# Observar resultado
imprimir ( escribir (resultados))  #lista
imprimir ( len (resultados))  #len == 1
#Imprimir los resultados línea por línea
para  i  en  resultados [ 0 ]:
    imprimir (yo)
<clase 'lista'>  1  [[ 0.4494054 1.8589294 -2.709025 -0.98785317]]  [[ 0.80108535 2.0312922 -2.3985271 -1.667168 ]] [[-0.487098 2.5169828  -3.8 384209 0,09941977]]  [[ 1,1755923 1,9356494 -2,7956083 -1,824508 ]] [  [ 0,6587918 1.5227697 -1.9370861 -1.2466118]]  [[ 1.9423198 1.8514836 -2.0579038 -3.0512297]]  [[-0.12070499 2.1658874 -3.2705145 -0.2214822 ]] [[ 2,30185 1,9300838 -2,6378424 -3,3231502]  ] [[ 1,7931688  1,7564571 -2,713827 -2,3772974]] [  [ 1,018136 1,9348547 -2,1037087 -2,093875 ]]  [[ 1,2455556 1,7356219 -2,3573794 -1,9229555]]  [[ 1,3166553 2,0454793 -2,1393437 -2,51 54655]] [  [ 2.2485528 ​​2.5826378 -2.3228188 -4.113832 ]] [[ 0,6856951 1,9657588 -2,340539 -1,5627216]]  [[ 0,34038985 2,5555618 -3,4037375 -1,1876322 ]]  [[ 1,7155951 2,2181606 -2,2069125 - 3,0874062]] [[-0,9589406 2,3568041 -3,914858  0,8861027]] [[-2,2687616 3,561953 -6,1434994  2,204158 ]]  [[-0.8965972 2.812673 -4.498936 0.67248255]]  [[-1.7266133 3.0567627 -5.3219457 1.823607 ]] [[  -1.2236824 2.9153998 -5.2624416 1. 1972692]] [[-1.6313993  2.393093 -4.390437 1.8520648]] [[  -2.261466 3.1709478 -5.7391357 2.475055 ]]  [[-2.0998657 2.7529852 -5.1272326 2.396462 ]]  [[-1.6497151 2.9010382 -5.0573497 1.7648369]]  [[-2.6754675 2.9362612 -5.56551 2.9 678605]] [[-1.073315 2.3352654 -4.07773 1.1857122]]  [[-0.88414484 2.4533503 -4.0443926 0.775055 ]] [[-1.7560171  3.3508494 -5.375548 1.40 13046]] [[-2.615417  4.013784 -6.8865647 2.4297483]] [[-1.829337 3.1974657 -5.3266735  1.5116838]]  [[-1.1488906 2.4435222 -4.151718 1.1106087]]  [[-2.672726 3.7604275 -6.60363 2.6530373]] [[  -1.3436769 2.810868 -4.783174 1.33638 45]] [[-7.1727552  -4.178957 6.645717 1.3258969]] [[  -10.802859 -8.898961 13.038587 0.8829916]]  [[-6.100724 -3.6756551 5.3887143 2.429795 ]]  [[-6.956199 -4.8285522 7.192293 1.4987972]] [[  -6.806343 -4.737133 7.0949545 1.9803 424]] [[-10.631139 -8.797351 12.851841 0.9559243]]  [[-9.890509 -7.7998743 11.965744 1.0906614]] [[  -6.637445 -4.125729 6.246958 2.3932 679]] [[-4.850948  -3.7300088 5.50579 -0.28020984]] [[  -5.89312 -3.9382315 5.5570445 1.115171 ] ]  [[-9.489717 -7.5113807 11.062157 1.4899993]]  [[-4.060526 -4.7304277 7.44195 -1.7170902]] [[  -6.123046 -5.145837 7.891695 -0.3783 728]] [[  -6.7471647 -5.1568007 7.3376994 -0.14631017]] [  [-5.768033 -6.0288777 9.360904 -1.9037125]]  [[-7.037687 -5.0647235 7.345336 1.0650041]] [[  -6.3333025 -4.003666 6.096233 2.0686429]]  [[-8.165305 -4.097 1665 5.59594 4.208836 ]] [[-6.3591156 -0.0809775 -2.1494312 5.8446784]]  [[-5.998541 -0.3071279 -1.633659 5.444659 ]] [[  -5.982375 -0.13737446 -2.0219755 5.5 88227 ]] [[  -6.2784123 -0.28474385 -1.8074901 5.720227 ]] [  [-5.9097333 0.21499354 - 2.4844441 5.4800773 ]]  [[-5.815046 0.34615326 -2.749436 5.516311 ]]  [[-6.144201 0.20839332 -2.5092714 5.6507225 ]] [[  -6.217258 -0,11974069 -2,2099724 5,8341565 ]]  [[-6,0395765 0,08458082 -2,2998967 5,641852 ]] [  [-6,292765 - 0,22815469 -1,8958219 5,7871137 ]]  [[-5,9349203 0,03097157 -2,209548 5,578063 ]]  [[-4,8454432 0,6837326 -2,8405902 4,569208 ]] [[  -5.5436296 -0.4322207 -1.2610528 5.0055714]] [[-5.8578863 -0.32924837 -1.6607574 5.3581743 ]]  [[-5.7073674 0.08094054 -2.3335297 5.431057 ]]
# Procesar el resultado con softmax y convertirlo en un valor de probabilidad
x = paddle.to_tensor(resultados[ 0 ])
m = paleta.nn.Softmax()
fuera = m(x)
imprimir (salir)
Tensor(forma=[67, 1, 4], dtype=float32, lugar=CUDAPlace(0), stop_gradient=True, [[[  0.18607847, 0.76180643, 0.00790692, 0.04420818]], [[ 
 0.21990354, 0.75249618, 0,00896723, 0,01863303] ], 
 [[0.04347746, 0.87683898, 0.00152336, 0.07816018]], 
 [[0.31181487, 0.66678441, 0.00587796, 0.01552279]], [[0.27809274, 0.6 5979725, 0,02074026, 0,04136980]], [[0,51592660, 
 0,47112727, 0,00944741 
 , 0,00349878]], 
 [[0.08482961, 0.83483732, 0.00363582, 0.07669736]], 
 [[0.58813888, 0.40553078, 0.00420919, 0.00212116]], [[0.50240386, 0.4842 9418, 0,00554229, 0,00775965]], 
 [[0,27857813, 0,69674349, 0,01227855 
 , 0,01239989]],
 [[0,37013263, 0,60421354, 0,01008376, 0,01557007]], 
 [[0,31991184, 0,66306269, 0,01009506, 0,00693045]], [[0,41515639, 0,5798 3309, 0,00429428, 0,00071625]], [[0,21048497, 0,75708681 
 , 
 0,01020809, 0,02222010]], 
 [[ 0,09612054, 0,88075089, 0,00227385, 0,02085473]], 
 [[0,37300166, 0,61655551, 0,00738223, 0,00306051]], [[0,02863417, 0,78866 822, 0,00148986, 0,18120776]], [[0,00232973, 0,79350960, 
 0,00004836, 
 0,20411235]], 
 [[0,02143462, 0,87504727, 0,00058431, 0,10293392]], 
 [[0,00643685, 0,76924914, 0,00017670, 0,22413737]], [[0,01332989, 0,83638644, 0,00023 486 
 , 0,15004875]],
 [[0,01116226, 0,62454951, 0,00070716, 0,36358106]], 
 [[0,00290894, 0,66527551, 0,00008983, 0,33172569]], [[0,00456953, 0,5853 8061, 0,00022136, 0,40982854]], [[0,00792769, 0,75078166 
 , 0,00026256, 
 0,24102813]], 
 [[ 0,00179510, 0,49116838, 0,00009976, 0,50693673]], 
 [[0,02448242, 0,73991507, 0,00121354, 0,23438902]], [[0,02903091, 0,81717 736, 0,00123135, 0,15256041]], [[0,00527186, 0,87065840, 
 0,00014126 
 , 0,12392850]], 
 [[0,00109510, 0,82885396, 0,00001529, 0,17003568]], 
 [[0,00550288, 0,83888549, 0,00016662, 0,15544505]], [[0,02129946, 0,77363062, 0,00105 744 
 , 0,20401244]],
 [[0.00120668, 0.75071740, 0.00002368, 0.24805219]], 
 [[0.01260382, 0.80315262, 0.00040434, 0.18383917]], [[0.00000099, 0.0000 1980, 0,99510950, 0,00486970]], [[0,00000000 
 , 0,00000000, 0,99999475 
 , 0,00000526]], 
 [[ 0,00000973, 0,00011000, 0,95056945, 0,04931074]], 
 [[0,00000071, 0,00000600, 0,99663687, 0,00335647]], [[0,00000091, 0,00000 722, 0,99401951, 0,00597238]], 
 [[0,00000000, 0,00000000, 0,99999321, 
 0,00000682]], 
 [[0,00000000, 0,00000000, 0,99998105, 0,00001892]], 
 [[0,00000248, 0,00003062, 0,97920632, 0,02076050]], [[0,00003168, 0,00009718, 0,99681 073 
 , 0,00306045]],
 [[0.00001052, 0.00007432, 0.98827934, 0.01163586]], 
 [[0.00000000, 0.00000001, 0.99993038, 0.00006964]], [[0.00001010, 0.0000 0517, 0,99987948, 0,00010525]], 
 [[0,00000082, 0,00000218, 0,99974102, 
 0,00025600]], 
 [[ 0,00000076, 0,00000375, 0,99943382, 0,00056168]], 
 [[0,00000027, 0,00000021, 0,99998665, 0,00001282]], [[0,00000057, 0,00000 407, 0,99812609, 0,00186927]], 
 [[0,00000393, 0,00004036, 0,98245114 
 , 0,01750455]], 
 [[0,00000084, 0,00004937, 0,80008936, 0,19986045]], 
 [[0,00000500, 0,00266204, 0,00033643, 0,99699652]], [[0,00001068, 0,00316434, 0,00083 980 
 , 0,99598515]],
 [[0.00000940, 0.00324916, 0.00049351, 0.99624795]], 
 [[0.00000613, 0.00245906, 0.00053635, 0.99699843]], [[0.00001125, 0.0051 4054, 0,00034567, 0,99450254]], [[0,00001192, 0,00565004 
 , 0,00025565, 
 0,99408239]], 
 [[ 0,00000751, 0,00430946, 0,00028455, 0,99539846]], 
 [[0,00000582, 0,00258814, 0,00032005, 0,99708599]], [[0,00000841, 0,00384 306, 0,00035409, 0,99579442]], [[0,00000566, 0,00243412, 
 0,00045929 
 , 0,99710089]], 
 [[0,00000996, 0,00388200, 0,00041306, 0,99569499]], 
 [[0,00007983, 0,02011120, 0,00059271, 0,97921628]], [[0,00002605, 0,00432196, 0,00188 679 
 , 0,99376523]],

        [[0.00001340, 0.00337382, 0.00089095, 0.99572182]],

        [[0.00001447, 0.00472310, 0.00042231, 0.99484009]]])
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/tensor/creation.py:125: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any behavior and is safe. 
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  if data.dtype == np.object:

为了观察预测结果,我们还需要把标签转换一下:


 
#用一个字典,指名标签对应的数值
label_dic = {}
for i, label in enumerate(labels):
    label_dic[i] = label
#预测标签结果写入predict_labels
predict_labels = []
#依次取results[0]中的每个图片的预测数组
para  obtener  resultados  [ 0 ]: 
    #np.argmax: Devuelve el índice del valor máximo en una matriz numpy
    #Nota: El índice es la etiqueta, no el valor máximo de los datos devueltos.
    lab_index = np.argmax(resultado)
    laboratorio = etiqueta_dic[lab_index]
    predict_labels.append(laboratorio)
#Mira los resultados de la predicción.
imprimir (predict_labels)
['M2', 'M2', 'M2', 'M2', 'M2', 'B1', 'M2', 'B1', 'B1', 'M2', 'M2', 'M2', ' M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2' , 'S3', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'M2', 'R0', 'R0', 'R0', ' R0', 'R0', 'R0', 'R0', 'R0', 'R0', 'R0', 'R0', 'R0', 'R0', 'R0', 'R0', 'R0' , 'R0', 'R0', 'S3', 'S3', 'S3', 'S3', 'S3', 'S3', 'S3', 'S3', 'S3','S3', 'S3', 'S3', 'S3', 'S3', 'S3'] 

Para observar el efecto de predicción de manera más intuitiva, generamos un archivo result.csv, enumeramos los resultados de la predicción en este archivo csv y ejecutamos el siguiente código para generar un archivo result.csv en el directorio actual.

Abra el archivo result.csv y podremos ver los resultados:


 
resultado_final = [ ]
file_name_test = train_parameters[ 'test_list_dir'
f =  abrir (nombre_archivo_prueba,  'r'
#Leer datos fila por fila
datos = f.readlines()
para  i  en el  rango ( len (datos)):
    #Divida cada línea de datos en 2 partes según espacios y tome el nombre de la ruta y el nombre del archivo de imagen de la primera parte, por ejemplo: R0/1.png
    img_path = datos[i].split( '\t' )[ 0 ]
    final_result.append(img_path +  ','  +  str (predict_labels[i]) +  '\n' )
f.cerrar()
con  abierto ( 'result.csv' , "w" como  f: 
    f.writelines(resultado_final)

5. Resumen

En este experimento, utilizamos el marco de aprendizaje profundo paddlepaddle para construir un modelo de clasificación de imágenes y completamos la tarea de clasificación de melocotón.

A través de este experimento, aprendimos:

  • Cómo utilizar el marco de aprendizaje profundo de paddlepaddle;
  • Cómo utilizar el marco de aprendizaje profundo paddlepaddle para construir un modelo de clasificación de duraznos;
  • Cómo completar el proceso de trabajo de aprendizaje profundo, como la capacitación, evaluación, guardado y predicción de modelos;

La tarea de clasificación de imágenes es una tarea básica en el campo de la visión por computadora (CV), aunque no es difícil, es muy importante y es la piedra angular de otras tareas de visión por computadora. Debemos hacer más trabajo práctico, depurar más código, aumentar la competencia y sentar las bases para proyectos de aprendizaje profundo más complejos.

Parte del artículo se reproduce en Image Classification-Peach Sorting-Paddle AI Studio Galaxy Community (baidu.com), y otras partes se combinan del original. Si te gusta este artículo, ¡dale me gusta, recopilalo y síguelo!

Supongo que te gusta

Origin blog.csdn.net/m0_63309778/article/details/133513426
Recomendado
Clasificación