paint-brush
Cómo entrenar un modelo de detección de objetos utilizando un conjunto de datos personalizado con MinIO y YOLOpor@minio
9,178 lecturas
9,178 lecturas

Cómo entrenar un modelo de detección de objetos utilizando un conjunto de datos personalizado con MinIO y YOLO

por MinIO13m2023/11/22
Read on Terminal Reader

Demasiado Largo; Para Leer

En esta publicación, crearemos un conjunto de datos de imágenes personalizado y luego entrenaremos un modelo You-Only-Look-Once (YOLO) para la omnipresente tarea de detección de objetos. Luego implementaremos un sistema que utiliza MinIO Bucket Notifications que puede realizar inferencias automáticamente en una nueva imagen.
featured image - Cómo entrenar un modelo de detección de objetos utilizando un conjunto de datos personalizado con MinIO y YOLO
MinIO HackerNoon profile picture
0-item
1-item

La visión por computadora sigue siendo una aplicación extremadamente convincente de la inteligencia artificial. Ya sea reconociendo elementos en un campo de batalla o prediciendo el rendimiento de los cultivos, la visión por computadora es posiblemente uno de los ámbitos de la IA de mayor valor comercial (y socialmente importante).


Sin embargo, un factor limitante para la adopción de las mejores capacidades de visión por computadora a menudo son las complejidades asociadas con la construcción de un conjunto de datos y el diseño de un sistema simple de extremo a extremo que realizará la tarea de visión por computadora en una nueva imagen.


En esta publicación de blog, veremos paso a paso cómo abordar estos problemas con las mejores herramientas de su clase, como CVAT y MinIO Bucket Notifications. Al final de esta publicación, podrá entrenar un modelo de detección de objetos en un conjunto de datos personalizado y usarlo para hacer predicciones cada vez que aparezca una nueva imagen.

La premisa

Digamos que queremos poder reconocer tipos de aeronaves presentes en imágenes de satélite. Supongamos también que estamos empezando desde cero: sin conjuntos de datos prediseñados ni modelos previamente entrenados. Aquí hay dos aviones de muestra que queremos detectar y reconocer en nuestras imágenes satelitales:


De izquierda a derecha: (1) Su-30, (2) Tu-95


Los pasos descritos en esta publicación se pueden generalizar a casi cualquier dominio. En lugar de detectar tipos de aeronaves, podríamos clasificar el uso del suelo o realizar una regresión para predecir el rendimiento de los cultivos. Más allá de las imágenes tradicionales, también podríamos entrenar y realizar inferencias sobre otros tipos de datos multidimensionales como nubes de puntos LiDAR o imágenes sísmicas 3D; se convierte simplemente en una cuestión de cómo se ven los datos de entrenamiento (y potencialmente un modelo de aprendizaje profundo diferente en lugar de YOLO). Si tiene más preguntas sobre cómo se vería esto para un caso de uso específico, ¡no dude en plantear un problema en el repositorio de GitHub!


Paso 1: Adquirir y gestionar muestras de formación

Para este proyecto, debido en gran parte a que no poseía un satélite de imágenes bajo demanda, visité aeródromos en Google Earth y tomé varias capturas de pantalla de áreas en las que algunos de estos aviones eran visibles. Reunir este conjunto de imágenes tomó bastante tiempo, así que las almacené todas en un depósito en mi servidor MinIO titulado "detección de objetos". En un entorno de producción, los beneficios de almacenar las muestras recolectadas en MinIO se vuelven aún más proféticos. La replicación activa-activa, los niveles más altos de cifrado y GET/PUT súper rápidos (por nombrar algunos) significan que sus muestras recopiladas diligentemente estarán altamente disponibles y serán seguras.

Paso 2: crear el conjunto de datos

Creando el conjunto de datos


Para entrenar un modelo de detección de objetos para su caso de uso, se necesita un conjunto de datos etiquetados (o "anotados"). Una gran herramienta para esto es CVAT de OpenCV. Una característica interesante es que CVAT proporciona una utilidad para conectar su depósito MinIO como un "almacenamiento en la nube" para enviar las imágenes de su depósito directamente a la herramienta de anotación del conjunto de datos. Para hacer esto, asegúrese de que el servidor CVAT pueda acceder al host de su servidor MinIO, especialmente si está ejecutando el servidor MinIO en sus instalaciones o localmente en su computadora portátil. Además, como nota, hay dos formas de usar CVAT: (1) usando la aplicación web proporcionada en app.cvat.ai o (2) ejecutándola localmente. En cualquier caso, una vez que tenga CVAT abierto, haga clic en "Almacenamiento en la nube" en la barra de menú. Desde allí, puede completar un formulario para adjuntar su depósito MinIO (compatible con S3):


