Using AWS Lambda docker image to add self module error - amazon-web-services

I want to build a docker image to add my deep learning model GRU into my lambda function.
Here is the GRUModel.py
import torch
import torch.nn as nn
class GRUModel(nn.Module):
def __init__(self, input_dim, hidden_dim, layer_dim, output_dim, dropout_prob):
super(GRUModel, self).__init__()
# Defining the number of layers and the nodes in each layer
self.layer_dim = layer_dim
self.hidden_dim = hidden_dim
# GRU layers
self.gru = nn.GRU(
input_dim, hidden_dim, layer_dim, batch_first=True, dropout=dropout_prob
)
# Fully connected layer
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
# Initializing hidden state for first input with zeros
h0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_()
# Forward propagation by passing in the input and hidden state into the model
out, _ = self.gru(x, h0.detach())
# Reshaping the outputs in the shape of (batch_size, seq_length, hidden_size)
# so that it can fit into the fully connected layer
out = out[:, -1, :]
# Convert the final state to our desired output shape (batch_size,
output_dim)
out = self.fc(out)
return out
Here is the lambda.py
import torch
import torch.nn as nn
import joblib
from GRUModel import GRUModel
def handler(event, context):
gruencoder=joblib.load("gruencoder.pkl")
response = {'statusCode': 200, 'body' : "OK"}
return response
Here is the Dockerfile
FROM public.ecr.aws/lambda/python:3.7
COPY lambda.py ${LAMBDA_TASK_ROOT}
COPY gruencoder.pkl .
COPY GRUModel.py .
RUN pip3 install joblib --target "${LAMBDA_TASK_ROOT}"
RUN pip3 install torch --target "${LAMBDA_TASK_ROOT}"
CMD ["lambda.handler"]
I run the lambda.py is working on the loacl, but it shows error on the lambda.
{
"errorMessage": "module '__main__' has no attribute 'GRUModel'",
"errorType": "AttributeError",
"stackTrace": [
" File \"/var/task/lambda.py\", line 22, in handler\n gruencoder=joblib.load(\"gruencoder.pkl\")\n",
" File \"/var/task/joblib/numpy_pickle.py\", line 587, in load\n obj = _unpickle(fobj, filename, mmap_mode)\n",
" File \"/var/task/joblib/numpy_pickle.py\", line 506, in _unpickle\n obj = unpickler.load()\n",
" File \"/var/lang/lib/python3.7/pickle.py\", line 1088, in load\n dispatch[key[0]](self)\n",
" File \"/var/lang/lib/python3.7/pickle.py\", line 1376, in load_global\n klass = self.find_class(module, name)\n",
" File \"/var/lang/lib/python3.7/pickle.py\", line 1430, in find_class\n return getattr(sys.modules[module], name)\n"
]
}

I think you need to add the ${LAMBDA_TASK_ROOT} target to your COPY commands for the .pkl and missing .py file:
FROM public.ecr.aws/lambda/python:3.7
COPY lambda.py ${LAMBDA_TASK_ROOT}
COPY gruencoder.pkl ${LAMBDA_TASK_ROOT}
COPY GRUModel.py ${LAMBDA_TASK_ROOT}
RUN pip3 install joblib --target "${LAMBDA_TASK_ROOT}"
RUN pip3 install torch --target "${LAMBDA_TASK_ROOT}"
CMD ["lambda.handler"]

Related

How to deploy the Deep learning model(computer vision ) in aws using lambda

