np.dot
두 개의 'float32'
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]
번호. 제외하고는 다음을 변경할 수 있습니다.
사례 1 : 슬라이스a
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]
인쇄 된 슬라이스에 정확히 같은 수를 곱한 결과도 달라집니다.
CASE 2 : 평평
a
의 1D 버전을 가지고 b
, 다음 조각 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]
사례 3 : 더 강력한 통제; 관련되지 않은 전체를 0으로 설정 : a[1:] = 0
CASE 1 코드에 추가하십시오 . 결과 : 불일치가 지속됩니다.
사례 4 : 이외의 색인을 확인 [0]
; 에서와 같이 [0]
결과는 생성 지점에서 고정 된 수의 배열 확대를 안정화하기 시작합니다. 산출
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()
따라서 2D * 2D의 경우 결과가 다르지만 1D * 1D와 일치합니다. 내 독서 중 일부에서 이것은 간단한 덧셈을 사용하여 1D-1D에서 비롯된 것으로 보이지만 2D-2D는 덜 정확한 성능 향상 돋보이는 'fancier'를 사용합니다 (예 : pairwise 덧셈은 반대입니다). 그럼에도 불구하고, 나는 1 번 a
이 정해진 '임계 값'을 지나서 얇아 질 때 불일치가 사라지는 이유를 이해할 수 없습니다 . 큰 a
하고 b
, 나중에이 임계 값은 거짓말로 보이지만 항상 존재한다.
np.dot
ND-ND 어레이에 대해 왜 부정확하고 일관성이 없는가? 관련 힘내
추가 정보 :
- 환경 : Win-10 OS, Python 3.7.4, Spyder 3.3.6 IDE, Anaconda 3.0 2019/10
- CPU : i7-7700HQ 2.8GHz
- Numpy v1.16.5
가능한 원인 라이브러리 : NumPy와 MKL - 또한 브래스 라이브러리; 주목 해 주신 Bi Rico 에게 감사합니다
스트레스 테스트 코드 : 언급 한 바와 같이, 더 큰 어레이의 주파수에서 불일치가 악화된다. 위의 내용을 재현 할 수없는 경우 아래 값을 지정해야합니다 (그렇지 않은 경우 더 큰 값을 입력하십시오). 내 결과
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]))
문제 심각도 : 불일치가 '소규모'이지만 수십억 개의 숫자가 몇 초 동안 곱해지고 전체 런타임에서 수조에 이르는 신경망에서 작동하는 경우 더 이상 그렇지 않습니다. 보고 된 모델 정확도는 이 스레드 당 전체 10 %에 따라 다릅니다 .
아래는 기본적으로 a[0]
w / len(a)==1
vs. 모델에 공급하여 얻은 배열의 gif입니다 len(a)==32
.
Paul 의 테스트 덕분에 다른 플랫폼 결과 :
사례 1 재생산 (일부) :
- 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
- 우분투 18.04.2 LTS + 도커-AMD FX-8150-jupyter / scipy-notebook-Python 3.7.3
참고 : 위의 것보다 훨씬 낮은 오류가 발생합니다. 첫 번째 행의 두 항목은 다른 행의 해당 항목에서 최소 유효 숫자가 1만큼 줄어 듭니다.
사례 1이 재현되지 않음 :
- 우분투 18.04.3 LTS-인텔 i7-8700K-IPython 5.5.0-파이썬 2.7.15+ 및 3.6.8 (2 테스트)
- 우분투 18.04.3 LTS-인텔 i5-3320M-IPython 5.5.0-파이썬 2.7.15+
- 우분투 18.04.2 LTS-AMD FX-8150-IPython 5.5.0-Python 2.7.15rc1
참고 사항 :
- 연결 Colab 노트북 및 jupyter 환경 내 시스템에서 관찰되는 것보다 (단지 처음 두 행에) 훨씬 적은 차이를 보여줍니다. 또한 사례 2는 (아직도) 부정확성을 나타내지 않았습니다.
- 이 매우 제한된 샘플 내에서 현재 (Dockerized) Jupyter 환경은 IPython 환경보다 더 취약합니다.
np.show_config()
게시하기에는 너무 길지만 요약하면 IPython 환경은 BLAS / LAPACK 기반입니다. Colab은 OpenBLAS 기반입니다. IPython Linux 환경에서 BLAS 라이브러리는 시스템에 설치됩니다. Jupyter 및 Colab에서는 / opt / conda / lib에서 제공됩니다.
업데이트 : 허용 된 답변은 정확하지만 광범위하고 불완전합니다. 코드 수준 에서 동작을 설명 할 수있는 사람 , 즉에 의해 사용되는 정확한 알고리즘 np.dot
과 위의 결과에서 관찰 된 '일관된 불일치'를 설명하는 방법에 대한 질문은 여전히 열려 있습니다 (의견 참조). 내 해독을 넘어서는 직접 구현이 있습니다 : sdot.c - arraytypes.c.src
ndarrays
일반적으로 숫자 정밀도 손실을 무시 하는 일반적인 알고리즘입니다 . 단순성 때문에 reduce-sum
각 축을 따라 작업 순서가 최적의 순서가 아닐 수 있습니다 ... 정밀 오차를 염두에두면 다음을 사용할 수도 있습니다.float64