Crear un almacenamiento en la nube


Ahora creemos nuestra nueva tarea de etiquetado en "Tareas":


Tarea de etiquetado


Se le solicitará un formulario para completar:


Crear una nueva tarea


Al crear la tarea, es importante definir correctamente las etiquetas de clase (definí dos etiquetas Rectángulo tituladas “SU30” y “TU95”, correspondientes a los dos planos que quería detectar):


Definición de etiquetas de clase


Ahora el paso restante es adjuntar nuestro depósito MinIO previamente agregado como fuente de datos. En "Seleccionar archivos", haga clic en "Almacenamiento en la nube" y complete el nombre que proporcionó para esa fuente anteriormente. Usé el nombre "minio-cv-bucket" arriba.


Adjuntar MinIO Bucket como fuente de datos


El proceso de carga tardará unos minutos. Una vez que se haya completado, debería poder ver su trabajo de anotación disponible en "Trabajos".


Carga completa


Ahora, al hacer clic en el trabajo, puedes comenzar a anotar cada una de tus imágenes. Advertencia: este puede ser un proceso que requiere mucho tiempo. Generalmente, en un entorno de producción con grandes necesidades de anotaciones, puede ser mejor delegar esta tarea a un equipo interno dedicado o a una empresa de etiquetado de datos de terceros.


Comenzando a anotar


Una vez que haya terminado de anotar, exporte el conjunto de datos en formato YOLO.


Exportar datos

Paso 3: organizar los datos de entrenamiento

Su conjunto de datos exportado tendrá el formato de un archivo zip. Una vez que lo descomprima, los archivos de texto de anotaciones con formato YOLO estarán dentro de una carpeta cerrada. No dudes en echarles un vistazo. En el formato YOLO, las anotaciones de cada imagen están en un archivo de texto donde cada línea contiene dos esquinas de un cuadro delimitador y la clase. El número de clase corresponde al orden en el que definiste las etiquetas al crear la tarea. Entonces, en este ejemplo, 0 correspondería al Su-30 y 1 correspondería al Tu-95.


En este punto, cree un nuevo directorio de trabajo (o ingrese uno que ya haya creado). Dentro de este directorio, cree un subdirectorio llamado "conjunto de datos". Dentro de 'conjunto de datos', cree directorios de manera que su directorio de trabajo se vea así:


 my_cv_project (WORKING DIRECTORY) |---- dataset |----images |----train |----val |----test |----annotations |----train |----val |----test



Ahora tendrás que llenar los subdirectorios train, val y test tanto para las imágenes como para sus anotaciones correspondientes (los archivos de texto). Depende de usted cómo desea recuperar y dividir sus muestras. Una buena práctica es dividir la cantidad total de muestras de capacitación en 80 % de capacitación, 10 % de validación y 10 % de prueba. Asegúrese de mezclar aleatoriamente sus imágenes antes de particionarlas.


Personalmente, utilicé mc cp del cliente MinIO en la línea de comando para recuperar rápidamente todas las imágenes de mi depósito de 'detección de objetos'. Alternativamente, si ya tiene todas sus imágenes de muestra en un solo lugar en su computadora local, puede trabajar directamente con eso. Una vez que tuve todas mis muestras en un solo lugar, utilicé un script de Python para mezclar, dividir y mover mis imágenes y anotaciones a los directorios train, val y test. Aquí está el script proporcionado para mayor comodidad . Si tiene alguna pregunta sobre cómo usarlo, ¡no dude en escribirnos en el repositorio !


En última instancia, asegúrese de que para cada imagen que haya colocado en imágenes/tren, imágenes/val o imágenes/prueba, el archivo .txt de anotación correspondiente también esté en el subdirectorio correspondiente dentro del directorio anotaciones/. Por ejemplo:


 my_cv_project (WORKING DIRECTORY) |---- dataset |----images |----train - 5.png - 3.png - 2.png |----val - 4.png |----test - 1.png |----annotations |----train - 5.txt - 3.txt - 2.txt |----val - 4.txt |----test - 1.txt


