Cho phép bắt đầu với ba mảng dtype=np.double
. Thời gian được thực hiện trên một CPU intel bằng cách sử dụng 1.7.1 xếp gọn được biên dịch với icc
và được liên kết với số mkl
của intel. Một cpu AMD với khối lượng 1.6.1 được biên dịch với gcc
mà không cần mkl
cũng được sử dụng để xác minh thời gian. Xin lưu ý timings quy mô gần tuyến tính với kích thước hệ thống và không phải do các chi phí nhỏ phát sinh trong các chức năng NumPy if
báo cáo những sự khác biệt sẽ hiển thị trong micro không mili giây:Tại sao einsum của numpy lại nhanh hơn các chức năng tích hợp của numpy?
arr_1D=np.arange(500,dtype=np.double)
large_arr_1D=np.arange(100000,dtype=np.double)
arr_2D=np.arange(500**2,dtype=np.double).reshape(500,500)
arr_3D=np.arange(500**3,dtype=np.double).reshape(500,500,500)
Đầu tiên cho phép nhìn vào np.sum
chức năng:
np.all(np.sum(arr_3D)==np.einsum('ijk->',arr_3D))
True
%timeit np.sum(arr_3D)
10 loops, best of 3: 142 ms per loop
%timeit np.einsum('ijk->', arr_3D)
10 loops, best of 3: 70.2 ms per loop
Powers:
np.allclose(arr_3D*arr_3D*arr_3D,np.einsum('ijk,ijk,ijk->ijk',arr_3D,arr_3D,arr_3D))
True
%timeit arr_3D*arr_3D*arr_3D
1 loops, best of 3: 1.32 s per loop
%timeit np.einsum('ijk,ijk,ijk->ijk', arr_3D, arr_3D, arr_3D)
1 loops, best of 3: 694 ms per loop
sản phẩm Outer:
np.all(np.outer(arr_1D,arr_1D)==np.einsum('i,k->ik',arr_1D,arr_1D))
True
%timeit np.outer(arr_1D, arr_1D)
1000 loops, best of 3: 411 us per loop
%timeit np.einsum('i,k->ik', arr_1D, arr_1D)
1000 loops, best of 3: 245 us per loop
Tất cả những điều trên nhanh gấp hai lần với np.einsum
. Đây nên là táo để so sánh táo như tất cả mọi thứ là cụ thể của dtype=np.double
. Tôi mong chờ tốc độ lên trong một hoạt động như thế này:
np.allclose(np.sum(arr_2D*arr_3D),np.einsum('ij,oij->',arr_2D,arr_3D))
True
%timeit np.sum(arr_2D*arr_3D)
1 loops, best of 3: 813 ms per loop
%timeit np.einsum('ij,oij->', arr_2D, arr_3D)
10 loops, best of 3: 85.1 ms per loop
Einsum có vẻ là ít nhất hai lần càng nhanh cho np.inner
, np.outer
, np.kron
, và np.sum
bất kể axes
lựa chọn. Ngoại lệ chính là np.dot
vì nó gọi DGEMM từ thư viện BLAS. Vì vậy, tại sao là np.einsum
nhanh hơn các hàm numpy khác tương đương?
Trường hợp DGEMM cho đầy đủ:
np.allclose(np.dot(arr_2D,arr_2D),np.einsum('ij,jk',arr_2D,arr_2D))
True
%timeit np.einsum('ij,jk',arr_2D,arr_2D)
10 loops, best of 3: 56.1 ms per loop
%timeit np.dot(arr_2D,arr_2D)
100 loops, best of 3: 5.17 ms per loop
Lý thuyết hàng đầu là từ @sebergs nhận xét rằng np.einsum
có thể tận dụng SSE2, nhưng ufuncs NumPy sẽ phải đến NumPy 1.8 (xem change log). Tôi tin rằng đây là câu trả lời đúng, nhưng có không phải có thể xác nhận nó. Một số bằng chứng hạn chế có thể được tìm thấy bằng cách thay đổi dtype của mảng đầu vào và quan sát sự khác biệt tốc độ và thực tế là không phải ai cũng quan sát cùng một xu hướng về thời gian.
Thư viện BLAS nào được liên kết với nhau? Nó có đa luồng không? –
Đa luồng MKL BLAS với AVX. – Daniel
Ngẫu nhiên, câu hỏi hay và ví dụ hay! Nó có thể là giá trị yêu cầu này trên danh sách gửi thư. Nó được đề cập trước đây (đặc biệt là liên quan đến 'sum'), nhưng tôi ngạc nhiên rằng' einsum' liên tục ~ 2x nhanh hơn 'bên ngoài',' bên trong', 'kron', v.v. Thật thú vị khi biết vị trí sự khác biệt đến từ. –