선형대수 연산
행렬 곱
섹션 제목: “행렬 곱”행렬 곱은 딥러닝에서 가장 빈번하게 사용되는 연산입니다. Linear 레이어, Attention 메커니즘 등 대부분이 행렬 곱으로 구성됩니다.
import torch
A = torch.tensor([[1.0, 2.0], [3.0, 4.0]]) # shape: (2, 2)
B = torch.tensor([[5.0, 6.0], [7.0, 8.0]]) # shape: (2, 2)
# 세 가지 방식 — 모두 동일한 결과print(A @ B) # @ 연산자 (권장)print(torch.matmul(A, B)) # 함수형 APIprint(torch.mm(A, B)) # 2D 전용
# tensor([[19., 22.],# [43., 50.]])행렬 곱 (A @ B) — 결과 셀에 마우스를 올려보세요
A
1
2
3
4
@
B
5
6
7
8
=
결과
19
22
43
50
@ vs mm vs matmul 차이
섹션 제목: “@ vs mm vs matmul 차이”| 함수 | 지원 차원 | 배치 연산 |
|---|---|---|
torch.mm(A, B) | 2D 전용 | 불가 |
torch.matmul(A, B) 또는 A @ B | 1D ~ ND | 가능 |
torch.bmm(A, B) | 3D 전용 (배치) | 전용 |
# matmul: 배치 행렬 곱 지원batch_A = torch.randn(32, 3, 4) # 32개 배치, (3×4) 행렬batch_B = torch.randn(32, 4, 5) # 32개 배치, (4×5) 행렬
result = torch.matmul(batch_A, batch_B)print(result.shape) # torch.Size([32, 3, 5])
# bmm: 배치 행렬 곱 전용 (3D만 허용)result = torch.bmm(batch_A, batch_B)print(result.shape) # torch.Size([32, 3, 5])벡터 내적: torch.dot()
섹션 제목: “벡터 내적: torch.dot()”torch.dot() 은 1D 텐서(벡터) 의 내적(dot product)을 계산합니다.
a = torch.tensor([1.0, 2.0, 3.0])b = torch.tensor([4.0, 5.0, 6.0])
# 내적: 1*4 + 2*5 + 3*6 = 32print(torch.dot(a, b)) # tensor(32.)
# 내적은 두 벡터의 유사도 측정에 활용# cos(θ) = dot(a, b) / (||a|| * ||b||)norm_a = torch.norm(a)norm_b = torch.norm(b)cosine = torch.dot(a, b) / (norm_a * norm_b)print(cosine) # tensor(0.9746) — 매우 유사한 방향전치: .T 와 torch.transpose()
섹션 제목: “전치: .T 와 torch.transpose()”A = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) # shape: (2, 3)
# .T: 모든 차원을 역순으로 뒤집음 (2D에서 전치와 동일)print(A.T)# tensor([[1., 4.],# [2., 5.],# [3., 6.]])print(A.T.shape) # torch.Size([3, 2])
# torch.transpose(t, dim0, dim1): 두 차원을 교환print(torch.transpose(A, 0, 1)) # A.T와 동일 (2D)
# 3D 텐서에서 transposet3 = torch.randn(2, 3, 4)print(torch.transpose(t3, 1, 2).shape) # torch.Size([2, 4, 3])역행렬과 행렬식: torch.linalg
섹션 제목: “역행렬과 행렬식: torch.linalg”A = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
# 역행렬A_inv = torch.linalg.inv(A)print(A_inv)# tensor([[-2.0000, 1.0000],# [ 1.5000, -0.5000]])
# 검증: A @ A_inv ≈ 단위행렬print(A @ A_inv)# tensor([[1.0000e+00, 0.0000e+00],# [8.8818e-16, 1.0000e+00]]) — 부동소수점 오차 존재
# 행렬식 (determinant)print(torch.linalg.det(A)) # tensor(-2.) — 1*4 - 2*3 = -2
# 행렬식이 0이면 역행렬이 존재하지 않음 (singular matrix)singular = torch.tensor([[1.0, 2.0], [2.0, 4.0]])print(torch.linalg.det(singular)) # tensor(0.)선형 시스템 풀기: torch.linalg.solve()
섹션 제목: “선형 시스템 풀기: torch.linalg.solve()”역행렬을 직접 구하는 것보다 solve() 가 더 수치적으로 안정합니다.
# Ax = b 풀기A = torch.tensor([[2.0, 1.0], [5.0, 3.0]])b = torch.tensor([4.0, 7.0])
x = torch.linalg.solve(A, b)print(x) # tensor([5., -6.])print(A @ x) # tensor([4., 7.]) — b와 일치고유값 분해 (Eigendecomposition)
섹션 제목: “고유값 분해 (Eigendecomposition)”정방 행렬 A를 A = Q Λ Q⁻¹ 로 분해합니다.
A = torch.tensor([[4.0, 1.0], [2.0, 3.0]])
# 고유값과 고유벡터eigenvalues, eigenvectors = torch.linalg.eig(A)print(eigenvalues) # tensor([5.+0.j, 2.+0.j]) — 복소수 형태print(eigenvectors) # 각 열이 고유벡터
# 실수 대칭 행렬은 eigh() 사용 (더 효율적)sym = torch.tensor([[3.0, 1.0], [1.0, 3.0]])eigenvalues, eigenvectors = torch.linalg.eigh(sym)print(eigenvalues) # tensor([2., 4.]) — 실수 보장SVD (특이값 분해)
섹션 제목: “SVD (특이값 분해)”SVD는 임의의 행렬 A를 A = U Σ Vᵀ 로 분해합니다. 차원 축소, 추천 시스템, 노이즈 제거 등에 활용합니다.
A = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) # shape: (2, 3)
U, S, Vh = torch.linalg.svd(A, full_matrices=False)print(U.shape) # torch.Size([2, 2])print(S.shape) # torch.Size([2]) — 특이값 (내림차순)print(Vh.shape) # torch.Size([2, 3])
print(S) # tensor([9.5080, 0.7729])
# 재구성 검증: U @ diag(S) @ Vh ≈ Areconstructed = U @ torch.diag(S) @ Vhprint(torch.allclose(A, reconstructed, atol=1e-5)) # True
# 저랭크 근사 (rank-1 근사)rank1 = S[0] * U[:, 0:1] @ Vh[0:1, :]print(rank1)# tensor([[1.0697, 1.8485, 2.6273],# [3.9303, 6.7951, 9.6600]]) — 원본의 근사torch.linalg 주요 함수 요약
섹션 제목: “torch.linalg 주요 함수 요약”| 함수 | 설명 |
|---|---|
torch.linalg.inv(A) | 역행렬 |
torch.linalg.det(A) | 행렬식 |
torch.linalg.solve(A, b) | 선형 시스템 Ax=b 풀기 |
torch.linalg.eig(A) | 고유값/고유벡터 (복소수) |
torch.linalg.eigh(A) | 고유값/고유벡터 (실수 대칭) |
torch.linalg.svd(A) | 특이값 분해 |
torch.linalg.norm(A) | 행렬/벡터 노름 |
torch.linalg.matrix_rank(A) | 행렬 랭크 |
torch.linalg.pinv(A) | 의사역행렬 (pseudo-inverse) |