layout | title | date | summary | categories | tags | |||||
---|---|---|---|---|---|---|---|---|---|---|
post |
2022-07-13 Log |
2022-07-13 20:00:00 +0900 |
PyTorch로 시작하는 딥 러닝 입문 |
|
|
torch
: 메인 네임스페이스torch.autograd
: 자동 미분을 위한 함수torch.nn
: 데이터 구조나 레이어 등 정의torch.optim
: 경사 하강법 등 파라미터 최적화 알고리즘 구현torch.utils.data
: 미니 배치용 유틸리티 함수torch.onnx
: ONNX의 포맷으로 모델을 저장할 때 사용
- 2D Tensor: (batch size, dim)
- 3D Tensor: (batch size, width, height)
- 3D Tensor(NLP): (batch size, length, dim)
torch.FloatTensor()
: 텐서 생성- 행렬 곱셈(
.matmul()
), 원소 별 곱셈(.mul()
,*
) dim=0
: 첫번째 차원(행) 제거 = 같은 열끼리 연산,dim=1
: 두번째 차원(열) 제거 = 같은 행끼리 연산view()
: reshape,squeeze()
: 1인 차원 제거,unsequeeze()
: 특정 위치에 1인 차원 추가cat()
,stack()
,ones_like()
,zeros_like()
- 기본 셋팅 및 변수 선언: seed 설정, x_train 및 y_train 선언
- 가중치와 편향의 초기화:
W = torch.zeros(1, requires_grad=True)
- 가설 세우기:
hypothesis = x_train * W + b
- 비용 함수 선언:
cost = torch.mean((hypothesis - y_train) ** 2)
- 경사 하강법 구현:
optimizer = optim.SGD([W, b], lr=0.01)
optimizer.zero_grad() # gradient를 0으로 초기화
# 파이토치가 미분을 통해 얻은 기울기를 이전에 계산된 기울기 값을 누적시키기 때문에 미분값을 초기화
cost.backword() # 비용 함수를 미분하여 gradient 계산
optimizer.step() # W와 b를 업데이트
requires_grad=True
,backward()
등
- x의 계수를 행렬로 변환해 W와 내적
- 5x3 크기의 x_train과 3x1 크기의 W를 내적해 5x1 크기의 y_train 계산
from torch import nn
import torch.nn.functional as F
model = nn.Linear(input_dim, output_dim)
cost = F.mse_loss(prediction, y_train)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
class LinearRegressionModel(nn.Module):
def __init__(self): #
super().__init__()
self.linear = nn.Linear(1, 1)
def forward(self, x):
return self.linear(x)
class CustomDataset(torch.utils.data.Dataset):
def __init__(self):
# 데이터셋의 전처리를 해주는 부분
def __len__(self):
# 데이터셋의 길이. 즉, 총 샘플의 수를 적어주는 부분
def __getitem__(self, idx):
# 데이터셋에서 특정 1개의 샘플을 가져오는 함수
hypothesis = 1 / (1 + torch.exp(-(x_train.matmul(W) + b)))
cost = F.binary_cross_entropy(hypothesis, y_train)
class BinaryClassifier(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(2, 1)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
return self.sigmoid(self.linear(x))
F.softmax(z, dim=1)
- F.softmax() + torch.log() = F.log_softmax()
- F.log_softmax() + F.nll_loss() = F.cross_entropy()
# One-Hot Encoding
y_one_hot = torch.zeros_like(hypothesis)
y_one_hot.scatter_(1, y_train.unsqueeze(1), 1)
model = nn.Sequential(
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 16),
nn.ReLU(),
nn.Linear(16, 10)
)
class CNN(torch.nn.Module):
def __init__(self):
super(CNN, self).__init__()
# 첫번째층
# ImgIn shape=(?, 28, 28, 1)
# Conv -> (?, 28, 28, 32)
# Pool -> (?, 14, 14, 32)
self.layer1 = torch.nn.Sequential(
torch.nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2))
# 두번째층
# ImgIn shape=(?, 14, 14, 32)
# Conv ->(?, 14, 14, 64)
# Pool ->(?, 7, 7, 64)
self.layer2 = torch.nn.Sequential(
torch.nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2))
# 전결합층 7x7x64 inputs -> 10 outputs
self.fc = torch.nn.Linear(7 * 7 * 64, 10, bias=True)
# 전결합층 한정으로 가중치 초기화
torch.nn.init.xavier_uniform_(self.fc.weight)
def forward(self, x):
out = self.layer1(x)
out = self.layer2(out)
out = out.view(out.size(0), -1) # 전결합층을 위해서 Flatten
out = self.fc(out)
return out
import torch.nn as nn
embedding_layer = nn.Embedding(num_embeddings=len(vocab),
embedding_dim=3,
padding_idx=1)
cannot import name 'load_state_dict_from_url'
- apply this change in
_download_hooks.py
try:
from torch.hub import load_state_dict_from_url
except ImportError:
from torch.utils.model_zoo import load_url as load_state_dict_from_url
from torchtext.vocab import build_vocab_from_iterator
vocab = build_vocab_from_iterator(sequences)
vocab.get_stoi() # 각 단어의 정수 인덱스가 저장된 딕셔너리
nn.RNN(input_dim, hidden_size, num_layers, batch_fisrt=True)
nn.LSTM(input_dim, hidden_size, num_layers, batch_fisrt=True)
class Net(nn.Module):
def __init__(self, vocab_size, input_size, hidden_size, batch_first=True):
super(Net, self).__init__()
self.embedding_layer = nn.Embedding(num_embeddings=vocab_size, # 워드 임베딩
embedding_dim=input_size)
self.rnn_layer = nn.RNN(input_size, hidden_size, # 입력 차원, 은닉 상태의 크기 정의
batch_first=batch_first)
self.linear = nn.Linear(hidden_size, vocab_size) # 출력은 원-핫 벡터의 크기를 가져야함. 또는 단어 집합의 크기만큼 가져야함.
def forward(self, x):
# 1. 임베딩 층
# 크기변화: (배치 크기, 시퀀스 길이) => (배치 크기, 시퀀스 길이, 임베딩 차원)
output = self.embedding_layer(x)
# 2. RNN 층
# 크기변화: (배치 크기, 시퀀스 길이, 임베딩 차원)
# => output (배치 크기, 시퀀스 길이, 은닉층 크기), hidden (1, 배치 크기, 은닉층 크기)
output, hidden = self.rnn_layer(output)
# 3. 최종 출력층
# 크기변화: (배치 크기, 시퀀스 길이, 은닉층 크기) => (배치 크기, 시퀀스 길이, 단어장 크기)
output = self.linear(output)
# 4. view를 통해서 배치 차원 제거
# 크기변화: (배치 크기, 시퀀스 길이, 단어장 크기) => (배치 크기*시퀀스 길이, 단어장 크기)
return output.view(-1, output.size(2))
# 모델 생성
model = Net(vocab_size, input_size, hidden_size, batch_first=True)
# 손실함수 정의
loss_function = nn.CrossEntropyLoss() # 소프트맥스 함수 포함이며 실제값은 원-핫 인코딩 안 해도 됨.
# 옵티마이저 정의
optimizer = optim.Adam(params=model.parameters())
class GRU(nn.Module):
def __init__(self, n_layers, hidden_dim, n_vocab, embed_dim, n_classes, dropout_p=0.2):
super(GRU, self).__init__()
self.n_layers = n_layers
self.hidden_dim = hidden_dim
self.embed = nn.Embedding(n_vocab, embed_dim)
self.dropout = nn.Dropout(dropout_p)
self.gru = nn.GRU(embed_dim, self.hidden_dim,
num_layers=self.n_layers,
batch_first=True)
self.out = nn.Linear(self.hidden_dim, n_classes)
def forward(self, x):
x = self.embed(x)
h_0 = self._init_state(batch_size=x.size(0)) # 첫번째 히든 스테이트를 0벡터로 초기화
x, _ = self.gru(x, h_0) # GRU의 리턴값은 (배치 크기, 시퀀스 길이, 은닉 상태의 크기)
h_t = x[:,-1,:] # (배치 크기, 은닉 상태의 크기)의 텐서로 크기가 변경됨. 즉, 마지막 time-step의 은닉 상태만 가져온다.
self.dropout(h_t)
logit = self.out(h_t) # (배치 크기, 은닉 상태의 크기) -> (배치 크기, 출력층의 크기)
return logit
def _init_state(self, batch_size=1):
weight = next(self.parameters()).data
return weight.new(self.n_layers, batch_size, self.hidden_dim).zero_()