The road of AI Popularization - Huawei cloud ModelArts and AI Gallery experience guide

Posted by mclamais on Sun, 16 Jan 2022 11:04:11 +0100

During school, I mainly studied machine learning and algorithms. I came into contact with big data by chance, and then I started big data. So far, I have also been engaged in the development of big data platform. However, I still cling to AI technology. I usually do some small things related to machine learning, try some demo s, and think that one day I can return to the familiar fields, just like the name of my blog, from big data to artificial intelligence. Since my work is also platform related, this ModelArts experience is not only a product user, but also a product learner for me. Without much to say, let's share with you our experience as a product user.

As a one-stop AI development platform, Huawei cloud ModelArts provides full cycle AI workflow management, enabling users to quickly create and deploy models. For beginners, the beginner tutorial guides users to quickly understand ModelArts products.

Beginner's Guide

The novice entry guide is the object detection project in automatic learning. After the "yunbao image data set", the object detection project is created in automatic learning to realize the model training and model deployment of "yunbao detection". Next, share the getting started project guide.

Create OBS object bucket

OBS is an object storage service of Huawei cloud. Since ModelArts has only been launched in some areas, it is necessary to ensure that the purchased OBS resources are in the same area as ModelArts. For example, I choose "Beijing IV" for all.

OBS has two modes: on-demand charging and volume charging. New users can experience 40G storage service for one year at 9 yuan. For detailed charging methods and purchase methods, please refer to:

Billing method: https://support.huaweicloud.com/drawer-obs/obs_99_0016.html

Purchase method: https://console.huaweicloud.com/console/?region=cn-north-4&locale=zh-cn#/obs/buy

Then create OBS bucket in the above area. For example, I created bigdataoai bucket here

Download data and upload to OBS

download https://modelarts-cnnorth1-market-dataset.obs.cn-north-1.myhuaweicloud.com/dataset-market/Yunbao-Data-Custom/archiver/Yunbao-Data-Custom.zip

Data, upload the data to OBS according to the prompt. There are two ways to upload, one is to upload directly through the web page, and the other is to upload through the OBS desktop tool OBS Browser +. The following describes the way to upload through OBS Browser +.

First, you need to download and install the tool here: https://support.huaweicloud.com/browsertg-obs/obs_03_1003.html . Take windows as an example:

First, apply for the access key. After obtaining the key, fill in the OBS Browser +.

After logging in, you can see the bucket we just created

Create a folder modelArt/dataset/yunbao in the bucket and upload the original data to this directory (you can drag and drop it directly)

Introduction to automatic learning

Then you can use the automatic learning function to train the model of the yunbao image just uploaded.

However, you need to authorize delegates before using them. This article takes the automatic creation of delegates as an example.

Click target detection in automatic learning to create a project using the data we just uploaded

After the project is created, you can use the labeled data for training. There are 20 labeled data in the original data, and the other 40 data are not labeled. In the subsequent steps, you can use manual labeling before model training.

model training

After the training, the following evaluation results are obtained,

The model can then be deployed online

Model use

Use the known and just trained model for prediction, and upload the image in eval through the page

Of course, images can also be detected by api calls.

according to https://support.huaweicloud.com/engineers-modelarts/modelarts_23_0063.html As described above, use postman to obtain X-Auth-Token

Then use the api of the model page to detect the image

This article uses curl to send pictures, (using postman to always return 400) to get the following results

Manually mark data retraining

Just now we used 20 labeled data to train the model. Now we manually label the remaining 40 images.

Retraining with the marked 60 pictures:

The results of retraining are as follows

It can be seen that its performance is improved compared with the training of 20 pictures.

CodeLab - out of the box online NoteBook development environment

Overview

A great advantage of platform is to use it out of the box. I like CodeLab very much. Next, let's experience how to develop using CodeLab.

First, click use now to enter the NoteBook development environment.

CodeLab currently directly supports the following types of machine learning frameworks. If you are not satisfied, you can also use conda to install them freely in the terminal.

Training fully connected networks with mnist data

Reference address: https://mxnet.apache.org/versions/1.5.0/tutorials/gluon/mnist.html

Let me take mxnet framework as an example to try to run the classic handwritten numeral recognition example.

First download training and test data

import mxnet as mx

# Select a fixed random seed for reproducibility
mx.random.seed(42)

def data_xform(data):
    """Move channel axis to the beginning, cast to float32, and normalize to [0, 1]."""
    return nd.moveaxis(data, 2, 0).astype('float32') / 255

