unsupported dtype conversion from C64 to F64
主线位置:张量主线的「计算」:复数结果变回实数 dtype 的那一步(取实部再做实数损失)。
版本:JAX 0.12.0.1(CPU,x64)、PyTorch 2.15.0(单线程)、tenferro-rs 0.8.0(CPU,native,单线程)
flowchart TB z["C64 张量"] --> cv["convert F64"] cv --> err["拒绝 有损"] z --> ca["cast F64"] ca --> re["实部"] re --> gr["可以求导"]
实验代码:tenferro 一侧是 bin p17_19_complex(release,CpuEngine::serial()),JAX / PyTorch 一侧是 p17_19_complex.py。M2 Max、macOS 27、rustc 1.99.0。
现象
z = [iπ/2, ln 2],取实部。JAX 和 PyTorch 里改 dtype 就能丢掉虚部,只是会提醒:
jnp.asarray(z).astype(jnp.float64)
jnp.real(z)
jax.grad(lambda z: jnp.sum(jnp.real(z) ** 2))(z)
zt.to(torch.float64)
jnp astype(float64) = [0. 0.69314718] warnings: ['DeprecationWarning: Casting from complex to real dtypes will soon raise a ValueError. Please first use jnp.real or jnp.imag to take the real/imaginary component of your input.']
jnp.real = [0. 0.69314718]
grad(sum(real(z)^2)) = [0. +0.j 1.38629436+0.j]
torch .to(float64) = [0. 0.69314718] warnings: ['UserWarning: Casting complex values to real discards the imaginary part (Triggered internally at ...)']
tenferro 里找 dtype 转换,最先看到的是 convert:
let z = TracedTensor::from_vec_col_major(vec![2], vec![C::new(0.0, FRAC_PI_2), C::new(LN_2, 0.0)])?;
z.convert(DType::F64)
convert(z, F64): Err(TracedTensor::convert: unsupported dtype conversion from C64 to F64: checked convert only accepts conversions allowed by dtype promotion; use explicit cast for lossy dtype projection)
建图那一行就失败。TracedTensor 上也没有 real / imag 方法可以代替。
出处
TracedTensor::convert 先做 validate_convert_dtype,只放行 dtype 提升格(promotion lattice)里的转换,不丢信息的方向才行,然后才调 cast:
pub fn convert(&self, to: DType) -> Result<TracedTensor> {
tenferro_tensor::validate::validate_convert_dtype("TracedTensor::convert", self.dtype, to)?;
self.cast(to)
}
cast 是「explicit dtype projection」,文档写着它可以截断、降精度、「project complex values to their real component」。JAX 正在往同一个方向走:上面的弃用警告说复数到实数的 astype 以后会报 ValueError。浮点到整数的 cast 另有运行时检查(NaN 报错),见 dtype。
修法
取实部用 cast(DType::F64):
let re = z.cast(DType::F64)?;
let lr = (&re * &re)?.reduce_sum(None)?;
let g = ad.grad(&lr, &z)?;
cast(z, F64) = [0.0, 0.6931471805599453]
grad(sum(cast(z)^2)) = [0.000000+0.000000i, 1.386294+0.000000i]
值和梯度都和 JAX 的 jnp.real 一致:Σ (Re z)² 的梯度是 2·Re z,虚部为 0,这里两种复数约定(复数求导)给出同一个数,因为梯度是实数。模长用 abs,它的输出本来就是 F64。
怎么确认没中招
- 代码里搜
convert(DType::F64)/convert(DType::F32):作用在复数上时一定失败,失败在建图时,不会静默。 - 反过来要小心的是
cast:它不检查方向,复数被cast成实数时虚部静默丢掉。只在确实要实部的地方用,旁边写一行注释。
小结
convert只做不丢信息的转换,C64 到 F64 报unsupported dtype conversion;JAX 的astype只给弃用警告。- 取实部用
cast(DType::F64),可求导,结果同jnp.real。 TracedTensor没有real/imag方法;模长用abs。
💬 关联讨论
发起讨论加载中...