You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

向Python multiprocessing.Process传递Keras模型报错问题

问题根因
  • Windows环境下Pythonmultiprocessing默认采用spawn模式创建子进程,所有传给子进程的参数都会先执行pickle序列化,再在子进程侧反序列化还原。
  • Keras模型内置的pickle序列化逻辑不会直接把模型权重写入序列化字节流,而是临时将模型存储到当前进程独占的内存文件系统(即报错中ram://开头的路径),反序列化阶段再从该路径读取模型文件完成加载。
  • 内存文件系统是进程级隔离的,子进程没有权限访问父进程ram://路径下的临时文件,因此反序列化时会抛出找不到变量文件的错误。通过clone_model得到的模型副本序列化逻辑和原模型完全一致,同样会触发该问题。移除模型传参后不会触发Keras模型的序列化/反序列化流程,因此多进程逻辑可正常运行。
可行解决方案

按稳定性从高到低排序:

  • 方案1:子进程内完成模型初始化(全平台兼容,最稳定)
    不要跨进程传递Keras模型对象,只传递可正常序列化的模型配置、numpy格式的权重数组,子进程启动后自行构建模型结构、加载权重。该方案完全避开了Keras模型跨进程序列化的坑,也不会触发TensorFlow会话、CUDA上下文跨进程错乱的问题,是实际生产环境优先选择的方案。
    参考修改代码:
    from multiprocessing import Process
    from tensorflow import keras
    from tensorflow.keras import layers
    
    def dumb_fun(x, model_weights):
        # 子进程内部独立构建模型结构
        input_layer = layers.Input(shape=(120,160,2))
        x = layers.Conv2D(32, (3, 3), activation='relu')(input_layer)
        x = layers.MaxPool2D((2, 2))(x)
        x = layers.Conv2D(64, (3, 3), activation='relu')(x)
        x = layers.MaxPool2D((2, 2))(x)
        x = layers.Conv2D(128, (3, 3), activation='relu')(x)
        x = layers.MaxPool2D((2, 2))(x)
        x = layers.Flatten()(x)
        x = layers.Dense(64, activation='relu')(x)
        x = layers.Dense(32, activation='relu')(x)
        actions = layers.Dense(5, activation='softmax')(x)
        model = keras.Model(input_layer, actions)
        # 加载传入的numpy格式权重
        model.set_weights(model_weights)
        print(x)
        print(model)
    
    if __name__ == '__main__':
        input_layer = layers.Input(shape=(120,160,2))
        x = layers.Conv2D(32, (3, 3), activation='relu')(input_layer)
        x = layers.MaxPool2D((2, 2))(x)
        x = layers.Conv2D(64, (3, 3), activation='relu')(x)
        x = layers.MaxPool2D((2, 2))(x)
        x = layers.Conv2D(128, (3, 3), activation='relu')(x)
        x = layers.MaxPool2D((2, 2))(x)
        x = layers.Flatten()(x)
        x = layers.Dense(64, activation='relu')(x)
        x = layers.Dense(32, activation='relu')(x)
        actions = layers.Dense(5, activation='softmax')(x)
        actor = keras.Model(input_layer, actions, name="actor")
    
        numbers = [1,1,2,3,5,8,13]
        num_procs = len(numbers)
    
        processes = []
        for i in range(num_procs):
            # 仅传递numpy格式的权重数组,不传递模型对象
            processes.append(Process(target=dumb_fun, args=(numbers[i], actor.get_weights())))
    
        for proc in processes:
            proc.start()
        for proc in processes:
            proc.join()
    
  • 方案2:切换多进程启动模式为fork(仅支持Linux/macOS,Windows不可用)
    fork模式下子进程会直接复制父进程的完整内存空间,不需要对传入参数做pickle序列化,自然不会触发内存文件系统访问的问题。但TensorFlow对fork模式的兼容性一般,GPU环境下容易出现CUDA上下文错乱的问题,仅建议CPU场景下临时使用。
    启用方式:在主程序入口、创建进程前添加如下代码
    import multiprocessing as mp
    mp.set_start_method('fork', force=True)
    
  • 方案3:通过磁盘文件中转模型(全平台兼容,性能较差)
    如果不想在子进程重复写模型构建逻辑,可以先将父进程的模型保存到实体磁盘路径,子进程只接收磁盘路径字符串,启动后自行调用keras.models.load_model加载模型。该方案本质和方案1逻辑一致,但会产生额外的磁盘IO开销,进程数量较多时启动速度慢。

内容的提问来源于stack exchange,提问作者Giuseppe Boezio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 19:27:21