Rq: Preload deep learning model

Created on 16 May 2019  路  4Comments  路  Source: rq/rq

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

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.

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()

All 4 comments

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()
Was this page helpful?
0 / 5 - 0 ratings