这个基准测试结果的原因是什么?

res*_*chu 11 benchmarking loops vectorization julia

将rgb图像转换为灰度图像的两个函数:

function rgb2gray_loop{T<:FloatingPoint}(A::Array{T,3})
  r,c = size(A)
  gray = similar(A,r,c)
  for i = 1:r
    for j = 1:c
      @inbounds gray[i,j] = 0.299*A[i,j,1] + 0.587*A[i,j,2] + 0.114 *A[i,j,3]
    end
  end
  return gray
end
Run Code Online (Sandbox Code Playgroud)

和:

function rgb2gray_vec{T<:FloatingPoint}(A::Array{T,3})
  gray = similar(A,size(A)[1:2]...)
  gray = 0.299*A[:,:,1] + 0.587*A[:,:,2] + 0.114 *A[:,:,3]
  return gray
end
Run Code Online (Sandbox Code Playgroud)

第一个是使用循环,而第二个使用矢量化.

在对它们进行基准测试时(使用Benchmark包),我得到了不同大小的输入图像的以下结果(f1是循环版本,f2矢量化版本):

A = rand(50,50,3):

| Row | Function | Average     | Relative | Replications |
|-----|----------|-------------|----------|--------------|
| 1   | "f1"     | 3.23746e-5  | 1.0      | 1000         |
| 2   | "f2"     | 0.000160214 | 4.94875  | 1000         |
Run Code Online (Sandbox Code Playgroud)

A = rand(500,500,3):

| Row | Function | Average    | Relative | Replications |
|-----|----------|------------|----------|--------------|
| 1   | "f1"     | 0.00783007 | 1.0      | 100          |
| 2   | "f2"     | 0.0153099  | 1.95527  | 100          |
Run Code Online (Sandbox Code Playgroud)

A = rand(5000,5000,3):

| Row | Function | Average  | Relative | Replications |
|-----|----------|----------|----------|--------------|
| 1   | "f1"     | 1.60534  | 2.56553  | 10           |
| 2   | "f2"     | 0.625734 | 1.0      | 10           |
Run Code Online (Sandbox Code Playgroud)

我期望一个函数比另一个函数更快(因为inbounds宏可能是f1).

但我无法解释为什么矢量化版本对于较大的图像变得更快.这是为什么?

res*_*chu 9

结果的答案是Julia中的多维数组以列主顺序存储.请参阅Julias Memory Order.

修复了循环版本,关于列主要顺序(交换的内部和外部循环变量):

function rgb2gray_loop{T<:FloatingPoint}(A::Array{T,3})
  r,c = size(A)
  gray = similar(A,r,c)
  for j = 1:c
    for i = 1:r
      @inbounds gray[i,j] = 0.299*A[i,j,1] + 0.587*A[i,j,2] + 0.114 *A[i,j,3]
    end
  end
  return gray
end
Run Code Online (Sandbox Code Playgroud)

新结果A = rand(5000,5000,3):

| Row | Function | Average  | Relative | Replications |
|-----|----------|----------|----------|--------------|
| 1   | "f1"     | 0.107275 | 1.0      | 10           |
| 2   | "f2"     | 0.646872 | 6.03004  | 10           |
Run Code Online (Sandbox Code Playgroud)

以及较小阵列的结果:

A = rand(500,500,3):

| Row | Function | Average    | Relative | Replications |
|-----|----------|------------|----------|--------------|
| 1   | "f1"     | 0.00236405 | 1.0      | 100          |
| 2   | "f2"     | 0.0207249  | 8.76671  | 100          |
Run Code Online (Sandbox Code Playgroud)

A = rand(50,50,3):

| Row | Function | Average     | Relative | Replications |
|-----|----------|-------------|----------|--------------|
| 1   | "f1"     | 4.29321e-5  | 1.0      | 1000         |
| 2   | "f2"     | 0.000224518 | 5.22961  | 1000         |
Run Code Online (Sandbox Code Playgroud)