반응형
- 참고 : 이수안컴퓨터연구소
Pytorch
페이스북이 초기 루아(Lua) 언어로 개발된 토치(Torch)를 파이썬 버전으로 개발하여 2017년도에 공개
초기에 토치(Torch)는 넘파이(NumPy) 라이브러리처럼 과학 연산을 위한 라이브러리로 공개
이후 GPU를 이용한 텐서 조작 및 동적 신경망 구축이 가능하도록 딥러닝 프레임워크로 발전시킴
파이썬답게 만들어졌고, 유연하면서도 가속화된 계산 속도를 제공
Pytorch 모듈 구조
파이토치의 구성요소
torch
: 메인 네임스페이스, 텐서 등의 다양한 수학 함수가 포함torch.autograd
: 자동 미분 기능을 제공하는 라이브러리torch.nn
: 신경망 구축을 위한 데이터 구조나 레이어 등의 라이브러리torch.multiprocessing
: 병럴처리 기능을 제공하는 라이브러리torch.optim
: SGD(Stochastic Gradient Descent)를 중심으로 한 파라미터 최적화 알고리즘 제공torch.utils
: 데이터 조작 등 유틸리티 기능 제공torch.onnx
: ONNX(Open Neural Network Exchange), 서로 다른 프레임워크 간의 모델을 공유할 때 사용
텐서(Tensors)
- 데이터 표현을 위한 기본 구조로 텐서(tensor)를 사용
- 텐서는 데이터를 담기위한 컨테이너(container)로서 일반적으로 수치형 데이터를 저장
- 넘파이(NumPy)의 ndarray와 유사
- GPU를 사용한 연산 가속 가능
import torch
# 버전확인
torch.__version__
>>1.12.1+cu113
텐서 초기화와 데이터 타입
- 초기화 되지 않은 텐서
x = torch.empty(4,2)
print(x) # 초기화 X
>> tensor([[6.6778e+01, 0.0000e+00],
[1.3024e+00, 1.1959e+00],
[ nan, 2.2405e+17],
[1.6457e+19, 1.7743e+28]])
- 무작위로 초기화된 텐서
x = torch.rand(4, 2)
print(x) # random 기준 초기화
>> tensor([[0.6760, 0.4138],
[0.2524, 0.4750],
[0.2445, 0.6606],
[0.9425, 0.7982]])
- 데이터 타입(dtype)이 long이고, 0으로 채워진 텐서
x = torch.zeros(4, 2, dtype=torch.long)
print(x) # long 정수형
>> tensor([[0, 0],
[0, 0],
[0, 0],
[0, 0]])
- 사용자가 입력한 값으로 텐서 초기화
x = torch.tensor([3, 2.3])
print(x)
>> tensor([3.0000, 2.3000])
- 2 x 4 크기, double 타입, 1로 채워진 텐서
x = x.new_ones(2, 4, dtype=torch.double)
print(x)
>> tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.]], dtype=torch.float64)
- x와 같은 크기, float 타입, 무작위로 채워진 텐서
x = torch.randn_like(x, dtype=torch.float) # 기존의 x와 같은 크기 만들어 주는것
print(x)
>> tensor([[-0.0198, -0.6520, 0.7265, 0.1030],
[-1.1093, -0.4835, 0.1521, 0.4217]])
- 텐서의 크기 계산
print(x.size())
>> torch.Size([2, 4])
데이터 타입(Data Type)
ft = torch.FloatTensor([1,2,3])
print(ft)
print(ft.dtype)
>> tensor([1., 2., 3.])
torch.float32
# type cast
print(ft.short())
print(ft.int())
print(ft.long())
>> tensor([1, 2, 3], dtype=torch.int16)
tensor([1, 2, 3], dtype=torch.int32)
tensor([1, 2, 3])
it = torch.IntTensor([1,2,3])
print(it)
print(it.dtype)
>> tensor([1, 2, 3], dtype=torch.int32)
torch.int32
print(ft.float())
print(ft.double())
print(ft.half())
>> tensor([1., 2., 3.])
tensor([1., 2., 3.], dtype=torch.float64)
tensor([1., 2., 3.], dtype=torch.float16)
CUDA Tensors
- .to 메소드를 사용하여 텐서를 어떠한 장치(cpu, gpu)로도 옮길 수 있음
x = torch.randn(1)
print(x)
print(x.item()) # 실제값
print(x.dtype)
>> tensor([0.3407])
0.34074530005455017
torch.float32
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # gpu check
print(device)
y = torch.ones_like(x, device= device)
print(y)
x = x.to(device)
print(x)
z = x + y
print(z)
print(z.to('cpu', torch.double))
>> cuda
tensor([1.], device='cuda:0')
tensor([0.3407], device='cuda:0')
tensor([1.3407], device='cuda:0')
tensor([1.3407], dtype=torch.float64)
다차원 텐서 표현
- 0D Tensor(Scalar)
- 하나의 숫자를 담고 있는 텐서(tensor)
- 축과 형상이 없음
t0 = torch.tensor(0)
print(t0.ndim)
print(t0.shape)
print(t0)
>> 0
torch.Size([])
tensor(0)
- 1D Tensor(Vector)
- 값들을 저장한 리스트와 유사한 텐서
- 하나의 축이 존재
t1 = torch.tensor([1,2,3])
print(t1.ndim)
print(t1.shape)
print(t1)
>> 1
torch.Size([3])
tensor([1, 2, 3])
- 2D Tensor(Matrix)
- 행렬과 같은 모양으로 두개의 축이 존재
- 일반적인 수치, 통계 데이터셋이 해당
- 주로 샘플(samples)과 특성(features)을 가진 구조로 사용
t2 = torch.tensor([[1,2,3], [4,5,6], [7,8,9]])
print(t2.ndim)
print(t2.shape)
print(t2)
>> 2
torch.Size([3, 3])
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
- 3D Tensor
- 큐브(cube)와 같은 모양으로 세개의 축이 존재
- 데이터가 연속된 시퀀스 데이터나 시간 축이 포함된 시계열 데이터에 해당
- 주식 가격 데이터셋, 시간에 따른 질병 발병 데이터 등이 존재
- 주로 샘플(samples), 타임스텝(timesteps), 특성(features)을 가진 구조로 사용
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)
>> 3
torch.Size([3, 3, 3])
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]]])
- 4D Tensor
- 4개의 축
- 컬러 이미지 데이터가 대표적인 사례 (흑백 이미지 데이터는 3D Tensor로 가능)
- 주로 샘플(samples), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용
- 5D Tensor
- 5개의 축
- 비디오 데이터가 대표적인 사례
- 주로 샘플(samples), 프레임(frames), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용
텐서의 연산(Operations)
- 텐서에 대한 수학 연산, 삼각함수, 비트 연산, 비교 연산, 집계 등 제공
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)) # 최소값 -0.5 , 최대값 0.5로 값 범위를 조정
>> tensor([[-0.6188, 0.1688]])
tensor([[0.6188, 0.1688]])
tensor([[-0., 1.]])
tensor([[-1., 0.]])
tensor([[-0.5000, 0.1688]])
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])))
>> tensor([[-0.6188, 0.1688]])
tensor(-0.6188)
tensor(0.1688)
tensor(-0.2250)
tensor(0.5569)
tensor(-0.1044)
tensor([1, 2, 3])
- max와 min은 dim 인자를 줄 경우 argmax와 argmin도 함께 리턴
- argmax : 최대값을 가진 인덱스
- argmin : 최소값을 가진 인덱스
x = torch.rand(2, 2)
print(x)
print(x.max(dim=0))
print(x.max(dim=1))
>> tensor([[0.4750, 0.1135],
[0.5480, 0.9679]])
torch.return_types.max(
values=tensor([0.5480, 0.9679]),
indices=tensor([1, 1]))
torch.return_types.max(
values=tensor([0.4750, 0.9679]),
indices=tensor([0, 1]))
x = torch.rand(2, 2)
print(x)
print(x.min(dim=0))
print(x.min(dim=1))
>> tensor([[0.0934, 0.3758],
[0.1591, 0.9207]])
torch.return_types.min(
values=tensor([0.0934, 0.3758]),
indices=tensor([0, 0]))
torch.return_types.min(
values=tensor([0.0934, 0.1591]),
indices=tensor([0, 0]))
x = torch.rand(2, 2)
print(x)
y = torch.rand(2,2)
print(y)
>> tensor([[0.7581, 0.5161],
[0.0705, 0.6911]])
tensor([[0.4239, 0.8904],
[0.8143, 0.9730]])
- torch.add : 덧셈
print(x + y)
print(torch.add(x,y))
>> tensor([[1.1820, 1.4065],
[0.8848, 1.6641]])
tensor([[1.1820, 1.4065],
[0.8848, 1.6641]])
- 결과 텐서를 인자로 제공
result = torch.empty(2,4)
torch.add(x,y, out=result)
print(result)
>> tensor([[1.1820, 1.4065],
[0.8848, 1.6641]])
- in-place 방식
- in-place 방식으로 텐서의 값을 변경하는 연산 뒤에는 _ 가 붙음
- x.copy_(y), x.t_()
print(x)
print(y)
y.add_(x) # 두 덧셈을 앞에 변수로 할당
print(y)
>> tensor([[0.7581, 0.5161],
[0.0705, 0.6911]])
tensor([[0.4239, 0.8904],
[0.8143, 0.9730]])
tensor([[1.1820, 1.4065],
[0.8848, 1.6641]])
- torch.sub : 뺄셈
print(x)
print(y)
print(x-y)
print(torch.sub(x,y))
print(x.sub(y))
>> tensor([[0.7581, 0.5161],
[0.0705, 0.6911]])
tensor([[1.1820, 1.4065],
[0.8848, 1.6641]])
tensor([[-0.4239, -0.8904],
[-0.8143, -0.9730]])
tensor([[-0.4239, -0.8904],
[-0.8143, -0.9730]])
tensor([[-0.4239, -0.8904],
[-0.8143, -0.9730]])
- torch.mul : 곱셈
print(x)
print(y)
print(x*y)
print(torch.mul(x,y))
print(x.mul(y))
>> tensor([[0.7581, 0.5161],
[0.0705, 0.6911]])
tensor([[1.1820, 1.4065],
[0.8848, 1.6641]])
tensor([[0.8961, 0.7260],
[0.0624, 1.1501]])
tensor([[0.8961, 0.7260],
[0.0624, 1.1501]])
tensor([[0.8961, 0.7260],
[0.0624, 1.1501]])
- torch.div : 나눗셈
print(x)
print(y)
print(x/y)
print(torch.div(x,y))
print(x.div(y))
>> tensor([[0.7581, 0.5161],
[0.0705, 0.6911]])
tensor([[1.1820, 1.4065],
[0.8848, 1.6641]])
tensor([[0.6414, 0.3670],
[0.0797, 0.4153]])
tensor([[0.6414, 0.3670],
[0.0797, 0.4153]])
tensor([[0.6414, 0.3670],
[0.0797, 0.4153]])
- torch.mm : 내적(dot product)
print(torch.matmul(x,y))
z = torch.mm(x,y)
print(z)
print(torch.svd(z))
>> tensor([[1.3528, 1.9252],
[0.6948, 1.2492]])
tensor([[1.3528, 1.9252],
[0.6948, 1.2492]])
torch.return_types.svd(
U=tensor([[-0.8552, -0.5182],
[-0.5182, 0.8552]]),
S=tensor([2.7502, 0.1281]),
V=tensor([[-0.5516, -0.8341],
[-0.8341, 0.5516]]))
텐서의 조작(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,:])
>> tensor([[1., 2.],
[3., 4.]])
tensor(1.)
tensor(2.)
tensor(3.)
tensor(4.)
tensor([1., 3.])
tensor([2., 4.])
tensor([1., 2.])
tensor([3., 4.])
- view : 텐서의 크기(size)나 모양(shape)을 변경
- 기본적으로 변경 전과 후에 텐서 안의 원소 개수가 유지되어야 함
- -1로 설정되면 계산을 통해 해당 크기값을 유추
x = torch.randn(4,5)
print(x)
y = x.view(20)
print(y)
z = x.view(5,-1) # -1로 하면 알아서 계산
print(z)
>> tensor([[-1.1282, 1.1669, 0.2316, -0.1395, 1.5400],
[ 0.4419, 0.1169, -0.1603, -0.9421, 0.6196],
[-1.8255, -0.3314, 0.8283, -0.3065, -2.6763],
[-1.4101, 0.9791, 1.4486, 1.6158, 0.0582]])
tensor([-1.1282, 1.1669, 0.2316, -0.1395, 1.5400, 0.4419, 0.1169, -0.1603,
-0.9421, 0.6196, -1.8255, -0.3314, 0.8283, -0.3065, -2.6763, -1.4101,
0.9791, 1.4486, 1.6158, 0.0582])
tensor([[-1.1282, 1.1669, 0.2316, -0.1395],
[ 1.5400, 0.4419, 0.1169, -0.1603],
[-0.9421, 0.6196, -1.8255, -0.3314],
[ 0.8283, -0.3065, -2.6763, -1.4101],
[ 0.9791, 1.4486, 1.6158, 0.0582]])
- item : 텐서에 값이 단 하나라도 존재하면 숫자값을 얻을 수 있음
- 스칼라값 하나만 존재해야 item() 사용 가능
x = torch.randn(1)
print(x)
print(x.item())
print(x.dtype)
>> tensor([-3.1644])
-3.1643731594085693
torch.float32
- squeeze : 차원을 축소
tensor = torch.rand(1, 3, 3)
print(tensor)
print(tensor.shape)
>> tensor([[[0.6248, 0.5859, 0.8387],
[0.3797, 0.7793, 0.1828],
[0.5774, 0.9446, 0.6532]]])
torch.Size([1, 3, 3])
t = tensor.squeeze()
print(t)
print(t.shape)
>> tensor([[0.6248, 0.5859, 0.8387],
[0.3797, 0.7793, 0.1828],
[0.5774, 0.9446, 0.6532]])
torch.Size([3, 3])
- unsqueeze : 차원을 증가
t = torch.rand(3, 3)
print(t)
print(t.shape)
>> tensor([[0.4361, 0.1716, 0.9609],
[0.2392, 0.6470, 0.6706],
[0.1481, 0.6010, 0.1357]])
torch.Size([3, 3])
tensor = t.unsqueeze(dim=0)
print(tensor)
print(tensor.shape)
>> tensor([[[0.4361, 0.1716, 0.9609],
[0.2392, 0.6470, 0.6706],
[0.1481, 0.6010, 0.1357]]])
torch.Size([1, 3, 3])
tensor = t.unsqueeze(dim=2)
print(tensor)
print(tensor.shape)
>> tensor([[[0.4361],
[0.1716],
[0.9609]],
[[0.2392],
[0.6470],
[0.6706]],
[[0.1481],
[0.6010],
[0.1357]]])
torch.Size([3, 3, 1])
- 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]))
>> tensor([1., 4.])
tensor([2., 5.])
tensor([3., 6.])
tensor([[1., 4.],
[2., 5.],
[3., 6.]])
- 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())
>> tensor([[[-0.4074, -0.6053, -0.4368],
[ 0.3416, 1.3137, 0.8975],
[ 0.0699, -1.2002, -2.6423]]])
tensor([[[ 0.8965, -0.7043, -3.1802],
[-0.7097, -0.4769, -0.1803],
[ 0.3862, -0.8335, -0.5471]]])
tensor([[[-0.4074, -0.6053, -0.4368],
[ 0.3416, 1.3137, 0.8975],
[ 0.0699, -1.2002, -2.6423]],
[[ 0.8965, -0.7043, -3.1802],
[-0.7097, -0.4769, -0.1803],
[ 0.3862, -0.8335, -0.5471]]])
torch.Size([2, 3, 3])
c = torch.cat((a,b), dim=1)
print(c)
print(c.size())
>> tensor([[[-0.4074, -0.6053, -0.4368],
[ 0.3416, 1.3137, 0.8975],
[ 0.0699, -1.2002, -2.6423],
[ 0.8965, -0.7043, -3.1802],
[-0.7097, -0.4769, -0.1803],
[ 0.3862, -0.8335, -0.5471]]])
torch.Size([1, 6, 3])
c = torch.cat((a,b), dim=2)
print(c)
print(c.size())
>> tensor([[[-0.4074, -0.6053, -0.4368, 0.8965, -0.7043, -3.1802],
[ 0.3416, 1.3137, 0.8975, -0.7097, -0.4769, -0.1803],
[ 0.0699, -1.2002, -2.6423, 0.3862, -0.8335, -0.5471]]])
torch.Size([1, 3, 6])
- chunk : 텐서를 여러 개로 나눌 때 사용 (몇 개로 나눌 것인가?)
tensor = torch.rand(3, 6)
print(tensor)
t1, t2, t3 = torch.chunk(tensor, 3, dim=1)
print(t1)
print(t2)
print(t3)
>> tensor([[0.6369, 0.0903, 0.5728, 0.6568, 0.7805, 0.1588],
[0.8261, 0.1895, 0.7192, 0.6303, 0.3786, 0.6664],
[0.6631, 0.9095, 0.6214, 0.7038, 0.1065, 0.4323]])
tensor([[0.6369, 0.0903],
[0.8261, 0.1895],
[0.6631, 0.9095]])
tensor([[0.5728, 0.6568],
[0.7192, 0.6303],
[0.6214, 0.7038]])
tensor([[0.7805, 0.1588],
[0.3786, 0.6664],
[0.1065, 0.4323]])
- split : chunk와 동일한 기능이지만 조금 다름 (텐서의 크기는 몇인가?)
tensor = torch.rand(3,6)
t1 , t2 = torch.split(tensor, 3, dim= 1)
print(tensor)
print(t1)
print(t2)
>> tensor([[0.4166, 0.6668, 0.2096, 0.7406, 0.1294, 0.0474],
[0.3829, 0.4303, 0.7670, 0.4424, 0.9527, 0.7197],
[0.8575, 0.1119, 0.3283, 0.3013, 0.8005, 0.8648]])
tensor([[0.4166, 0.6668, 0.2096],
[0.3829, 0.4303, 0.7670],
[0.8575, 0.1119, 0.3283]])
tensor([[0.7406, 0.1294, 0.0474],
[0.4424, 0.9527, 0.7197],
[0.3013, 0.8005, 0.8648]])
torch <--> numpy
Torch Tensor(텐서)를 NumPy array(베열)로 변환 가능
- numpy()
- from_numpy()
Tensor가 CPU상에 있다면 Numpy 배열은 메모리 공간을 공유하므로 하나가 변하면, 다른 하나도 변함
a = torch.ones(7) print(a) >> tensor([1., 1., 1., 1., 1., 1., 1.]) b = a.numpy() print(b) >> [1. 1. 1. 1. 1. 1. 1.] a.add_(1) print(a) print(b) >> tensor([2., 2., 2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2. 2. 2.]
import numpy as np
a = np.ones(7)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
[2. 2. 2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2., 2., 2.], dtype=torch.float64)
반응형
'Study > Self Education' 카테고리의 다른 글
Pytorch 기본기 - 3 (0) | 2024.07.02 |
---|---|
Pytorch 기본기 - 2 (0) | 2024.07.02 |
핸즈온 머신러닝 - 14 (0) | 2024.06.19 |
핸즈온 머신러닝 - 13 (0) | 2024.06.19 |
핸즈온 머신러닝 - 12 (0) | 2024.06.19 |