I have deep learning model that loads into GPU
I want to preload and reuse it every time I execute job.
I have found https://python-rq.org/docs/workers/#performance-notes, but don't know how to access objects from job code
custom_worker.py
import sys
from rq import Connection, Worker, SimpleWorker
import cv2
import numpy as np
from cv.cnn_model import init_model, predict
__model = init_model("config.json", "weights.data")#loads to GPU
with Connection():
qs = sys.argv[1:] or ['default']
w = SimpleWorker(qs)
w.work()
job.py
def detect(image_path):
image = cv2.imread(image_path)
data = predict(__model, image) #should use preloaded __model
return data
I have found a solution using a custom worker to pass loaded model to job function
but this looks ugly!
class CustomWorker(SimpleWorker):
def __init__(self, *args, **kwargs):
self.__model = init_model("config.json", "weights.data")
SimpleWorker.__init__(self, *args, **kwargs)
def execute_job(self, job, queue):
job.args = (job.args[0], self.__model)
return self.perform_job(job, queue)
job.py
def detect(image_path, model):
image = cv2.imread(image_path)
data = predict(model, image) #used preloaded model
return data
TBH I don't know if you could do any better. This is probably how I would do it as well. Why do you think it's ugly?
@hnykda It is ugly because I`m violating encapsulation of Worker class changing its args variable. Originally it should represent values passes from the caller "result = q.enqueue(predict, "1.jpeg")" There only one parameter!
but I have found better solution
Finally, I understood how this should work. RQ uses importlib.import_module to load function. So every time you call the function it loads jobs file. So as I understand to fix this, you should load this file BEFORE worker execution.
import library_that_you_want_preloaded
should be replaced with
from job import predict
not this
import cv2
import numpy as np
from cv.cnn_model import init_model, predict
__model = init_model("config.json", "weights.data")#loads to GPU
My final script looks like this
job.py
import cv2
import numpy as np
from cv.cnn_model import init_model, predict
def init_weights():
global __model
__model =init_model("config.json", "weights.data")
def predict(image_path):
image = cv2.imread(image_path)
data = predict(__model, image)
return data
worker.py
import sys
from rq import Connection, SimpleWorker
from job import predict, init_weights
with Connection():
qs = sys.argv[1:] or ['default']
init_weights()#I initialize model before workers start
w = SimpleWorker(qs)#I use SimpleWorker because it does not fork
w.work()
Most helpful comment
Finally, I understood how this should work. RQ uses importlib.import_module to load function. So every time you call the function it loads jobs file. So as I understand to fix this, you should load this file BEFORE worker execution.
should be replaced with
not this
My final script looks like this
job.py
worker.py