³µÍ×

Amazon SageMaker ¤Î¥¨¥ó¥É¥Ý¥¤¥ó¥È¤Ë·±ÎýºÑ¤ß¥â¥Ç¥ë¤ò¥Ç¥×¥í¥¤¤·¤Æ¿äÏÀ¤ò¹Ô¤Ã¤Æ¤ß¤¿¡£
¾°¡¢º£²ó¤Ï PyTorch ¤òÍøÍѤ·¤¿¤¬¡¢ ¾¤Ë¤â tensorflow ¤ä chainer ¤Ê¤É¾¤Î¥Õ¥ì¡¼¥à¥ï¡¼¥¯¤âÍøÍѤǤ­¤ë¡£

Amazon SageMaker ¤Ç PyTorch ¤ò»ÈÍÑ
https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/pytorch.html

Ìܼ¡

¥â¥Ç¥ë¥Ç¡¼¥¿¤òºîÀ®¤·S3¥Ð¥±¥Ã¥È¤Ë¾å¤²¤ë

¥â¥Ç¥ë¤Ï PyTorch¤Ç½Å²óµ¢Ê¬ÀÏ ¤ÇºîÀ®¤·¤¿¤â¤Î¤ò¤½¤Î¤Þ¤ÞÍøÍѤ¹¤ë¡£

¥¢¥Ã¥×¥í¡¼¥É¤¹¤ë¥Õ¥©¥ë¥À¤Î¹½À®

°Ê²¼¤Î¹½À®¤Î¥Õ¥©¥ë¥À¤òºîÀ®¤¹¤ë¡£

sample_torch_model.tgz
¡¡¨¦ sample_torch_model.pth ... ¥¨¥¯¥¹¥Ý¡¼¥È¤·¤¿·±ÎýºÑ¤ß¥â¥Ç¥ë
¡¡¨¦ sample_torch_model_scalar.json ... º£²ó¤Ï¥¨¥ó¥É¥Ý¥¤¥ó¥È¦¤ÇÆþÎϥǡ¼¥¿¤Îɸ½à²½¤ò¤·¤¿¤¤¤Î¤ÇɬÍפʾðÊó¤òJSON²½¤·¤Æ°ì½ï¤Ë¥¢¥Ã¥×¤·¤Æ¤ª¤¯(¸å½Ò)

¥â¥Ç¥ë¤ÎºîÀ® µÚ¤Ó ¥¨¥¯¥¹¥Ý¡¼¥È

¥â¥Ç¥ë¤Ï PyTorch¤Ç½Å²óµ¢Ê¬ÀÏ ¤ÇºîÀ®¤·¤¿¤â¤Î¤ò¤½¤Î¤Þ¤Þ»ÈÍÑ¡£

¤¢¤È¤Ï°Ê²¼¤ÎÄ̤ꡢ¥¨¥¯¥¹¥Ý¡¼¥È¤¹¤ë¤À¤±¡£

import json
import os

model_name = "sample_torch_model"
if not os.path.exists(model_name):
    os.mkdir(model_name)

# ·±ÎýºÑ¤ß¥â¥Ç¥ë¤òÊݸ
model_path = f"{model_name}/{model_name}.pth"
#model_state = model.state_dict()
#model_state["my_scaler_params"] = scaler.get_params()
#model_state["my_scaler_mean"] = scaler.mean_
#model_state["my_scaler_var"] = scaler.var_
#model_state["my_scaler_scale"] = scaler.scale_
#torch.save(model_state, model_path)
torch.save(model.state_dict(), model_path)

#
# ɸ½à²½¤ËɬÍפÊÃͤòJSON¤ËÊݸ
#
scaler_dict = {}
scaler_dict["my_scaler_params"] = scaler.get_params()
scaler_dict["my_scaler_mean"] = scaler.mean_.tolist()
scaler_dict["my_scaler_var"] = scaler.var_.tolist()
scaler_dict["my_scaler_scale"] = scaler.scale_.tolist()
with open(f"{model_name}/{model_name}_scalar.json", "w") as f:
    f.write(json.dumps(scaler_dict))

