背景
在实验机器学习时,我经常重复使用以前训练过的模型,通过酸洗/不腌制。然而,在处理特征提取部分时,不要混淆不同的模型是一个挑战。因此,我想添加一个检查,以确保使用与测试数据完全相同的特征提取过程来训练模型。
问题
我的想法是:与模型一起,我会在泡菜转储中包含一个哈希值,该值对特征提取过程进行指纹处理。
当训练一个模型或使用它进行预测/测试时,模型包装器会被赋予一个符合特定协议的特征提取类。当然,在该类上使用hash()是行不通的,因为它在不同的调用中并不持久。因此,我想我也许可以找到定义类的源文件,并从该文件中获取一个散列值。
但是,可能有一种方法可以直接从类的内存中获得一个稳定的散列值。这有两个优点:如果找不到源文件,它也能工作。它可能会忽略对源文件的无关更改(例如。修复模块docstring中的错误)。类有可以在这里使用的代码对象吗?
发布于 2018-10-07 04:21:17
您所要寻找的只是一个包含类定义的所有显着细节的散列过程。(可以通过递归地包含基类定义来包含基类。)为了最小化错误匹配,基本思想是向类的序列化应用宽(加密)散列。所以从pickle开始:它支持比hash更多的类型,当它使用标识时,它使用基于名称的可复制标识。这使得它成为递归策略的基本情况的一个很好的选择:处理内容重要的函数和类,并让它处理引用的任何辅助对象。
因此,按情况定义序列化。如果对象在下面任何情况下都属于最后一个情况,则调用它为特殊对象。
tuple:tlen的序列化
dict:dlen的序列化
C__bases__的序列化vars的序列化
f__defaults__的序列化__kwdefaults__的序列化(在Python-3中)__closure__的序列化(但使用单元格值而不是单元格本身)vars的序列化__code__的序列化
pickle根本不支持它们):cco_argcount、co_nlocals、co_flags、co_code、co_consts、co_names、co_freevars和co_cellvars;没有一个是特殊的。
s或m__func__的序列化
pfget、fset和fdel
pickle.dumps(x,-1)(实际上您从未存储过:只需在顶级函数中创建您选择的hashlib对象,然后在递归部分update中依次使用序列化的每一段。)
类型标记是为了避免冲突,特别是避免前缀无关。二进制泡菜已经没有前缀了。您可以根据对容器内容的确定性分析(即使是启发式的)或上下文来做出关于容器的决定,只要您是一致的。
和往常一样,平衡假阳性和假阴性有一定的技巧:对于一个函数,您可以包括__globals__ (为了避免大规模的(如果不是无限的序列化)已经序列化的对象的剪枝),或者仅仅包括在其中找到的任何__name__。省略co_varnames会忽略重命名局部变量,这很好,除非内省很重要;同样,对于co_filename和co_name也是如此。
您可能需要支持更多类型:查找不正确的静态属性和默认参数(因为它们包含对特定类型的引用)或根本不支持pickle。当然,请注意,某些类型(如文件对象)是不可选的,因为序列化它们很困难或不可能(尽管与pickle不同,一旦完成code对象,您就可以像处理任何其他函数一样处理lambda)。在可能出现错误匹配的情况下,您可以选择只序列化这类对象的类型(一如既往,以字符?作为前缀以区别于实际处于该位置的类型)。
https://stackoverflow.com/questions/46768213
复制相似问题