1.[Numpy]의 곱연산자
- '*'
- '*' 연산자는 원소별(element-wise) 곱셈
- 스칼라 곱
- 별연산은 같은 shape 여야만 계산
- 다른 경우는 (1, n)꼴 일때 브로드캐스팅 적용
- 브로드캐스팅 지원
- 'dot'
- 'dot'함수는 두 행렬간의 내적(dot product)
- 앞의 행렬의 마지막 축과 뒤의 행렬의 두 번째 축간의 내적 수행
- '@'
- 행렬 곱셈
- 행렬이라는 2차원 공간에서는 내적 'dot'과 같은 역할
- 3차원부터는 텐서곱(외적)이라 다른 결과
- 마지막 축에 대해서만 행렬 곱셈
- pytorch의 'matmul', '@'와 동일한 행렬곱셈
- np의 'matmul'과도 동일
2.[pytorch] 의 곱연산자
- 'mul'
- 원소별(element-wise) 곱셈
- 브로드캐스팅 지원
- 'matmul'
- 행렬곱셈
- '@'와 동일
- 3차원부터는 텐서곱(외적)
- '@'
- 행렬곱셈
- 'matmul'와 동일
- 3차원부터는 텐서곱(외적)
3.numpy vs pytorch 비교
3-1.numpy - * vs pytorch - mul
동일한 연산결과
# NumPy에서의 *
A_numpy = np.array([[1, 2, 3]])
B_numpy = np.array([[2], [2]])
result_numpy = A_numpy * B_numpy
print(A_numpy.shape, B_numpy.shape)
# pytorch에서의 mul
A_torch = torch.tensor([[1, 2, 3]])
B_torch = torch.tensor([[2], [2]])
result_torch = torch.mul(A_torch, B_torch)
print("NumPy * result:\n", result_numpy)
print("PyTorch mul result:\n", result_torch)
(1, 3) (2, 1)
NumPy * result:
[[2 4 6]
[2 4 6]]
PyTorch mul result:
tensor([[2, 4, 6],
[2, 4, 6]])
3-2.numpy - dot, @(=matmul)
동일하지 않는 결과, 2차원 행렬곱에서는 np.dot 과 np.matmul(=@) 연산이 행렬내적으로 동일하나 3차원 이상의 텐서곱 연산에서는
np.matmul(=@) 외적으로 연산함.
# 3차원 배열 생성
A = np.random.rand(2, 3, 4)
B = np.random.rand(2, 4, 5)
# np.dot 수행
result_dot = np.dot(A, B)
# @ 연산자 수행
result_at = A @ B
print("Shape of A:", A.shape)
print("Shape of B:", B.shape)
# 앞의 행렬의 마지막 축과 뒤의 행렬의 두 번째 축간의 내적 수행
# 2차원 행렬인 경우 행렬내적으로 같은 결과가 나오겠지만
# 3차원 텐서부터 'dot' 결과값 다름
print("Shape of Result (dot):", result_dot.shape)
print("Shape of Result (@):", result_at.shape)
Shape of A: (2, 3, 4)
Shape of B: (2, 4, 5)
Shape of Result (dot): (2, 3, 2, 5)
Shape of Result (@): (2, 3, 5)
3-3.pytorch - matmul, @
동일한 결과, 2차원 torch.matmul, @, np.matmul(=@)는 2차원 행렬연산에서는 np.dot과 동일하지만 3차원 이상 텐서곱에서는 외적으로 np.dot과 다름.
# 3차원 텐서 생성
A = torch.rand(2, 3, 4)
B = torch.rand(2, 4, 5)
# torch.matmul 수행
result_matmul = torch.matmul(A, B)
# @ 연산자 수행
result_at = A @ B
print("Shape of A:", A.shape)
print("Shape of B:", B.shape)
print("Shape of Result (matmul):", result_matmul.shape)
print("Shape of Result (@):", result_at.shape)
Shape of A: torch.Size([2, 3, 4])
Shape of B: torch.Size([2, 4, 5])
Shape of Result (matmul): torch.Size([2, 3, 5])
Shape of Result (@): torch.Size([2, 3, 5])
4.결론
결론적으로, 헷갈린다. 헷갈리면 '@'로 numpy든 torch든 통일하는것도 나쁘지 않은 방법.
2차원 배열(=행렬)의 경우는 이러나 저러나 동일하다는 것을 기억하자.
그리고 스칼라 곱 연산자인 np의 '*'와 torch의 'mul'은 브로드 캐스팅이 적용되니 유의하자.
300x250
반응형
'프로그래밍 > Python' 카테고리의 다른 글
텐서 차원 변경하기(pytorch - squeeze, unsqueeze/ numpy - squeeze, expand_dims) (0) | 2023.12.04 |
---|---|
배열구조 바꾸기(numpy - reshape, pytorch - view/reshape) (0) | 2023.12.01 |
tensor(텐서) 개념 및 numpy, pytorch 비교하기 (0) | 2023.12.01 |
[python] 문자열에서 특정 문자열 찾기(find, index, rfind, rindex) (1) | 2023.11.17 |
[python] List 두 인자 위치 변경하기(스와프, swap) (0) | 2023.11.17 |