tar.gz ¤Ë¤¹¤ë

³¬Áؤòºî¤ê¤¿¤¯¤Ê¤«¤Ã¤¿¤Î¤Ç¡¢¤¤¤Ã¤¿¤óÂоݥե©¥ë¥À¤Ë°ÜÆ°¤·¤ÆƱ¤¸¥Õ¥©¥ë¥À¤Î¤â¤Î¤ò¥¢¡¼¥«¥¤¥Ö¤·¤¿¡£

cd sample_torch_model
tar czfv ../sample_torch_model.tar.gz .
cd ../

S3¤Ë¥¢¥Ã¥×¥í¡¼¥É

¥Ð¥±¥Ã¥ÈºîÀ®

aws s3 mb s3://¥Ð¥±¥Ã¥È̾

s3¤Ë¥¢¥Ã¥×¥í¡¼¥É

aws s3api put-object --bucket ºîÀ®¤·¤¿¥Ð¥±¥Ã¥È̾ --key sample_torch_model.tar.gz --body ./sample_torch_model.tar.gz

¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹¤ÎºîÀ®

Amazon SageMaker ¥³¥ó¥½¡¼¥ë¤«¤é ¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹ ¤Ë°ÜÆ°¸å¡¢[¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹¤ÎºîÀ®] ¤ò²¡²¼¤·¤ÆºîÀ®¤¹¤ë¡£

º£²ó¤Ï°Ê²¼¤ÎÄ̤êºîÀ®¤·¤¿¡£
¢¨°Ê²¼¤Ëµ­ºÜ¤Î¤Ê¤¤¤â¤Î¤Ï¡¢Á´¤Æ̤ÁªÂò ¤Þ¤¿¤Ï ¥Ç¥Õ¥©¥ë¥ÈÃͤǺîÀ®¤·¤¿¡£

ÀßÄê̾ÀßÄêÆâÍÆÊä­
¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹Ì¾sample-notebook1
¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹¤Î¥¿¥¤¥×ml.t2.medium
Elastic Inferenceº£²ó¤Ï»ÈÍѤ·¤Ê¤¤¿äÏÀ¤ò¥¬¥ó¥¬¥ó¹Ô¤¦¾ì¹ç¤Ï»ÈÍѤ¹¤ë(GPU¤¬»È¤¨¤ë)
¥é¥¤¥Õ¥µ¥¤¥¯¥ëÀßÄê¤Ê¤·
¥Ü¥ê¥å¡¼¥à¥µ¥¤¥º5GB
IAM ¥í¡¼¥ë[¿·¤·¤¤¥í¡¼¥ë¤ÎºîÀ®] ¤«¤é ºîÀ®¡ÖǤ°Õ¤Î S3 ¥Ð¥±¥Ã¥È¡×¤Ø¤Î¥¢¥¯¥»¥¹¤òµö²Ä¡£
¥ë¡¼¥È¥¢¥¯¥»¥¹Í­¸ú²½

¤·¤Ð¤é¤¯¤¹¤ë¤È¥¹¥Æ¡¼¥¿¥¹¤¬ [Pending] ¤«¤é [InService] ¤ËÊѤï¤ë¤Î¤Ç¡¢[Jupyter ¤ò³«¤¯] ¤«¤é jupyter notebook ¤ò³«¤¯¡£

[Êä­]
¶²¤é¤¯ IAM ¥í¡¼¥ë ( AmazonSageMakerFullAccess ) ¤¬ÀßÄꤵ¤ì¤Æ¤¤¤ëIAM¥æ¡¼¥¶¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð¡¢¥í¡¼¥«¥ë¤Î jupyter ¤Ç¤âÌäÂê¤Ê¤¤¤È»×¤ï¤ì¤ë¡£
¢¨º£²ó¤Ï»î¤·¤Æ¤¤¤Ê¤¤¡£