train_data = mx.gluon.data.vision.MNIST(train=True).transform_first(data_xform)
val_data = mx.gluon.data.vision.MNIST(train=False).transform_first(data_xform)

Load data

batch_size = 100
train_loader = mx.gluon.data.DataLoader(train_data, shuffle=True, batch_size=batch_size)
val_loader = mx.gluon.data.DataLoader(val_data, shuffle=False, batch_size=batch_size)

Import necessary packages

from __future__ import print_function  # only relevant for Python 2
import mxnet as mx
from mxnet import nd, gluon, autograd
from mxnet.gluon import nn

Building a fully connected network

net = nn.HybridSequential(prefix='MLP_')
with net.name_scope():
    net.add(
        nn.Flatten(),
        nn.Dense(128, activation='relu'),
        nn.Dense(64, activation='relu'),
        nn.Dense(10, activation=None)  # loss function includes softmax already, see below
    )

Network initialization, training with cpu

ctx = mx.cpu(0)
net.initialize(mx.init.Xavier(), ctx=ctx)

Define how to train the fully connected network built above

trainer = gluon.Trainer(
    params=net.collect_params(),
    optimizer='sgd',
    optimizer_params={'learning_rate': 0.04},
)

Define loss function

metric = mx.metric.Accuracy()
loss_function = gluon.loss.SoftmaxCrossEntropyLoss()

Repeat 10 times

num_epochs = 10

for epoch in range(num_epochs):
    for inputs, labels in train_loader:
        # Possibly copy inputs and labels to the GPU
        inputs = inputs.as_in_context(ctx)
        labels = labels.as_in_context(ctx)

        # The forward pass and the loss computation need to be wrapped
        # in a `record()` scope to make sure the computational graph is
        # recorded in order to automatically compute the gradients
        # during the backward pass.
        with autograd.record():
            outputs = net(inputs)
            loss = loss_function(outputs, labels)

        # Compute gradients by backpropagation and update the evaluation
        # metric
        loss.backward()
        metric.update(labels, outputs)

        # Update the parameters by stepping the trainer; the batch size
        # is required to normalize the gradients by `1 / batch_size`.
        trainer.step(batch_size=inputs.shape[0])

    # Print the evaluation metric and reset it for the next epoch
    name, acc = metric.get()
    print('After epoch {}: {} = {}'.format(epoch + 1, name, acc))
    metric.reset()

The training accuracy after 10 times is 0.9725

Next, we use the test set to verify the effect

metric = mx.metric.Accuracy()
for inputs, labels in val_loader:
    # Possibly copy inputs and labels to the GPU
    inputs = inputs.as_in_context(ctx)
    labels = labels.as_in_context(ctx)
    metric.update(labels, net(inputs))
print('Validaton: {} = {}'.format(*metric.get()))
assert metric.get()[1] > 0.96

The test accuracy is 0.9679

Training lenet network with mnist data

Next, we use the above data to train lenet and test the accuracy of the model

Define lenet

lenet = nn.HybridSequential(prefix='LeNet_')
with lenet.name_scope():
    lenet.add(
        nn.Conv2D(channels=20, kernel_size=(5, 5), activation='tanh'),
        nn.MaxPool2D(pool_size=(2, 2), strides=(2, 2)),
        nn.Conv2D(channels=50, kernel_size=(5, 5), activation='tanh'),
        nn.MaxPool2D(pool_size=(2, 2), strides=(2, 2)),
        nn.Flatten(),
        nn.Dense(500, activation='tanh'),
        nn.Dense(10, activation=None),
    )

Training lenet network

trainer = gluon.Trainer(
    params=lenet.collect_params(),
    optimizer='sgd',
    optimizer_params={'learning_rate': 0.04},
)
metric = mx.metric.Accuracy()
num_epochs = 10

for epoch in range(num_epochs):
    for inputs, labels in train_loader:
        inputs = inputs.as_in_context(ctx)
        labels = labels.as_in_context(ctx)

        with autograd.record():
            outputs = lenet(inputs)
            loss = loss_function(outputs, labels)

        loss.backward()
        metric.update(labels, outputs)

        trainer.step(batch_size=inputs.shape[0])

    name, acc = metric.get()
    print('After epoch {}: {} = {}'.format(epoch + 1, name, acc))
    metric.reset()

for inputs, labels in val_loader:
    inputs = inputs.as_in_context(ctx)
    labels = labels.as_in_context(ctx)
    metric.update(labels, lenet(inputs))
