转移守卫#
JAX 在类型转换和输入分片期间可能会在主机和设备之间以及设备之间传输数据。为了记录或禁止任何意外的传输,用户可以配置一个 JAX 传输守卫。
JAX 传输保护区分两种类型的传输:
显式传输:
jax.device_put*()
和jax.device_get()
调用。隐式传输:其他传输(例如,打印一个
DeviceArray
)。
转移守卫可以根据其守卫级别采取行动:
"allow"
: 静默允许所有传输(默认)。"log"
: 记录并允许隐式传输。静默允许显式传输。"disallow"
: 禁止隐式转账。静默允许显式转账。"log_explicit"
: 记录并允许所有传输。"disallow_explicit"
: 禁止所有转账。
当不允许传输时,JAX 将引发一个 RuntimeError
。
传输守卫使用标准的 JAX 配置系统:
一个
--jax_transfer_guard=GUARD_LEVEL
命令行标志和jax.config.update("jax_transfer_guard", GUARD_LEVEL)
将设置全局选项。with jax.transfer_guard(GUARD_LEVEL): ...
上下文管理器将在上下文管理器的范围内设置线程本地选项。
请注意,与其他 JAX 配置选项类似,新创建的线程将使用全局选项,而不是创建线程的作用域中的任何活动线程本地选项。
转移守卫也可以根据转移方向更有选择性地应用。标志和上下文管理器名称后缀有相应的转移方向(例如,--jax_transfer_guard_host_to_device
和 jax.config.transfer_guard_host_to_device
):
"host_to_device"
: 将 Python 值或 NumPy 数组转换为 JAX 设备上的缓冲区。"device_to_device"
: 将 JAX 设备缓冲区复制到不同的设备。"device_to_host"
: 获取JAX设备上的缓冲区。
在CPU设备上获取缓冲区总是被允许的,无论传输保护级别如何。
以下展示了使用传输守卫的示例。
>>> jax.config.update("jax_transfer_guard", "allow") # This is default.
>>>
>>> x = jnp.array(1)
>>> y = jnp.array(2)
>>> z = jnp.array(3)
>>>
>>> print("x", x) # All transfers are allowed.
x 1
>>> with jax.transfer_guard("disallow"):
... print("x", x) # x has already been fetched into the host.
... print("y", jax.device_get(y)) # Explicit transfers are allowed.
... try:
... print("z", z) # Implicit transfers are disallowed.
... assert False, "This line is expected to be unreachable."
... except:
... print("z could not be fetched")
x 1
y 2
z could not be fetched