栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python构建一个pipeline算法框架

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python构建一个pipeline算法框架

1. 设计需求

算法流水线框架需求:

(1)日志功能

(2)计算文件下载保持功能(针对图片)

(3)多线程/多进程功能

(4)算子相互解耦

2.工程目录规划

用文件夹结构展示

----algo(算子模块)

---------__init__.py

---------algo_base.py

---------algo_database.py

---------algo_datadict.py

..............................

----data(测试数据)

--------image.raw

--------image_scene.png

----utility(工具模块)

-------utility_image.py

-------utility_log.py

----test(测试模块)

--------__init__.py

--------test_engine.py

--------test_image.py

-----config.py(配置文件)

-----core_engine.py(计算引擎)

3. 算子模块 3.1 共享数据字典

algo_database.py

from copy import deepcopy
from weakref import ref


class AlgoDataDict:

    def __init__(self):
        self.__datadict = {}

    @property
    def datadict(self):
        return self.__datadict

    @datadict.setter
    def datadict(self, value):
        self.__datadict = deepcopy(value)

    def append(self, label, value):
        if label is not self.__datadict.keys():
            self.__datadict[label] = (value,)
        else:
            self.__datadict[label] = self.__datadict[label] + (value,)

    def get(self, labels):
        if not isinstance(labels, (tuple,set,list)):
            yield None
        else:
            for label in labels:
                if label in self.__datadict.keys():
                    yield self.__datadict[label]
                else:
                    yield None

    def clear(self):
        self.__datadict.clear()

    def remove(self, labels):
        for label in labels:
            if label in self.__datadict.keys():
                self.__datadict.pop(label)



algo_datadict.py

import threading
from weakref import WeakValueDictionary
from algo.algo_datadict import AlgoDataDict


def singleton(cls):
    _instance = {}

    def inner():
        if cls not in _instance:
            _instance[cls] = cls()

        return _instance[cls]

    return inner


@singleton
class AlgoDataBase(object):
    def __init__(self):
        self.pool = WeakValueDictionary()
        self.lock = threading.Lock()

    def create_dict(self, thread_id):
        with self.lock:
            self.pool[thread_id] = algo_dict = AlgoDataDict()
            return algo_dict

    def get_dict(self, task_id):
        with self.lock:
            if task_id in self.pool.keys():
                return self.pool.get(task_id)
            self.pool[task_id] = algo_dict = AlgoDataDict()
            return algo_dict

    def clear_dict(self, task_id):
        with self.lock:
            if task_id in self.pool.keys():
                algo_dict = self.pool.pop(task_id)
                algo_dict.clear()

3.2 算子基类:
from abc import ABC, abstractmethod
from copy import deepcopy
from algo.algo_database import AlgoDataBase


class AlgoBase(ABC):

    def __init__(self, algo_name, attribute, task_id):
        self._attribute = deepcopy(attribute)
        self.algo_name = deepcopy(algo_name)
        self.db = AlgoDataBase()
        self.data_dict = self.db.get_dict(task_id)

    @property
    def attribute(self):
        return self._attribute

    @attribute.setter
    def attribute(self, value):
        self._attribute = value

    @abstractmethod
    def before_run(self):
        """callback before process function"""

    @abstractmethod
    def process(self, *args, **kwargs):
        """algorithm core to process data"""

    @abstractmethod
    def after_run(self):
        """callback after process function"""
3.3 算子子类
from algo.algo_base import AlgoBase
from utility.utility_log import log_enter_fun, UserError, print_error_msg, print_info
from utility.utility_image import read_image, bytes2array, show_array_in_window


class AlgoIn(AlgoBase):

    label = "input"

    def before_run(self):
        print_info(self.algo_name)

    @log_enter_fun
    def process(self, *args, **kwargs):
        """
        :param args: args[0] is path of image
                     args[1] is the row number of image
                     args[2] is the col number of image
        :param kwargs: {}
        :return: None
        """
        if len(args) < 3:
            return None
        else:
            path = args[0]
            row = args[1]
            col = args[2]
            try:
                buffer = read_image(path)
                array2 = bytes2array(buffer, row, col)
                show_array_in_window("input image", array2, 1, 1, 1)
                self.data_dict.append(self.label, array2)
            except UserError as e:
                print_error_msg(e)

    def after_run(self):
        print_info(self.algo_name)
4. 框架基础 4.1 日志文件代码
import logging
import traceback
from functools import wraps
from datetime import datetime

global log_level


