torch : 메인 네임스페이스, 텐서 등의 다양한 수학 함수가 포함
torch.autograd : 자동 미분 기능을 제공하는 라이브러리
torch.nn : 신경망 구축을 위한 데이터 구조나 레이어 등의 라이브러리
torch.multiprocessing : 병렬 처리 기능을 제공하는 라이브러리
torch.optim : SGD를 중심으로 파라미터 최적화 알고리즘 제공
torch.utils : 데이터 조작 등 유틸리티 기능 제공
torch.onnx : ONNX, 서로 다른 프레임워크 간의 모델을 공유할 때 사용
텐서(Tensors)
- 데이터 표현을 위한 기본 구조로 텐서를 사용
- 텐서는 데이터를 담기위한 컨테이너로서 일반적으로 수치형 데이터를 저장
- 넘파이(Numpy)의 ndarray와 유사
- GPU를 사용한 연산 가속 기능
import torch
torch.__version__
텐서 초기화와 데이터 타입
초기화되지 않은 텐서
x = torch.empty(4, 2)
print(x)

무작위로 초기화된 텐서
x = torch.rand(4, 2)
print(x)

데이터타입(dtype)이 long이고, 0으로 채워진 텐서
x = torch.zeros(4, 2, dtype=torch.long)
print(x)

사용자가 입력한 값으로 텐서 초기화
x = torch.tensor([3, 2.3])
print(x)

2 x 4 크기, double타입, 1로 채워진 텐서
x = x.new_ones(2, 4, dtype = torch.double)
print(x)

x와 같은 크기, float 타입, 무작위로 채워진 텐서
x = torch.randn_like(x, dtype=torch.float)
print(x)
그 전에 x의 크기와 like (기존의 텐서 모양이랑 같은 것으로 만들어달라)

텐서의 크기 계산
print(x.size())

데이터타입

ft = torch.FloatTensor([1, 2, 3])
print(ft)
print(ft.dtype)

print(ft.short())
print(ft.int())
print(ft.long())

타입캐스팅
it = torch.IntTensor([1, 2,3 ])
print(it)
print(it.dtype)

print(it.float())
print(it.double())
print(it.half())

CUDA TENSOR
.to 메소드를 사용하여 텐서를 어떠한 장치로도 옮길 수 있음
x = torch.randn(1)
print(x)
print(x.item())
print(x.dtype)

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
y = torch.ones_like(x, device=device)
print(y)
x = x.to(device) #to를 통해서 device로 옮기기
print(x)
z = x + y
print(z)
print(z.to('cpu', torch.double))

다차원 텐서 표현
0D Tensor(Scalar)
- 하나의 숫자를 담고 있는 텐서
- 축과형상이 없음
t0 = torch.tensor(0)
print(t0.ndim)
print(t0.shape)
print(t0)

1D Tensor(Vector)
- 값들을 저장한 리스트와 유사한 텐서
- 하나의 축이 존재
t1 = torch.tensor([1,2,3])
print(t1.ndim)
print(t1.shape)
print(t1)

2D Tensor(Matrix)
- 행렬과 같은 모양으로 두개의 축이 존재
- 일반적인 수치, 통계 데이터셋이 해당
- 주로 샘플과 특성을 가진 구조로 사용
t2 = torch.tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(t2.ndim)
print(t2.shape)
print(t2)

3D Tensor
- 큐브(cube)와 같은 모양으로 세개의 축이 존재
- 데이터가 연속된 시퀀스 데이터나 시간 축이 포함된 시계열 데이터에 해당
- 주식 가격 데이터셋, 시간별 질병 발볍 데이터등이 존재
- 샘플, 타임스텝, 특성 등 구조로 사용
t3 = torch.tensor([[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]],
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]],
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]])
print(t3.ndim)
print(t3.shape)
print(t3)

4D Tensor
- 4개의 축
- 컬러 이미지 데이터가 대표적인 사례
- 샘플, 높이, 너비, 컬러 를 가진 구조로 사용
5D Tensor
- 5개의 축
- 비디오 데이터가 대표적인 사례
- 샘플, 프레임, 높이, 너비, 컬러 채널 을 가진 구조로 사용
#텐서의 연산
import math
a = torch.rand(1, 2) * 2 - 1
print(a)
print(torch.abs(a))
print(torch.ceil(a))
print(torch.floor(a))
print(torch.clamp(a, -0.5, 0.5))

absolute하니 음수가 사라짐 올림, 내림, clamp 최대 최소값 찍어내림
print(a)
print(torch.min(a))
print(torch.max(a))
print(torch.mean(a))
print(torch.std(a))
print(torch.prod(a))
print(torch.unique(torch.tensor([1, 2, 3, 1, 2, 2])))

