运行GitHub开源word2vec.py遇_pickle.PicklingError问题求助
我帮你定位并解决这个_pickle.PicklingError问题!你猜的没错,这个错误确实是因为多进程Pool在传递参数时,需要对对象进行Pickle序列化,但numpy的c_double_Array_100这类ctypes数组类型无法被正常序列化——这类动态生成的ctypes数组类,Pickle找不到对应的全局属性定义,所以序列化失败。
下面是几个可行的解决方案,按推荐优先级排序:
1. 替换为原生支持Pickle的numpy数组
最直接的方法是把代码中c_double_Array_100类型的数组替换成numpy的ndarray,因为ndarray是原生支持Pickle序列化的,而且和原数组的功能完全兼容。
比如原来的代码如果是这样创建数组的:
from numpy.ctypeslib import c_double arr_type = c_double * 100 weights = arr_type()
可以改成:
import numpy as np weights = np.zeros(100, dtype=np.float64)
如果代码中需要和ctypes函数交互,也可以随时把ndarray转换成ctypes数组(比如用weights.ctypes.data_as(ctypes.POINTER(ctypes.c_double))),不影响功能,但传递给多进程时用ndarray就不会有Pickle问题。
2. 使用进程间共享对象传递数组
如果必须保留ctypes数组的形式,可以用multiprocessing.Manager创建可共享的数组对象,这样不需要Pickle整个数组,而是在进程间共享内存:
from multiprocessing import Pool, Manager import numpy as np import ctypes def worker(shared_arr): # 将共享数组转换成numpy数组使用 arr = np.frombuffer(shared_arr.get_obj(), dtype=np.float64) # 这里写你的worker逻辑,比如更新词向量权重 arr[0] += 1.0 if __name__ == "__main__": manager = Manager() # 创建长度为100的double类型共享数组 shared_weights = manager.Array('d', 100) with Pool() as pool: pool.apply(worker, (shared_weights,))
这种方式适合需要在多个进程间共享更新同一个数组的场景。
3. 调整代码逻辑,避免传递不可序列化对象
检查你的代码中,传递给Pool.map或Pool.apply的参数里是否直接包含了c_double_Array_100对象。如果是某个类的属性持有这个数组,可以把数组转换成普通Python列表(比如list(weights))传递给子进程,在子进程里再重新构建成需要的类型;或者把数组的初始化逻辑放到子进程内部,不在主进程创建后传递。
另外,顺带提醒一下:你运行代码的命令-train test_word2vec.py -model out.txt看起来有点问题——原仓库的word2vec.py中-train参数应该指定训练文本数据文件,而不是代码文件,这可能会导致后续其他错误,记得改成对应的训练数据路径哦!
内容的提问来源于stack exchange,提问作者semenbari