Ahora, nuestros datos están en su lugar. Es hora de echar un vistazo a nuestro modelo de detección de objetos y comenzar a entrenar.

Paso 4: el modelo de detección de objetos

El estándar de oro actual (en términos de rendimiento y facilidad de uso) para el reconocimiento de objetos es la clase de modelos YOLO (Sólo miras una vez). En el momento de escribir este artículo, YOLOv8 es la última versión y Ultralytics la mantiene como código abierto. YOLOv8 proporciona una API simple que podemos aprovechar para entrenar el modelo en nuestras anotaciones recién creadas (y eventualmente también ejecutar inferencia).


Descarguemos YOLOv8:


 $ pip install ultralytics


Ahora podemos usar la herramienta CLI YOLOv8 o el SDK de Python para entrenar, validar y predecir. Consulte los documentos de YOLOv8 para obtener más información.

Paso 5: Entrenamiento

En su directorio de trabajo, defina un archivo YAML que especifique las ubicaciones del conjunto de datos y los detalles sobre las clases. Observe cómo las rutas son las mismas que creé anteriormente en el directorio de trabajo. Llamé a mi archivo ' objdetect.yaml '. Además, tenga en cuenta que las dos etiquetas de clases de aeronaves deben definirse en el mismo orden en que estaban en CVAT.


 train: ./dataset/images/train/ val: ./dataset/images/val/ test: ./dataset/images/test/ # number of classes nc: 2 # class names names: ["SU-30","TU-95"]


Comience a entrenar el modelo YOLOv8 en nuestro conjunto de datos con el siguiente comando (usando la herramienta YOLO CLI). Consulte los documentos de YOLO para obtener más información sobre las diferentes opciones que puede configurar para la capacitación. Aquí, inicio el entrenamiento durante 100 épocas y establezco un tamaño de imagen de 640 píxeles (todas nuestras imágenes de entrenamiento se escalarán en consecuencia durante el entrenamiento):


 $ yolo task=detect \ mode=train \ model=yolov8s.pt \ data=objdetect.yaml \ epochs=100 \ imgsz=640


El entrenamiento llevará un tiempo, especialmente si estás trabajando en una computadora portátil (como yo), ¡así que ahora es un buen momento para tomar un descanso (o leer con anticipación 😀)!


Al final del ciclo de entrenamiento, su modelo entrenado, junto con otros gráficos y tablas interesantes, se almacenarán en un directorio generado automáticamente llamado "ejecuciones". La salida del terminal (como a continuación) indicará la ubicación específica de los resultados de la última ejecución. Cada vez que entrene un modelo, se generará un directorio similar dentro de 'runs/detect/'.


 Results saved to runs/detect/train


Nota: run/detect/train/weights/ contendrá los archivos PT con los pesos entrenados exactos. Recuerda esta ubicación para más adelante.

Paso 5B: Validación y prueba del modelo

Puede ejecutar la validación con el siguiente comando:


 $ yolo task=detect \ mode=val \ model=path/to/best.pt \ data=objdetect.yaml


Los resultados se almacenarán automáticamente en una carpeta en su directorio de trabajo con una ruta del formato 'runs/detect/val'.


Para realizar inferencia en el conjunto de prueba, puede utilizar el siguiente comando:


 $ yolo task=detect \ mode=predict \ model=path/to/best.pt \ conf=0.5 \ source=dataset/images/test


Los resultados se almacenarán en 'ejecuciones/detectar/predecir'. Aquí hay algunos resultados de predicción en el conjunto de prueba:


Resultados de la predicción


Paso 6: Nueva inferencia de imágenes mediante notificaciones de depósito MinIO

Ahora que tenemos un modelo entrenado que puede reconocer algunos tipos de aeronaves presentes en una imagen de satélite, ¿cómo podemos utilizarlo para nuevas imágenes de forma sencilla ?


Uso de notificaciones de depósito MinIO


MinIO Bucket Notifications es una herramienta perfecta para esto. Podemos construir un sistema que pueda realizar automáticamente una inferencia de detección de objetos en una nueva imagen colocada en nuestro depósito con la ayuda de un webhook.


