2015-05-10 3 views
3

Я хотел бы инициализировать 3d тензора (многомерный массив) со значениями «по диагонали Gaussian»Быстрая тензор инициализация в Джулии

exp(-32*(u^2 + 16*(v^2 + w^2))) 

где u = 1/sqrt(3)*(x+y+z) и v,w являются любыми две координатами ортогональных u, дискретизирован на равномерной сетке на [-1,1]^3. Следующий код обеспечивает:

function gaussian3d(n) 
    q = qr(ones(3,1), thin=false)[1] 
    x = linspace(-1.,1., n) 
    p = Array(Float64,(n,n,n)) 
    square(x) = x*x 
    [email protected] 3 i p begin 
     @inbounds p[i_1,i_2,i_3] = 
      exp(
       -32*(
        square(q[1,1]*x[i_1] + q[2,1]*x[i_2] + q[3,1]*x[i_3]) 
        + 16*(
         square(q[1,2]*x[i_1] + q[2,2]*x[i_2] + q[3,2]*x[i_3]) + 
         square(q[1,3]*x[i_1] + q[2,3]*x[i_2] + q[3,3]*x[i_3]) 
        ) 
       ) 
      ) 
    end 
    return p 
end 

Это, однако, довольно медленно. Например, если я заменяю определяющую функцию exp(x*y*z), код работает быстрее на 50 раз. Кроме того, макрос @time сообщает ~ 20% GC-времени для вышеуказанного кода, который я не понимаю, откуда они. (Эти числовые значения были получены с n = 128.) Мои вопросы поэтому

  • Как я могу ускорить этот кусок кода?
  • Где скрыто выделение памяти, которое вызывает накладные расходы GC?
+2

Попробуйте определить свою функцию '' square'' в области верхнего уровня или уровня модуля. Внутренние функции недостаточно оптимизированы. – mlubin

+0

Определение 'square' на верхнем уровне, похоже, несколько увеличивает производительность, но коэффициент усиления лишь немного превышает неопределенность в сроках. – gTcV

+0

Просто любопытно, есть ли применение для этого тензора? Исключительно маленькие значения * и * охватывают сотни порядков. – rickhg12hs

ответ

2

не зная ничего о 3D тензоров со значениями «по диагонали Gaussian», используя square комментарий от оригинального поста, «набрав» q (@code_warntype helps here: Большой скачок производительности), и далее Специализируя @nloops, это работает намного быстрее на платформах, на которых я его пробовал.

julia> square(x::Float64) = x * x 
square (generic function with 1 method) 

julia> function my_gaussian3d(n) 
      q::Array{Float64,2} = qr(ones(3,1), thin=false)[1] 
      x = linspace(-1.,1., n) 
      p = Array(Float64,(n,n,n)) 
      [email protected] 3 i p d->x_d=x[i_d] begin 
       @inbounds p[i_1,i_2,i_3] = 
        exp(
         -32*(
          square(q[1,1]*x_1 + q[2,1]*x_2 + q[3,1]*x_3) 
          + 16*(
           square(q[1,2]*x_1 + q[2,2]*x_2 + q[3,2]*x_3) + 
           square(q[1,3]*x_1 + q[2,3]*x_2 + q[3,3]*x_3) 
          ) 
         ) 
        ) 
      end 
      return p 
     end 
my_gaussian3d (generic function with 1 method) 

julia> @time gaussian3d(128); 
elapsed time: 3.952389337 seconds (1264 MB allocated, 4.50% gc time in 57 pauses with 0 full sweep) 

julia> @time gaussian3d(128); 
elapsed time: 3.527316699 seconds (1264 MB allocated, 4.42% gc time in 58 pauses with 0 full sweep) 

julia> @time my_gaussian3d(128); 
elapsed time: 0.285837566 seconds (16 MB allocated) 

julia> @time my_gaussian3d(128); 
elapsed time: 0.28476448 seconds (16 MB allocated, 1.22% gc time in 0 pauses with 0 full sweep) 

julia> my_gaussian3d(128) == gaussian3d(128) 
true 
+0

Я действительно задаюсь вопросом, может ли генерация тензора также масштабирование 'q' и выполнение свертки (на основе FFT?). Здесь также много симметрии, которая дублирует вычисления. По крайней мере, увольнения могут быть уменьшены/устранены. – rickhg12hs

+0

Ввод строки 'q' является ключом к производительности. На первый взгляд, я думал, что это избыточно, поскольку в момент объявления компилятор мог легко вывести тип 'q', но еще раз просмотрев руководство Julia, я понял, что этого недостаточно: нам также нужно обещать компилятор, что мы никогда не будем пытаться назначить что-нибудь еще 'q'! Будучи самим начинающим Джулией, я думаю, что это то, на что нападают многие новички-новички, поэтому, возможно, вы хотите более четко выделить это в своем ответе. Спасибо за вашу помощь, так или иначе! – gTcV

+1

Нет, вам обычно не нужно обещать, что вы не измените тип 'q' внутри функции: компилятор может понять это сам. Вероятно, это нестабильность типа в функции 'qr'. Было бы полезно открыть проблему. – tholy

Смежные вопросы