如何拆分大于2GiB的分类器对象进行Pickle序列化?
解决Python2中Pickle大体积SVC分类器的2GiB限制问题
当然可以用拆分字节的方案来解决这个问题!Python2的cPickle确实存在单个字符串不能超过2GiB的硬限制,而你训练的SVC分类器在序列化时生成的字节流刚好触发了这个阈值。拆分序列化的思路完全可行,而且不需要依赖任何第三方库,完美符合你的需求。
序列化代码修改
我们先把分类器序列化为完整的字节流,再拆分成多个小于2GiB的片段写入文件,同时记录片段数量方便后续还原:
from sklearn.svm import SVC import cPickle import time def train_clf(X,y,clf_name): start_time = time.time() # 训练分类器(保持你的原有逻辑) clf = SVC(C = 0.01, kernel='poly') clf.fit(X,y) print 'fit done... {} seconds'.format(time.time() - start_time) # 先将分类器序列化为完整字节流 pickle_bytes = cPickle.dumps(clf, protocol=cPickle.HIGHEST_PROTOCOL) # 定义单个片段大小(设为1.5GiB,留足余量避免触发2GiB限制) chunk_size = int(1.5 * 1024 * 1024 * 1024) # 1572864000 bytes # 拆分字节流为多个小片段 chunks = [pickle_bytes[i:i+chunk_size] for i in xrange(0, len(pickle_bytes), chunk_size)] with open(clf_name, "wb") as fo: # 先写入片段总数,反序列化时需要知道要读取多少个片段 cPickle.dump(len(chunks), fo, protocol=cPickle.HIGHEST_PROTOCOL) # 逐个写入每个字节片段 for chunk in chunks: cPickle.dump(chunk, fo, protocol=cPickle.HIGHEST_PROTOCOL) return time.time() - start_time
反序列化代码修改
读取时先获取片段数量,再逐个读取片段并拼接回完整字节流,最后反序列化得到分类器:
import cPickle import time def load_clf(clf_name): start_time = time.time() with open(clf_name, 'rb') as fo: # 读取片段总数 num_chunks = cPickle.load(fo) # 拼接所有字节片段 full_pickle_bytes = '' for _ in xrange(num_chunks): chunk = cPickle.load(fo) full_pickle_bytes += chunk # 反序列化还原分类器 clf = cPickle.loads(full_pickle_bytes) load_time = time.time() - start_time return clf, load_time
方案原理与注意事项
- 核心逻辑:绕过cPickle对单个序列化字符串的2GiB限制,先把大对象转成完整字节流,拆分后分别序列化每个小片段,反序列化时再拼接还原。
- 片段大小选择:不要把片段设为刚好2GiB,建议留10-30%的余量(比如1.5GiB),避免因为字节流的额外结构导致单个片段接近或超过限制。
- 兼容性:完全基于Python2标准库实现,不需要安装任何第三方模块,符合你的环境要求。
- 测试建议:可以先用一个小型的SVC模型测试这套序列化/反序列化流程是否能正常还原分类器,确认无误后再应用到你的大体积模型上。
内容的提问来源于stack exchange,提问作者CIsForCookies
相关产品推荐
相关产品推荐

