Blog de Amazon Web Services (AWS)

Creación de un flujo de trabajo de etiquetado, entrenamiento e implementación de aprendizaje automático con Amazon SageMaker, PyTorch y Amazon SageMaker Ground Truth

Por Evandro Franco, Arquitecto de Soluciones en Startups en AWS

 

Amazon SageMaker es un servicio de aprendizaje automático (ML) totalmente administrado en el que los científicos y desarrolladores de datos pueden crear y entrenar modelos de aprendizaje automático de forma rápida y sencilla e implementarlos en un ambiente administrado, listo para producción.

Para entrenar un modelo de aprendizaje automático, necesita tener una gran cantidad de datos (conjunto de datos), con una buena definición y etiquetados correctamente. Amazon SageMaker Ground Truth le ayuda con la tarea de crear este conjunto de datos de alta calidad. Le permite utilizar empleados de terceros, de Amazon Mechanical Turk, o la fuerza de trabajo de la propia empresa.

Uno de los framewroks de aprendizaje automático de código abierto más utilizados en el mercado es PyTorch. Le permite acelerar el desarrollo, desde la creación de prototipos hasta la producción. Utilizaremos PyTorch en este ejemplo para mostrar también la flexibilidad y facilidad de integrar este framework con Amazon SageMaker.

 

Resumen de la solución

Inicialmente, para esta demostración, entrenaremos un modelo para clasificar imágenes de objetos. Estas imágenes fueron seleccionadas del conjunto de datos público de Caltech 256, que consta de más de 30.000 imágenes etiquetadas en 256 categorías distintas (clases). A partir de este conjunto de datos vamos a trabajar con una muestra de las siguientes 4 clases:

  • Beer Mug (Taza de cerveza);
  • Coffee Mug (taza de café);
  • Teapot (tetera);
  • Wine Bottle (botella de vino);

Nota : Para demostrar el flujo del desarrollo de modelos deaprendizaje automático, desde el etiquetado en SageMaker Ground Truth, la preparación de datos hasta la implementación del modelo, puede seleccionar 20 imágenes de cada categoría, con un total de 80 imágenes.  En un escenario real, probablemente se necesitaría un conjunto de datos más grande para mejorar el rendimiento del modelo.

 

 

Creación de los recursos necesarios (requisitos previos)

Para empezar, deberá crear un bucket en Amazon S3 (o utilizar uno existente). El tutorial «Crear un bucket» presenta el paso a paso cómo crear un bucket.

A continuación, seleccione veinte imágenes aleatorias del conjunto de datos citado en el paso anterior, teniendo en cuenta solo las cuatro categorías mencionadas (010.beer-mug, 041.coffee-mug, 212.teapot e 246.wine-bottle) y cargue estas imágenes a S3, utilizando un solo directorio, ya que utilizaremos Amazon SageMaker Ground Truth para etiquetar.

 

Creación del trabajo de etiquetado en SageMaker Ground Truth

Ahora que hemos creado un bucket en S3 y hemos cargado las imágenes, utilizaremos Amazon SageMaker Ground Truth para que las imágenes sin etiquetar puedan clasificarse antes del proceso de entrenamiento.

Para empezar, vaya a SageMaker desde la consola de AWS y, en el menú izquierdo, haga clic en Etiquetado de trabajos en la sección Ground Truth.

Establezca los siguientes atributos en el fragmento Visión general del trabajo:

  • Nombre del trabajo: labeling-demo
  • Configuración de datos de entrada: seleccione la opción «Configuración automatizada de datos»
  • Configuración de datos:
    • Ubicación de S3 para datasets de entrada: Navegue a través de S3 hasta el directorio con las imágenes.
    • Ubicación de S3 para datasets de salida: Navegue a través de S3 hasta el directorio vacío o mantenga la misma configuración regional.
  • Tipo de datos: Imagen
  • Rol de IAM: Especifique un rol con permiso de AmazonsageMakerFullAccess.
  • Haga clic en el botón «Completar configuración de datos».  Este paso creará un archivo de manifiesto para las imágenes, que será utilizado por Ground Truth.

 

 