¥Ç¥×¥í¥¤

¥¨¥ó¥È¥ê¥Ý¥¤¥ó¥È¤È¤Ê¤ë¥Õ¥¡¥¤¥ë¤ÎºîÀ®

¤Þ¤º¥¨¥ó¥È¥ê¥Ý¥¤¥ó¥È¤È¤Ê¤ë¥Õ¥¡¥¤¥ë¤ò¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹¾å¤ËºîÀ®¤¹¤ë¡£
²òÀâ¤Ï¸å½Ò¤¹¤ë»ö¤È¤·¤Æ¤Þ¤º¤Ï¥³¡¼¥É¡£

entry_point.py

import argparse
import logging
import sagemaker_containers
import requests

import torch
import torch.nn as nn
import numpy as np
from six import BytesIO
from sklearn.preprocessing import StandardScaler

import os
import io
import json
import glob
import time
import re

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

JSON_CONTENT_TYPE = 'application/json'
XNPY_CONTENT_TYPE = 'application/x-npy'
CSV_CONTENT_TYPE  = 'text/csv'

INPUT_SIZE = 2
OUTPUT_SIZE = 1

class LinearRegression(nn.Module):
    """¥â¥Ç¥ëÄêµÁ"""
    def __init__(self, input_size, output_size):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(input_size, output_size)
    def forward(self, x): 
        out = self.linear(x)
        return out

def model_fn(model_dir):
    """¥â¥Ç¥ë¤Î¥í¡¼¥É."""
    logger.info('START model_fn')
    model = LinearRegression(INPUT_SIZE, OUTPUT_SIZE)
    # ¥â¥Ç¥ë¤Î¥Ñ¥é¥á¡¼¥¿ÀßÄê
    with open(os.path.join(model_dir, 'sample_torch_model.pth'), 'rb') as f:
        model.load_state_dict(torch.load(f))
    # Æȼ«¥Ñ¥é¥á¡¼¥¿¤òÀßÄê
    with open(os.path.join(model_dir, 'sample_torch_model_scalar.json')) as f:
        my_state = json.load(f)
        for k,v in my_state.items():
            model.__dict__[k] = v
    logger.info('END   model_fn')
    return model

def input_fn(request_body, content_type=JSON_CONTENT_TYPE):
    """ÆþÎϥǡ¼¥¿¤Î·Á¼°ÊÑ´¹."""
    logger.info('START input_fn')
    logger.info(f'content_type: {content_type}')
    logger.info(f'request_body: {request_body}')
    logger.info(f'type: {type(request_body)}')
    if content_type == XNPY_CONTENT_TYPE:
        stream = BytesIO(request_body)
        input_data = np.load(stream)
    elif content_type == CSV_CONTENT_TYPE:
        request_body = request_body.encode("utf-8") if isinstance(request_body, str) else request_body
        input_data = np.loadtxt(BytesIO(request_body), delimiter=",")
    elif content_type == JSON_CONTENT_TYPE:
        input_data = np.array(json.loads(request_body))
    else:
        # TODO: content_type¤Ë±þ¤¸¤Æ¥Ç¡¼¥¿·¿ÊÑ´¹
        logger.error(f"content_type invalid: {content_type}")
        input_data = {"errors": [f"content_type invalid: {content_type}"]}
    logger.info('END   input_fn')
    return input_data

def predict_fn(input_data, model):
    """¿äÏÀ."""
    logger.info('START predict_fn')

    if isinstance(input_data, dict) and 'errors' in input_data:
        logger.info('SKIP  predict_fn')
        logger.info('END   predict_fn')
        return input_data
        
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.to(device)
    model.eval()

    # ÀâÌÀÊÑ¿ô¤Îɸ½à²½
    scaler = StandardScaler()
    scaler.set_params(**model.my_scaler_params)
    scaler.mean_ = model.my_scaler_mean
    scaler.var_ = model.my_scaler_var
    scaler.scale_ = model.my_scaler_scale
    scaled_input_data = scaler.transform(input_data)
    converted_input_data = torch.Tensor(scaled_input_data)

    # ¿äÏÀ
    with torch.no_grad():
        logger.info('END   predict_fn')
        return model(converted_input_data.to(device))