I have trained in background removal with my custom images and I am new to deploying computer vision models. please, anyone, share the blog how to deploy the Pytorch deep learning model(computer vision) using lambda.
I have written some lambda functions to take the input image and predict the segment and give output as a background removal image.
I am not sure this function is correct or not. please check this function as well.
Define imports
try:
import unzip_requirements
except ImportError:
pass
import json
from io import BytesIO
import time
import os
import base64
import boto3
import numpy as np
from skimage import io
import matplotlib.pyplot as plt
from preprocessing import RescaleT, ToTensorLab
import torch
import numpy as np
from PIL import Image
from network.u2net import U2NET
# Define two functions inside handler.py: img_to_base64_str to
# convert binary images to base64 format and load_models to
# load the four pretrained model inside a dictionary and then
# keep them in memory
def img_to_base64_str(img):
buffered = BytesIO()
img.save(buffered, format="PNG")
buffered.seek(0)
img_byte = buffered.getvalue()
img_str = "data:image/png;base64," + base64.b64encode(img_byte).decode()
return img_str
def load_models(s3, bucket):
model = U2NET(3,1)
response = s3.get_object(
Bucket=bucket, Key=f"models/u2net/u2net.pth")
state = torch.load(BytesIO(response["Body"].read()),map_location=torch.device('cpu'))
model.load_state_dict(state)
model.eval()
return model
def preprocess_raw_img(raw_img_array):
"""
This function preprocesses a raw input array in a way such that it can be fed into the U-2-Net architecture
:param raw_img_array:
:return:
"""
rescaler = RescaleT(320)
rescaled_img = rescaler(raw_img_array)
tensor_converter = ToTensorLab(flag=0)
tensor_img = tensor_converter(rescaled_img)
tensor_img = tensor_img.unsqueeze(0)
return tensor_img
def normPRED(d):
ma = torch.max(d)
mi = torch.min(d)
dn = (d-mi)/(ma-mi)
return dn
def resize_img_to_orig(prediction_np, orig_img):
image = Image.fromarray(prediction_np * 255).convert('RGB')
image_original = image.resize((orig_img.shape[1], orig_img.shape[0]), resample=Image.BILINEAR)
return image_original
def mask_to_orig_size(orig_img, rescale, threshold):
mask_orig_size = np.array(orig_img, dtype=np.float64)
mask_orig_size /= rescale
mask_orig_size[mask_orig_size > threshold] = 1
mask_orig_size[mask_orig_size <= threshold] = 0
return mask_orig_size
def extract_foreground(mask_orig_size):
shape = mask_orig_size.shape
a_layer_init = np.ones(shape=(shape[0], shape[1], 1))
mul_layer = np.expand_dims(mask_orig_size[:, :, 0], axis=2)
a_layer = mul_layer * a_layer_init
rgba_out = np.append(mask_orig_size, a_layer, axis=2)
return rgba_out
def input_to_rgba_inp(input_arr, rescale):
input_arr = np.array(input_arr, dtype=np.float64)
shape = input_arr.shape
input_arr /= rescale
a_layer = np.ones(shape=(shape[0], shape[1], 1))
rgba_inp = np.append(input_arr, a_layer, axis=2)
return rgba_inp
def u2net_api_call(raw_img_array, model):
"""
This function takes as input an image array of any size. The goal is to return only the object in the foreground of
the image.
Therefore, the raw input image is preprocessed, fed into the deep learning model. Afterwards the foreground of the
original image is extracted from the mask which was generated by the deep learning model.
"""
THRESHOLD = 0.9
RESCALE = 255
preprocessed_img = preprocess_raw_img(raw_img_array)
d1, d2, d3, d4, d5, d6, d7 = model(preprocessed_img)
prediction = d1[:, 0, :, :]
prediction = normPRED(prediction)
prediction_np = prediction.squeeze().cpu().data.numpy()
img_orig_size = resize_img_to_orig(prediction_np, raw_img_array)
mask_orig_size = mask_to_orig_size(img_orig_size, RESCALE, THRESHOLD)
rgba_out = extract_foreground(mask_orig_size)
rgba_inp = input_to_rgba_inp(raw_img_array, RESCALE)
rem_back = (rgba_inp * rgba_out)
return rem_back
s3 = boto3.client("s3")
bucket = "sagemaker-m-model"
model = load_models(s3, bucket)
def lambda_handler(event,Context):
if event.get("source") in ["aws.events", "serverless-plugin-warmup"]:
print('Lambda is warm!')
return {}
data = json.loads(event["body"])
print("data keys :", data.keys())
image = data["image"]
image = image[image.find(",")+1:]
dec = base64.b64decode(image + "===")
image = Image.open(io.BytesIO(dec))
#image = image.convert("RGB")
# loading the model with the selected style based on the model_id payload
model = model
# resize the image based on the load_size payload
#load_size = int(data["load_size"])
with torch.no_grad():
background_removed = u2net_api_call(image, model)
output_image = background_removed[0]
# deprocess, (0, 1)
output_image = output_image.data.cpu().float() * 0.5 + 0.5
output_image = output_image.numpy()
output_image = np.uint8(output_image.transpose(1, 2, 0) * 255)
output_image = Image.fromarray(background_removed)
# convert the PIL image to base64
result = {
"output": img_to_base64_str(output_image)
}
# send the result back to the client inside the body field
return {
"statusCode": 200,
"body": json.dumps(result),
"headers": {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
}
I have tried with the Serverless framework, I got some errors. I understand how to solve this.
Running "serverless" from node_modules
Warning: Invalid configuration encountered
at 'custom.warmup.events': must be object
at 'custom.warmup.timeout': must be object
at 'functions.transformImage.warmup': must be object
Learn more about configuration validation here: http://slss.io/configuration-validation
Deploying br to stage dev (us-east-1)
Warning: WarmUp: Skipping warmer "events" creation. No functions to warm up.
Warning: WarmUp: Skipping warmer "timeout" creation. No functions to warm up.
✖ Stack br-dev failed to deploy (11s)
Environment: linux, node 16.14.0, framework 3.4.0 (local) 3.4.0v (global), plugin 6.1.2, SDK 4.3.1
Docs: docs.serverless.com
Support: forum.serverless.com
Bugs: github.com/serverless/serverless/issues
Error:
Error: `docker run --rm -v /home/suri/project1/rmbg/br/cache/cf58e2124c894818b4beab8df9ac26ac92eeb326c8c74fc7e60e8f08ea86df1e_x86_64_slspyc:/var/task:z -v /home/suri/project1/rmbg/br/cache/downloadCacheslspyc:/var/useDownloadCache:z lambci/lambda:build-python3.6 /bin/sh -c chown -R 0\:0 /var/useDownloadCache && python3.6 -m pip install -t /var/task/ -r /var/task/requirements.txt --cache-dir /var/useDownloadCache && chown -R 0\:0 /var/task && chown -R 0\:0 /var/useDownloadCache` Exited with code 1
at ChildProcess.<anonymous> (/home/suri/project1/rmbg/br/node_modules/child-process-ext/spawn.js:38:8)
at ChildProcess.emit (node:events:520:28)
at ChildProcess.emit (node:domain:475:12)
at maybeClose (node:internal/child_process:1092:16)
at Process.ChildProcess._handle.onexit (node:internal/child_process:302:5)
3 deprecations found: run 'serverless doctor' for more details

Pass numpy's include dir to Cmake from Setuptools

I have a C++ library which I have successfully exposed to python using Pybind11.
In the CmakeLists.txt file, I have added the numpy include like this:
include_directories("C:\\Python37\\Lib\\site-packages\\numpy\\core\\include")
This works, but is undesirable. I would like to pass the numpy include directory from my setup.py file.
My setup.py file looks very much like this one:
import os
import re
import sys
import sysconfig
import platform
import subprocess
from distutils.version import LooseVersion
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext
class CMakeExtension(Extension):
def __init__(self, name, sourcedir=''):
Extension.__init__(self, name, sources=[])
self.sourcedir = os.path.abspath(sourcedir)
class CMakeBuild(build_ext):
def run(self):
try:
out = subprocess.check_output(['cmake', '--version'])
except OSError:
raise RuntimeError(
"CMake must be installed to build the following extensions: " +
", ".join(e.name for e in self.extensions))
if platform.system() == "Windows":
cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)',
out.decode()).group(1))
if cmake_version < '3.1.0':
raise RuntimeError("CMake >= 3.1.0 is required on Windows")
for ext in self.extensions:
self.build_extension(ext)
def build_extension(self, ext):
extdir = os.path.abspath(
os.path.dirname(self.get_ext_fullpath(ext.name)))
cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir,
'-DPYTHON_EXECUTABLE=' + sys.executable]
cfg = 'Debug' if self.debug else 'Release'
build_args = ['--config', cfg]
if platform.system() == "Windows":
cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(
cfg.upper(),
extdir)]
if sys.maxsize > 2**32:
cmake_args += ['-A', 'x64']
build_args += ['--', '/m']
else:
cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
build_args += ['--', '-j2']
env = os.environ.copy()
env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(
env.get('CXXFLAGS', ''),
self.distribution.get_version())
if not os.path.exists(self.build_temp):
os.makedirs(self.build_temp)
subprocess.check_call(['cmake', ext.sourcedir] + cmake_args,
cwd=self.build_temp, env=env)
subprocess.check_call(['cmake', '--build', '.'] + build_args,
cwd=self.build_temp)
print() # Add an empty line for cleaner output
setup(
name='python_cpp_example',
version='0.1',
author='Benjamin Jack',
author_email='benjamin.r.jack#gmail.com',
description='A hybrid Python/C++ test project',
long_description='',
# add extension module
ext_modules=[CMakeExtension('python_cpp_example')],
# add custom build_ext command
cmdclass=dict(build_ext=CMakeBuild),
zip_safe=False,
)
After having a look at some SO questions like this, I know that you can get the numpy include directory with numpy.get_include().
However, adding the include directory to the path inside the function build_extension with this line ext.include_dirs.append(numpy.get_include()) seems to have no effect.
I'd like to know how to pass the include directory properly.
Is your cmake build using the wrong numpy path or not finding numpy at all? If it's the wrong path, you could try prepending instead of appending numpy.get_include():
ext.include_dirs.insert(0,numpy.get_include())

