Preparing a Docker image
In this part we want to package everything into a docker container. We use an AWS base image for our Dockerfile. You can find the public images from aws here (public.ecr.aws –> gallery.ecr.aws). In the gallery you can search for “python lambda” and we can find “python by AWS Lambda”. Then go to the “image tags” and find 3.8 or 3.9 or sth else and copy the link (like: public.ecr.aws/lambda/python:3.8)
FROM public.ecr.aws/lambda/python:3.9
RUN pip install keras-image-helper
RUN pip install tflite-runtime
COPY clothing-model.tflite .
COPY lambda_function.py .
CMD [ "lambda_function.lambda_handler" ]
Then let’s build the dockerfile.
docker build -t clothing-model .
docker run -it --rm -p 8080:8080 clothing-model:latest
Now we can write a python test file (test.py) with the following content and run it to test our lamda function.
import requests
url = 'http://localhost:8080/2015-03-31/functions/function/invocations'
data = {'url': 'http://bit.ly/mlbookcamp-pants'}
result = requests.post(url, json=data).json()
print(result)
But we’re getting one error: “{‘errorMessage’: “Unable to import module ‘lambda_function’: /lib64/libm.so.6: version `GLIBC_2.27′ not found (required by /var/lang/lib/python3.9/site-packages/tflite_runtime/_pywrap_tensorflow_interpreter_wrapper.so)”, ‘errorType’: ‘Runtime.ImportModuleError’, ‘requestId’: ‘3ad9eb7e-b087-4495-a376-d8d3506e699f’, ‘stackTrace’: []}” The reason is that the libraries were compiled for a different version of linux. Our Docker image is a aws based linux but the libraries were compiled for a debian based linux. So we need to compile the libraries for the aws environment.
But you don’t really need to do it by your own. Alexey provide a compiled version on his github repo (github.com/alexeygrigorev/tflite-aws-lambda) We can use that precompiled version but we need to rebuild our docker image with the adapted line.
FROM public.ecr.aws/lambda/python:3.9
RUN pip install keras-image-helper
#RUN pip install tflite-runtime
RUN pip install https://github.com/alexeygrigorev/tflite-aws-lambda/raw/main/tflite/tflite_runtime-2.7.0-cp39-cp39-linux_x86_64.whl
COPY clothing-model.tflite .
COPY lambda_function.py .
CMD [ "lambda_function.lambda_handler" ]
Still we get an error: “{‘errorMessage’: ‘Unable to marshal response: Object of type float32 is not JSON serializable’, ‘errorType’: ‘Runtime.MarshalError’, ‘requestId’: ‘c72d4226-6f20-4377-b666-7d05f4367099’, ‘stackTrace’: []}”
This error is an expected error. This means that it doesn’t know what to do with object of type “float32”. This error is a know error from previous sessions. With flask we had the same error. What we need to do is converting the elements of numpy array into usual python floats. That means we need to adapt the code of lambda_function.py
def predict(url):
X = preprocessor.from_url(url)
interpreter.set_tensor(input_index, X)
interpreter.invoke()
preds = interpreter.get_tensor(output_index)
# What happens here is we take an numpy array and it will converted to usual
# python list with usul python floats.
float_predictions = preds[0].tolist()
return dict(zip(classes, float_predictions))
Now we can rerun again and it should work now.
docker build -t clothing-model . docker run -it --rm -p 8080:8080 clothing-model:latest
Output of test.py: {‘dress’: -1.8251237869262695, ‘hat’: -5.563746929168701, ‘longsleeve’: -1.7097409963607788, ‘outwear’: -1.1727796792984009, ‘pants’: 8.934737205505371, ‘shirt’: -2.175368070602417, ‘shoes’: -2.9585258960723877, ‘shorts’: 2.3701159954071045, ‘skirt’: -1.7067642211914062, ‘t-shirt’: -4.354998588562012}