def set_log_level(level):
    global log_level
    log_level = level
    log_format = "%(levelname)s-%(asctime)s-[*] %(message)s"
    if log_level <= logging.DEBUG:
        logging.basicConfig(level=logging.DEBUG, format=log_format)
    elif log_level <= logging.INFO:
        logging.basicConfig(level=logging.INFO, format=log_format)
    else:
        logging.basicConfig(level=logging.ERROR, format=log_format)


def print_info(fmt):
    global log_level
    if log_level <= logging.INFO:
        now = datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')[:-3]
        print('INFO-{0}-{1}'.format(now, fmt))


def log_debug(fmt):
    logging.debug(fmt)


def log_info(fmt):
    logging.info(fmt)


def log_error(fmt):
    logging.error(fmt)


def print_error_msg():
    global log_level
    if log_level <= logging.DEBUG:
        msg = traceback.format_exc()
        print(msg)


def log_enter_fun(fun):
    @wraps(fun)
    def wrapper(*args, **kwargs):
        print_info('[' + fun.__name__+']' + " enter.")
        fun(*args, **kwargs)
        print_info('['+fun.__name__+']' + " exit.")
    return wrapper


class UserError(Exception):
    def __init__(self, fmt):
        self.args = fmt

    def __str__(self):
        str_args = "".join(self.args)
        return repr("{0} at {1}".format(str_args, id(self)))
4.2 图像文件代码
import cv2
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from utility.utility_log import UserError


def show_image_in_window(img, title="image"):
    cv.imshow(title, img)


def keep_image_in_window():
    while 1:
        if cv2.waitKey(0) == ord('q'):
            break


def close_image_in_window(win_name=''):
    if win_name == '':
        cv.destroyAllWindows()
    else:
        cv.destroyWindow(win_name)


def array2image(array2):
    pass


def image2array(image):
    pass


def create_figure(nrows, ncols):
    fig, axes = plt.subplots(nrows, ncols)
    return fig, axes


def show_array_in_window(title, array2, nrows, ncols, index):
    if array2 is None:
        return
    plt.figure()
    plt.subplot(nrows, ncols, index)
    plt.title(title)
    plt.imshow(array2, cmap="gray")


def keep_array_in_window():
    plt.show(block=True)


def bytes2array(buffer, row, col):
    try:
        array = np.frombuffer(buffer, dtype=np.uint16, count=row*col, offset=0)
        array2 = array.reshape(col, row)
        return array2
    except (TypeError, RuntimeError):
        raise UserError("Failed to convert buffer to image")


def array2bytes(array2):
    try:
        buffer = array2.tobytes()
        return buffer
    except (TypeError, RuntimeError):
        raise UserError("Failed to convert array2 to buffer")


def read_image(path):
    try:
        buffer = None
        with open(path, 'rb') as f:
            buffer = f.read()
        return buffer
    except (OSError, TypeError):
        raise UserError("Failed to read image")


def write_image(path, buffer):
    try:
        with open(path, 'wb') as f:
            f.write(buffer)
    except (OSError, TypeError):
        raise UserError("Failed to write image")

4.3 计算引擎
from concurrent.futures import ThreadPoolExecutor
from utility.utility_log import UserError, log_error
import algo.all_algo as algo
import config


class CoreEngine:

    def __init__(self):
        self.tasks = []
        self._executor = ThreadPoolExecutor(max_workers = config.global_thread_num)

    def start(self, arguments, task_id):
        try:
            task = self._executor.submit(CoreEngine.run(arguments, task_id))
            self.tasks.append({'id': task_id, 'task': task})
        except (UserError, RuntimeError) as e:
            log_error(e)

    @staticmethod
    def run(arguments, task_id):
        try:
            input_image = algo.AlgoIn("InputData", None, task_id)
            path = "./data/image.raw16"
            row = 8032
            col = 6000
            input_image.before_run()
            input_image.process(path, row, col)
            input_image.after_run()

            attribute = {'key': 1, 'key2': 2}
            awb = algo.AlgoAWB("AWB", attribute, 1)
            awb.before_run()
            awb.process()
            awb.after_run()

        except UserError as e:
            log_error(e)
5. 测试模块
import unittest
from core_engine import CoreEngine
from utility.utility_log import *
import __init__


class TestEngineFunctions(unittest.TestCase):
    def test_init(self):
        set_log_level(level=20)

        core_engine = CoreEngine()

        algo_list = [{'name': 'AlgoIn', 'attribute': {}}, {'name': 'algo_dmc', 'attribute': {}}]
        task_id = 1
        core_engine.start(algo_list, task_id)

        self.assertEqual(True, True)  # add assertion here


if __name__ == '__main__':
    unittest.main()

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/982329.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号