.max와 min은 dim 인자를 줄 경우 argmax와 argmin도 함께 리턴
- argmax : 최대값을 가진 인덱스
- argmin : 최소값을 가진 인덱스
x = torch.rand(2, 2)
print(x)
print(x.max(dim=0))
print(x.max(dim=1))

dim = 0 위아래로 묶어서 (열)
dim = 1 행단위로 묶어서
x = torch.rand(2, 2)
print(x)
y = torch.rand(2, 2)
print(y)

#torch.add 덧셈
print(x + y)
print(torch.add(x, y))

result = torch.empty(2, 4)
torch.add(x, y, out=result)
print(result)

결과 텐서를 인자로 제공, result를 빈 empty로 지정하고 더한 값을 result에 넣어지도록 만들면 됩니다.
#in-place 방식 : in-place 방식으로 텐서의 값을 변경하는 연산 뒤에는 _가 붙음
#x.copy_(y), x.t_()
print(x)
print(y)
y.add_(x) #return한 값이 y의 값이 되도록
print(y)
print(x)
print(y)
print(x * y)
print(torch.muul(x, y))
print(x.mul(y))
이렇게 해도 뺄셈이 가능합니다.
print(x)
print(y)
print(x * y)
print(torch.muul(x, y))
print(x.mul(y))
print(x)
print(y)
print(x / y)
print(torch.div(x, y))
print(x.div(y))
torch.mm : 내적 (dot product)
print(x)
print(y)
print(torch.matmul(x, y))
z= torch.mm(x, y)
print(z)
print(torch.svd(z))

텐서의 조작(Manipulations)
인덱싱(Indexing) : Numpy처럼 인덱싱 형태로 사용 가능
x - torch.Tensor([[1, 2],
[3, 4],])
print(x)
print(x[0,0])
print(x[0,1])
print(x[1,0])
print(x[1,1])
print(x[:0])
print(x[:, 1])
print(x[0, :])
print(x[1, :])
1, 2, 3, 4 출력이 나옵니다.
[1,2]가 0위치 [3,4]가 1위치입니다.. 그래서 연달아 출력이 되는 것을 알 수 있습니다. 슬라이싱 같은 경우는 슬라이싱으로 커버를 하는데 전체 1234중에서 0번째는 1,3이 나옵니다.
행은 슬라이싱으로 다 선택합니다. 행은 다 선택하면서 0번째 컬럼만 출력해줘 라고 하는 것으로 1,3이 나오면 1번째 컬럼을 선택해줘 하니 2,4가 나옵니다.
이제 열을 슬라이싱하고 행을 정합니다. 열을 출력하는 것이니 1, 2가 나오고 이후에는 3, 4가 나옵니다.
view: 텐서의 크기(size)나 모양(shape)을 변경
- 기본적으로 변경 전과 후에 텐서 안의 원소 개수가 유지되어야 함
- -1로 설정되면 계산을 통해 해당 크기값을 유추
x = torch.randn(4, 5)
print(x)
y = x.view(20)
print(y)

x = torch.randn(4, 5)
print(x)
y = x.view(20)
print(y)
z = x.view(5, -1) #-1을 하면 나머지는 알아서 해달라는 것
print(z) #행은 5개인데 나머지는 -1 전체 숫자에 알아서 해서 5x4 가 나옴

item : 텐서에 값이 단 하나라도 존재하면 숫자값을 얻을 수 있음
x = torch.randn(1)
print(x)
print(x.item())
print(x.dtype)

스칼라값 하나만 존재해야지만 item()사용 가능

2개하면 RuntimeError 발생
squeeze : 차원을 축소 (제거)
tensor = torch.rand(1, 3, 3)
print(tensor)
print(tensor.shape)

t = tensor.squeeze()
print(t)
print(tensor.shape)
unsqueeze 차원을 증가(생성)
t = torch.rand(3, 3)
print(t)
print(t.shape)
tensor = t.unsqueeze(dim =0)
print(tensor)
print(tensor.shape)

첫번째 차원에 대해서 늘려달라고 할 때 이렇게 1, 3, 3이 됩니다.

stack : 텐서간 결합
x =torch.FloatTensor([1, 4])
print(x)
y = torch.FloatTensor([2, 5])
print(y)
z= torch.FloatTensor([3, 6])
print(z)
print(torch.stack([x, y, z]))

텐서간의 결합이 합쳐진 것을 볼 수 있습니다.
cat: 텐서를 결합하는 메소드(concatenate)
- 넘파이의 stack과 유사하지만, 쌓을 dim이 존재해야함
- 해당 차원을 늘려준 후 결합
a = torch.randn(1, 3, 3)
print(a)
b = torch.randn(1, 3, 3)
print(b)
c = torch.cat((a, b), dim=0)
print(c)
print(c.size())

