콘텐츠로 이동

섹션 요약: 텐서 연산

연산연산자함수 APIin-place
덧셈a + btorch.add(a, b)a.add_(b)
뺄셈a - btorch.sub(a, b)a.sub_(b)
곱셈 (원소별)a * btorch.mul(a, b)a.mul_(b)
나눗셈a / btorch.div(a, b)a.div_(b)
거듭제곱a ** btorch.pow(a, b)a.pow_(b)
나머지a % btorch.remainder(a, b)
행렬 곱a @ btorch.matmul(a, b)
연산연산자함수 API반환
같음a == btorch.eq(a, b)bool 텐서
다름a != btorch.ne(a, b)bool 텐서
a > btorch.gt(a, b)bool 텐서
작음a < btorch.lt(a, b)bool 텐서
전체 동일torch.equal(a, b)Python bool
근사 비교torch.allclose(a, b)Python bool
함수설명dim 지원
t.sum()합계
t.mean()평균
t.std()표준편차
t.max()최댓값예 (값+인덱스)
t.min()최솟값예 (값+인덱스)
t.argmax()최댓값 인덱스
t.argmin()최솟값 인덱스
t.any()하나라도 True
t.all()모두 True
카테고리함수
지수/로그exp, log, log2, log10, log1p
삼각함수sin, cos, tan, asin, acos, atan
반올림ceil, floor, round, trunc
범위 제한clamp(min, max)
절댓값/제곱근abs, sqrt, rsqrt, square, pow
함수설명
torch.dot(a, b)벡터 내적
torch.matmul(A, B)행렬 곱 (ND)
torch.bmm(A, B)배치 행렬 곱 (3D)
A.T전치
torch.linalg.inv(A)역행렬
torch.linalg.det(A)행렬식
torch.linalg.svd(A)SVD
torch.linalg.eig(A)고유값 분해

in-place 연산은 새 텐서를 할당하지 않으므로 메모리 사용량이 줄어들지만 , 항상 빠른 것은 아닙니다.

import torch
import time
t = torch.randn(10_000_000)
# out-of-place
start = time.time()
for _ in range(100):
result = t + 1.0
print(f"out-of-place: {time.time() - start:.3f}초")
# in-place
start = time.time()
for _ in range(100):
t.add_(1.0)
print(f"in-place: {time.time() - start:.3f}초")
상황권장 방식
autograd 사용 중out-of-place 필수
메모리가 병목인 추론 코드in-place 고려
일반적인 학습 코드out-of-place (안전)
버퍼 초기화 (zero_())in-place 적합

Python for 루프는 PyTorch 텐서 연산에 비해 수십~수백 배 느립니다.

import torch
import time
n = 1_000_000
a = torch.randn(n)
b = torch.randn(n)
# 방법 1: Python for 루프
start = time.time()
result = torch.zeros(n)
for i in range(n):
result[i] = a[i] * b[i] + 1.0
loop_time = time.time() - start
# 방법 2: 벡터화된 텐서 연산
start = time.time()
result = a * b + 1.0
vec_time = time.time() - start
print(f"for 루프: {loop_time:.3f}초")
print(f"벡터화: {vec_time:.4f}초")
print(f"속도 향상: {loop_time / vec_time:.0f}배")
# 일반적으로 100~500배 빠름

벡터화 변환 패턴:

# 나쁜 예: for 루프로 조건부 처리
result = torch.zeros_like(scores)
for i in range(len(scores)):
if scores[i] > 0.5:
result[i] = scores[i] * 2
else:
result[i] = 0.0
# 좋은 예: 마스킹과 텐서 연산
mask = scores > 0.5
result = torch.where(mask, scores * 2, torch.zeros_like(scores))

1. 원소별 곱을 행렬 곱으로 혼동

섹션 제목: “1. 원소별 곱을 행렬 곱으로 혼동”
A = torch.randn(3, 3)
B = torch.randn(3, 3)
wrong = A * B # 원소별 곱 — 행렬 곱이 아님
correct = A @ B # 행렬 곱
a = torch.tensor([1.0, 2.0])
b = torch.tensor([1.0, 2.0])
# equal: Python bool 반환
if torch.equal(a, b): # 올바른 조건문
print("같음")
# eq: bool 텐서 반환 — 조건문에 바로 쓰면 오류
# if torch.eq(a, b): # RuntimeError!
if torch.eq(a, b).all(): # 올바른 사용
print("모두 같음")
# 나쁜 예
result = torch.tensor([0.1]) + torch.tensor([0.2])
print(result == 0.3) # tensor([False]) — 오차 때문
# 좋은 예
print(torch.allclose(result, torch.tensor([0.3]))) # True
m = torch.tensor([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]]) # shape: (2, 3)
# dim=0: 행이 줄어듦 → 각 열의 합
print(m.sum(dim=0)) # tensor([5., 7., 9.]) shape: (3,)
# dim=1: 열이 줄어듦 → 각 행의 합
print(m.sum(dim=1)) # tensor([ 6., 15.]) shape: (2,)
m = torch.randn(4, 3)
# 나쁜 예: keepdim 없이 나누기
row_mean = m.mean(dim=1) # shape: (4,)
# normalized = m - row_mean # shape 불일치!
# 좋은 예: keepdim=True 사용
row_mean = m.mean(dim=1, keepdim=True) # shape: (4, 1)
normalized = m - row_mean # 올바른 브로드캐스팅

퀴즈를 불러오는 중...