En un nivel alto, tenemos 3 pasos. Primero, necesitamos definir un punto final que pueda servir como webhook para realizar la detección de objetos en una nueva imagen con nuestro modelo entrenado. En segundo lugar, necesitamos configurar algunas variables de entorno para la implementación de nuestro servidor MinIO que le indiquen que acceda a nuestro punto final de webhook cuando ocurra algún evento. En tercer lugar, debemos configurar sobre qué tipos de eventos de depósito (es decir, PUT) queremos actuar. Repasemos esto paso a paso.


Aquí está el código para un servidor simple basado en Flask ( detección_server.py ) que ejecuta inferencia en una nueva imagen agregada al depósito MinIO:


 """ This is a simple Flask inference server implementation that serves as a webhook for the event of a new image being added to a MinIO bucket. Object detection using YOLO will be performed on that image and the resulting predictions will be returned. """ from flask import Flask, request, abort, make_response from ultralytics import YOLO import tempfile from minio import Minio # Make sure the following are populated with your MinIO details # (Best practice is to use environment variables!) MINIO_ENDPOINT = '' MINIO_ACCESS_KEY = '' MINIO_SECRET_KEY = '' model = YOLO('/PATH/TO/best.pt') # load a custom model (path to trained weights) client = Minio( MINIO_ENDPOINT, access_key=MINIO_ACCESS_KEY, secret_key=MINIO_SECRET_KEY, ) app = Flask(__name__) @app.route('/', methods=['POST']) async def inference_bucket_webhook(): """ This endpoint will be called when a new object is placed in your inference bucket """ if request.method == 'POST': # Get the request event from the 'POST' call event = request.json bucket = event['Records'][0]['s3']['bucket']['name'] obj_name = event['Records'][0]['s3']['object']['key'] with tempfile.TemporaryDirectory() as temp_dir: temp_file_name = temp_dir+'/'+obj_name client.fget_object(bucket, obj_name, temp_file_name) # See https://docs.ultralytics.com/modes/predict/ for more information about YOLO inference options results = model.predict(source=temp_file_name, conf=0.5, stream=False) # A list of bounding boxes (if any) is returned. # Each bounding box is in the format [x1, y1, x2, y2, probability, class]. result = {"results": results[0].boxes.data.tolist()} print(result) resp = make_response(result, 200) return resp else: abort(400) if __name__ == '__main__': app.run()


Iniciemos el servidor de inferencia:


 $ python detection_server.py * Serving Flask app 'detection_server' * Debug mode: off * Running on http://127.0.0.1:5000 Press CTRL+C to quit


Tome nota del nombre de host y el puerto en el que se ejecuta la aplicación Flask.


A continuación, comencemos a trabajar en la configuración de los webhooks en el lado de MinIO. Primero, establezca las siguientes variables de entorno. Reemplace <YOURFUNCTIONNAME> con un nombre de función de su elección. Para simplificar, elegí "inferencia". Además, asegúrese de que la variable de entorno del punto final esté configurada en el host y puerto correctos para su servidor de inferencia. En este caso, http://localhost:5000 es donde se ejecuta nuestra aplicación Flask.


 $ export MINIO_NOTIFY_WEBHOOK_ENABLE_<YOURFUNCTIONNAME>=on $ export MINIO_NOTIFY_WEBHOOK_ENDPOINT_<YOURFUNCTIONNAME>=http://localhost:5000


Ahora, reinicie el servidor MinIO usando el comando mc admin service restart ALIAS o si está iniciando el servidor por primera vez, también puede usar el comando del servidor minio . Para obtener más información sobre cómo reiniciar/reiniciar el servidor MinIO, consulte los documentos de MinIO. Nota: ALIAS debe reemplazarse con el alias de la implementación de su servidor MinIO. Para obtener más información sobre cómo configurar un alias o ver los alias existentes, consulte los documentos .


Finalmente, agreguemos el depósito y el evento sobre el que queremos recibir notificaciones. En nuestro caso, queremos recibir notificaciones sobre eventos ` put` (creación de nuevos objetos) en nuestro depósito. Hice un cubo nuevo y vacío para este propósito titulado "detección-inferencia", así que lo sustituiré por "CUBO".


 $ mc event add ALIAS/BUCKET arn:minio:sqs::<YOURFUNCTIONNAME>:webhook --event put