def output_fn(prediction, accept=JSON_CONTENT_TYPE):
    """½ÐÎϥǡ¼¥¿¤Î·Á¼°ÊÑ´¹."""
    logger.info('START output_fn')
    logger.info(f"accept: {accept}")

    if isinstance(prediction, dict) and 'errors' in prediction:
        logger.info('SKIP  output_fn')
        response = json.dumps(prediction)
        content_type = JSON_CONTENT_TYPE
    elif accept == XNPY_CONTENT_TYPE:
        buffer = BytesIO()
        np.save(buffer, prediction)
        response = buffer.getvalue()
        content_type = XNPY_CONTENT_TYPE
    elif accept == JSON_CONTENT_TYPE:
        response = json.dumps({"results": [prediction.data[i].item() for i in range(len(prediction.data))]})
        content_type = JSON_CONTENT_TYPE
    else:
        # TODO: ¥³¥ó¥Æ¥ó¥Ä¥¿¥¤¥×¤Ë±þ¤¸¤ÆÊÑ´¹
        response = json.dumps({"results": [prediction.data[i].item() for i in range(len(prediction.data))]})
        content_type = JSON_CONTENT_TYPE

    logger.info('END   output_fn')
    return response, content_type


if __name__ == '__main__':
    # ·±Îý¤·¤Æ¤«¤é¥Ç¥×¥í¥¤¤¹¤ë¾ì¹ç¤Ï¤³¤³¤Ç¹Ô¤¦
    logger.info("process main!")
    pass

¥¨¥ó¥È¥ê¥Ý¥¤¥ó¥È¤Î²òÀâ

»²¹Í
https://sagemaker.readthedocs.io/en/stable/using_pytorch.html#load-a-model
https://sagemaker.readthedocs.io/en/stable/using_pytorch.html#serve-a-pytorch-model

¼ÂÁõ¤¹¤ëɬÍפ¬¤¢¤ë´Ø¿ô

¾åµ­¤Ç¥¨¥ó¥È¥ê¥Ý¥¤¥ó¥È¤Ë»ØÄꤷ¤¿¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢°Ê²¼¤Î´Ø¿ô¤ò´Þ¤á¤ëɬÍפ¬¤¢¤ë¡£

´Ø¿ô̾ÀâÌÀ
model_fn¥â¥Ç¥ë¤Î¥í¡¼¥É¤ò¹Ô¤¦´Ø¿ô
input_fnÆþÎϥǡ¼¥¿¤Î·Á¼°ÊÑ´¹¤ò¹Ô¤¦´Ø¿ô
predict_fn¿äÏÀ¤ò¹Ô¤¦´Ø¿ô
output_fn·ë²Ì¤ò¸Æ¤Ó½Ð¤·¸µ¤ËÊֵѤ¹¤ë»þ¤Ë·Á¼°ÊÑ´¹¤ò¹Ô¤¦´Ø¿ô

¥â¥Ç¥ë¤Î¥í¡¼¥É ( model_fn )

model_fn ¤Ç¤Ï¥â¥Ç¥ë¤Î¥í¡¼¥É¤ò¹Ô¤¦¡£
¤ä¤ë»ö¤Ï¡¢°ú¿ô¤ÇÅϤäƤ¯¤ë¥â¥Ç¥ë¥Ç¥£¥ì¥¯¥È¥êÇÛ²¼¤Î¥â¥Ç¥ë¤òÍøÍѤ¹¤ë·Á¼°¤Ë¹ç¤ï¤»¤Æ¥í¡¼¥É¤¹¤ë¤À¤±¡£
¥â¥Ç¥ë¤Î¾¤ËÊ̤Υǡ¼¥¿ (º£²ó¤Ç¤¤¤¦¤Èɸ½à²½ÍѤÎJSON) ¤ò´Þ¤á¤Æ¥¢¥Ã¥×¥í¡¼¥É¤·¤¿¾ì¹ç¤Ï¡¢¤³¤³¤ÇÍøÍѤ¹¤ë»ö¤¬¤Ç¤­¤ë¡£

