FastChain против графических процессоров в DiffEqFlux

Для обучения модели на GPU я использую

dudt = Chain(Dense(3,100,tanh),
    Dense(100,3)) |> gpu

против

Обучение ЦП

dudt = FastChain(   
              FastDense(3,100,tanh),
              FastDense(100,3))

Более 1000 итераций Fastchain на порядки быстрее, чем GPU Tesla K40c. Это ожидаемое поведение? В противном случае, мог ли я что-то не так с реализацией модели на графических процессорах. MWE для реализации на GPU следующим образом:

function lorenz(du,u,p,t)
    σ = p[1]; ρ = p[2]; β = p[3]
    du[1] = σ*(u[2]-u[1])
    du[2] = u[1]*(ρ-u[3]) - u[2]
    du[3] = u[1]*u[2] - β*u[3]
    return 
end
u0 = Float32[1.0,0.0,0.0]               
tspan = (0.0,1.0)                      
para = [10.0,28.0,8/3]                      
prob = ODEProblem(lorenz, u0, tspan, para)  
t = range(tspan[1],tspan[2],length=101)
ode_data = Array(solve(prob,Tsit5(),saveat=t))
ode_data = cu(ode_data)

u0train = [1.0,0.0,0.0] |> gpu
tspantrain = (0.0,1.0)  
ttrain = range(tspantrain[1],tspantrain[2],length=101)  
dudt = Chain(Dense(3,100,tanh),
    Dense(100,3)) |> gpu
n_ode = NeuralODE((dudt),tspantrain,Tsit5(),saveat=ttrain)

function predict_n_ode(p)
  n_ode(u0train,p)
end

function loss_n_ode(p)
    pred = predict_n_ode(p) |> gpu
    loss = sum(abs2, pred .- ode_data)
    loss,pred
end

res1 = DiffEqFlux.sciml_train(loss_n_ode, n_ode.p, ADAM(0.01), cb=cb, maxiters = 1000)

1 ответ

Эта модель слишком мала для параллелизма графического процессора, чтобы действительно иметь значение. Нейронная сеть состоит из трех матвеков, 100x3, 100x100, 3x100. Единственное ядро ​​с ядром, которое, вероятно, приближается к безубыточности, - это средний, где матрица 100x100 умножается на вектор длиной 100.

Например, на моей машине:

using BenchmarkTools, CuArrays
A = rand(100,100); x = rand(100);
@btime A*x; # 56.299 μs (1 allocation: 896 bytes)
gA = cu(A); gx = cu(x)
@btime gA*gx; # 12.499 μs (6 allocations: 160 bytes)

A = rand(100,3); x = rand(3);
@btime A*x; # 251.695 ns (1 allocation: 896 bytes)
gA = cu(A); gx = cu(x)
@btime gA*gx; # 12.212 μs (6 allocations: 160 bytes)

Таким образом, хотя ускорение самой большой операции действительно существует, этого недостаточно, чтобы преодолеть замедление, перенеся другие небольшие операции на графический процессор. Это связано с тем, что графические процессоры имеют высокий этаж (на моей машине около 12 с), поэтому вы должны убедиться, что ваша проблема достаточно велика, чтобы она действительно имела смысл. Как правило, машинное обучение выигрывает от графических процессоров, потому что в нем преобладают большие матричные умножения со слоями размером в десятки тысяч.

Другие вопросы по тегам