Python ConfigParser - module object is not callable in Fedora 23

Trying to read an .ini db file from python to test a connection to a PostGres database
Python Version 2.7.11
In Fedora, I installed with
sudo dnf install python-configparser
Install 1 Package
Total download size: 41 k
Installed size: 144 k
Is this ok [y/N]: y
Downloading Packages:
python-configparser-3.5.0b2-0.2.fc23.noarch.rpm 40 kB/s | 41 kB 00:01
Total 31 kB/s | 41 kB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Installing : python-configparser-3.5.0b2-0.2.fc23.noarch 1/1
Verifying : python-configparser-3.5.0b2-0.2.fc23.noarch 1/1
Installed:
python-configparser.noarch 3.5.0b2-0.2.fc23
in my config.py I do a
import configparser
when I run my script I get 'module' object is not callable
db.ini
[test1]
host=IP address
database=db
port=5432
user=username
password=pswd
[test2]
host=localhost
database=postgres
port=7999
user=abc
password=abcd
config.py
#!/usr/bin/env python
#from configparser import ConfigParser
import configparser
def config(filename='database.ini', section='gr'):
# create a parser
parser = configparser()
# read config file
parser.read(filename)
# get section, default to gr
db = {}
if parser.has_section(section):
params = parser.items(section)
for param in params:
db[param[0]] = param[1]
else:
raise Exception('Section {0} not found in the {1} file'.format(section, filename))
return db
testing.py
#!/usr/bin/env python
import psycopg2
from config import config
def connect():
""" Connect to the PostgreSQL database server """
conn = None
try:
# read connection parameters
params = config()
# connect to the PostgreSQL server
print('Connecting to the PostgreSQL database...')
conn = psycopg2.connect(**params)
# create a cursor
cur = conn.cursor()
# execute a statement
print('PostgreSQL database version:')
cur.execute('SELECT version()')
# display the PostgreSQL database server version
db_version = cur.fetchone()
print(db_version)
# close the communication with the PostgreSQL
cur.close()
except (Exception, psycopg2.DatabaseError) as error:
print(error)
finally:
if conn is not None:
conn.close()
print('Database connection closed.')
if __name__ == '__main__':
connect()
[root#svr mytest]# ./testing.py
'module' object is not callable
any ideas ?
thank you.
You have an error in your parser creation, see the ConfigParser examples:
An example of reading the configuration file again:
import ConfigParser
config = ConfigParser.RawConfigParser()
config.read('example.cfg')
In Python, a module is basically just a file, so if you want to use anything from this module, you have to specify what from the module you want. In your case, change the lines to
# create a parser
parser = configparser.ConfigParser()
This way, you are using the class ConfigParser from the module.
You can also use the follow to import the parser:
from configparser import ConfigParser
instead of
import configparser
I had the same issue as you and this worked for me.

difficulties with cx_freeze setup for kivy with Python 2.7

I am trying to build a package for just a simple Python 2.7 + kivy 1.9.1 script using cx_freeze. Unfortunately I get the following error when executing the DoScroll.exe file:
File "C:\Utils\Pyhton27\lib\site-packages\kivy\lang.py", line 1829, in load_file
with open(filename, 'r') as fd:
IOError: [Errno 2] No such file or directory: 'C:\Projects\Testing\build\exe.win32-2.7\library.zip\kivy\data\style.kv'
The zip file does not contain the kivy\data folder. So my idea was to add the kivy package explicitly to the setup.py file. But this does not help.
How could I resolve this issue?
The setup.py file I am using:
import sys
from cx_Freeze import setup, Executable
base = None
if sys.platform == "win32":
base = "Win32GUI"
options = {
'build_exe': {
'packages': ['kivy']
}
}
executables = [
Executable('DoScroll.py', base=base)
]
setup(name='scroller',
version='0.1',
description='demo scroller',
executables = executables,
options=options
)

Error in TensorFlow program

I am learning TensorFlow and I stumble upon this example code for creating simple multi-layer sigmoid network. The program in the link is for MNIST database and hand written digit classification.
I want to train a network for regression task. I have 30 inputs(float) which is used to predict one output(float). So I tweaked the code to change the task from classification to regression.
My problem is that I'm getting an error in tf.Session.run(). The code and the error log is given below.
import test2
import tensorflow as tf
feed_input = test2.read_data_sets()
learning_rate = 0.001
training_epochs = 100
batch_size = 1716
display_step = 1
n_hidden_1 = 256
n_hidden_2 = 256
n_hidden_3 = 256
n_input = 30
x = tf.placeholder("float", [None, n_input])
y = tf.placeholder("float", [None])
def multilayer_perceptron(_X, _weights, _biases):
#Hidden layer with RELU activation
layer_1 = tf.nn.relu(tf.add(tf.matmul(_X, _weights['h1']), _biases['b1']))
#Hidden layer with RELU activationn_hidden_3
layer_2 = tf.nn.relu(tf.add(tf.matmul(layer_1, _weights['h2']), _biases['b2']))
layer_3 = tf.nn.relu(tf.add(tf.matmul(layer_2, _weights['h3']), _biases['b3']))
return tf.matmul(layer_3, weights['out']) + biases['out']
weights = {
'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),
'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
'h3': tf.Variable(tf.random_normal([n_hidden_2, n_hidden_3])),
'out': tf.Variable(tf.random_normal([n_hidden_3, 1]))
}
biases = {
'b1': tf.Variable(tf.random_normal([n_hidden_1])),
'b2': tf.Variable(tf.random_normal([n_hidden_2])),
'b3': tf.Variable(tf.random_normal([n_hidden_3])),
'out': tf.Variable(tf.random_normal([1]))
}
pred = multilayer_perceptron(x, weights, biases)
n_pred = tf.mul(pred, tf.convert_to_tensor(10000.00))
cost = tf.nn.sigmoid_cross_entropy_with_logits(n_pred, y)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate).minimize(cost)
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
# Training cycle
for epoch in range(training_epochs):
avg_cost = 0
total_batch = int(feed_input.train._num_examples / batch_size)
# Loop over all batches
for i in range(total_batch):
batch_xs, batch_ys = feed_input.train.next_batch(batch_size)
# Fit training using batch data
sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})
# Compute average loss
avg_cost += sess.run(cost, feed_dict={x: batch_xs, y: batch_ys}) / total_batch
# Display logs per epoch step
if epoch % display_step == 0:
print "Epoch:", '%04d' % (epoch+1), "cost=", "{:.9f}".format(avg_cost)
print "Optimization Finished!"
runfile('/mnt/sdb6/Projects/StockML/demo1.py',
wdir='/mnt/sdb6/Projects/StockML')
Reloaded modules: tensorflow.python.ops.nn_grad,
tensorflow.python.training.momentum,
. . . .
tensorflow.python.util.protobuf,
google.protobuf.internal.enum_type_wrapper,
tensorflow.python.ops.nn_ops, tensorflow.python,
tensorflow.python.platform.test,
google.protobuf.internal.api_implementation, tensorflow,
google.protobuf.internal.encoder
Traceback (most recent call last):
File "", line 1, in
runfile('/mnt/sdb6/Projects/StockML/demo1.py', wdir='/mnt/sdb6/Projects/StockML')
File
"/usr/lib/python2.7/dist-packages/spyderlib/widgets/externalshell/sitecustomize.py",
line 685, in runfile
execfile(filename, namespace)
File
"/usr/lib/python2.7/dist-packages/spyderlib/widgets/externalshell/sitecustomize.py",
line 78, in execfile
builtins.execfile(filename, *where)
File "/mnt/sdb6/Projects/StockML/demo1.py", line 69, in
sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})
File
"/home/rammak/.local/lib/python2.7/site-packages/tensorflow/python/client/session.py",
line 345, in run
results = self._do_run(target_list, unique_fetch_targets, feed_dict_string)
File
"/home/rammak/.local/lib/python2.7/site-packages/tensorflow/python/client/session.py",
line 406, in _do_run
except tf_session.StatusNotOK as e:
AttributeError: 'module' object has no attribute 'StatusNotOK'
Protobuf error is usually an installation issue , run it in a virtual env
# On Mac:
$ sudo easy_install pip # If pip is not already installed
$ sudo pip install --upgrade virtualenv
Next, set up a new virtualenv environment. To set it up in the directory ~/tensorflow, run:
$ virtualenv --system-site-packages ~/tensorflow
$ cd ~/tensorflow
Then activate the virtualenv:
$ source bin/activate # If using bash
$ source bin/activate.csh # If using csh
(tensorflow)$ # Your prompt should change
Inside the virtualenv, install TensorFlow:
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.5.0-py2-none-any.whl
You can then run your TensorFlow program like:
(tensorflow)$ python tensorflow/models/image/mnist/convolutional.py
# When you are done using TensorFlow:
(tensorflow)$ deactivate # Deactivate the virtualenv
$ # Your prompt should change back
If you just begin to learn TensorFlow, I would suggest you trying out examples in TensorFlow/skflow first and then once you are more familiar with TensorFlow it would be fairly easy for you to insert TensorFlow code to build a custom model you want (there are also examples for this).
Hope those examples for images and text understanding could get you started and let us know if you encounter any issues! (post issues or tag skflow in SO).
Change your logging level from WARN to INFO, so that can get a better visualization of the error you're getting.
For knowledge purpose, you should know there are 5 logging levels:
DEBUG
INFO
WARN
ERROR
FATAL