2015-04-20 16 views
11

Hai chức năng chuyển đổi một hình ảnh rgb đến một hình ảnh thang xám:Lý do cho kết quả điểm chuẩn này là gì?

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 

Và:

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 

là Người đầu tiên sử dụng các vòng lặp, trong khi cái thứ hai sử dụng vector hóa.

Khi benchmarking họ (với gói Benchmark) tôi nhận được kết quả như sau cho hình ảnh đầu vào có kích thước khác nhau (f1 là phiên bản lặp, f2 phiên bản vectorized):

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   | 

A = rand(500,500,3) :

| Row | Function | Average | Relative | Replications | 
|-----|----------|------------|----------|--------------| 
| 1 | "f1"  | 0.00783007 | 1.0  | 100   | 
| 2 | "f2"  | 0.0153099 | 1.95527 | 100   | 

A = rand(5000,5000,3):

| Row | Function | Average | Relative | Replications | 
|-----|----------|----------|----------|--------------| 
| 1 | "f1"  | 1.60534 | 2.56553 | 10   | 
| 2 | "f2"  | 0.625734 | 1.0  | 10   | 

Tôi mong đợi một hàm sẽ nhanh hơn hàm kia (có thể là f1 vì macro cận cảnh).

Nhưng tôi không thể giải thích, tại sao phiên bản vectơ trở nên nhanh hơn cho hình ảnh lớn hơn. Tại sao vậy?

+2

Tôi nghĩ rằng tuyên bố 'xám = tương tự (A, kích thước (A) [1: 2] ...) 'trong phiên bản vectorized là không cần thiết, ngôn ngữ sẽ tạo thích hợp kích thước mảng trực tiếp từ câu lệnh thứ hai. Điều này không giải thích tại sao phiên bản vectơ lại nhanh hơn. – cfh

+1

Off-topic, nhưng bạn có thể nói 'convert (Array {Gray {Float64}}, A)' nếu bạn đang 'sử dụng Images'. – tholy

Trả lời

9

Câu trả lời cho kết quả là các mảng đa chiều trong Julia được lưu trữ theo thứ tự cột lớn.Xem Julias Memory Order.

cố định phiên bản lặp, liên quan đến cột lớn theo đơn đặt hàng (biến vòng lặp bên trong và bên ngoài hoán đổi):

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 

Kết quả mới cho A = rand(5000,5000,3):

| Row | Function | Average | Relative | Replications | 
|-----|----------|----------|----------|--------------| 
| 1 | "f1"  | 0.107275 | 1.0  | 10   | 
| 2 | "f2"  | 0.646872 | 6.03004 | 10   | 

Và kết quả cho mảng nhỏ:

A = rand(500,500,3):

| Row | Function | Average | Relative | Replications | 
|-----|----------|------------|----------|--------------| 
| 1 | "f1"  | 0.00236405 | 1.0  | 100   | 
| 2 | "f2"  | 0.0207249 | 8.76671 | 100   | 

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   | 
+0

Rất đẹp. Bạn cũng có thể thử macro '@ simd' trên các vòng lặp của mình và xem liệu nó có tăng tốc thêm nữa không? – cfh

+0

@cfh '@ simd' không mang lại sự thay đổi đáng kể về hiệu suất. – reschu

1

Chỉ cần suy đoán bởi vì tôi không biết Julia-Lang:

Tôi nghĩ rằng tuyên bố gray = ... theo hình thức vectorized tạo ra một mảng mới, nơi tất cả các giá trị tính toán được lưu trữ, trong khi mảng cũ được loại bỏ. Trong f1 các giá trị được ghi đè tại chỗ, do đó không cần phân bổ bộ nhớ mới. Phân bổ bộ nhớ khá tốn kém nên phiên bản vòng lặp với ghi đè tại chỗ nhanh hơn cho số thấp.

Nhưng phân bổ bộ nhớ thường là chi phí tĩnh (phân bổ gấp đôi không mất nhiều gấp đôi) và phiên bản vectơ được tính toán nhanh hơn (có thể song song?) Nên nếu các con số đủ lớn thì phép tính nhanh hơn khác với phân bổ bộ nhớ.

+2