Puede comprobar que ha configurado el tipo de evento correcto para las notificaciones del depósito verificando si se genera " s3:ObjectCreated:* " cuando ejecuta este comando:


 $ mc event ls local/detect-inference arn:minio:sqs::<YOURFUNCTIONNAME>:webhook


Para obtener una explicación más detallada sobre la publicación de eventos de depósito en un webhook, consulte los documentos . ¡Ahora estamos listos para probar la detección de objetos en una imagen completamente nueva!

Probando nuestro sistema de inferencia

Aquí está la nueva imagen (titulada '1.png') sobre la que quiero realizar inferencias:


Probando el sistema de inferencia


Dejo la nueva imagen en mi depósito de 'detección-inferencia':


Colocar imagen en un nuevo depósito


Casi al instante, puedo ver los siguientes resultados en mi servidor Flask:


 $ python detection_server.py * Serving Flask app 'detection_server' * Debug mode: off * Running on http://127.0.0.1:5000 Press CTRL+C to quit image 1/1 /var/folders/xf/q7x0z8sn5nvckccp1g0m1vpm0000gn/T/tmpo6jx3w8u/1.png: 448x736 2 SU-30s, 101.0ms Speed: 4.1ms preprocess, 101.0ms inference, 5.8ms postprocess per image at shape (1, 3, 448, 736) {'results': [[1927.78369140625, 627.7123413085938, 1995.090576171875, 715.3443603515625, 0.8142037987709045, 0.0], [1735.740234375, 477.2108154296875, 1809.181640625, 555.767578125, 0.7766116261482239, 0.0]]} 127.0.0.1 - - [14/Sep/2023 15:39:21] "POST / HTTP/1.1" 200 -


Tenga en cuenta que cada cuadro delimitador detectado en la lista de resultados está en formato YOLO [x1, y1, x2, y2, probabilidad, clase]. Aquí están los cuadros delimitadores y las clases previstas superpuestas a la imagen original:


Los otros dos aviones no son Su-30. Mi conjunto de datos inicial incluía aproximadamente 100 imágenes, por lo que me sorprendió que el modelo ya fuera capaz de captar los matices entre aviones de apariencia similar. Supongo que la lección aquí es: ¡nunca subestimes el descenso de gradiente!


Nota: Para entornos de producción y/o modelos grandes de aprendizaje automático, es una buena idea utilizar un marco de servicio de modelos establecido como PyTorch Serve o Triton Server para hacer que la inferencia sea más sólida y confiable. Si está interesado en eso, consulte la publicación anterior sobre Optimización del servicio de modelos de IA con MinIO y PyTorch Serve .

Pensamientos concluyentes

¡Lo hicimos! Analizamos cómo MinIO y CVAT se unieron para mantener nuestras muestras de imágenes recopiladas seguras y disponibles, así como también cómo crear nuestro conjunto de datos de detección de objetos personalizado. Luego, entrenamos nuestro propio modelo YOLO personalizado para nuestra tarea personalizada. Por último, con poco más de 50 líneas de código, armamos un servidor de inferencia usando MinIO Bucket Notifications que podría ejecutar una nueva imagen más allá de nuestro modelo de detección de objetos entrenado personalizado.


MinIO y YOLO implementados en el borde.


Además, para la mayoría de las aplicaciones de visión por computadora de misión crítica, es mejor realizar inferencias en el borde. De lo contrario, dichas aplicaciones son vulnerables a la latencia asociada con la carga de nuevos datos a la nube pública y la espera de que un servidor de inferencia en la nube regrese con una respuesta, sin mencionar los riesgos de una conexión de red defectuosa. Por esta razón, un proceso de visión por computadora centrado en MinIO como capa de datos tiene mucho más sentido. Imagine un dron volando sobre un aeródromo, capaz de capturar, almacenar y utilizar nuestro modelo entrenado en nuevas imágenes con hardware y software completamente integrado. Con una implementación local del servidor MinIO, el sistema de inferencia basado en notificaciones de depósitos que creamos al final de la publicación funciona perfectamente para este escenario y muchos otros similares.


Si tiene alguna pregunta, únase a nuestro canal Slack o envíenos una nota a [email protected] . Estamos aquí para ayudarte.


También publicado aquí .