Misalkan kita mengambil np.dotdua 'float32'array 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]
Angka Kecuali, mereka dapat berubah:
KASUS 1 : irisana
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]
Hasil berbeda, meskipun potongan yang dicetak berasal dari angka yang sama persis dikalikan.
KASUS 2 : ratakan
a, ambil versi 1D b, lalu iris 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]
KASUS 3 : kontrol yang lebih kuat; setel semua entires yang tidak terlibat menjadi nol : tambahkan a[1:] = 0ke kode CASE 1. Hasil: perbedaan tetap ada.
KASUS 4 : periksa indeks selain [0]; seperti untuk [0], hasil mulai menstabilkan # pembesaran array tetap dari titik kreasi mereka. Keluaran
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()
Oleh karena itu, untuk kasus 2D * 2D, hasilnya berbeda - tetapi konsisten untuk 1D * 1D. Dari beberapa bacaan saya, ini tampaknya berasal dari 1D-1D menggunakan penambahan sederhana, sedangkan 2D-2D menggunakan 'pelamun', penambahan peningkatan kinerja yang mungkin kurang tepat (misalnya penambahan berpasangan melakukan sebaliknya). Meskipun demikian, saya tidak dapat memahami mengapa perbedaan menghilang jika saya pernah adipotong melewati 'ambang'; semakin besar adan b, kemudian ambang ini tampaknya terletak, tetapi selalu ada.
Semua berkata: mengapa tidak np.dottepat (dan tidak konsisten) untuk array ND-ND? Git yang relevan
Info tambahan :
- Lingkungan : Win-10 OS, Python 3.7.4, Spyder 3.3.6 IDE, Anaconda 3.0 2019/10
- CPU : i7-7700HQ 2,8 GHz
- Numpy v1.16.5
Kemungkinan perpustakaan pelakunya : Numpy MKL - juga perpustakaan BLASS; terima kasih kepada Bi Rico untuk mencatat
Kode uji stres : seperti yang disebutkan, perbedaan memperburuk frekuensi dengan array yang lebih besar; jika di atas tidak dapat direproduksi, di bawah ini seharusnya (jika tidak, coba redup yang lebih besar). Output saya
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]))
Tingkat keparahan masalah : perbedaan yang ditunjukkan 'kecil', tetapi tidak lagi ketika beroperasi pada jaringan saraf dengan miliaran angka dikalikan beberapa detik, dan triliunan selama runtime keseluruhan; keakuratan model yang dilaporkan berbeda dengan keseluruhan 10 persen, per utas ini .
Di bawah ini adalah gif dari array yang dihasilkan dari pengumpanan ke model yang pada dasarnya a[0], dengan len(a)==1vs len(a)==32.:

Hasil PLATFORMS LAINNYA , sesuai dan dengan terima kasih atas pengujian Paul :
Kasus 1 direproduksi (sebagian) :
- Google Colab VM - Intel Xeon 2.3 G-Hz - Jupyter - Python 3.6.8
- Win-10 Pro Docker Desktop - 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
Catatan : ini menghasilkan kesalahan yang jauh lebih rendah daripada yang ditunjukkan di atas; dua entri pada baris pertama dimatikan oleh 1 di digit paling tidak signifikan dari entri yang sesuai di baris lain.
Kasus 1 tidak direproduksi :
- Ubuntu 18.04.3 LTS - Intel i7-8700K - IPython 5.5.0 - Python 2.7.15+ dan 3.6.8 (2 tes)
- 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
Catatan :
- The terkait CoLab notebook dan jupyter lingkungan menunjukkan perbedaan yang jauh lebih rendah (dan hanya untuk dua baris pertama) dari yang diamati pada sistem saya. Juga, Kasus 2 tidak pernah (belum) menunjukkan ketidaktepatan.
- Dalam sampel yang sangat terbatas ini, lingkungan Jupyter (Dockerized) saat ini lebih rentan daripada lingkungan IPython.
np.show_config()terlalu panjang untuk diposkan, tetapi dalam ringkasan: IPython envs berbasis BLAS / LAPACK; Colab berbasis OpenBLAS. Dalam IPython Linux envs, perpustakaan BLAS diinstal-sistem - di Jupyter dan Colab, mereka berasal dari / opt / conda / lib
UPDATE : jawaban yang diterima akurat, tetapi luas dan tidak lengkap. Pertanyaannya tetap terbuka bagi siapa saja yang dapat menjelaskan perilaku di tingkat kode - yaitu, algoritma yang tepat digunakan oleh np.dot, dan bagaimana hal itu menjelaskan 'ketidakkonsistenan yang konsisten' yang diamati pada hasil di atas (juga lihat komentar). Berikut adalah beberapa implementasi langsung di luar pengartian saya: sdot.c - arraytypes.c.src
ndarraysbiasanya mengabaikan kehilangan presisi numerik. Karena untuk kesederhanaannya reduce-sumdi setiap sumbu, urutan operasi mungkin bukan yang optimal ... Perhatikan bahwa jika Anda keberatan dengan kesalahan presisi Anda sebaiknya menggunakanfloat64