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

如何在Julia Flux中为自定义Layer正确启用GPU支持?

问题:自定义Flux层GPU支持报错修复

我希望为自定义Layer添加GPU支持,以下是我的网络构建代码:

# MyDense
struct MyDense
    d1
    d2     
end
MyDense(p::Pair) = MyDense(Dense(p), Dense(p))
(m::MyDense)(x) = m.d1(x) + m.d2(x)
# multiple-dispatch for gpu function on the custom layer
Flux.gpu(layer::MyDense) = MyDense(Flux.gpu(layer.d1), Flux.gpu(layer.d2))

# Define our model, a multi-layer perceptron with one hidden layer of size 3:
model = Chain(
    Dense(2 => 3, tanh),   # activation function inside layer
    BatchNorm(3),
    MyDense(3 => 2),
    softmax) |> gpu        # move model to GPU, if available

我参考相关回答为自定义层编写了Flux.gpu的多分派方法,但运行时报错:

ERROR: ArgumentError: cannot take the CPU address of a CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}
Stacktrace:
  [1] unsafe_convert(#unused#::Type{Ptr{Float32}}, x::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
    @ CUDA C:\Users\Herr LU\.julia\packages\CUDA\DfvRa\src\array.jl:319
  [2] gemm!(transA::Char, transB::Char, alpha::Float32, A::Matrix{Float32}, B::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}, beta::Float32, C::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
    @ LinearAlgebra.BLAS C:\Users\Herr LU\AppData\Local\Programs\Julia-1.8.2\share\julia\stdlib\v1.8\LinearAlgebra\src\blas.jl:1514
  [3] gemm_wrapper!(C::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}, tA::Char, tB::Char, A::Matrix{Float32}, B::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}, _add::LinearAlgebra.MulAddMul{true, true, Bool, Bool})
    @ LinearAlgebra C:\Users\Herr LU\AppData\Local\Programs\Julia-1.8.2\share\julia\stdlib\v1.8\LinearAlgebra\src\matmul.jl:674
  [4] mul!
    @ C:\Users\Herr LU\AppData\Local\Programs\Julia-1.8.2\share\julia\stdlib\v1.8\LinearAlgebra\src\matmul.jl:161 [inlined]
  [5] mul!
    @ C:\Users\Herr LU\AppData\Local\Programs\Julia-1.8.2\share\julia\stdlib\v1.8\LinearAlgebra\src\matmul.jl:276 [inlined]
  [6] *
    @ C:\Users\Herr LU\AppData\Local\Programs\Julia-1.8.2\share\julia\stdlib\v1.8\LinearAlgebra\src\matmul.jl:148 [inlined]
  [7] (::Dense{typeof(identity), Matrix{Float32}, Vector{Float32}})(x::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
    @ Flux C:\Users\Herr LU\.julia\packages\Flux\ZdbJr\src\layers\basic.jl:172
  [8] (::MyDense)(x::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
    @ Main e:\Master Thesis\lu_jizhou\Learning\FluxTrial.jl:14
  [9] macro expansion
    @ C:\Users\Herr LU\.julia\packages\Flux\ZdbJr\src\layers\basic.jl:53 [inlined]
 [10] _applychain(layers::Tuple{Dense{typeof(tanh), CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}, CUDA.CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}}, BatchNorm{typeof(identity), CUDA.CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, Float32, CUDA.CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}}, MyDense, typeof(softmax)}, x::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
    @ Flux C:\Users\Herr LU\.julia\packages\Flux\ZdbJr\src\layers\basic.jl:53
 [11] (::Chain{Tuple{Dense{typeof(tanh), CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}, CUDA.CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}}, BatchNorm{typeof(identity), CUDA.CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, Float32, CUDA.CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}}, MyDense, typeof(softmax)}})(x::CUDA.CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
    @ Flux C:\Users\Herr LU\.julia\packages\Flux\ZdbJr\src\layers\basic.jl:51
 [12] top-level scope
    @ e:\Master Thesis\lu_jizhou\Learning\FluxTrial.jl:25

请问该如何解决这个问题?


解决方案

问题根源

报错栈显示,MyDense内部的Dense层参数仍为CPU端的Matrix/Vector类型,但输入已经是GPU上的CuArray,导致CPU与GPU张量混合运算,触发了取CUDA数组CPU地址的错误。

问题出在MyDense的构造逻辑:调用MyDense(3 => 2)时生成的是CPU上的Dense层,后续的gpu方法虽尝试迁移,但需确保所有子层参数完全转移到GPU。

修复代码

修改自定义层的设备迁移逻辑,确保递归迁移所有子层,同时补充双向迁移的cpu方法:

# MyDense
struct MyDense
    d1
    d2     
end

MyDense(p::Pair) = MyDense(Dense(p), Dense(p))

# 递归迁移子层到GPU
Flux.gpu(layer::MyDense) = MyDense(Flux.gpu(layer.d1), Flux.gpu(layer.d2))
# 补充CPU迁移方法,保证双向兼容
Flux.cpu(layer::MyDense) = MyDense(Flux.cpu(layer.d1), Flux.cpu(layer.d2))

# 构建并迁移模型到GPU
model = Chain(
    Dense(2 => 3, tanh),
    BatchNorm(3),
    MyDense(3 => 2),
    softmax) |> gpu

# 验证子层参数是否已迁移到GPU
println(typeof(model[3].d1.weight))  # 应输出 CUDA.CuArray{Float32,2,...}

若仍有问题,可直接在构造MyDense时指定设备:

# 构造函数支持指定设备,默认使用GPU(若可用)
MyDense(p::Pair, device=gpu) = MyDense(device(Dense(p)), device(Dense(p)))

# 构建模型
model = Chain(
    Dense(2 => 3, tanh),
    BatchNorm(3),
    MyDense(3 => 2),
    softmax) |> gpu

核心注意事项

  • 自定义层的gpu/cpu方法必须递归迁移所有子层与参数到对应设备
  • 确保模型迁移后,所有参与运算的张量(层参数、输入)都在同一设备上
  • 禁止CPU与GPU张量混合运算,这是触发此类错误的核心原因

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:10:19