Как ускорить несколько трансляций в Юлии - PullRequest
0 голосов
/ 24 ноября 2018

Эта функция Джулии кажется довольно неэффективной (на порядок медленнее, чем эквивалентный код Pythran / C ++, даже после разогрева Джулии) ...

function my_multi_broadcast(a)
    10 * (2*a.^2 + 4*a.^3) + 2 ./ a
end

arr = ones(1000, 1000)
my_multi_broadcast(arr)

Я полагаю, что только яне пишите правильно ... Как можно ускорить такие "мульти-трансляции" в Юлии?Я думаю / надеюсь, мне не нужно расходовать петли ...

Редактировать после первого ответа

Спасибо!С моей установкой решения Pythran (на месте и вне места) все еще работают в 1,5-2 раза (без OpenMP).Есть ли способ активировать SIMD инструкции в Юлии?Или другой способ ускорить такие вычисления ЦП?

Код Python:

from transonic import jit

@jit
def broadcast(a):
    return 10 * (2*a**2 + 4*a**3) + 2 / a

@jit
def broadcast_inplace(a):
    a[:] = 10 * (2*a**2 + 4*a**3) + 2 / a

Редактировать после @simd предложения

Кажется, что @simd неработать из коробки, то есть просто добавив его в начале строки.

ERROR: LoadError: LoadError: Base.SimdLoop.SimdError("for loop expected")
Stacktrace:
 [1] compile(::Expr, ::Bool) at ./simdloop.jl:54
 [2] @simd(::LineNumberNode, ::Module, ::Any) at ./simdloop.jl:126
 [3] include at ./boot.jl:317 [inlined]
 [4] include_relative(::Module, ::String) at ./loading.jl:1044
 [5] include(::Module, ::String) at ./sysimg.jl:29
 [6] exec_options(::Base.JLOptions) at ./client.jl:231
 [7] _start() at ./client.jl:425

Полагаю, что нужно было бы расширить циклы for, но тогда код (i) станет намного менее читаемым и (ii) больше не будет зависеть от измерения.

Кажется, у нас есть случай, когда простой код Python / Numpy может быть ускорен с Pythran быстрее, чем тот, что мы получаем с Julia (кроме случаев, когда есть способ ускорить это в Julia? И будущая версия Julia может решить эту проблему).Интересно ...

1 Ответ

0 голосов
/ 24 ноября 2018

Передавайте все операции следующим образом:

julia> function my_multi_broadcast2(a)
           @. 10 * (2*a^2 + 4*a^3) + 2 / a
       end
my_multi_broadcast2 (generic function with 1 method)

Разница в том, что в 10 * (2*a.^2 + 4*a.^3) + 2 ./ a вы фактически не используете преимущества широковещательного слияния, поскольку * и две + не передаются.

Запись @. 10 * (2*a^2 + 4*a^3) + 2 / a эквивалентна 10 .* (2 .* a.^2 .+ 4 .* a.^3) .+ 2 ./ a.

А вот сравнение производительности

julia> @btime my_multi_broadcast($arr);
  58.146 ms (18 allocations: 61.04 MiB)

julia> @btime my_multi_broadcast2($arr);
  5.982 ms (4 allocations: 7.63 MiB)

Как это сравнить с Pythran / C ++, как мы получаем примерно10-кратное ускорение?

Наконец, обратите внимание, что если бы вы могли мутировать arr на месте, написав:

julia> function my_multi_broadcast3(a)
           @. a = 10 * (2*a^2 + 4*a^3) + 2 / a
       end
my_multi_broadcast3 (generic function with 1 method)

julia> @btime my_multi_broadcast3($arr);
  1.840 ms (0 allocations: 0 bytes)

, который еще быстрее и выполняет нулевое распределение (я не знаю, хотите ли выизмените arr на месте или создайте новый массив, чтобы я показал оба подхода).

...