Есть ли хороший шаблон для сериализации / десериализации (маринования) классов numba? Следующее дает мне

    other = pkl.loads(pkl.dumps(jc))
  File "/usr/lib/python2.7/copy_reg.py", line 71, in _reduce_ex
    state = base(self)
TypeError: function takes at most 0 arguments (1 given)

Я бы хотел пройти много уроков.

@jitclass([
    ('uncal_minRange', float64),
    ('uncal_maxRange', float64),
    ('nSize', int64),
    ('cal_percent', int64),
])
class SomeJitClass(object):
    def __init__(self, uncal_minRange=0.0, uncal_maxRange=0.0, nSize=0, cal_percent=0.0 ):
        self.uncal_minRange   = uncal_minRange
        self.uncal_maxRange   = uncal_maxRange
        self.cal_percent      = cal_percent
        self.nSize = nSize

    def compare(self, other):
        return self.uncal_minRange == other.uncal_minRange and \
            self.uncal_maxRange == other.uncal_maxRange and \
            self.cal_percent == other.cal_percent and \
            self.nSize == other.nSize


import unittest
class FastOpsTest(unittest.TestCase):

    def test_jit_class(self):
        import cPickle as pkl
        jc = SomeJitClass(1,2,3,4)
        print jc
        self.assertTrue(jc.compare(SomeJitClass(1,2,3,4)))
        self.assertFalse(jc.compare(SomeJitClass(1,2,3,5)))
        other = pkl.loads(pkl.dumps(jc))
        self.assertTrue(jc.compare(other))
1
user48956 13 Мар 2018 в 02:34

2 ответа

Лучший ответ

Ниже приведено возможное решение, но в стороне, мне трудно рекомендовать использование jitclass в его текущей (начало 2018 года) реализации - просто слишком ограничительно / незрело. Если возможно, оставаясь в numba-land, я бы попытался использовать простые массивы / бесплатные функции, и / или именованные кортежи могут быть хорошим решением для объединения некоторых связанных состояний. Вдобавок / в качестве альтернативы cython - хороший инструмент для разработки более богатых типов, которые могут лучше работать с python.

Тем не менее, вот возможный обходной путь. Я использую немного внутреннего устройства numba, поэтому, возможно, не будет стабильным в будущем.

def dumps_jitclass(jc):
    typ = jc._numba_type_
    fields = typ.struct

    data = {
        'name': typ.classname,
        'struct': {k: getattr(jc, k) for k in fields}
    }
    return pickle.dumps(data)

def loads_jitclass(s):
    data = pickle.loads(s)
    cls = globals()[data['name']]
    instance = cls(**data['struct'])
    return instance

# usage
In [148]: jc = loads_jitclass(dumps_jitclass(SomeJitClass(1, 2, 3, 4)))

In [149]: oth = SomeJitClass(1, 2, 3, 4)

In [150]: jc.compare(oth)
Out[150]: True
3
chrisb 13 Мар 2018 в 17:38

Благодаря ответу @chrisb. Внес некоторые изменения в свой проект (от начинающего декоратора).

import pickle
from functools import wraps, update_wrapper

import numpy as np
from numba import jitclass, int32, float64

class jitpickler:
    '''
    pickler
    '''
    def __init__(self, jitobj):
        self.__dict__['obj'] = jitobj
        self.__dict__['__module__'] = jitobj.__module__
        self.__dict__['__doc__'] = jitobj.__doc__

    def __getstate__(self):
        obj = self.__dict__['obj']
        typ = obj._numba_type_
        fields = typ.struct

        return typ.classname, {k: getattr(obj, k) for k in fields}

    def __setstate__(self, state):
        name, value = state
        cls = globals()[name]
        value['_decorator'] = False
        jitobj = cls(**value)
        self.__init__(jitobj)

    def __getattr__(self, attr):
        return getattr(self.__dict__['obj'], attr)

    def __setattr__(self, attr, value):
        return setattr(self.__dict__['obj'], attr, value)

    def __delattr__(self, attr):
        return delattr(self.__dict__['obj'], attr)

def jitpickle(cls):
    decoratorkw = '_decorator'
    @wraps(cls)
    def decorator(*args, **kwargs):
        if kwargs.get(decoratorkw, True):
            kwargs.pop(decoratorkw, None)
            return jitpickler(cls(*args, **kwargs))
        else:
            kwargs.pop(decoratorkw, None)
            return cls(*args, **kwargs)
    return decorator

Когда использовать это

spec = [
    ('value', int32),
    ('array', float64[:])]
@jitpickle
@jitclass(spec)
class cls:
    def __init__(self, value, array):
        self.value = value
        self.array = array


a = cls(10, np.array([1.1,2.2]))
s = pickle.dumps(a)
b = pickle.loads(s)
print(b.value, b.array)

Ps: update_wrapper не работал для перегрузки __setattr__. И я не хочу делать __setattr__ слишком толстым.

1
l460289052 7 Фев 2020 в 08:25