ÆþÎϥǡ¼¥¿¤Î·Á¼°ÊÑ´¹ ( input_fn )

input_fn ¤Ç¤ÏÆþÎϥǡ¼¥¿¤Î·Á¼°ÊÑ´¹¤ò¹Ô¤¦¡£

°ú¿ô¤Î¥³¥ó¥Æ¥ó¥Ä¥¿¥¤¥×¤«¤éÆþÎϥǡ¼¥¿¤Î·Á¼°¤òȽÊ̤·¤Æ¡¢¿äÏÀÍѤΥǡ¼¥¿·¿¤ËÊÑ´¹¤¹¤ëºî¶È¤ò¹Ô¤¦»ö¤Ë¤Ê¤ë¡£
¾°¡¢º£²ó»î¤·¤¿£³¤Ä¤Î·Á¼°( numpy.ndarray¡¢csv¡¢json ) ¤Î¾ì¹ç¡¢°ú¿ô¤Î¥Ç¡¼¥¿¤ÏÁ´¤Æ bytearray ¤ÇÅϤäƤ¯¤ë°Ù¡¢
bytearray ¤ò numpy.ndarray ¤ËÊÑ´¹¤¹¤ëºî¶È¤ò¹Ô¤Ã¤¿¡£

º£²ó¤Ï PyTorch ¤ò»ÈÍѤ·¤Æ¤¤¤ë¤Î¤Ç¡¢¤³¤³¤Ç torch.Tensor ¤Þ¤ÇÊÑ´¹¤·¤Æ¤ª¤¤¤Æ¤â¤è¤«¤Ã¤¿¤Î¤À¤¬¡¢
ɸ½à²½ÍѤÎÆȼ«¥Ñ¥é¥á¡¼¥¿¤ò¥â¥Ç¥ë¤Ë°ú¤ÃÉÕ¤±¤Æ¤ª¤ê¡¢¤³¤³¤Ç¤Ïɸ½à²½¤Þ¤Ç¹Ô¤¦»ö¤¬¤Ç¤­¤Ê¤«¤Ã¤¿¤Î¤Ç¡¢¤¤¤Ã¤¿¤ó numpy.ndarray ¤Þ¤Ç¤ÎÊÑ´¹¤È¤·¤¿¡£
¢¨°ú¿ô¤Ë¥â¥Ç¥ë¤¬¤Ê¤¤°Ù¡£

¿äÏÀ¤Î¼Â¹Ô ( predict_fn )

input_fn ¤Ç·Á¼°ÊÑ´¹¤·¤¿¥Ç¡¼¥¿¤òÆþÎϤȤ·¤Æ¼ÂºÝ¤Î¿äÏÀ¤ò¹Ô¤¦¡£
¥¨¥ó¥É¥Ý¥¤¥ó¥È¤Î¥¤¥ó¥¹¥¿¥ó¥¹¥¿¥¤¥×¤Ë¤è¤Ã¤Æ¤Ï GPU ¤¬ÍøÍѤǤ­¤Ê¤¤°Ù¡¢GPU/CPU ¤É¤Á¤é¤Ç¤â¿äÏÀ¤¬¤Ç¤­¤ë¤è¤¦¤Ë¼ÂÁõ¤·¤Æ¤ª¤¯¡£

º£²ó¤Ï¡¢ÅÔ¹ç¾å¤³¤³¤Çɸ½à²½ µÚ¤Ó torch.Tensor ¤Ø¤ÎÊÑ´¹¤Þ¤Ç¹Ô¤Ã¤¿¡£

