<jupyter_start><jupyter_text>Image Classification @Edge with SageMaker Neo + Pytorch + Resnet18**SageMaker Studio Kernel**: Data ScienceIn this exercise you'll:   - Get a pre-trained model from the torchvision model zoo: Resnet18   - Prepare the model to compile it with Neo   - Compile the model for the target: **X86_64**   - Get the optimized model and run a simple local test  install dependencies<jupyter_code>!apt update -y && apt install -y libgl1
!pip install torch==1.7.0 torchvision==0.8.0 opencv-python dlr==1.8.0<jupyter_output><empty_output><jupyter_text>1) Load a pre-trained model from the model zoo and trace it with Pytorch JIT-> SagMaker Neo expectes the model in the traced format<jupyter_code>import torch
import torchvision.models as models
img_size = 224
resnet18 = models.resnet18(pretrained=True)
input_shape = [1, 3, img_size, img_size]
trace = torch.jit.trace(resnet18.float().eval(), torch.zeros(input_shape).float())
trace.save("model.pth")<jupyter_output><empty_output><jupyter_text>2) Create a package with the model and upload to S3<jupyter_code>import tarfile
import sagemaker

sagemaker_session = sagemaker.Session()
model_name='resnet18'

with tarfile.open("model.tar.gz", "w:gz") as f:
    f.add("model.pth")
    f.list()

s3_uri = sagemaker_session.upload_data('model.tar.gz', key_prefix=f'{model_name}/model')
print(s3_uri)<jupyter_output><empty_output><jupyter_text>3) Compile the model with SageMaker Neo (X86_64)<jupyter_code>import time
import boto3
import sagemaker

role = sagemaker.get_execution_role()
sm_client = boto3.client('sagemaker')
compilation_job_name = f'{model_name}-pytorch-{int(time.time()*1000)}'
sm_client.create_compilation_job(
    CompilationJobName=compilation_job_name,
    RoleArn=role,
    InputConfig={
        'S3Uri': s3_uri,
        'DataInputConfig': f'{{"input": [1,3,{img_size},{img_size}]}}',
        'Framework': 'PYTORCH'
    },
    OutputConfig={
        'S3OutputLocation': f's3://{sagemaker_session.default_bucket()}/{model_name}-pytorch/optimized/',
        'TargetPlatform': { 
            'Os': 'LINUX', 
            'Arch': 'X86_64',
        },
    },
    StoppingCondition={ 'MaxRuntimeInSeconds': 900 }
)
while True:
    resp = sm_client.describe_compilation_job(CompilationJobName=compilation_job_name)    
    if resp['CompilationJobStatus'] in ['STARTING', 'INPROGRESS']:
        print('Running...')
    else:
        print(resp['CompilationJobStatus'], compilation_job_name)
        break
    time.sleep(5)<jupyter_output><empty_output><jupyter_text>4) Download the compiled model<jupyter_code>output_model_path = f's3://{sagemaker_session.default_bucket()}/{model_name}-pytorch/optimized/model-LINUX_X86_64.tar.gz'
!aws s3 cp $output_model_path /tmp/model.tar.gz
!rm -rf model_classifier && mkdir model_classifier
!tar -xzvf /tmp/model.tar.gz -C model_classifier<jupyter_output><empty_output><jupyter_text>5) Run the model locally  download the labels and a sample image<jupyter_code>%matplotlib inline
import numpy as np
import cv2
import matplotlib.pyplot as plt
import os
import urllib.request

labels_url='https://raw.githubusercontent.com/DenWhiteHouse/DogClassification/master/imagenet1000_clsidx_to_labels.txt'
image_url='https://sagemaker-examples.readthedocs.io/en/latest/_images/cat2.jpg'
if not os.path.exists('cat.jpg'):
    urllib.request.urlretrieve(labels_url, 'labels.txt')
    urllib.request.urlretrieve(image_url, 'cat.jpg')
# quick and dirty parser for the labels
labels = {}
for l in open('labels.txt', 'r').read().splitlines():
    l = l.strip().replace('{', '').replace('}', '')
    l = l[:-1] if l.endswith(',') else l
    cls_id,label = [t.strip() for t in l.split(':')]
    labels[int(cls_id)] = label[1:-1] # remove the single quotes<jupyter_output><empty_output><jupyter_text>load the model using the runtime DLR<jupyter_code>import dlr
# load the model (CPU x86_64)
model = dlr.DLRModel('model_classifier', 'cpu')
# load the image and make it squared if needed
img = cv2.cvtColor(cv2.imread('cat.jpg'), cv2.COLOR_BGR2RGB)
h,w,c = img.shape
if w!=h: # pad the image and make it square
    sqr_size = max(h,w)
    sqr_img = np.zeros((sqr_size, sqr_size, c), dtype=np.uint8)
    sqr_img[:h, :w],img = img,sqr_img
# resize the image to the expected size+transform it to pytorch/imagenet format
x = cv2.resize(img, (img_size, img_size)).astype(np.float32) / 255.0
# normalize
x -= [0.485, 0.456, 0.406]
x /= [0.229, 0.224, 0.225]
x = x.transpose(2,0,1) # HWC --> CHW
c,h,w = x.shape
x = x.reshape(1,c,h,w) # CHW --> NCHW
y = model.run(x)
idx = np.argmax(y)
print(f"Class id: {idx}, Score: {y[0][0][idx]}, Label: {labels[idx]}")
plt.imshow(img)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14038830808619587, 'fraction_numerical': 0.02645615532323448, 'mean_word_length': 4.987228607918263, 'pattern_counts': {'":': 1, '<': 29, '<?xml version=': 0, '>': 32, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '413881', 'license': 'MIT-0', 'n_tokens_mistral': 1797, 'n_tokens_neox': 1714, 'n_words': 371, 'path': 'tutorials/01_ImageClassificationPytorchResnet18.ipynb', 'repo_name': 'vrakesh/ml-edge-getting-started', 'size': '4687'}