【问题标题】:Saving an sklearn.svm.SVR model as JSON instead of pickling将 sklearn.svm.SVR 模型保存为 JSON 而不是酸洗
【发布时间】:2022-08-22 12:44:18
【问题描述】:

我有一个训练有素的 SVR 模型,需要保存在JSON格式而不是酸洗。

JSONifying 训练模型背后的想法是简单地捕获权重和其他“拟合”属性的状态。然后,我可以稍后设置这些属性来进行预测。这是我做的一个实现:

    # assume SVR has been trained
    regressor = SVR()
    regressor.fit(x_train, y_train)

    # saving the regressor params in a JSON file for later retrieval
    with open(f\'saved_regressor_params.json\', \'w\', encoding=\'utf-8\') as outfile:
        json.dump(regressor.get_params(), outfile)

    # finding the fitted attributes of SVR()
    # if an attribute is trailed by \'_\', it\'s a fitted attribute
    attrs = [i for i in dir(regressor) if i.endswith(\'_\') and not i.endswith(\'__\')]
    remove_list = [\'coef_\', \'_repr_html_\', \'_repr_mimebundle_\'] # unnecessary attributes
    
    for attr in remove_list:
        if attr in attrs:
            attrs.remove(attr)


    # deserialize NumPy arrays and save trained attribute values into JSON file
    attr_dict = {i: getattr(regressor, i) for i in attrs}

    for k in attr_dict:
        if isinstance(attr_dict[k], np.ndarray):
            attr_dict[k] = attr_dict[k].tolist()

    # dump JSON for prediction
    with open(f\'saved_regressor_{index}.json\', \'w\', encoding=\'utf-8\') as outfile:    
        json.dump(attr_dict, 
                    outfile, 
                    separators=(\',\', \':\'), 
                    sort_keys=True, 
                    indent=4)

这将创建两个单独的 json 文件。一个名为 saved_regressor_params.json 的文件保存了 SVR 所需的某些参数,另一个名为 saved_regressor.json 的文件将属性及其训练值存储为对象。示例(saved_regressor.json):

{
    \"_dual_coef_\":[
        [
            -1.0,
            -1.0,
            -1.0,
        ]
    ],
    \"_intercept_\":[
        1.323423423
    ],
         ...
         ...

    \"_n_support_\":[
        3
    ]
}

稍后,我可以创建一个新的 SVR() 模型,并通过从我们刚刚创建的现有 JSON 文件中调用它们来简单地将这些参数和属性设置到其中。然后,调用predict() 方法进行预测。像这样(在一个新文件中):

predict_svr = SVR()

#load the json from the files
obj_text = codecs.open(\'saved_regressor_params.json\', \'r\', encoding=\'utf-8\').read()
params = json.loads(obj_text)

obj_text = codecs.open(\'saved_regressor.json\', \'r\', encoding=\'utf-8\').read()
attributes = json.loads(obj_text)

#setting params
predict_svr.set_params(**params)

# setting attributes
for k in attributes:
        if isinstance(attributes[k], list):
            setattr(predict_svr, k, np.array(attributes[k]))
        else:
            setattr(predict_svr, k, attributes[k])
        
predict_svr.predict(...)

但是,在此过程中,由于某种原因,无法设置名为:n_support_ 的特定属性。即使我忽略n_support_ 属性,它也会产生额外的错误。 (我的逻辑是错误的还是我在这里遗漏了什么?)

因此,我正在寻找不同的方式或巧妙的方法将 SVR 模型保存为 JSON。

我已经尝试过现有的第三方帮助程序库,例如:sklearn_json。这些库倾向于完美地导出线性模型,而不是支持向量。

    标签: machine-learning scikit-learn svm


    【解决方案1】:

    基于docs(1.1.2 版),在 OP 中缺少一个可重现的示例

    from sklearn.svm import SVR
    from sklearn.pipeline import make_pipeline
    from sklearn.preprocessing import StandardScaler
    import numpy as np
    n_samples, n_features = 10, 5
    rng = np.random.RandomState(0)
    y = rng.randn(n_samples)
    X = rng.randn(n_samples, n_features)
    regressor = SVR(C=1.0, epsilon=0.2)
    regressor.fit(X, y)
    

    然后是 JSON 序列化/反序列化的草图

    import json
    # serialize
    serialized = json.dumps({
        k: v.tolist() if isinstance(v, np.ndarray) else v 
        for k, v in regressor.__dict__.items()
    })
    
    # deserialize
    regressor2 = SVR()
    regressor2.__dict__ = {
         k: np.asarray(v) if isinstance(v, list) else v 
         for k, v in json.loads(serialized).items()
    }
    
    # test
    assert np.all(regressor.predict(X) == regressor2.predict(X))
    

    编辑:序列化保留数据类型

    解决评论中提到的第一个问题的一个不太优雅的解决方案是将数据类型与数据一起保存。

    import json
    # serialize
    
    
    serialized = json.dumps({
        k: [v.tolist(), 'np.ndarray', str(v.dtype)] if isinstance(v, np.ndarray) else v 
        for k, v in regressor.__dict__.items()
    })
    
    # deserialize
    regressor2 = SVR()
    regressor2.__dict__ = {
         k: np.asarray(v[0], dtype=v[2]) if isinstance(v, list) and v[1] == 'np.ndarray' else v 
         for k, v in json.loads(serialized).items()
    }
    
    # test
    assert np.all(regressor.predict(X) == regressor2.predict(X))
    

    【讨论】:

    • 这在设置属性时效果很好。一旦我调用predict() 方法,它就会抛出这个错误:ValueError: Buffer dtype mismatch, expected 'int32_t' but got 'long'
    猜你喜欢
    • 2021-04-30
    • 2014-09-15
    • 1970-01-01
    • 2015-04-14
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多