Thanks Bo. This is really very helpful. This makes life lot easier. Specially I like the Sage maker deployment part. I will test the same and get back to you.
I also found another way to update the fastai version:
Simply supply the PyTorchModel
instance with a source_dir
parameter.
Put a requirements.txt
and your entry point file in the specified folder. In the requirements.txt
list your desired fastai version and you`re good to go.
hey @matt.mcclean When opening the lesson 1 pets on sagemaker it says kernel not found The documentation says chose conda fastai but its not one of my options which one do i chose or is there another issue?
Iâve been yak shaving for 2 days and this was the key information i needed thank you!
Glad my comment could provide help, I was stuck some time as well.
Hi @faib
Letâs say this is the code -
pets_estimator = PyTorch(entry_point='source/pets.py', base_job_name='fastai-pets', role=role, framework_version='1.0.0', train_instance_count=1, train_instance_type='ml.p3.2xlarge')
You are suggesting to add the source_dir parameter (âsourceâ) and the requirement.txt file into it, right?
Can you also explain how would you mention the version in that and by doing so how it will work?
I was going through the PyTorch Sagemaker doc- https://sagemaker.readthedocs.io/en/stable/sagemaker.pytorch.html
and I found this explanation for source_dir-
source_dir ( str ) â Path (absolute or relative) to a directory with any other training source code dependencies aside from tne entry point file (default: None). Structure within this directory are preserved when training on Amazon SageMaker.
You can instantiate the PyTorch class like this
mail_model=PyTorchModel(model_data=model_artefact,
name=name,
role=role,
framework_version='1.1.0',
entry_point='serve.py',
predictor_cls=TextPredictor,
source_dir='my_src'
)
my_src
is a folder containing serve.py
and requirements.txt
.
The requirements.txt
file has the usual structure and contains e.g.:
fastai==1.0.52
Hope this helps.
You need to use the kernel named "Python 3"
The notebook url is returning a 404. could you update please?
@tbass134 Yes. I will update it, the new link is https://github.com/bentoml/BentoML/tree/master/guides/deployment/deploy-with-sagemaker. I will also update my reply as well. Thanks for point out the dead link!
We update the example guide for sagemaker deployment. You can find the new guide at https://github.com/bentoml/BentoML/tree/master/guides/deployment/deploy-with-sagemaker
Hi @faib, just following through with this and am stuck with the predictor_cls=TextPredictor.
What does your TextPredictor class look like?
my model accepts a single string of text but im not sure how to pass this for Sagemaker modelâs .predict()
getting this error from CloudWatch when trying to deploy :
Traceback (most recent call last):
File â/usr/local/lib/python3.6/dist-packages/gunicorn/workers/base_async.pyâ, line 56, in handle
self.handle_request(listener_name, req, client, addr)
File â/usr/local/lib/python3.6/dist-packages/gunicorn/workers/ggevent.pyâ, line 160, in handle_request
addr)
File â/usr/local/lib/python3.6/dist-packages/gunicorn/workers/base_async.pyâ, line 107, in handle_request
respiter = self.wsgi(environ, resp.start_response)
File â/usr/local/lib/python3.6/dist-packages/sagemaker_pytorch_container/serving.pyâ, line 107, in main
user_module_transformer.initialize()
File â/usr/local/lib/python3.6/dist-packages/sagemaker_containers/_transformer.pyâ, line 157, in initialize
self._model = self._model_fn(_env.model_dir)
File â/usr/local/lib/python3.6/dist-packages/sagemaker_containers/_functions.pyâ, line 87, in wrapper
six.reraise(error_class, error_class(e), sys.exc_info()[2])
File â/usr/local/lib/python3.6/dist-packages/six.pyâ, line 692, in reraise
raise value.with_traceback(tb)
File â/usr/local/lib/python3.6/dist-packages/sagemaker_containers/_functions.pyâ, line 85, in wrapper
return fn(*args, **kwargs)
File â/usr/local/lib/python3.6/dist-packages/serve.pyâ, line 15, in model_fn
learn = load_learner(model_dir, fname=âexport.pklâ)
also tried to print the fastai version on the deployement fase it give me : 1.0.39
solution ?
Hi @matt.mcclean I would like to thank you first of all,
I have a model created with Transformers and Fastai , and I have tried to deploy it ,this is my serve.py file
import logging, requests, os, io, glob, time
import json
import fastai
from transformers import BertTokenizer
from transformers import PreTrainedModel
from fastai.text import *
print("Fastai version "+str(fastai.__version__))
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
JSON_CONTENT_TYPE = 'application/json'
#redefining transformers custom model
class FastAiBertTokenizer(BaseTokenizer):
"""Wrapper around BertTokenizer to be compatible with fast.ai"""
def __init__(self, tokenizer: BertTokenizer, max_seq_len: int=128, **kwargs):
self._pretrained_tokenizer = tokenizer
self.max_seq_len = max_seq_len
def __call__(self, *args, **kwargs):
return self
def tokenizer(self, t:str) -> List[str]:
"""Limits the maximum sequence length"""
return ["[CLS]"] + self._pretrained_tokenizer.tokenize(t)[:self.max_seq_len - 2] + ["[SEP]"]
class CustomTransformerModel(nn.Module):
def __init__(self, transformer_model: PreTrainedModel):
super(CustomTransformerModel,self).__init__()
self.transformer = transformer_model
def forward(self, input_ids):
# Return only the logits from the transfomer
logits = self.transformer(input_ids)[0]
return l
print(CustomTransformerModel)
# loads the model into memory from disk and returns it
def model_fn(model_dir):
logger.info('model_fn')
print("model directory "+str(model_dir))
path = Path(model_dir)
learn = load_learner(model_dir, 'fastai.pkl')
return learn
# Perform prediction on the deserialized object, with the loaded model
def predict_fn(input, model):
logger.info("Calling model")
start_time = time.time()
predict_class,predict_idx,predict_values = model.predict(input)
print("--- Inference time: %s seconds ---" % (time.time() - start_time))
print(f'Predicted class is {str(predict_class)}')
print(f'Predict confidence score is {predict_values[predict_idx.item()].item()}')
return json.dumps({
"input": input,
"pred_class": str(pred_class),
"pred_idx":sorted(
zip(learner.data.classes, map(float, pred_idx)),
key=lambda p: p[1],
reverse=True
),
"predictions": sorted(
zip(learner.data.classes, map(float, outputs)),
key=lambda p: p[1],
reverse=True
)
})
# return dict(class = str(predict_class),confidence = predict_values[predict_idx.item()].item())
# Serialize the prediction result into the desired response content type
def output_fn(prediction, accept=JSON_CONTENT_TYPE):
logger.info('Serializing the generated output.')
if accept == JSON_CONTENT_TYPE: return json.dumps(prediction), accept
raise Exception('Requested unsupported ContentType in Accept: {}'.format(accept))
but when trying to deploy the model using PyTorch container, the problem is that when I try to load the model using load_learner() this function search for the CustomTransformerModel class , but since the file is in the serve.py ,the class name is
<class âserve.CustomTransformerModelâ> and the function is searching for
<class 'main.CustomTransformerModel> so it doesnât find it,
and I get this error from CloudWatch logs :
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/sagemaker_containers/_functions.py", line 85, in wrapper
return fn(*args, **kwargs)
File "/opt/ml/code/serve.py", line 47, in model_fn
learn = load_learner(model_dir, 'fastai.pkl')
File "/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py", line 598, in load_learner
state = torch.load(source, map_location='cpu') if defaults.device == torch.device('cpu') else torch.load(source)
File "/usr/local/lib/python3.6/dist-packages/torch/serialization.py", line 387, in load
return _load(f, map_location, pickle_module, **pickle_load_args)
File "/usr/local/lib/python3.6/dist-packages/torch/serialization.py", line 574, in _load
result = unpickler.load()
AttributeError: Can't get attribute 'CustomTransformerModel' on <module '__main__' from '/usr/local/bin/gunicorn'>
how could I solve this ?
Looks to be a problem with how your model has been serialized into a pickle object rather than being a SageMaker issue. Have you tried to export and load the model locally first? You can also try and get the SageMaker inference working locally on your machine by specifying the instance type parameter to be âlocalâ and it will deploy into a Docker container on your SageMaker/Jupyter notebook instance
@matt.mcclean Thank you I have solved this issue by retraining my model and instead of putting classes in notebook I have maked them on a module called utils.py , and when deploying model to SageMaker I have used utils.py as the name of the entry so that python when looks for the classes will find it .
I have another question what is the type_content that I must set in PytorchModel parameter before deploying when I am dealing with text , I have used Text/plain and itâs not supported by the model , I have also tried to use the unput_fn but didnât succeded , could you please show how to use deserialization function input_fn or how we could use content_type in text ?
Hi Matt, hope you are fine.
I need your help with deploying a fastai trained image-classifier to sagemaker:
model=PyTorchModel(model_data=model_artefact, name=name_from_base(âJulian73ClsEFFB3-modelâ),
role=role, framework_version=â1.8.0â, py_version=âpy3â, entry_point=âmy_src/serve.pyâ,
predictor_cls=ImagePredictor)
predictor = model.deploy(initial_instance_count=1, instance_type=âml.m4.xlargeâ)
This is my serve.py
`
import logging, requests, os, io, glob, time
from fastai.vision.all import *
from fastai.basics import *
logger = logging.getLogger(name)
logger.setLevel(logging.DEBUG)
JSON_CONTENT_TYPE = âapplication/jsonâ
JPEG_CONTENT_TYPE = âimage/jpegâ
loads the model into memory from disk and returns it
def model_fn(model_dir):
logger.info(âmodel_fnâ)
path = Path(model_dir)
learn = load_learner(model_dir, fname=âEFFB3-73CLS-24May.pklâ)
return learn
Deserialize the Invoke request body into an object we can perform prediction on
def input_fn(request_body, content_type=JPEG_CONTENT_TYPE):
logger.info(âDeserializing the input data.â)
# process an image uploaded to the endpoint
if content_type == JPEG_CONTENT_TYPE: return open_image(io.BytesIO(request_body))
# process a URL submitted to the endpoint
if content_type == JSON_CONTENT_TYPE:
img_request = requests.get(request_body[âurlâ], stream=True)
return open_image(io.BytesIO(img_request.content))
raise Exception(âRequested unsupported ContentType in content_type: {}â.format(content_type))
Perform prediction on the deserialized object, with the loaded model
def predict_fn(input_object, model):
logger.info(âCalling modelâ)
start_time = time.time()
predict_class,predict_idx,predict_values = model.predict(input_object)
print("â Inference time: %s seconds â" % (time.time() - start_time))
print(fâPredicted class is {str(predict_class)}â)
print(fâPredict confidence score is {predict_values[predict_idx.item()].item()}â)
return dict(class_name = str(predict_class),
confidence = predict_values[predict_idx.item()].item())
Serialize the prediction result into the desired response content type
def output_fn(prediction, accept=JSON_CONTENT_TYPE):
logger.info(âSerializing the generated output.â)
if accept == JSON_CONTENT_TYPE: return json.dumps(prediction), accept
raise Exception(âRequested unsupported ContentType in Accept: {}â.format(accept))
`
I am facing error, load_learner not defined.
Thanks for any help.
Now my error is:
FileNotFoundError: [Errno 2] No such file or directory: â/opt/ml/model/model.pthâ
load_learner has changed is youâre using the latest fastai, the only argument is fname so you need to give the full path there like
def model_fn(model_dir):
path = Path(model_dir)
return load_learner(path/'export.pkl')