__init__.py — 包初始化模块¶
模块路径: verl/__init__.py
文件概述¶
__init__.py 是整个 verl 包的入口文件。当你写 import verl 时,Python 会首先执行这个文件。它承担了以下职责:
- 导出核心接口:将最重要的类
DataProto暴露给外部用户 - 读取版本号:从文件中读取 verl 的版本信息
- 配置日志:设置全局日志级别
- 加载外部模块:支持用户通过环境变量注入自定义模块
- 适配不同硬件:对华为 NPU 设备做兼容性修补(monkey-patch)
- 可选集成 ModelScope:支持从 ModelScope 下载模型(替代 HuggingFace Hub)
在整个框架中,这个文件是最顶层的入口,决定了用户 import verl 之后能直接访问到什么。
关键代码讲解¶
1. 导入核心类 DataProto¶
这一行从同目录下的 protocol.py 中导入了 DataProto 类。DataProto 是 verl 框架中最核心的数据结构,用于在不同模块(Actor、Critic、Reward Model 等)之间传递数据。通过在 __init__.py 中导入,用户可以直接用 verl.DataProto 来访问它。
2. 读取版本号¶
version_folder = os.path.dirname(os.path.join(os.path.abspath(__file__)))
with open(os.path.join(version_folder, "version/version")) as f:
__version__ = f.read().strip()
这段代码从 verl/version/version 文件中读取版本号字符串。__file__ 是 Python 的内置变量,指向当前文件的路径。通过 os.path.dirname 得到 verl/ 目录,再拼接出版本文件的完整路径。
3. 设置日志级别¶
将全局日志级别设为 WARNING,意味着默认情况下只有警告和错误信息会被打印出来,debug 和 info 级别的日志会被静默。
4. 公开 API 声明¶
__all__ 定义了当用户执行 from verl import * 时,哪些名字会被导出。这里只导出了 DataProto 和 __version__,说明这两个是 verl 对外的核心接口。
5. 外部模块加载机制¶
modules = os.getenv("VERL_USE_EXTERNAL_MODULES", "")
if modules:
modules = modules.split(",")
import_external_libs(modules)
通过环境变量 VERL_USE_EXTERNAL_MODULES,用户可以指定逗号分隔的外部模块名。verl 会在启动时自动导入这些模块。这是一种插件机制,允许用户在不修改 verl 源码的情况下扩展功能。
6. ModelScope 集成¶
if os.getenv("VERL_USE_MODELSCOPE", "False").lower() == "true":
if importlib.util.find_spec("modelscope") is None:
raise ImportError(
"You are using the modelscope hub, please install modelscope by `pip install modelscope -U`"
)
from modelscope.utils.hf_util import patch_hub
patch_hub()
当环境变量 VERL_USE_MODELSCOPE 设为 true 时,verl 会用 ModelScope 的下载器替换 HuggingFace Hub 的下载器。这对于国内用户来说非常有用,因为 ModelScope 的下载速度通常更快。patch_hub() 是一个 monkey-patch 操作,它修改了 HuggingFace 的内部函数,使其从 ModelScope 下载模型。
7. NPU 设备兼容性修补¶
if is_npu_available:
import torch
try:
if hasattr(torch.nested.nested_tensor, "__wrapped__"):
torch.nested.nested_tensor = torch.nested.nested_tensor.__wrapped__
if hasattr(torch.nested.as_nested_tensor, "__wrapped__"):
torch.nested.as_nested_tensor = torch.nested.as_nested_tensor.__wrapped__
except AttributeError:
pass
华为 Ascend NPU 的 PyTorch 适配层(torch-npu)会对 torch.nested.nested_tensor 做拦截包装,但这个包装在某些场景下会报错。这段代码通过 __wrapped__ 属性取回原始函数,绕过 NPU 的拦截。
接下来还有一段 TensorDict 的修补:
import tensordict
if parse_version(tensordict.__version__) < parse_version("0.10.0"):
from tensordict.base import TensorDictBase
def _sync_all_patch(self):
from torch._utils import _get_available_device_type, _get_device_module
device_type = _get_available_device_type()
if device_type is None:
return
device_module = _get_device_module(device_type)
device_module.synchronize()
TensorDictBase._sync_all = _sync_all_patch
在分布式场景中,worker 计算完毕后会通过 TensorDict 将数据传回 CPU。这个传输操作默认是非阻塞的(non-blocking),如果不等待传输完成就使用数据,会出现精度问题。TensorDict 官方已经为 CUDA 和 MPS 设备修复了这个问题,但没有覆盖 NPU 设备。这段 patch 为 NPU 添加了同步支持。
核心类/函数列表¶
| 名称 | 类型 | 作用 |
|---|---|---|
DataProto |
类(从 protocol 导入) | verl 框架的核心数据传输协议 |
__version__ |
字符串 | verl 的版本号 |
import_external_libs |
函数(从 utils 导入) | 动态导入外部模块 |
set_basic_config |
函数(从 utils 导入) | 设置日志基础配置 |
is_npu_available |
布尔值(从 utils 导入) | 检测当前环境是否有 NPU 设备 |
与其他模块的关系¶
verl/__init__.py
├── 导入 verl/protocol.py → 获取 DataProto 类
├── 导入 verl/utils/device.py → 获取 is_npu_available
├── 导入 verl/utils/import_utils.py → 获取 import_external_libs
├── 导入 verl/utils/logging_utils.py→ 获取 set_basic_config
└── 读取 verl/version/version → 获取版本号
protocol.py是最重要的依赖,DataProto是 verl 对外的核心 APIutils/目录下的工具函数为初始化过程提供支持- 这个文件本身不被其他 verl 内部模块依赖,它只作为包的"门面"存在
小结¶
__init__.py 是 verl 包的入口文件,主要做三件事:
- 暴露核心 API:将
DataProto和__version__作为包级别的公开接口 - 环境适配:通过环境变量支持外部模块加载、ModelScope 集成、NPU 兼容
- 基础配置:设置日志级别
作为初学者,你只需要记住:import verl 之后可以用 verl.DataProto 来创建和操作数据,这就是这个文件最核心的作用。其他的兼容性修补和环境适配在日常使用中是透明的。