printf("ho_tari\n");
ep.46 파이토치(PyTorch) 본문
2024.9.10
파이토치(PyTorch)
- 페이스북이 초기 루아(Lua) 언어로 개발된 토치(Torch)를 파이썬 버전으로 개발하여 2017년도에 공개
- 초기에 토치(Torch)는 넘파이(NumPy) 라이브러리처럼 과학 연산을 위한 라이브러리로 공개
- 이후 GPU를 이용한 텐서 조작 및 동적 신경망 구축이 가능하도록 딥러닝 프레임워크로 발전시킴
- 파이썬답게 만들어졌고, 유연하면서도 가속화된 계산 속도를 제공
파이토치 모듈 구조
파이토치의 구성요소
- 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__
텐서 초기화와 데이터 타입
초기화 되지 않은 텐서
x = torch.empty(4,2) # 쓰레기 값
print(x)
무작위로 초기화된 텐서
x = torch.rand(4,2) # 랜덤값
print(x)
데이터 타입(dtype)이 long이고, 0으로 채워진 텐서
# int64
x = torch.zeros(4,2, dtype=torch.long)
print(x)
사용자가 입력한 값으로 텐서 초기화
x = torch.tensor([3,2.3])
print(x)
2 x 4 크기, double 타입, 1로 채워진 텐서
x = torch.ones(2,4,dtype=torch.double)
#x = x.new_ones(2,4, dtype=torch.double)
print(x)
x와 같은 크기, float 타입, 무작위로 채워진 텐서
# float32
x = torch.rand_like(x, dtype=torch.float)
print(x)
텐서의 크기 계산
print(x.size())
데이터 타입(Data Type)
# float32
ft = torch.FloatTensor([1,2,3])
print(ft)
print(ft.dtype)
# type casting, ft는 현재 float32
print(ft.short())
print(ft.int())
print(ft.long())
# 정수 int32
it = torch.IntTensor([1,2,3])
print(it)
print(it.dtype)
print(it.float())
print(it.double())
print(it.half())
CUDA Tensors
- .to 메소드를 사용하여 텐서를 어떠한 장치(cpu, gpu)로도 옮길 수 있음
x = torch.randn(1)
print(x)
print(x.item()) # python scalar 값 얻음. tensor에 하나의 값이 아니라 여러개가 존재한다면 사용 불가능
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)
print(x)
z = x + y
print(z)
print(z.to('cpu', torch.double))
다차원 텐서 표현
0D Tensor(Scalar)
- 하나의 숫자를 담고 있는 텐서(tensor)
- 축과 형상이 없음
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)
- 행렬과 같은 모양으로 두개의 축이 존재
- 일반적인 수치, 통계 데이터셋이 해당
- 주로 샘플(samples)과 특성(features)을 가진 구조로 사용
t2 = torch.tensor([[1,2,3],
[4,5,6],
[7,8,9]])
print(t2.ndim)
print(t2.shape)
print(t2)
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)
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.4,0.4))
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))
print(x)
print('---')
print(x.min(dim=0))
print('---')
print(x.min(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)
print(result)
torch.add(x,y, out=result)
print(result)
in-place 방식
- in-place방식으로 텐서의 값을 변경하는 연산 뒤에는 _''가 붙음
- x.copy_(y), x.t_()
print(x)
print(y)
y.add_(x) # y.add(x)
print(y)
torch.sub: 뺄셈
print(x)
print(y)
print(x-y)
print(torch.sub(x,y))
print(x.sub_(y)) # y.sub(x)
torch.mul: 곱셉
print(x)
print(y)
print(x * y)
print(torch.mul(x,y))
print(x.mul(y)) # y.mul_(x)
torch.div: 나눗셈
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,:])
view: 텐서의 크기(size)나 모양(shape)을 변경
- 기본적으로 변경 전과 후에 텐서 안의 원소 개수가 유지되어야 함
- -1로 설정되면 계산을 통해 해당 크기값을 유추
x = torch.randn(4,5)
print(x)
y = x.view(20) # 1차원 reshape
print(y)
z = x.view(5,-1) # 2차원 reshape
print(z)
item: 텐서에 값이 단 하나라도 존재하면 숫자값을 얻을 수 있음
x = torch.randn(1)
print(x)
print(x.item())
print(x.dtype)
스칼라값 하나만 존재해야 item() 사용 가능
x = torch.randn(2)
print(x)
# print(x.item()) # 요소가 하나일 경우에 item 사용 가능
print(x.dtype)
squeeze: 차원을 축소(제거)
tensor = torch.rand(1,3,3)
print(tensor)
print(tensor.shape)
t = tensor.squeeze() # 한차원 축소 된 3차원에서 2차원으로
print(t)
print(t.shape)
unsqueeze: 차원을 증가(생성)
t = torch.rand(3,3)
print(t)
print(t.shape)
# t는 2차원
tensor = t.unsqueeze(dim=0) # 0번축 한차원 증가됨 2차원에서 3차원으로
print(tensor)
print(tensor.shape)
# t는 2차원
tensor = t.unsqueeze(dim=2) # 2번축 한차원 증가됨 2차원에서 3차원으로
print(tensor)
print(tensor.shape)
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())
c=torch.cat((a,b),dim=1)
print(c)
print(c.size())
c=torch.cat((a,b),dim=2)
print(c)
print(c.size())
chunk: 텐서를 여러 개로 나눌 때 사용 (몇 개로 나눌 것인가?)
tensor = torch.rand(3,6)
print(tensor)
t1,t2,t3 = torch.chunk(tensor,3,dim=1)
print(t1)
print(t2)
print(t3)
split: chunk와 동일한 기능이지만 조금 다름 (텐서의 크기는 몇인가?)
tensor = torch.rand(3,6)
t1,t2 = torch.split(tensor,3,dim=1)
print(tensor)
print(t1)
print(t2)
torch ↔ 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)
import numpy as np
a = np.ones(7)
b = torch.from_numpy(a)
np.add(a,1,out=a) # add_()
print(a)
print(b)
Autograd(자동미분)
- torch.autograd 패키지는 Tensor의 모든 연산에 대해 자동 미분 제공
- 이는 코드를 어떻게 작성하여 실행하느냐에 따라 역전파가 정의된다는 뜻
- backprop를 위해 미분값을 자동으로 계산
requires_grad 속성을 True로 설정하면, 해당 텐서에서 이루어지는 모든 연산들을 추적하기 시작
기록을 추적하는 것을 중단하게 하려면, .detach()를 호출하여 연산기록으로부터 분리
a = torch.randn(3,3)
a = a * 3
print(a)
print(a.requires_grad)
requires_grad_(...)는 기존 텐서의 requires_grad 값을 바꿔치기(in-place)하여 변경
grad_fn: 미분값을 계산한 함수에 대한 정보 저장 (어떤 함수에 대해서 backprop 했는지)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b)
print(b.grad_fn)
기울기(Gradient)
x = torch.ones(3,3,requires_grad=True)
print(x)
y = x+5
print(y)
z = y * y
out = z.mean()
print(z,out)
계산이 완료된 후, .backward()를 호출하면 자동으로 역전파 계산이 가능하고, .grad 속성에 누적됨
print(out)
out.backward()
print(out)
grad: data가 거쳐온 layer에 대한 미분값 저장
print(x)
print(x.grad)
x = torch.randn(3,requires_grad=True)
y = x * 2
while y.data.norm() < 1000: # 절대값의 합 1000보다 작은 경우 계속 2를 곱함
y = y * 2
print(y)
v = torch.tensor([0.1,1.0,0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)
with torch.no_grad()를 사용하여 기울기의 업데이트를 하지 않음
기록을 추적하는 것을 방지하기 위해 코드 블럭을 with torch.no_grad()로 감싸면 기울기 계산은 필요없지만, requires_grad=True로 설정되어 학습 가능한 매개변수를 갖는 모델을 평가(evaluate)할 때 유용
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad(): # 기울기를 업데이트 하지 않음
print((x ** 2).requires_grad)
detach(): 내용물(content)은 같지만 require_grad가 다른 새로운 Tensor를 가져올 때
print(x.requires_grad)
y = x.detach()
print(y.requires_grad)
print(x.eq(y).all())
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
# b는 더하기 연산, 자동으로 더하기 미분이 등록됨
b = a + 2
print(b)
# c는 6에 자승 연산을 함. 자동으로 자승 미분이 등록됨
c = b ** 2
print(c)
out = c.sum()
print(out)
print(out)
out.backward()
a의 grad_fn이 None인 이유는 직접적으로 계산한 부분이 없었기 때문
print(a.data)
print(a.grad)
print(a.grad_fn)
print(b.data)
print(b.grad)
print(b.grad_fn)
print(c.data)
print(c.grad)
print(c.grad_fn)
print(out.data)
print(out.grad)
print(out.grad_fn)
데이터 준비
파이토치에서는 데이터 준비를 위해 torch.utils.data의 Dataset과 DataLoader 사용 가능
- Dataset에는 다양한 데이터셋이 존재 (MNIST, FashionMNIST, CIFAR10, ...)
- Vision Dataset: https://pytorch.org/vision/stable/datasets.html
- Text Dataset: https://pytorch.org/text/stable/datasets.html
- Audio Dataset: https://pytorch.org/audio/stable/datasets.html
- DataLoader와 Dataset을 통해 batch_size, train 여부, transform 등을 인자로 넣어 데이터를 어떻게 load할 것인지 정해줄 수 있음
from torch.utils.data import Dataset, DataLoader
토치비전(torchvision)은 파이토치에서 제공하는 데이터셋들이 모여있는 패키지
- transforms: 전처리할 때 사용하는 메소드 (https://pytorch.org/docs/stable/torchvision/transforms.html)
- transforms에서 제공하는 클래스 이외는 일반적으로 클래스를 따로 만들어 전처리 단계를 진행
import torchvision.transforms as transforms
from torchvision import datasets
DataLoader의 인자로 들어갈 transform을 미리 정의할 수 있고, Compose를 통해 리스트 안에 순서대로 전처리 진행
ToTensor()를 하는 이유는 torchvision이 PIL Image 형태로만 입력을 받기 때문에 데이터 처리를 위해서 Tensor형으로 변환 필요
mnist_transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize(mean=(0.5,),std=(1.0,))])
trainset = datasets.MNIST(root='/conten/',
train=True,download=True,
transform = mnist_transform)
testset = datasets.MNIST(root='/conten/',
train=False,download=True,
transform = mnist_transform)
DataLoader는 데이터 전체를 보관했다가 실제 모델 학습을 할 때 batch_size 크기만큼 데이터를 가져옴
train_loader = DataLoader(trainset, batch_size=8, shuffle=True, num_workers=2)
test_loader = DataLoader(testset, batch_size=8, shuffle=False, num_workers=2)
dataiter = iter(train_loader)
images, labels = dataiter.next()
images.shape, labels.shape
torch_image = torch.squeeze(images[0])
torch_image.shape
import matplotlib.pyplot as plt
figure = plt.figure(figsize=(12,6))
cols, rows = 4, 2
for i in range(1, cols*rows+1):
sample_idx = torch.randint(len(trainset),size=(1,)).item()
img, label = trainset[sample_idx]
figure.add_subplot(rows,cols,i)
plt.title(label)
plt.axis('off')
plt.imshow(img.squeeze(),cmap='gray')
plt.show()
신경망 구성
- 레이어(layer): 신경망의 핵심 데이터 구조로 하나 이상의 텐서를 입력받아 하나 이상의 텐서를 출력
- 모듈(module): 한 개 이상의 계층이 모여서 구성
- 모델(model): 한 개 이상의 모듈이 모여서 구성
torch.nn 패키지
주로 가중치(weights), 편향(bias)값들이 내부에서 자동으로 생성되는 레이어들을 사용할 때 사용 (weight값들을 직접 선언 안함)
import torch.nn as nn
nn.Linear 계층 예제
input = torch.randn(128,20)
print(input)
m = nn.Linear(20,30)
print(m)
output = m(input)
print(output)
print(output.size())
nn.Conv2d 계층 예시
input = torch.randn(20,16,50,100)
print(input.size())
m = nn.Conv2d(16,33,3,stride=2)
m = nn.Conv2d(16,33,(3,5),stride=(2,1),padding = (4,2))
m = nn.Conv2d(16,33,(3,5),stride=(2,1),padding = (4,2),dilation=(3,1))
print(m)
output = m(input)
print(output.size())
컨볼루션 레이어(Convolution Layers)
nn.Conv2d 예제
- in_channels: channel의 갯수
- out_channels: 출력 채널의 갯수
- kernel_size: 커널(필터) 사이즈
nn.Conv2d(in_channels=1,out_channels=20,kernel_size=5,stride=1)
layer = nn.Conv2d(1,20,5,1).to(torch.device('cpu'))
layer
weight 확인
weight = layer.weight
weight.shape
weight는 detach()를 통해 꺼내줘야 numpy()변환이 가능
weight = weight.detach()
weight = weight.numpy()
weight.shape
plt.imshow(weight[0,0,:,:],'jet')
plt.colorbar()
plt.show()
print(images.shape)
print(images[0].size())
input_image = torch.squeeze(images[0])
print(input_image.size())
input_data = torch.unsqueeze(images[0],dim=0)
print(input_data.size())
output_data = layer(input_data)
output = output_data.data
output_arr = output.numpy()
output_arr.shape
plt.figure(figsize=(15,30))
plt.subplot(131)
plt.title("input")
plt.imshow(input_image,'gray')
plt.subplot(132)
plt.title("weight")
plt.imshow(weight[0,0,:,:],'jet')
plt.subplot(133)
plt.title("output")
plt.imshow(output_arr[0,0,:,:],'gray')
plt.show()
풀링 레이어(Pooling layers)
- F.max_pool2d
- stride
- kernel_size
- torch.nn.MaxPool2d 도 많이 사용
import torch.nn.functional as F
pool = F.max_pool2d(output,2,2)
pool.shape
- MaxPool Layer는 weight가 없기 때문에 바로 numpy()변환 가능
pool_arr = pool.numpy()
pool_arr.shape
plt.figure(figsize=(10,15))
plt.subplot(121)
plt.title("input")
plt.imshow(input_image,'gray')
plt.subplot(122)
plt.title("output")
plt.imshow(pool_arr[0,0,:,:],'gray')
plt.show()
선형 레이어(Linear layers)
1d만 가능하므로 .view()를 통해 1d로 펼쳐줘야함
flatten = input_image.view(1,28*28)
flatten.shape
lin = nn.Linear(784,10)(flatten)
lin.shape
lin
plt.imshow(lin.detach().numpy(),'jet')
plt.colorbar()
plt.show()
비선형 활성화 (Non-linear Activations)
F.softmax와 같은 활성화 함수 등
with torch.no_grad():
flatten = input_image.view(1,28*28)
lin = nn.Linear(784,10)(flatten)
softmax = F.softmax(lin,dim=1)
softmax
np.sum(softmax.numpy())
F.relu
- ReLU 함수를 적용하는 레이어
- nn.ReLU로도 사용 가능
inputs = torch.randn(4,3,28,28).to(device)
inputs.shape
layer = nn.Conv2d(3,20,5,1).to(device)
output = F.relu(layer(inputs))
output.shape
신경망 종류
모델 정의
nn.Module 상속 클래스 정의
- nn.Module을 상속받는 클래스 정의
- __init__(): 모델에서 사용될 모듈과 활성화 함수 등을 정의
- forward(): 모델에서 실행되어야 하는 연산을 정의
class Model(nn.Module):
def __init__(self,inputs):
super(Model,self).__init__()
self.layer = nn.Linear(inputs,1)
self.activation = nn.Sigmoid()
def forward(self,x):
x = self.layer(x)
x = self.activation(x)
return x
model = Model(1)
print(list(model.children()))
print(list(model.modules()))
nn.Sequential을 이용한 신경망 정의
- nn.Sequential 객체로 그 안에 각 모듈을 순차적으로 실행
- __init__()에서 사용할 네트워크 모델들을 nn.Sequential로 정의 가능
- forward()에서 실행되어야 할 계산을 가독성 높게 작성 가능
class Model(nn.Module):
def __init__(self):
super(Model,self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(in_channels=3,out_channels=64,kernel_size=5),
nn.ReLU(inplace=True),
nn.MaxPool2d(2)
)
self.layer2 = nn.Sequential(
nn.Conv2d(in_channels=64,out_channels=30,kernel_size=5),
nn.ReLU(inplace=True),
nn.MaxPool2d(2)
)
self.layer3 = nn.Sequential(
nn.Linear(in_features=30*5*5,out_features=10,bias=True),
nn.ReLU(inplace=True)
)
def forward(self,x):
x = self.layer1(x)
x = self.layer2(x)
x = x.view(x.shape[0],-1)
x = self.layer3(x)
return x
model = Model()
print(list(model.children()))
print(list(model.modules()))
모델 파라미터
손실 함수(Loss function)
- 예측 값과 실제 값 사이의 오차 측정
- 학습이 진행되면서 해당 과정이 얼마나 잘 되고 있는지 나타내는 지표
- 모델이 훈련되는 동안 최소화될 값으로 주어진 문제에 대한 성공 지표
- 손실 함수에 따른 결과를 통해 학습 파라미터를 조정
- 최적화 이론에서 최소화 하고자 하는 함수
- 미분 가능한 함수 사용
- 파이토치의 주요 손실 함수
- torch.nn.BCELoss: 이진 분류를 위해 사용
- torch.nn.CrossEntropyLoss: 다중 클래스 분류를 위해 사용
- torch.nn.MSELoss: 회귀 모델에서 사용
criterion = nn.MSELoss()
criterion = nn.CrossEntropyLoss()
티마이저(Optimizer)
- 손실 함수를 기반으로 모델이 어떻게 업데이트되어야 하는지 결정 (특정 종류의 확률적 경사 하강법 구현)
- optimizer는 step()을 통해 전달받은 파라미터를 모델 업데이트
- 모든 옵티마이저의 기본으로 torch.optim.Optimizer(params, defaults) 클래스 사용
- zero_grad()를 이용해 옵티마이저에 사용된 파라미터들의 기울기를 0으로 설정
- torch.optim.lr_scheduler를 이용해 에포크(epochs)에 따라 학습률(learning rate) 조절
- 파이토치의 주요 옵티마이저: optim.Adadelta, optim.Adagrad, optim.Adam, optim.RMSprop, optim.SGD
학습률 스케줄러(Learning rate scheduler)
- 학습시 특정 조건에 따라 학습률을 조정하여 최적화 진행
- 일정 횟수 이상이 되면 학습률을 감소(decay)시키거나 전역 최소점(global minimum) 근처에 가면 학습률을 줄이는 등
- 파이토치의 학습률 스케줄러 종류
- optim.lr_scheduler.LambdaLR: 람다(lambda) 함수를 이용해 그 결과를 학습률로 설정
- optim.lr_scheduler.StepLR: 단계(step)마다 학습률을 감마(gamma) 비율만큼 감소
- optim.lr_scheduler.MultiStepLR: StepLR과 비슷하지만 특정 단계가 아니라 지정된 에포크에만 감마 비율로 감소
- optim.lr_scheduler.ExponentialLR: 에포크마다 이전 학습률에 감마만큼 곱함
- optim.lr_scheduler.CosineAnnealingLR: 학습률을 코사인(cosine) 함수의 형태처럼 변화시켜 학습률일 커지기도 하고 작아지기도 함
- optim.lr_scheduler.ReduceLROnPlateau: 학습이 잘되는지 아닌지에 따라 동적으로 학습률 변화
지표(Metrics)
- 모델의 학습과 테스트 단계를 모니터링
!pip install torchmetrics
import torchmetrics
preds = torch.randn(10,5).softmax(dim=-1)
target = torch.randint(5,(10,))
print(preds, target)
acc = torchmetrics.functional.accuracy(preds, target)
print(acc)
metric = torchmetrics.Accuracy()
n_batches = 10
for i in range(n_batches):
preds = torch.randn(10,5).softmax(dim=-1)
ratget = torch.randint(5,(10,))
acc = metric(preds, target)
print(acc)
acc = metric.compute()
print(acc)
선형 회귀 모델(Linear Regression Model)
데이터 생성
X = torch.randn(200,1)*10
y = X + 3 * torch.randn(200,1)
plt.scatter(X.numpy(), y.numpy())
plt.ylabel('y')
plt.xlabel('x')
plt.grid()
plt.show()
모델 정의 및 파라미터
class LinearRegressionModel(nn.Module):
def __init__(self):
super(LinearRegressionModel,self).__init__()
self.linear = nn.Linear(1,1)
def forward(self,x):
pred = self.linear(x)
return pred
model = LinearRegressionModel()
print(model)
print(list(model.parameters()))
w, b =model.parameters()
w1,b1 = w[0][0].item(), b[0].item()
x1 = np.array([-30,30])
y1 = w1*x1 + b1
plt.plot(x1,y1,'r')
plt.scatter(X,y)
plt.grid()
plt.show()
손실 함수 및 옵티마이저
import torch.optim as optim
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(),lr=0.001)
모델 학습
epochs = 100
losses = []
for epoch in range(epochs):
optimizer.zero_grad()
y_pred = model(X)
loss = criterion(y_pred,y)
losses.append(loss.item())
loss.backward()
optimizer.step()
plt.plot(range(epochs),losses)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()
w1,b1 = w[0][0].item(), b[0].item()
x1 = np.array([-30,30])
y1 = w1*x1 + b1
plt.plot(x1,y1,'r')
plt.scatter(X,y)
plt.grid()
plt.show()
FashionMNIST 분류 모델
GPU 설정
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
device
데이터 로드
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,),(0.5,))])
trainset = datasets.FashionMNIST(root = '/content/',
train=True,download=True,
transform=transform)
testset = datasets.FashionMNIST(root = '/content/',
train=False,download=True,
transform=transform)
train_loader = DataLoader(trainset, batch_size = 128, shuffle=True,num_workers=2)
test_loader = DataLoader(testset, batch_size = 128, shuffle=False,num_workers=2)
images, labels = next(iter(train_loader))
images.shape, labels.shape
labels_map = {
0:'T-Shirt',
1:'Trouser',
2:'Pullover',
3:'Dress',
4:'Coat',
5:'Sandal',
6:'Shirt',
7:'Sneaker',
8:'Bag',
9:'Ankle Boot'
}
figure = plt.figure(figsize=(12,12))
cols,rows = 4,4
for i in range(1,cols*rows+1):
image = images[i].squeeze()
label_idx = labels[i].item()
label = labels_map[label_idx]
figure.add_subplot(rows,cols,i)
plt.title(label)
plt.axis('off')
plt.imshow(image,cmap='gray')
plt.show()
모델 정의 및 파라미터
class NeuralNet(nn.Module):
def __init__(self):
super(NeuralNet,self).__init__()
self.conv1 = nn.Conv2d(1,6,3)
self.conv2 = nn.Conv2d(6,16,3)
self.fc1 = nn.Linear(16*5*5, 120)
self.fc2 = nn.Linear(120,84)
self.fc3 = nn.Linear(84,10)
def forward(self,x):
x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
x = F.max_pool2d(F.relu(self.conv2(x)),2)
x = x.view(-1,self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self,x):
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
net = NeuralNet()
print(net)
params = list(net.parameters())
print(len(params))
print(params[0].size())
input = torch.randn(1,1,28,28)
out = net(input)
print(out)
손실함수와 옵티마이저
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
모델 학습
배치수 확인
total_batch = len(train_loader)
print(total_batch)
for epoch in range(10):
running_loss =0.0
for i,data in enumerate(train_loader,0):
inputs, labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs,labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 100 == 99:
print('Epoch : {}, lter: {}, Loss: {}'.format(epoch+1, i+1, running_loss/2000))
running_loss = 0.0
모델의 저장 및 로드
- torch.save: net.state_dict()를 저장
- torch.load: load_state_dict로 모델을 로드
PATH = './fashion_mnist.pth'
torch.save(net.state_dict(),PATH)
net = NeuralNet()
net.load_state_dict(torch.load(PATH))
net.parameters
모델 테스트
def imshow(image):
image = image/2 + 0.5
npimg = image.numpy()
fig = plt.figure(figsize=(16,8))
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
import torchvision
dataiter = iter(test_loader)
images, labels = dataiter.next()
imshow(torchvision.utils.make_grid(images[:6]))
outputs = net(images)
_,predicted = torch.max(outputs,1)
print(predicted)
print(''.join('{},'.format(labels_map[int(predicted[j].numpy())])for j in range(6)))
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = net(images)
outputs = net(images)
_,predicted = torch.max(outputs.data,1)
total += labels.size(0)
correct+=(predicted == labels).sum().item()
print(100*correct/total)
'두산 로보틱스 부트캠프 ROKEY > Computer Vision 교육' 카테고리의 다른 글
ep.48 딥러닝 이미지 분류 실습(2) (0) | 2024.09.12 |
---|---|
ep.47 딥러닝 이미지 분류 실습(1) (0) | 2024.09.11 |
ep.45 인공신경망(Artificial Neural Network) (0) | 2024.09.09 |
ep.44 딥러닝 (0) | 2024.09.06 |
ep.43 합성곱 신경망(CNN) (0) | 2024.09.05 |