Trong Julia, hoạt động được vector hóa thường chậm hơn so với các phần tử nguyên tử vì các toán tử thứ hai tạo ra ít thời gian hơn. Phiên bản vectơ ở đây sẽ tạo ra ba mảng tạm thời và sau đó tổng hợp chúng lại với nhau, trong khi phiên bản phần tử không cần thêm bất kỳ thời gian nào và chỉ sử dụng một vòng lặp đơn. – cfh

+0

@cfh Đây là những gì tôi nghĩ - tác động bộ nhớ là nhiều hơn cho vectorized. Nhưng mặt khác, một phiên bản vectơ có thể được tính song song trên 4 lõi. Và có thể có điểm hòa vốn, trong đó CPU gấp 4 lần mang lại nhiều lợi ích hơn chi phí phân bổ bộ nhớ. Bạn đã thử nghiệm trên một quad-core? – Falco

+0

Tôi không nghĩ rằng các tính toán này được tự động phân phối qua lõi trong Julia tại thời điểm này. – cfh

0

Tôi không thể tạo lại kết quả của bạn.

Xem máy tính xách tay này IJulia: http://nbviewer.ipython.org/urls/gist.githubusercontent.com/anonymous/24c17478ae0f5562c449/raw/8d5d32c13209a6443c6d72b31e2459d70607d21b/rgb2gray.ipynb

Các số liệu mà tôi có được là:

In [5]: 

@time rgb2gray_loop(rand(50,50,3)); 
@time rgb2gray_vec(rand(50,50,3)); 

elapsed time: 7.591e-5 seconds (80344 bytes allocated) 
elapsed time: 0.000108785 seconds (241192 bytes allocated) 

In [6]: 

@time rgb2gray_loop(rand(500,500,3)); 
@time rgb2gray_vec(rand(500,500,3)); 

elapsed time: 0.021647914 seconds (8000344 bytes allocated) 
elapsed time: 0.seconds (24001192 bytes allocated) 

In [7]: 

@time rgb2gray_loop(rand(5000,5000,3)); 
@time rgb2gray_vec(rand(5000,5000,3)); 

elapsed time: 0.902367223 seconds (800000440 bytes allocated) 
elapsed time: 1.237281103 seconds (2400001592 bytes allocated, 7.61% gc time) 

Đúng như dự đoán, phiên bản lặp là nhanh hơn vì những đóng góp lớn. Cũng lưu ý cách phiên bản vectơ phân bổ ba lần bộ nhớ nhiều.

Tôi cũng muốn chỉ ra rằng tuyên bố gray = similar(A,size(A)[1:2]...) là không cần thiết và có thể bỏ qua. Nếu không phân bổ không cần thiết này, các kết quả cho các vấn đề lớn nhất là:

@time rgb2gray_loop(rand(5000,5000,3)); 
@time rgb2gray_vec(rand(5000,5000,3)); 

elapsed time: 0.953746863 seconds (800000488 bytes allocated, 3.06% gc time) 
elapsed time: 1.203013639 seconds (2200001200 bytes allocated, 7.28% gc time) 

Vì vậy, việc sử dụng bộ nhớ đã đi xuống, nhưng tốc độ không cải thiện rõ rệt.

+0

Tôi có thể tạo lại kết quả của mình với @time. Tôi đoán Falco là đúng và kết quả có liên quan đến một số loại song song trên máy của tôi .... – reschu

+1

@reschu: Điều đó không đúng. Đầu tiên, Julia không tự động song song. Cũng lưu ý rằng thời gian cho phiên bản lặp của bạn phát triển tệ hơn tuyến tính với kích thước của vấn đề: từ thứ hai đến vấn đề thứ ba, nó chậm hơn 200x, mặc dù kích thước vấn đề chỉ lớn hơn 100x. Một cái gì đó kỳ lạ phải xảy ra ở đó. – cfh

+1

Có, bạn đã đúng. Và tôi đã tìm ra nó là gì. Điều tôi đọc đầu tiên khi bắt đầu với Julia: Thứ tự cột lớn. Việc hoán đổi các hàng và cột trong vòng lặp lồng nhau dẫn đến kết quả mong đợi. – reschu

Các vấn đề liên quan