Autograd : 자동 미분(Automatic Differentiation)
- autograd 패키지는 텐서의 모든 연산에 대하여 자동 미분을 제공.
텐서 (Tensors)
- torch.Tensor는 패키지에서 가장 중심이 되는 클래스. 텐서의 속성 중 .requires_grad를 True로 세팅하면, 텐서의 모든 연산에 대하여 추적을 시작한다. 계산 작업이 모두 수행 되었다면 .backward()를 호출하여 모든 그라디언트들을 자동으로 계산할 수 있다. 이 텐서를 위한 그라디언트는 .grad 속성에 누적되어 저장 된다.
뉴럴 네트워크 ( 신경망, Neural Networks )
- 뉴럴 네트워크는 torch.nn 패키지를 이용하여 생성.
일반적인 뉴럴 네트워크의 학습 절차.
- 학습 가능한 파라미터나 weight(가중치)가 있는 뉴럴 네트워크를 정의.
- 입력 데이터셋을 네트워크에 넣음.
- 네트워크를 통해 입력 값을 처리.
- loss를 계산. 출력(output)과 정답(target)의 차이
- 그라디언트(기울기)를 네트워크의 파라미터로 역전파 시킨다.
- 네트워크의 파라미터들을 갱신.
Dataset 클래스
- pytorch의 Dataset 클래스를 상속받아 custom dateset 클래스 생성 가능.
- 기본적으로 3개의 함수를 상속 받아 생성
Example
# Custom_Dataset Class
class Custom_Dataset(Dataset):
def __init__(self,x ,y ,data_set,transform=None):
self.x = x
self.y = y
self.data = data_set
self.transform = transform
def __len__(self):
return len(self.x)
def __getitem__(self,idx):
x = self.x[idx]
y = self.y[idx]
if self.data == 'cifar':
img = Image.fromarray(x)
elif self.data == 'svhn':
img = Image.fromarray(np.transpose(x, (1, 2, 0)))
x = self.transform(img)
return x, y, idx
MNIST DATA SET을 이용한 실습.
transforms.Compose TORCHVISION.TRANSFORMS
- 쉽게 말해 우리의 데이터를 전처리하는 패키지.
- 타입이나 데이터 argument를 하기위한 함수 내장.
실습
- transforms.ToTensor()
- 데이터 타입을 Tensor 형태로 변경
- transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
- 이미지의 경우 픽셀 값 하나는 0 ~ 255 값을 갖는다. 하지만 ToTensor()로 타입 변경시 0 ~ 1 사이의 값으로 바뀜.
- transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))를 이용하여 -1 ~ 1사이의 값으로 normalized 시킴
- datasets.MNIST()
- root : 경로 지정
- train : train or test 데이터를 받아옴.
- transorm 우리가 사전에 설정해 놓은 데이터 처리 형태
- download 데이터 셋이 없을때.
torch.utils.data.DataLoader torch.utils.data.DataLoader
- dataset : 우리가 불러올 데이터 셋
- batch_size = batch 단위 만큼 데이터를 뽑아옴.
- shuffle : 데이터를 shuffle할 것인지.
Normalize
- 크게 두가지 연산으로 나눠짐.
- scaling : 데이터의 scale을 줄여줌.
- centering : 데이터의 중심을 원점으로 맞춰주는 것.
- ToTensor()를 해주면 scaling을 해준거고, Normalize를 해주면 centering + rescaling을 해준것.
- 정확하게 하기 위해선 학습 데이터로부터 각 픽셀별로 평균을 구하던가 채널별로 평균을 구해서 centering 해야함 .
mnist image
- 28 x 28 픽셀로 구성.
- input으로 들어갈 경우 28 x 28 = 784로 변경.
- view()를 이용해 28x28 -> 784
기본적인 네트워크 구조 만들기
- class를 이용해 생성 *nn.Module 상속
- init() 에서 super를 통해 상속.
- 기본적으로 init, forword 함수 생성.
- init 함수에서 super(classname, self).init() 정의.
PyTorch: 사용자 정의 nn 모듈
- forward에 사용할 layer를 생성.
- 입력 Variable을 받아 다른 모듈 또는 Variable의 autograd 연산을 사용하여 출력 Variable을 생성하는 forward 를 정의
nn vs F
- nn의 경우 레이어 안에서 weight 공유가 가능.
- F의 경우 단순한 연산 기능만.
Pytorch : nn
- 연산 그래프와 autograd는 복잡한 연산자를 정의하고 도함수(derivative)를 자동으로 계산
- 모듈은 입력 Variable을 받고 출력 Variable을 계산
Network 객체 생성 및 손실 함수, 최적화 함수 생성.
- model = Net().cuda() : .cuda() 를 이용해 GPU로 할당 가능. -> 기본 구조는 .cuda()를 쓰지 않음.
- 기본적으로 .cuda()는 model 부분과 아래 설명될 Variable().cuda()에 쓰임.
- criterion : 손실함수 지정.
- nn.CrossEntropyLoss()의 경우 기본적으로 LogSoftmax()가 내장.
- optimizer : 최적화 함수 지정. :
- model.parameters()를 통해 model의 파라미터들을 할당.
- lr : learning_rate 지정
import torch.optim as optim
# use gpu -> .cuda() -> model and Variable
model = Network().cuda()
# This criterion combines nn.LogSoftmax() and nn.NLLLoss() in one single class. so not use softmax()
criterion = nn.CrossEntropyLoss()
optimizer = optim.RMSprop(model.parameters(), lr=0.01)
train의 기본 구조
- output = model(data) : 모델에서 정의한 forward 단계실행. 모델에 data를 전달하여 예상하는 label 값 계산
- loss = criterion(output, label) : 모델에서 나온 output과 label을 이용해 loss 계산
- optimizer.zero_grad() : 갱신할 Variable들에 대한 모든 변화도를 0으로 만듬
- loss.backward() : 역전파 단계 실행. 모델의 Variable들에 대한 손실의 변화도를 계산합니다.
- optimizer.step() : 가중치 갱신.
train_loader : MNIST의 train 데이터를 받아오는 함수. *data, label 값을 return 해줌. Variable : Variable 클래스는 Tensor를 감싸고 있으며, Tensor에 정의된 거의 모든 연산을 지원. 계산을 마친 후에 .backward()를 호출하면, 자동으로 모든 그레디언트 계산.
예측값과 결과값을 비교해 ACC 구하기
- torch.max() : 텐서 배열의 최대 값이 들어있는 index를 리턴하는 함수.
- pred.eq(data) : pred 값과 data값을 비교하는 함수.
- torch.max를 통해서 모델을 통해 나온 예측 결과를 구하고, pred.eq(data)를 이용해 예측값과 실제값을 구함.
- batch 단위 계산이기 떄문에 sum()을 통해 일치하는 갯수들의 합을 구함.
from torch.autograd import Variable
def train(epoch):
model.train()
train_loss = 0
train_acc = 0
for data, label in train_loader:
data, label = Variable(data).cuda(), Variable(label).cuda()
output = model(data)
loss = criterion(output, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
pred = output.data.max(1, keepdim=True)[1]
train_acc += pred.eq(label.data.view_as(pred)).sum()
train_loss /= len(train_loader.dataset)
print('Train Epoch: {} Average loss: {:.4f} Accuracy : {:.4f}%)'.format(epoch, train_loss, 100. * train_acc / len(train_loader.dataset)))
Test 구조
- Test 시에는 train 에서 학습된 파라미터를 가지고 모델에만 통과를 시켜주기 때문에 학습 시 파라미터 업데이트를 진행하지 않음.
- model.eval() 를 통해 Test 과정이라고 내부적으로 알려줌.
- 나중에 배울 train과 test시 다르게 적용되는 여러 기법들(batch_norm, dropout)을 model.train(), model.eval() 통해 간단히 따로 구현 가능.
- 기본적으로 test_loader를 통해 데이터들을 불러오고 데이터들을 Variable에 할당시키고 loss와 acc를 계산.
- model.eval()을 써서 상관없는 부분이지만 Variable을 단순히 backprob을 시키지 않게 하기 위한 volatile=True 파라미터가 존재.
- backprob이 필요없는 변수들에 대해서 메모리 절약과 학습 속도를 높힐 수 있음.
def test():
model.eval()
test_loss = 0
test_acc = 0
for data, target in test_loader:
# volatile=True no use backprob
data, target = Variable(data, volatile=True).cuda(), Variable(target).cuda()
output = model(data)
test_loss += criterion(output, target).item()
pred = output.data.max(1, keepdim=True)[1]
test_acc += pred.eq(target.data.view_as(pred)).sum()
test_loss /= len(test_loader.dataset)
print('Test set: Average loss: {:.4f}, Accuracy: {:.0f}%)'.format(test_loss, 100. * test_acc / len(test_loader.dataset)))
학습 및 테스트 실험
- epoch 수를 정하고 학습 및 테스트 실험.