½ÐÎϥǡ¼¥¿¤Î·Á¼°ÊÑ´¹ ( output_fn )

¸Æ¤Ó½Ð¤·¸µ¤Ç»ØÄꤵ¤ì¤¿ accept ¤ÎÃͤ˱þ¤¸¤Æ¡¢½ÐÎÏ·Á¼°¤ÎÊÑ´¹¤ò¹Ô¤¦¡£
º£²ó¤Ï¡¢¥µ¥ó¥×¥ë¤È¤·¤Æ numpy.ndarray¡¢csv¡¢json ¤Î£³¤Ä¤À¤±¼ÂÁõ¤·¤Æ¤ß¤¿¡£

¿äÏÀ»þ¤Î½èÍý¤Îή¤ì

¿äÏÀ»þ¤Î½èÍý¤Ï°Ê²¼¤ÎÄ̤ê¼Â¹Ô¤µ¤ì¤ë¡£

input_object = input_fn(request_body, request_content_type)

prediction = predict_fn(input_object, model)

output = output_fn(prediction, response_content_type)

¤½¤Î¾

¤³¤³¤é¤Ø¤ó¤ò¸«¤ë¸Â¤ê¡¢Â¾¤Î°Í¸¥é¥¤¥Ö¥é¥êÅù¤¬¤¢¤ë¾ì¹ç¤Ë¤Ï¥â¥Ç¥ë¥Ç¡¼¥¿¤Ë´Þ¤á¤Æ¥¢¥Ã¥×¥í¡¼¥É¤¹¤ë»ö¤¬¤Ç¤­¤ëÌÏÍÍ¡£
https://sagemaker.readthedocs.io/en/stable/using_pytorch.html#optional-arguments

¥¨¥ó¥É¥Ý¥¤¥ó¥È¤ÎºîÀ®¡¢¥Ç¥×¥í¥¤

¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹¾å¤«¤é°Ê²¼¤ò¼Â¹Ô¤¹¤ë¡£

# ¥¨¥ó¥É¥Ý¥¤¥ó¥È¤ÎºîÀ®¡¢¥Ç¥×¥í¥¤
sagemaker_session = sagemaker.Session()
role = sagemaker.get_execution_role()

# ¥â¥Ç¥ë¤ÎºîÀ®
pytorch_model = PyTorchModel(model_data="s3://¥Ð¥±¥Ã¥È̾/sample_torch_model.tar.gz",
                             role=role,
                             framework_version='1.3.1',
                             entry_point="entry_point.py")
# ¥Ç¥×¥í¥¤¥Ñ¥é¥á¡¼¥¿
deploy_params = {
    'instance_type'          : 'ml.t2.medium'  # ¤ª»î¤·ÍÑ (https://aws.amazon.com/jp/sagemaker/pricing/instance-types/ )
    ,'initial_instance_count' : 1              # ¤ª»î¤·ÍÑ
    #,'endpoint_name'          : 'sample-torch-model4'  # ¥¨¥ó¥É¥Ý¥¤¥ó¥È̾¤ò»ØÄꤷ¤Æ¤Î¥Ç¥×¥í¥¤¤¬²¿¸Î¤«¤Ç¤­¤Ê¤¤
}

# ¥Ç¥×¥í¥¤
predictor = pytorch_model.deploy(**deploy_params)

https://sagemaker.readthedocs.io/en/stable/sagemaker.pytorch.html#sagemaker.pytorch.model.PyTorchModel

¥Ç¥×¥í¥¤¤·¤¿¥¨¥ó¥É¥Ý¥¤¥ó¥È¤ò»È¤Ã¤Æ¿äÏÀ¤·¤Æ¤ß¤ë

import pandas as pd

# ÆþÎϥǡ¼¥¿ ([Éô²°¤Î¹­¤µ, ÃÛǯ¿ô])
input_data = [[60.0, 10.0], [50.0, 10.0], [40.0, 10.0]]