En el fragmento Tipo de tarea, seleccione:

  • Imagen: Porque nuestro conjunto de datos se compone de imágenes.
  • Clasificación de imagen (etiqueta única): porque cada imagen tiene un solo objeto o etiqueta.

 

 

Haga clic en Siguiente para el siguiente paso.

Nota: En este ejemplo será considerado el primer acceso a Ground Truth. Si este acceso ya se ha realizado, podrá ver los equipos que se crearon previamente.

 

En el fragmento de los trabajadores:

  • Tipos de trabajador: seleccione la opción Privado
  • Nombre del equipo: my-private-team
  • Invitar a comentadores privados: lista de correo, separada por comas
  • Organización: demo-org
  • Contacto: Correo electrónico de contacto para los trabajadores
  • Tiempo de espera de tarea: 5 minutos (tiempo máximo para una sola tarea. Una sola tarea corresponde a una sola imagen).
  • Tiempo de vencimiento de la tarea: 10 días (este tiempo de espera considera el trabajo como un todo, es decir, el conjunto de imágenes).

 

 

En el fragmento de la Clasificación de imágenes (etiqueta única) herramienta de etiquetado, puede definir la plantilla que parecerá etiquetar las imágenes:

  • Introduzca una descripción para las imágenes para que el anotador sepa como clasificar, por ejemplo:
    • Por favor clasifique las imágenes en una de las cuatro clases:
  • Rellene las opciones de etiquetado:
    • 01.beer-mug
    • 02.coffee-mug
    • 03.teapot
    • 04.wine-bottle

 

 

Puede hacer clic en el botón de vista previa para abrir una página de muestra de cómo se mostrará a los trabajadores.

Haga clic en Crear para completar y crear el trabajo.

Después de unos minutos, los usuarios registrados recibirán un correo electrónico con acceso al portal donde podrán empezar a etiquetar.

 

 

Una vez finalizado el etiquetado, algunos metadatos estarán disponibles en la carpeta de salida de S3. Dentro de esta estructura, dos son importantes:

  • manifiestos: contiene los archivos de manifiesto de salida del trabajo.
  • anotaciones:
    • worker-response: Contiene la respuesta individual de cada trabajador.
    • consolidated-annotation: contiene las anotaciones deseadas.

Para obtener más información, consulte esta documentación sobre los resultados de Ground Truth

 

Creación de un notebook:

También utilizaremos una instancia de notebook de SageMaker. El tutorial «Crear una instancia de Notebooks» muestra cómo crear un notebook de Jupyter en SageMaker Jupyter. Como el propósito de este blog es para probar, se puede usar una instancia de tipo ml.t3.medium.

Con la instancia de notebook creada, cree un notebook utilizando el kernel conda_pytorch_p36:

 

 

A continuación, ejecute el siguiente fragmento de código con las bibliotecas, s3 Bucket y otras referencias que SageMaker utilizará:

 
       
importar sagemaker
de sagemaker.tuner import IntegerParameter, CategoricalParameter, ContinuousParameter, HyperParameterTuner

sagemaker_session = sagemaker.Sesión ()

# Cubo de destino
cubo = '<your-bucket-name>
prefijo = "<your-bucket-prefix/subfolders>

rol = sagemaker.get_execution_role ()

 

Exploración de los datos de Amazon SageMaker Ground Truth

Para explorar los datos generados por Ground Truth, crearemos un nuevo Notebook. En este notebook, importe las dependencias:

 
       
importar el, json
importar pandas como pd
importar fnmatch
importar boto3
de botocore.config import Config
importar sagemaker

s3 = boto3.resource ('s3')
sagemaker_session = sagemaker.Sesión ()

# Cubo de destino
cucharón = "<your-bucket-name>
prefijo = "<prefix-with-ground-truth-output>
new_prefix= "<new-prefix-to-organize-data>

 

