如何存储缩放参数以供以后使用
Posted
技术标签:
【中文标题】如何存储缩放参数以供以后使用【英文标题】:How to store scaling parameters for later use 【发布时间】:2016-06-26 23:13:21 【问题描述】:我想应用scikit-learn
提供的缩放sklearn.preprocessing.scale
模块来使我将用于训练支持向量机分类器的数据集居中。
然后我如何存储标准化参数,以便我也可以将它们应用于我想要分类的数据?
我知道我可以使用standarScaler
,但我可以以某种方式将其序列化到一个文件中,这样每次我想运行分类器时就不必将它与我的数据相匹配吗?
【问题讨论】:
【参考方案1】:我认为最好的方法是在fit
之后对其进行腌制,因为这是最通用的选项。也许您稍后会创建一个由特征提取器和缩放器组成的管道。通过腌制(可能是复合的)阶段,您可以使事情变得更加通用。 sklearn documentation on model persistence 讨论了如何做到这一点。
话虽如此,您可以查询sklearn.preprocessing.StandardScaler
获取拟合参数:
scale_:ndarray,形状(n_features,) 数据的每个特征相对缩放。 0.17 版中的新功能:建议使用 scale_ 而不是弃用的 std_。 mean_ : 形状为 [n_features] 的浮点数组 训练集中每个特征的平均值。
以下简短的 sn-p 说明了这一点:
from sklearn import preprocessing
import numpy as np
s = preprocessing.StandardScaler()
s.fit(np.array([[1., 2, 3, 4]]).T)
>>> s.mean_, s.scale_
(array([ 2.5]), array([ 1.11803399]))
【讨论】:
应该有一种方法可以使用之前拟合保存的参数来构建标准缩放器。【参考方案2】:使用标准缩放器进行缩放
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(data)
scaled_data = scaler.transform(data)
保存 mean_ 和 var_ 以备后用
means = scaler.mean_
vars = scaler.var_
(您可以打印和复制粘贴方式和变量或使用 np.save.... 保存到磁盘)
以后使用保存的参数
def scale_data(array,means=means,stds=vars **0.5):
return (array-means)/stds
scale_new_data = scale_data(new_data)
【讨论】:
【参考方案3】:您可以使用 joblib 模块来存储缩放器的参数。
from joblib import dump
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(data)
dump(scaler, 'scaler_filename.joblib')
稍后您可以加载缩放器。
from joblib import load
scaler = load('scaler_filename.joblib')
transformed_data = scaler.transform(new_data)
【讨论】:
你可以使用它,但它在某些方面更好吗?这是标准库的一部分吗?新的 pickle 是否缓解了 joblib 最初试图解决的一些问题?不知道,但这些信息会很有帮助。【参考方案4】:Pickle 带来了一个安全漏洞,允许攻击者在服务器上执行任意代码。条件是:
可以用服务器上的另一个pickle文件替换pickle文件(如果没有对pickle进行审计,即签名验证或哈希比较)
相同,但在开发人员 PC 上(攻击者入侵了一些开发人员 PC
如果您的服务器端应用程序以 root 身份执行(或在 docker 容器中以 root 身份执行),那么这绝对值得您关注。
可能的解决方案:
模型训练应该在安全的环境中进行
经过训练的模型应该由来自另一个安全环境的密钥签名,该密钥不会加载到 gpg-agent(否则攻击者可以很容易地替换签名)
CI 应在隔离环境(隔离)中测试模型
使用python3.8或更高版本,添加了安全钩子以防止代码注入技术
或者只是避免泡菜:)
一些链接:
https://docs.python.org/3/library/pickle.html
Python: can I safely unpickle untrusted data?
https://github.com/pytorch/pytorch/issues/52596
https://www.python.org/dev/peps/pep-0578/
避免酸洗的可能方法:
# scaler is fitted instance of MinMaxScaler
scaler_data_ = np.array([scaler.data_min_, scaler.data_max_])
np.save("my_scaler.npy", allow_pickle=False, scaler_data_)
#some not scaled X
Xreal = np.array([1.9261148646249848, 0.7327923702472628, 118, 1083])
scaler_data_ = np.load("my_scaler.npy")
Xmin, Xmax = scaler_data_[0], scaler_data_[1]
Xscaled = (Xreal - Xmin) / (Xmax-Xmin)
Xscaled
# -> array([0.63062502, 0.35320565, 0.15144766, 0.69116555])
【讨论】:
由于安全问题,泡菜是个坏主意吗?还是有其他原因? @AdrianTompkins 是的,因为可以用任何其他对象替换泡菜对象并在主机上执行它。加上酸洗在酸洗协议的兼容性方面产生了不必要的限制 @AdrianTompkins 感谢您提出这个问题。我实际上在答案中有一个错误。现在它是固定的。添加了 allow_pickle=False :) 并在 numpy 源码中提供了参考 “酸洗在生产中是一个坏主意”的说法具有误导性,特别是因为您通过链接引用的原因。您不应该笼统地声明,尤其是如果您是该行业的新手 - 这会误导整个社区。span> @wellplayed 感谢您的留言。我试图在描述我的立场时更加透明。我更新了答案。如果您不同意,请提供您的想法、论据以上是关于如何存储缩放参数以供以后使用的主要内容,如果未能解决你的问题,请参考以下文章
初始化Open IDC auth dance时存储GET请求参数以供以后使用
如何 $.post 一个 js 变量并将其存储到 php 以供以后使用,类似于 LocalStorage?