# ¿äÏÀ
predict_data = np.array(input_data)
results = predictor.predict(predict_data)

# ·ë²Ìɽ¼¨
result_df = pd.DataFrame(results, columns=["²ÈÄÂ(Ëü±ß)"])
result_df["¹­¤µ(­Ö)"] = predict_data[:,0]
result_df["ÃÛǯ¿ô"] = predict_data[:,1]
result_df

·ë²Ì

²ÈÄÂ(Ëü±ß) ¹­¤µ(­Ö) ÃÛǯ¿ô
0 8.117216 60.0 10.0
1 7.191902 50.0 10.0
2 6.266588 40.0 10.0

Lambda¤Ê¤É¤«¤é¥¨¥ó¥É¥Ý¥¤¥ó¥È¤òÍøÍѤ¹¤ë

#
# sage maker°Ê³°¤«¤é¥¨¥ó¥É¥Ý¥¤¥ó¥È¤òÍøÍѤ·¤Æ¿äÏÀ
#
import boto3
import json

# ÆþÎϥǡ¼¥¿ ([Éô²°¤Î¹­¤µ, ÃÛǯ¿ô])
input_data = [[60.0, 10.0], [50.0, 10.0], [40.0, 10.0]]

# ¥¨¥ó¥É¥Ý¥¤¥ó¥È̾
endpoint_name = "pytorch-inference-2020-02-28-12-35-37-541"

# JSON¤òÁ÷¿®¤¹¤ë¾ì¹ç
request_body = json.dumps(input_data)
content_type = "application/json"
accept_type  = "application/json"

# CSV¤òÁ÷¿®¤¹¤ë¾ì¹ç
#request_body = '\n'.join([','.join([str(x) for x in rec]) for rec in input_data])
#content_type = "text/csv"
#accept_type  = "application/json"

# ¿äÏÀ
client = boto3.client('sagemaker-runtime')
response = client.invoke_endpoint(
    EndpointName=endpoint_name,
    Body=request_body,
    ContentType=content_type,
    Accept=accept_type
)

# ·ë²Ìɽ¼¨
print("### response (Body°Ê³°)###")
print(json.dumps({k:v for k,v in response.items() if k != 'Body'}, indent=4))
print("### response (Body) ###")
response_dict = json.loads(response['Body'].read().decode("utf-8"))
print(json.dumps(response_dict, indent=4))

·ë²Ì

### response (Body°Ê³°)###
{
    "ResponseMetadata": {
        "RequestId": "f5cca038......",
        "HTTPStatusCode": 200,
        "HTTPHeaders": {
            "x-amzn-requestid": "f5cca038......",
            "x-amzn-invoked-production-variant": "AllTraffic",
            "date": "Sat, 29 Feb 2020 XX:XX:XX GMT",
            "content-type": "application/json",
            "content-length": "69"
        },
        "RetryAttempts": 0
    },
    "ContentType": "application/json",
    "InvokedProductionVariant": "AllTraffic"
}
### response (Body) ###
{
    "results": [
        8.117216110229492,
        7.191902160644531,
        6.26658821105957
    ]
}

¸åÊÒÉÕ¤±

¥Î¡¼¥È¥Ö¥Ã¥¯¥¤¥ó¥¹¥¿¥ó¥¹¤«¤é°Ê²¼¤ò¼Â¹Ô¤¹¤ë»ö¤Ç¥¨¥ó¥É¥Ý¥¤¥ó¥È¤Îºï½ü¤¬²Äǽ¡£

sagemaker.Session().delete_endpoint(predictor.endpoint)

¥È¥Ã¥×   º¹Ê¬ ¥Ð¥Ã¥¯¥¢¥Ã¥× ¥ê¥í¡¼¥É   °ìÍ÷ ñ¸ì¸¡º÷ ºÇ½ª¹¹¿·   ¥Ø¥ë¥×   ºÇ½ª¹¹¿·¤ÎRSS
Last-modified: 2020-03-02 (·î) 02:02:14 (1517d)