En la variable de prefijo, utilice la ruta utilizada para la salida del trabajo Ground Truth.

Utilice el siguiente ejemplo de código para descargar la salida a su notebook y evaluar lo que se generó:

sagemaker_session.download_data('<local_path>', bucket , prefix)

El siguiente extracto leerá el manifiesto generado con los datos de los trabajadores que etiquetaron las imágenes:

 
       
# Lectura de archivos de manifiesto
path_to_json = prefijo + "<path to output on manifest folder>

json_files = [pos_json para pos_json en os.listdir (path_to_json) si pos_json.endswith ('.manifest')]

archivos = []
para el índice, js en enumerate (json_files):
    con open (os.path.join (path_to_json, js)) como json_file:
        archivos += lista(json_file)

manifest_data= []
para i en archivos:
    temp = json.loads (i)
    manifest_data.append (temp)

manifest_data

Finalmente, el siguiente fragmento reorganizará las imágenes etiquetadas en S3, ya en una estructura de carpetas que utilizaremos en los siguientes pasos:

 
       
importar numpy como np

para i en manifest_data:
    src_ref = i [«source-ref»]
    nombre_archivo = src_ref.split («/») [-1]
    label = i ["<JOB-NAME> -metadata»] [«nombre-clase»]
    si np.random.rand (1) < 0,2:
        new_path = new_prefijo + '/test/' + etiqueta +  archivo '/ '+
        print (new_path)
        S3.object (bucket, new_path) .copy_from (copysource=src_ref.replace («s3://»,«»))
    otra cosa:
        new_path = new_prefijo + '/train/' + etiqueta +  archivo '/ '+
        print (new_path)
        S3.object (bucket, new_path) .copy_from (copysource=src_ref.replace («s3://»,«»))

 
       Nota: El valor <JOB-NAME> debe cambiarse por el nombre del trabajo utilizado en Ground Truth.  En este ejemplo hemos utilizado un factor aleatorio para separar el conjunto de datos en entrenamiento y prueba, solo para el propósito de demostración.    
       

Entrnando un modelo en SageMaker

Utilizaremos una técnica de aprendizaje automático llamada Transfer Learning. En la práctica, no siempre es necesario entrenar una red neuronal convolucional desde cero, porque es difícil poseer un conjunto de datos de tamaño suficiente, además de demandar un tiempo de entrenamiento muy grande. En su lugar, es común usar un conjunto de datos grande, preentrenar una red con ese conjunto de datos y luego usar este modelo preentrenado como punto de partida para desarrollar el nuevo modelo con el nuevo conjunto de datos para otro dominio específico, en gran medida acelerando el tiempo de entrenamiento y sin necesidad de tantas imágenes. En este ejemplo, utilizamos la red ResNet18, preformada con el dataset ImageNet. A continuación utilizaremos el script transfer_learning.py con el código completo utilizando la técnica de aprendizaje de transferencia y el framework PyTorch. Este script será el punto de entrada para el entrenamiento e implementación de nuestro modelo:  
# transfer_learning.py
importación argparse
importar json
registro de importación
importación
tiempo de importación
importar sys
antorcha de importación
importar antorch.distribuido como dist
importar antorch.nn como nn
importar torch.nn.funcional como F
importar torch.optim como optim
desde torch.optim import lr_scheduler
importar torch.utils.data
importar torch.utils.data.distribuido
importar torchvision
importar numpy como np
de conjuntos de datos de importación de torchvision, transformaciones, modelos
importar copia
de colecciones importar OrderedDict

logger = logging.getLogger (__name__)
Logger.setLevel (Loggging.Debug)
Logger.AddHandler (logging.streamHandler (sys.stdout))

def _get_data_loader (batch_size, training_dir, is_distributed, **kwargs):
    logger.info («Obtener el conjunto de datos en data_loader»)
    
    data_transforms = {
    'train': Transforms.Compose ([
        transforms.randomresizedCrop (size=256, escala= (0.8, 1.0)),
        Transformes.Rotación aleatoria (degresis=15),
        transforms.randomHorizontalFlip (),
        transforms.centerCrop (size=224),
        transforms.totensor (),
        Transformes.Normalizar ([0,485, 0.456, 0.406], [0,229, 0.224, 0.225])
    ]),
    'prueba': Transforms.Compose ([
        transformes.Redimensionar (256),
        Transforms.CenterCrop (224),
        transforms.totensor (),
        Transformes.Normalizar ([0,485, 0.456, 0.406], [0,229, 0.224, 0.225])
    ]),
    }

    data_dir = formación_dir
    image_datasets = {x: Datasets.ImageFolder (os.path.join (data_dir, x),
                                          transformaciones de datos [x])
                  para x en ['tren', 'test']}

    train_sampler = torch.utils.Data.Distributed.DistributedSampler (conjunto de datos) si is_distributed else Ninguno
    
    dataloaders = {x: torch.utils.data.DataLoader (image_datasets [x], batch_size=batch_size,
                                                shuffle=train_sampler es Ninguno, 
                                                sampler=train_sampler, **kwargs)
                  para x en ['tren', 'test']}
    
    dataset_size = {x: len (image_datasets [x]) para x en ['tren', 'test']}

    devolver dataloaders, dataset_size

def model_fn (model_dir):
    probar:
        logger.info ('model_fn')
        device = «cuda» si torch.cuda.is_available () else «cpu»
        con open (os.path.join (model_dir, 'model.pth'), 'rb') como f:
            ckpt = torch.load (f, map_location='cpu')
        optimizador = ckpt ['optimizador']
        época = ckpt ['época']
        modelo = ckpt ['modelo']
        load_dict = orderedDict ()
        para k, v en model.items ():
            if k.startswith ('módulo. '):
                k_ = k.replace ('módulo. ', ")
                load_dict [k_] = v
            otra cosa:
                load_dict [k] = v
        
        modelo = models.resnet18 (preentrenado=False)
        num_ftrs = model.fc.in_features
        
        model.fc = nn.secuencial (
            nn.lineal (núm_ftrs, 256),
            nn.relu (),
            nn.abandono escolar (0,4),
            NN.lineal (256, 4), 
            NN.logSoftMax (dim=1) # Para usar nllLoss ()
        )
        
        model.load_state_dict (load_dict)
        devolver modelo.to (dispositivo)
    excepto la excepción como errr:
        imprimir (err)
        elevar

def save_model (modelo, optimizador, epoch, model_dir):
    logger.info («Guardar el modelo. «)
    path = os.path.join (model_dir, 'model.pth')
    # manera recomendada desde http://pytorch.org/docs/master/notes/serialization.html
    antorch.save (
        {
            «modelo» : model.state_dict (), 
            «optimizer»: optimizer.state_dict (),
            «época»: época
        },
        ruta)

def train_model (dataloaders, dataset_size, dispositivo, modelo, criterio, optimizador, 
                programador, núm_épochs=10):
    desde = time.time ()

    best_model_wts = copiar.deepcopy (model.state_dict ())
    best_acc = 0.0

    para época en rango (num_epochs):
        print ('Epoch {}/{}'.format (epoch, núm_épochs - 1))
        imprimir ('-' * 10)

        # Cada época tiene una fase de entrenamiento y validación
        para la fase de [«tren», «ensayo»]:
            si fase == 'tren':
                model.train () # Establecer el modelo en modo de entrenamiento
            otra cosa:
                model.eval () # Establecer modelo en modo de valor

            running_loss = 0,0
            corrining_correct=0

            # Iterar sobre los datos.
            para entradas, etiquetas en dataloaders [fase]:
                entradas = entradas.to (dispositivo)
                labels = etiquetas.to (dispositivo)

                # cero los gradientes de parámetros
                optimizer.zero_grad ()

                # hacia adelante
                # rastrear la historia si sólo está en tren
                con torch.set_grad_enabled (fase == 'tren'):
                    salidas = modelo (entradas)
                    _, preds = torch.max (salidas, 1)
                    pérdida = criterios (salidas, etiquetas)

                    # retroce+ optimizar sólo si está en fase de entrenamiento
                    si fase == 'tren':
                        pérdidas.retroceder ()
                        optimizer.step ()

                N.º de estadísticas
                running_loss += loss.item () * inputs.size (0)
                running_corrects += torch.sum (preds == etiquetas.data)
            si fase == 'tren':
                programador.step ()

            epoch_loss = running_loss/dataset_size [fase]
            epoch_acc = running_corrects.double () /dataset_size [fase]

            print ('{} Pérdida: {:.4f} Acc: {:.4f}'.format (
                fase, epoch_loss, époch_acc))

            # copia profunda del modelo
            if phase == 'test' y epoch_acc > best_acc:
                best_acc = époch_acc
                best_model_wts = copiar.deepcopy (model.state_dict ())

        imprimir ()

    time_elapsed = time.time () - desde
    print ('Formación completa en formato {:.0f}m {:.0f}s'..formato (
        tiempo_elapsed//60, tiempo_transcursido% 60))
    print ('Mejor acc val: {:4f}'.format (best_acc))

    # carga de los mejores pesos del modelo
    model.load_state_dict (best_model_wts)
    modelo de devolución

tren de def (args):
    is_distributed = len (args.hosts) > 1 y args.backend no es Ninguno
    logger.debug («Capacitación distribuida - {}".format (is_distributed))
    use_cuda = args.num_gpus > 0
    logger.debug («Número de GPU disponibles - {}".format (args.num_gpus))
    kwargs = {'num_workers': 1 , pin_memory: True} si use_cuda else {}
    dispositivo = torch.device («cuda» si use_cuda else «cpu»)

    si es distribuido:
        # Inicializar el entorno distribuido.
        mundo_size = len (args.hosts)
        os.environ ['WORLD_SIZE'] = str(mundo_size)
        host_rank = args.hosts.index (args.current_host)
        dist.init_process_group (backend=args.backend, rank=host_rank, world_size=world_size)
        logger.info ('Inicializado el entorno distribuido:\ '{}\' backend en {} nodos. ' .format (
            args.backend, dist.get_world_size ()) + 'La clasificación actual del host es {}. Número de GPU: {}'.format (
            dist.get_rank (), args.num_gpus))

    # establecer la semilla para generar números aleatorios
    antorch.manual_seed (args.seed)
    si use_cuda:
        antorch.cuda.manual_seed (args.seed)

    dataloaders, dataset_size = _get_data_loader (args.batch_size, args.data_dir, is_distributed, **kwargs)

    model_ft = models.resnet18 (preentrenad=True)
    num_ftrs = model_ft.fc.in_features
    
    # Cambiar la capa final del modelo de Resnet18 para Transfer Learning
    #model_ft .fc = nn.lineal (núm_ftrs, 4)
    model_ft.fc = nn.secuencial (
        nn.lineal (núm_ftrs, 256),
        nn.relu (),
        nn.abandono escolar (0,4),
        NN.lineal (256, 4), 
        NN.logSoftMax (dim=1) # Para usar nllLoss ()
    )

    model_ft = model_ft.to (dispositivo)
    si es_distribuido y use_cuda:
        #multi -máquina multi-gpu caso
        model_ft = torch.nn.Parallel.DistributedDataParallel (model_ft)
    otra cosa:
        # caso de una sola máquina multi-gpu o una sola máquina o multi-máquina CPU caso
        model_ft = Torch.nn.DataParallel (model_ft)

    criterio = nnllloss ()

    # Tenga en cuenta que todos los parámetros están optimizados
    optimizer_ft = optim.sgd (model_ft.parameters (), lr=args.lr, momentum=args.momentum)

    # Descomposición LR por un factor de 0.1 cada 7 épocas
    exp_lr_scheduler = lr_scheduler.steplr (optimizer_ft, step_size=7, gamma=0.1)

    # Entrenamiento
    model_ft = train_model (dataloaders, dataset_size, dispositivo, model_ft, criterios, 
                            optimizer_ft, exp_lr_scheduler, args.épochs)

    # Guardar modelo
    save_model (model_ft, optimizer_ft, args.epochs, args.model_dir)

if __name__ == '__main__':
    analizador = argParse.ArgumentParser ()

    # Directorios de puntos de control de datos y modelos
    parser.add_argumento ('—lote size', type=int, default=4, metavar='N',
                        help='tamaño de lote de entrada para entrenamiento (predeterminado: 4)')
    parser.add_argumento ('—test-lote size', type=int, default=1000, metavar='N',
                        help='tamaño del lote de entrada para pruebas (predeterminado: 1000)')
    parser.add_argumento ('—épocas', type=int, default=10, metavar='N',
                        help='número de épocas a entrenar (por defecto: 10)')
    parser.add_argumento ('—lr', type=float, default=0.001, metavar='LR',
                        help='tasa de aprendizaje (predeterminado: 0.001)')
    parser.add_argumento ('—momentum', type=float, default=0.9, metavar='M',
                        help='impulso SGD (valor predeterminado: 0.9)')
    parser.add_argumento ('—seed', type=int, default=1, metavar='S',
                        help='semilla aleatoria (predeterminado: 1)')
    parser.add_argumento ('—log-interval', type=int, default=100, metavar='N',
                        help='cuántos lotes esperar antes de registrar el estado de formación')
    parser.add_argumento ('—backend', type=str, default=Ninguno,
                        help='backend para entrenamiento distribuido (tcp, gloo en cpu y gloo, nccl en gpu) ')

    # Entorno de contenedor
    parser.add_argumento ('—hosts', type=list, default=json.loads (os.environ ['SM_HOSTS']))
    parser.add_argumento ('—current-host', type=str, default=os.environ ['SM_CURRENT_HOST'])
    parser.add_argumento ('—model-dir', type=str, default=os.environ ['SM_MODEL_DIR'])
    parser.add_argumento ('—data-dir', type=str, default=os.environ ['SM_CHANNEL_TRAINING'])
    parser.add_argumento ('—núm-gpus', type=int, default=os.environ ['SM_NUM_GPUS'])

    tren (parser.parse_args ())
 En este script, es importante tener en cuenta los siguientes fragmentos 
       
    • if __name__ == ‘__main__‘: el punto de entrada del código, donde se manejan los argumentos y se llama al método de entrenamiento train () ;
    • def train (args): tiene toda la lógica de entrenamiento modelo;
    • def model_fn (model_dir): Ejecutado sólo para inferencia, es responsable de cargar la plantilla al inicio del contenedor de inferencia de SageMaker.
    Después de analizar este script, se puede crear en el mismo directorio que el notebook. Volviendo al notebook crearemos un estimador de SageMaker, que tendrá las instrucciones necesarias para el proceso de entrenamiento, indicando los principales parámetros:
    • El script py creado en el paso anterior como entrada;
    • Un rol (IAM) con los permisos necesarios;
    • El tipo de instancia de entrenamiento (en este caso, como es un ejemplo, se puede usar la instancia m5.large);
    • Número de instancias (en este caso, sólo una).
 
       
# Creando el estimador
de sagemaker.pytorch importar PyTorch

pytorch_estimator = PyTorch ('transfer_learning.py',
                            roles = rol,
 instance_type='ml.m5.large',
                            instance_count=1,
                            framework_version='1.5.0',
                            py_version='py3',
                           )

Después de esto, para iniciar el proceso de entrenamiento, simplemente ejecute el siguiente fragmento de código:

 

bucket_uri = 's3://' + bucket + '/' + prefix

pytorch_estimator.fit({'training': bucket_uri})

 

Este fragmento toma la ruta a las imágenes de S3 y pasa como parámetro al proceso de formación de SageMaker. Durante este entrenamiento, SageMaker lanzará las instancias requeridas (definidas en el paso anterior), ejecutará el entrenamiento, guardará la plantilla formada en S3 y finalizará las instancias.

 

Inferir el resultado en SageMaker

Una vez finalizado el proceso de entrenamiento, puede implementar el modelo en una instancia de inferencia de SageMaker. Esta instancia está optimizada y preparada con las dependencias necesarias para reducir la necesidad de administración de infraestructura. Esta instancia ya tiene un endpoint HTTPS para acceder a la plantilla y devuelve una predicción. Para obtener más información, visite la página Implementar una plantilla en los servicios de alojamiento de SageMaker.

A través del siguiente comando es posible crear una instancia de inferencia para probar el modelo:

predictor = pytorch_estimator.deploy(initial_instance_count=1, instance_type='ml.m5.xlarge')

Como en el entrenamiento, aquí también definimos la cantidad y el tipo de instancia.

Para probar, utilice el siguiente script, que usará cualquier imagen (se puede usar cualquier imagen del conjunto de datos original, preferiblemente una que no se haya utilizado en el proceso de entrenamiento):

 
       
desde la imagende importación de PIL 

cargador = transforms.Compose ([
            transformes.Redimensionar (256),
            Transforms.CenterCrop (224),
            transforms.totensor (),
            Transformes.Normalizar ([0,485, 0.456, 0.406], [0,229, 0.224, 0.225])
        ])

def image_loader (image_name):
    «» «cargar imagen, devuelve tensor cuda» «»
    image = Image.open (nombre_imagen_)
    image = cargador (imagen) .float ()
    image = image.unsqueeze (0) 
    devolver imagen

image = image_loader (» 02_coffee_mug.jpg «)

importar numpy como np

objects_category = ['01-taza de cerveza','02-taza de café','03-tetera','04 botella de vino']

response = predictor.predict (imagen)
output = torch.exp (torch.tensor (respuesta))
index = np.argmax (salida)
print («Resultado —> etiqueta:» + objects_category [índice] + «| probabilidad:» + str(salida [0] [índice]))
 
       

El resultado se verá algo así como el resultado a continuación:

Result --> label: 02-coffee-mug | probability: tensor(0.6101, dtype=torch.float64)

Como el propósito aquí es sólo demostrativo, el preprocesamiento para cambiar el tamaño de la imagen y normalizar los canales RGB de la imagen antes de enviarlo al modelo y también post-procesamiento para la conversión a escala entre 0 y 1 de la probabilidad se hizo directamente en el notebook. Sin embargo, esta lógica podría incluirse en las funciones input_fn, predict_fn y output_fn dentro del script python (transfer_learning.py) que se usaría tanto en entrenamiento como en inferencia. Más detalles sobre cómo personalizar la lógica de inferencia se pueden encontrar aquí.

 

Limpiar recursos

Para evitar costos no deseados, el endpoint creado para la inferencia de plantilla se puede eliminar al finalizar, utilizando el comando:

predictor.delete_endpoint()

 

Conclusión

En esta publicación, demostramos cómo crear un flujo de trabajo de Machine Learning, desde el etiquetado de imágenes hasta la formación, el uso de un guión PyTorch en SageMaker, y terminando con la creación de una instancia de inferencia para hacer inferencias en tiempo real.

 

 


Sobre el autor

Evandro Franco es arquitecto de soluciones para el equipo de Startups de Amazon Web Services. En su puesto, ayuda a las startups a superar los desafíos empresariales aprovechando la plataforma de AWS. Tiene más de 15 años de experiencia en el campo de la tecnología. En su tiempo libre, le gusta correr y pasar tiempo con su familia.

 

 

 

Revisor

Luisa Vesga es arquitecta de soluciones para el equipo de Startups de Amazon Web Services. En su puesto, ayuda a las startups a superar los desafíos empresariales aprovechando la plataforma de AWS. Tiene más de 10 años de experiencia en el campo de la tecnología.