Misalkan kita mengambil np.dot
dua '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:] = 0
ke 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 a
dipotong melewati 'ambang'; semakin besar a
dan b
, kemudian ambang ini tampaknya terletak, tetapi selalu ada.
Semua berkata: mengapa tidak np.dot
tepat (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)==1
vs 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
ndarrays
biasanya mengabaikan kehilangan presisi numerik. Karena untuk kesederhanaannya reduce-sum
di setiap sumbu, urutan operasi mungkin bukan yang optimal ... Perhatikan bahwa jika Anda keberatan dengan kesalahan presisi Anda sebaiknya menggunakanfloat64