Giả sử chúng ta lấy np.dot
hai 'float32'
mảng 2D:
res = np.dot(a, b) # see CASE 1
print(list(res[0])) # list shows more digits
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
Số. Ngoại trừ, họ có thể thay đổi:
TRƯỜNG HỢP 1 : láta
np.random.seed(1)
a = np.random.randn(9, 6).astype('float32')
b = np.random.randn(6, 6).astype('float32')
for i in range(1, len(a)):
print(list(np.dot(a[:i], b)[0])) # full shape: (i, 6)
[-0.9044868, -1.1708502, 0.90713596, 3.5594249, 1.1374012, -1.3826287]
[-0.90448684, -1.1708503, 0.9071359, 3.5594249, 1.1374011, -1.3826288]
[-0.90448684, -1.1708503, 0.9071359, 3.5594249, 1.1374011, -1.3826288]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
Kết quả khác nhau, mặc dù lát cắt được lấy từ cùng một số chính xác được nhân lên.
TRƯỜNG HỢP 2 : làm phẳng
a
, lấy phiên bản 1D b
, sau đó cắt a
:
np.random.seed(1)
a = np.random.randn(9, 6).astype('float32')
b = np.random.randn(1, 6).astype('float32')
for i in range(1, len(a)):
a_flat = np.expand_dims(a[:i].flatten(), -1) # keep 2D
print(list(np.dot(a_flat, b)[0])) # full shape: (i*6, 6)
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
TRƯỜNG HỢP 3 : kiểm soát mạnh mẽ hơn; đặt tất cả các mục nhập không liên quan về 0 : thêm a[1:] = 0
vào mã CASE 1. Kết quả: sự khác biệt vẫn tồn tại.
TRƯỜNG HỢP 4 : kiểm tra các chỉ số khác ngoài [0]
; như đối với [0]
, các kết quả bắt đầu ổn định một số mở rộng mảng cố định từ điểm sáng tạo của chúng. Đầu ra
np.random.seed(1)
a = np.random.randn(9, 6).astype('float32')
b = np.random.randn(6, 6).astype('float32')
for j in range(len(a) - 2):
for i in range(1, len(a)):
res = np.dot(a[:i], b)
try: print(list(res[j]))
except: pass
print()
Do đó, đối với trường hợp 2D * 2D, kết quả khác nhau - nhưng phù hợp với 1D * 1D. Từ một số bài đọc của tôi, điều này dường như xuất phát từ 1D-1D bằng cách sử dụng phép cộng đơn giản, trong khi 2D-2D sử dụng 'fancier', bổ sung tăng hiệu suất có thể kém chính xác hơn (ví dụ: bổ sung cặp đôi thì ngược lại). Tuy nhiên, tôi không thể hiểu tại sao sự khác biệt lại biến mất trong trường hợp 1 một lần a
được cắt qua một 'ngưỡng'; càng lớn a
và b
, ngưỡng này càng muộn, nhưng nó luôn tồn tại.
Tất cả đã nói: tại sao np.dot
không chính xác (và không nhất quán) cho mảng ND-ND? Git có liên quan
Thông tin bổ sung :
- Môi trường : HĐH Win-10, Python 3.7.4, Spyder 3.3.6 IDE, Anaconda 3.0 2019/10
- CPU : i7-7700HQ 2,8 GHz
- Numpy v1.16.5
Thư viện thủ phạm có thể có : Numpy MKL - cũng là thư viện BLASS; cảm ơn Bi Rico đã chú ý
Mã kiểm tra ứng suất : như đã lưu ý, sự khác biệt làm trầm trọng thêm về tần số w / mảng lớn hơn; nếu ở trên không thể tái tạo, bên dưới nên (nếu không, hãy thử độ mờ lớn hơn). Đầu ra của tôi
np.random.seed(1)
a = (0.01*np.random.randn(9, 9999)).astype('float32') # first multiply then type-cast
b = (0.01*np.random.randn(9999, 6)).astype('float32') # *0.01 to bound mults to < 1
for i in range(1, len(a)):
print(list(np.dot(a[:i], b)[0]))
Mức độ nghiêm trọng của sự cố : sự khác biệt được hiển thị là 'nhỏ', nhưng không còn như vậy khi hoạt động trên mạng thần kinh với hàng tỷ số được nhân lên trong vài giây và hàng nghìn tỷ trên toàn bộ thời gian chạy; độ chính xác của mô hình được báo cáo khác nhau bởi toàn bộ 10 phần trăm, trên mỗi luồng này .
Dưới đây là một gif của mảng kết quả từ ăn đến một mô hình những gì cơ bản a[0]
, w / len(a)==1
vs len(a)==32
:
Kết quả PLATFORMS KHÁC , theo và nhờ vào thử nghiệm của Paul :
Trường hợp 1 được sao chép (một phần) :
- Google Colab VM - Intel Xeon 2.3 G-Hz - Jupyter - Python 3.6.8
- Máy tính để bàn Win-10 Pro Docker - Intel i7-8700K - jupyter / scipy-notebook - Python 3.7.3
- Ubuntu 18.04.2 LTS + Docker - AMD FX-8150 - jupyter / scipy-notebook - Python 3.7.3
Lưu ý : những lỗi này mang lại lỗi thấp hơn nhiều so với hình trên; hai mục trên hàng đầu tiên bị tắt 1 trong chữ số có nghĩa ít nhất từ các mục tương ứng trong các hàng khác.
Trường hợp 1 không được sao chép :
- Ubuntu 18.04.3 LTS - Intel i7-8700K - IPython 5.5.0 - Python 2.7.15+ và 3.6.8 (2 bài kiểm tra)
- Ubuntu 18.04.3 LTS - Intel i5-3320M - IPython 5.5.0 - Python 2.7.15+
- Ubuntu 18.04.2 LTS - AMD FX-8150 - IPython 5.5.0 - Python 2.7.15rc1
Ghi chú :
- Các môi trường máy tính xách tay và jupyter Colab được liên kết cho thấy sự khác biệt ít hơn nhiều (và chỉ cho hai hàng đầu tiên) so với quan sát trên hệ thống của tôi. Ngoài ra, Trường hợp 2 không bao giờ (chưa) cho thấy sự thiếu chính xác.
- Trong mẫu rất hạn chế này, môi trường Jupyter (Dockerized) hiện tại dễ bị ảnh hưởng hơn môi trường IPython.
np.show_config()
quá dài để đăng, nhưng tóm lại: IPython envs dựa trên BLAS / LAPACK; Colab dựa trên OpenBLAS. Trong IPython Linux envs, các thư viện BLAS được cài đặt hệ thống - trong Jupyter và Colab, chúng đến từ / opt / conda / lib
CẬP NHẬT : câu trả lời được chấp nhận là chính xác, nhưng rộng và không đầy đủ. Câu hỏi vẫn mở cho bất kỳ ai có thể giải thích hành vi ở cấp mã - cụ thể là thuật toán chính xác được sử dụng np.dot
và cách giải thích 'sự không nhất quán nhất quán' được quan sát trong các kết quả trên (cũng xem bình luận). Dưới đây là một số triển khai trực tiếp ngoài việc giải mã của tôi: sdot.c - Arraytypes.c.src
ndarrays
bỏ qua mất chính xác số. Bởi vì để đơn giản chúng reduce-sum
dọc theo từng trục, thứ tự của các thao tác có thể không phải là tối ưu ... Lưu ý rằng nếu bạn nhớ lỗi chính xác, bạn cũng có thể sử dụngfloat64