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

FastAPI+Uvicorn加载序列化FunctionTransformer出现NameError问题

NameError: name 'np' is not defined when loading pickled FunctionTransformer in FastAPI/Uvicorn

问题背景

用FastAPI搭建微服务,加载通过dill序列化的sklearn FunctionTransformer(内部依赖lambda调用numpy)时,本地测试正常,但Uvicorn启动后(尤其是reload=True模式,复杂项目中甚至非reload模式)触发NameError: name 'np' is not defined。Transformer定义如下:

my_transformer = sklearn.preprocessing.FunctionTransformer(
    func = lambda y: -np.log(y / 100),
    inverse_func = lambda y_transformed: np.exp(-y_transformed) * 100,
)

问题根源

pickle(含dill)序列化lambda函数时,不会保存lambda依赖的外部全局变量(比如np),仅保存变量名称字符串。在Uvicorn环境中加载时:

  • 启用reload=True时,Uvicorn会创建子进程重新加载应用模块,此时lambda的闭包作用域和序列化时的环境不一致,子进程全局命名空间中np的引用无法被lambda正确绑定。
  • 复杂项目中,模块结构、import顺序或Uvicorn多进程启动方式,会导致加载transformer的进程全局命名空间里np的名称无法被lambda识别,即便模块已import numpy。

解决方法

1. 替换lambda为具名函数(推荐)

lambda序列化天生脆弱,改用明确的具名函数可让dill正确捕获依赖:

import numpy as np
from sklearn.preprocessing import FunctionTransformer

def forward_transform(y):
    return -np.log(y / 100)

def inverse_transform(y_transformed):
    return np.exp(-y_transformed) * 100

my_transformer = FunctionTransformer(func=forward_transform, inverse_func=inverse_transform)

重新序列化该transformer后,FastAPI服务加载时只要环境安装numpy,即可正常运行,不受Uvicorn启动方式影响。

2. 确保加载环境全局绑定np

若必须保留lambda,在FastAPI入口模块顶部明确import numpy并绑定为np:

# 应用入口文件最顶部
import numpy as np
# 其余import代码...

但该方法稳定性差,复杂项目中若模块import顺序或进程隔离导致np不在加载transformer的作用域内,仍会报错,仅适用于简单场景。

3. 用cloudpickle替代dill序列化

cloudpickle对lambda和外部依赖的序列化支持更完善,可尝试替换序列化工具:

import cloudpickle

# 序列化时
with open("my_transformer.cloudpickle", "wb") as f:
    cloudpickle.dump(my_transformer, f)

# FastAPI中加载
with open("my_transformer.cloudpickle", "rb") as f:
    my_transformer = cloudpickle.load(f)

但仍优先推荐具名函数方案,lambda的可读性和可维护性均逊于具名函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:55:24