print('Validaton: {} = {}'.format(*metric.get()))
assert metric.get()[1] > 0.985

As can be seen from the figure below, the training and testing accuracy of lenet has reached 0.9905 and 0.9879

lenet model export

Next, we export the trained lenet network to the local.

Download the above two files locally and then upload them to OBS.

Creating AI applications using lenet model

After the above steps, we import the lenet model into the following directory of OBS.

In addition, we also need two files to implement model deployment, one is reasoning code and the other is configuration file. The official has provided the reasoning code for handwritten numeral recognition. We can use it directly. The code content is:

customize_service.py

import mxnet as mx
import requests
import zipfile
import json
import shutil
import os
import numpy as np

from mxnet.io import DataBatch
from mms.log import get_logger
from mms.model_service.mxnet_model_service import MXNetBaseService
from mms.utils.mxnet import image, ndarray


logger = get_logger()


def check_input_shape(inputs, signature):
    '''Check input data shape consistency with signature.

    Parameters
    ----------
    inputs : List of NDArray
        Input data in NDArray format.
    signature : dict
        Dictionary containing model signature.
    '''
    assert isinstance(inputs, list), 'Input data must be a list.'
    assert len(inputs) == len(signature['inputs']), 'Input number mismatches with ' \
         'signature. %d expected but got %d.' \
                                           % (len(signature['inputs']), len(inputs))
    for input, sig_input in zip(inputs, signature['inputs']):
        assert isinstance(input, mx.nd.NDArray), 'Each input must be NDArray.'
        assert len(input.shape) == \
               len(sig_input['data_shape']), 'Shape dimension of input %s mismatches with ' \
                                'signature. %d expected but got %d.' \
                                % (sig_input['data_name'], len(sig_input['data_shape']),
                                   len(input.shape))
        for idx in range(len(input.shape)):
            if idx != 0 and sig_input['data_shape'][idx] != 0:
                assert sig_input['data_shape'][idx] == \
                       input.shape[idx], 'Input %s has different shape with ' \
                                         'signature. %s expected but got %s.' \
                                         % (sig_input['data_name'], sig_input['data_shape'],
                                            input.shape)

class DLSMXNetBaseService(MXNetBaseService):
    '''MXNetBaseService defines the fundamental loading model and inference
       operations when serving MXNet model. This is a base class and needs to be
       inherited.
    '''
    def __init__(self, model_name, model_dir, manifest, gpu=None):
        print ("-------------------- init classification servive -------------")
        self.model_name = model_name
        self.ctx = mx.gpu(int(gpu)) if gpu is not None else mx.cpu()
        self._signature = manifest['Model']['Signature']
        data_names = []
        data_shapes = []
        for input in self._signature['inputs']:
            data_names.append(input['data_name'])
            # Replace 0 entry in data shape with 1 for binding executor.
            # Set batch size as 1
            data_shape = input['data_shape']
            data_shape[0] = 1
            for idx in range(len(data_shape)):
                if data_shape[idx] == 0:
                    data_shape[idx] = 1
            data_shapes.append(('data', tuple(data_shape)))
        
        # Load MXNet module
        epoch = 0
        try:
            param_filename = manifest['Model']['Parameters']
            epoch = int(param_filename[len(model_name) + 1: -len('.params')])
        except Exception as e:
            logger.warning('Failed to parse epoch from param file, setting epoch to 0')

        sym, arg_params, aux_params = mx.model.load_checkpoint('%s/%s' % (model_dir, manifest['Model']['Symbol'][:-12]), epoch)
        self.mx_model = mx.mod.Module(symbol=sym, context=self.ctx,
                                      data_names=['data'], label_names=None)
        self.mx_model.bind(for_training=False, data_shapes=data_shapes)
        self.mx_model.set_params(arg_params, aux_params, allow_missing=True)

    def _preprocess(self, data):
        img_list = []
        for idx, img in enumerate(data):
            input_shape = self.signature['inputs'][idx]['data_shape']
            # We are assuming input shape is NCHW
            [h, w] = input_shape[2:]
            if input_shape[1] == 1:
                img_arr = image.read(img, 0)
            else:
                img_arr = image.read(img)
            img_arr = image.resize(img_arr, w, h)
            img_arr = image.transform_shape(img_arr)
            img_list.append(img_arr)
        return img_list

    def _postprocess(self, data):
        dim = len(data[0].shape)
        if dim > 2:
            data = mx.nd.array(np.squeeze(data.asnumpy(), axis=tuple(range(dim)[2:])))
        sorted_prob = mx.nd.argsort(data[0], is_ascend=False)
        top_prob = map(lambda x: int(x.asscalar()), sorted_prob[0:5])
        return [{'probability': float(data[0, i].asscalar()), 'class': i}
                for i in top_prob]

    def _inference(self, data):
        '''Internal inference methods for MXNet. Run forward computation and
        return output.

        Parameters
        ----------
        data : list of NDArray
            Preprocessed inputs in NDArray format.

        Returns
        -------
        list of NDArray
            Inference output.
        '''
        # Check input shape
        check_input_shape(data, self.signature)
        data = [item.as_in_context(self.ctx) for item in data]
        self.mx_model.forward(DataBatch(data))
        return self.mx_model.get_outputs()[0]

    def ping(self):
        '''Ping to get system's health.

        Returns
        -------
        String
            MXNet version to show system is healthy.
        '''
        return mx.__version__

    @property
    def signature(self):
        '''Signiture for model service.

        Returns
        -------
        Dict
            Model service signiture.
        '''
        return self._signature