a와 b를 concatenate할 때, 첫번째 차원 dijm=0이 기준이기에 1, 3, 3를 2개 합치니 2, 3, 3 차원이 되는 것을 볼 수 있습니다. 앞의 차원을 기준으로 합쳐주는 것입니다.

dim =1로 바꾸면 1, 6, 3이 나오는 것을 볼 수 잇습니다.
chunk : 텐서를 여러 개로 나눌 때 사용 (몇 개로 나눌 것인가?)
tensor = torch.rand(3, 6)
print(tensor)
t1, t2, t3 = torch.chunk(tensor, 3, dim=1)
print(t1)
print(t2)
print(t3)

기준이 1번째 차원이기에 다음과 같이 나누는 것을 볼 수 있습니다.
split : chunk와 동일한 기능이지만 조금 다름(텐서의 크기는 몇인가?
tensor = torch.rand(3, 6)
t1, t2 = torch.split(tensor, 3, dim=1)
print(tensor)
print(t1)
print(t2)

toirch <> numpy
- Torch Tensor를 Numpy Array로 변환 가능
- numpy()
- from_numpy()
- Tensor가 CPU상에 있다면 NumPy 배열은 메모리 공간을 공유하므로 하나가 변하면, 다른 하나도 변함
a = torch.ones(7)
print(a)

b = a.numpy()
print(b)

a.add_(1)
print(a)
print(b)

텐서가 cpu상에 있으면 넘파이가 메모리를 공유하는 것인데 넘파이는 효율적인 메모리를 유지하기 위해 공간을 shared하면서 변하면 다 바뀌는 형태여서 출력하는 것이 둘 다 a에 반영을 시켰더니 b도 메모리에 공유되어서 바뀌는 것을 볼 수 있습니다.
import numpy as np
a = np.ones(7)
b = torch.from_numpy(a)
np.add(a, 1, out=a)

Autograd(자동미분)
- torch.autograd 패키지는 Tensor의 모든 연산에 대해 자동 미분 제공
- 이는 코드를 어떻게 작성하여 실행하느냐에 따라 역전파가 정의된다는 뜻
- backprop를 위해 미분값을 자동으로 계산
required_grad 속성을 True로 설정하면, 해당 텐서에서 이루어지는 모든 연산들을 추적하기 시작
기록을 추적하는 것을 중단하게 하려면, detach()를 호출하여 연산기록으로부터 분리
a =torch.randn(3, 3)
a = a * 3
print(a)
print(a.requires_grad)

a.requires_grad_(True) #_를 붙이면 inplace 즉 바꾼 값을 바로 적용
print(a.requires_grad)
b = (a * a).sum()
print(b)
print(b.grad_fn)

기울기
x = torch.ones(3, 3, requires_grad=True)
print(x)

y = x + 5
print(y)

z = y * y
out = z.mean()
print(z, out)

print(out)
out.backward()
역전파 계산을 하는 것이 가능합니다. 계산이 완료된 후 backward()를 호출하면 자동으로 역전파 계산이 가능하고,.grad 속성이 누적됨
grad: data가 거쳐온 layer에 대한 미분값 저장
print(x)
print(x.grad)

x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v) #v기준으로 backward가 되는 것을 알 수 있습니다.
print(x.grad)

with torch.no_grad()를 사용하면 기울기의 업데이트를 하지 않습니다.
기록을 추적하는 것을 방지하기 위해 코드 블럭을 with torch.no_grad()로 감싸면 기울기 계산은 필요없지만, requires_grad=True로 설정되어 학습 가능한 매개변수를 갖는 모델을 평가할 때 유용
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)

detach() : 내용물은 같지만 requires_grad가 다른 새로운 Tensor를 가져올 때
print(x.requires_grad)
y = x,detach()
print(y.requires_grad)
print(x.eq(y).all())
detach를 하면 더이상 gradient 계산을 안합니다.
자동 미분 흐름 예제
- 계산 흐름 a -> b -> c -. out
- backwarD()를 통해 a<- b<- c<- out를 계산하여 a.grad에 채워지도록
a = torch.ones(2, 2)
print(a)
a = torch.ones(2, 2, requires_grad=True)
print(a)
print(a.data)
print(a.grad)
print(a.grad_fn)

b = a + 2
print(b)
c = b ** 2
print(c)
out = c.sum()
print(out)
out.backward()

print(a.data)
print(a.grad)
print(a.grad_fn)

backward를 통해서 자동미분이 수행되는 것을 볼 수 있습니다.
'IT 프로그래밍 > AI' 카테고리의 다른 글
| Numpy (3) | 2025.07.08 |
|---|---|
| pytorch / dataset (1) | 2025.07.07 |
| Broad casting (0) | 2025.06.20 |
| [Transformer]1 (1) | 2025.05.19 |
| 워드임베딩 , 트랜스포머 (0) | 2025.05.19 |