The next step is the configuration file. Its content is that we can modify the content in metrics according to the accuracy of our own model

config.json

{"model_type": "MXNet", "metrics": {"f1": 0.39542, "accuracy": 0.987426, "precision": 0.395875, "recall": 0.394966}, "dependencies": [], "model_algorithm": "image_classification", "apis": [{"procotol": "http", "url": "/", "request": {"Content-type": "multipart/form-data", "data": {"type": "object", "properties": {"images": {"type": "file"}}}}, "method": "post", "response": {"Content-type": "multipart/form-data", "data": {"required": ["predicted_label", "scores"], "type": "object", "properties": {"scores": {"items": {"minItems": 2, "items": [{"type": "string"}, {"type": "number"}], "type": "array", "maxItems": 2}, "type": "array"}}}}}]}

Copy the above two files to OBS

Next, we can build AI applications based on the above model.

After the application is created, the application can then be deployed online.

Add environment variable

input_data_name: images

input_data_shape: 0,1,28,28

output_data_shape: 0,10

Wait for the deployment to complete before performing the prediction operation. Since we define the image size as 28x28 in the model, the image we input is a 28x28 black-and-white digital image.

The image can be obtained by the following methods:

Get mnist pictures through search engine search, and then take screenshots:

Then use the online picture resizing tool to adjust the picture to 28x28,

Online picture adjustment tool website: https://www.iloveimg.com/zh-cn/resize-image#resize-options,pixels

Then, after the above operations, we get a 28x28 black-and-white handwritten 7 image

Upload this image in forecast

Then click forecast to get the following forecast results

Lenet MNIST 28x28 handwritten numeral recognition model release

Click the following link to enter the model publishing page

https://developer.huaweicloud.com/develop/aigallery/model/list

Final release page

https://developer.huaweicloud.com/develop/aigallery/model/detail?id=d6fcb13b-adc8-448e-a523-5d7f5d44b7a2

Subscribe model from AI Gallery

AI gallery is an AI application market based on ModelArts. This function greatly reduces the development threshold of AI model. In the AI model market based on AI Gallery, users can directly use the model even if they do not understand AI knowledge and subscribe to model services. I think with the progress of technology and the development of society, AI will certainly tend to be civilian, and the function of AI gallery is a great pioneer in this direction.

Next, let's share with you how to subscribe to the model I just released and then deploy it quickly.

First, enter the model subscription page and click subscribe: https://developer.huaweicloud.com/develop/aigallery/model/detail?id=d6fcb13b-adc8-448e-a523-5d7f5d44b7a2

After the subscription is completed, go to the console and select the cloud service area where ModelArts is located. I still choose Beijing 4. After entering the console, you can directly deploy the model online

Similarly, when deploying the model, add the following environment variables

input_data_name: images

input_data_shape: 0,1,28,28

output_data_shape: 0,10

After the model is successfully deployed, handwritten numeral recognition can be carried out

summary

Huawei cloud modelArts and AI Gallery pave a very broad path for AI popularization, and people at all levels can walk on it. Competent AI developers can focus more on model and algorithm development without paying attention to the details of the underlying hardware; Ordinary users can use the automatic learning module for model development and deployment; For students without any AI prior knowledge, with AI Gallery, AI applications can be easily deployed in just a few steps.

From the perspective of the platform, I like this product very much. Advanced functions, easy to start, and tall capabilities are directly popularized through the platform, which may also be the direction of platform development in our work.

Topics: AI Huawei Cloud modelarts