Pytorch의 모든 것
( 참고 : https://wikidocs.net/book/2788 )
Contents
[ Basics ]
-
1차원 텐서
-
2차원 텐서
-
브로드캐스팅 (Broadcasting)
-
행렬 곱셈 & 곱셈
-
평균
-
덧셈
-
Max & Argmax
-
view
-
squeeze
-
unsqueeze
-
Type Casting
-
Concatenate
-
Stack
-
torch.ones_like
&torch.zeros_like
-
Linear Regression (naive)
-
Linear Regression (nn.Module)
-
Linear Regression (Class)
-
Mini Batch & Data Loader
-
Custom Dataset
-
Linear Regression (with Custom Dataset)
-
Softmax
-
One-hot Encoding (
scatter_
) -
Softmax의 loss function 구하기
-
Softmax Regression (nn.Module)
-
Softmax Regression (Class)
-
MNIST Classification ( Single NN )
-
MNIST Classification ( MLP 1 )
-
MNIST Classification ( MLP 2 )
-
Batch Normalization & Layer Normalization
[ Vision & NLP ]
-
basics of CNN
-
NLP의 basic
-
네이버 영화 리뷰 전처리
-
Torchtext (1) 영어
-
Torchtext (2) 한글
-
Torchtext의
batch_first
-
nn.Embedding()
-
Pre-trained Word Embedding
-
Pre-trained Word Embedding 종류들
-
RNN basic
-
Pytorch RNN ( LSTM )
-
Pytorch CharRNN ( 텍스트 생성 )
-
Pytorch Word RNN ( 텍스트 생성 )
-
Pytorch Sentiment Classification (다대일)
-
Pytorch Sequence Labeling (다대다)
1. 1차원 텐서
-
torch.FloatTensor([ ~ ])
-
x.size()
( =x.shape
)
t = torch.FloatTensor([0., 1., 2., 3., 4., 5., 6.])
print(t.dim()) # rank. 즉, 차원
print(t.shape) # shape
print(t.size()) # shape
#---------------------------------
1
torch.Size([7])
torch.Size([7])
2. 2차원 텐서
t = torch.FloatTensor([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.],
[10., 11., 12.]
])
print(t.dim()) # rank. 즉, 차원
print(t.size()) # shape
#---------------------------------
2
torch.Size([4, 3])
3. 브로드캐스팅 (Broadcasting)
- 불가피하게 크기가 다른 행렬 또는 텐서에 대해서 사칙 연산을 수행할 필요
- Pytorch에서는 자동으로 크기를 맞춰서 연산을 수행하게 만드는 브로드캐스팅이라는 기능을 제공
1) 일반적인 경우
m1 = torch.FloatTensor([[3, 3]])
m2 = torch.FloatTensor([[2, 2]])
print(m1 + m2)
#---------------------------------
tensor([[5., 5.]])
2) Vector + Scalar
m1 = torch.FloatTensor([[1, 2]])
m2 = torch.FloatTensor([3]) # [3] -> [3, 3]
print(m1 + m2)
#--------------------------
tensor([4., 5.],
[5., 6.]])
4. 행렬 곱셈 & 곱셈
행렬 곱셈(.matmul)
vs원소 별 곱셈(.mul)
m1 = torch.FloatTensor([[1, 2], [3, 4]])
m2 = torch.FloatTensor([[1], [2]])
print('Shape of Matrix 1: ', m1.shape) # 2 x 2
print('Shape of Matrix 2: ', m2.shape) # 2 x 1
#--------------------------
Shape of Matrix 1: torch.Size([2, 2])
Shape of Matrix 2: torch.Size([2, 1])
[ matrix multiplication ]
print(m1.matmul(m2)) # 2 x 1
#--------------------------
tensor([[ 5.],
[11.]])
[ multiplication ]
print(m1 * m2) # 2 x 2
print(m1.mul(m2))
#--------------------------
tensor([[1., 2.],
[6., 8.]])
tensor([[1., 2.],
[6., 8.]])
5. 평균
[ 1차원 벡터 ]
t = torch.FloatTensor([1, 2])
#--------------------------
print(t.mean())
tensor(1.5000)
[ 2차원 행렬 ]
dim=0
: 1번째(index=0) 차원을 의미- (기존) (2x2) \(\rightarrow\) (mean) (1x2)
- (행x열) \(\rightarrow\) (열,)
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)
print(t.mean())
print(t.mean(dim=0)) # (행,열)에서 '행(0)' 제거 ( = 열 별로 평균)
print(t.mean(dim=1)) # (행,열)에서 '열(1)' 제거 ( = 행 별로 평균)
#--------------------------
tensor([[1., 2.],
[3., 4.]])
tensor(2.5000)
tensor([2., 3.])
tensor([1.5000, 3.5000])
6. 덧셈
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)
print(t.sum())
print(t.sum(dim=0)) # (행,열)에서 '행(0)' 제거 ( = 열 별로 덧셈)
print(t.sum(dim=1)) # (행,열)에서 '열(1)' 제거 ( = 행 별로 덧셈)
print(t.sum(dim=-1)) # (행,열)에서 '열(-1)' 제거 ( = 행 별로 덧셈)
#--------------------------
tensor([[1., 2.],
[3., 4.]])
tensor(10.)
tensor([4., 6.])
tensor([3., 7.])
tensor([3., 7.])
7. Max & Argmax
dim
을 설정하면, max & argmax 두 가지 value 모두 반환
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)
print(t.max())
print(t.max(dim=0)) # (행,열)에서 '행(0)' 제거 ( = 열 별로 최대)
print(t.max(dim=1)) # (행,열)에서 '열(1)' 제거 ( = 행 별로 최대)
print(t.max(dim=-1)) # (행,열)에서 '열(-1)' 제거 ( = 행 별로 최대)
#--------------------------
tensor([[1., 2.],
[3., 4.]])
tensor(4.)
(tensor([3., 4.]), tensor([1, 1]))
(tensor([2., 4.]), tensor([1, 1]))
(tensor([2., 4.]), tensor([1, 1]))
8. view
t = np.array([[[0, 1, 2],
[3, 4, 5]],
[[6, 7, 8],
[9, 10, 11]]])
ft = torch.FloatTensor(t)
print(ft.shape)
#--------------------------
torch.Size([2, 2, 3])
[ 3차원 \(\rightarrow\) 2차원 ]
x.view([-1,n])
: (?,n)의 크기로 바꾸기
print(ft.view([-1, 3])) # ft라는 텐서를 (?, 3)의 크기로 변경
print(ft.view([-1, 3]).shape)
#--------------------------
tensor([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.]])
torch.Size([4, 3]) # (2,2,3) -> (2x2,3)
[ 3차원 \(\rightarrow\) 3차원 ]
- 3차원 텐서에서 3차원 텐서로 차원은 유지하되, 크기(shape)를 바꾸는 작업
print(ft.view([-1, 1, 3])) # ft라는 텐서를 (?, 1, 3)의 크기로 변경
print(ft.view([-1, 1, 3]).shape)
#--------------------------
tensor([[[ 0., 1., 2.]],
[[ 3., 4., 5.]],
[[ 6., 7., 8.]],
[[ 9., 10., 11.]]])
torch.Size([4, 1, 3])
9. squeeze
- 스퀴즈(Squeeze) :1인 차원을 제거한다
ft = torch.FloatTensor([[0], [1], [2]])
print(ft)
print(ft.shape)
print(ft.squeeze())
print(ft.squeeze().shape)
#--------------------------
tensor([[0.],
[1.],
[2.]])
torch.Size([3, 1])
tensor([0., 1., 2.])
torch.Size([3]) # [3,1] -> [3]
10. unsqueeze
- 언스퀴즈(Unsqueeze) : 특정 위치에 1인 차원을 추가한다.
ft = torch.Tensor([0, 1, 2])
print(ft.shape)
print(ft.unsqueeze(0)) # 첫번째 차원(=0)을 의미한다.
print(ft.unsqueeze(0).shape)
#--------------------------
torch.Size([3])
tensor([[0., 1., 2.]])
torch.Size([1, 3]) # [3] -> [1,3]
- 방금 한 연산을 앞서 배운 view로도 구현 가능
- 2차원으로 바꾸고 싶으면서 & 첫번째 차원은 1이기를 원한다면…
print(ft.view(1, -1))
print(ft.view(1, -1).shape)
#--------------------------
tensor([[0., 1., 2.]])
torch.Size([1, 3])
- unsqueeze의 인자로 1을 넣으면, 2번째 차원에 차원 추가
print(ft.unsqueeze(1))
print(ft.unsqueeze(1).shape)
#--------------------------
tensor([[0.],
[1.],
[2.]])
torch.Size([3, 1])
11. Type Casting
-
CPU :
torch.xxTensor
-
GPU :
torch.cuda.xxTensor
.
lt = torch.LongTensor([1, 2, 3, 4])
print(lt.float())
#--------------------------
tensor([1., 2., 3., 4.])
bt = torch.ByteTensor([True, False, False, True])
print(bt)
print(bt.long())
print(bt.float())
#--------------------------
tensor([1, 0, 0, 1], dtype=torch.uint8)
tensor([1, 0, 0, 1])
tensor([1., 0., 0., 1.])
12. Concatnate
torch.cat([ ])
x = torch.FloatTensor([[1, 2], [3, 4]])
y = torch.FloatTensor([[5, 6], [7, 8]])
print(torch.cat([x, y], dim=0)) # (2,2)&(2,2) -> (4,2)
print(torch.cat([x, y], dim=1)) # (2,2)&(2,2) -> (2,4)
#--------------------------
tensor([[1., 2.],
[3., 4.],
[5., 6.],
[7., 8.]])
tensor([[1., 2., 5., 6.],
[3., 4., 7., 8.]])
13. Stack
( 참고 : https://stackoverflow.com/questions/54307225/whats-the-difference-between-torch-stack-and-torch-cat-functions )
torch.cat([ ])
: Concatenates sequence of tensors along a new dimension.torch.stack([])
: Concatenates the given sequence of seq tensors in the given dimension.
So if A
and B
are of shape (3, 4)
torch.cat([A, B], dim=0)
will be of shape (6, 4)torch.stack([A, B], dim=0)
will be of shape (2, 3, 4)
x = torch.FloatTensor([1, 4]) # (2)
y = torch.FloatTensor([2, 5]) # (2)
z = torch.FloatTensor([3, 6]) # (2)
print(torch.cat([x.unsqueeze(0), y.unsqueeze(0), z.unsqueeze(0)], dim=0)) # (3,2)
print(torch.stack([x, y, z])) # (3,2)
print(torch.stack([x, y, z], dim=1)) # (2,3)
#--------------------------
tensor([[1., 4.],
[2., 5.],
[3., 6.]])
tensor([[1., 4.],
[2., 5.],
[3., 6.]])
tensor([[1., 2., 3.],
[4., 5., 6.]])
14. torch.ones_like
& torch.zeros_like
x = torch.FloatTensor([[0, 1, 2], [2, 1, 0]])
print(x)
print(torch.ones_like(x))
print(torch.zeros_like(x))
#--------------------------
tensor([[0., 1., 2.],
[2., 1., 0.]])
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[0., 0., 0.],
[0., 0., 0.]])
15. Linear Regression (naive)
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
torch.manual_seed(1)
x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])
# 가중치 0으로 초기화 & requires_grad 통해 학습 대상으로 설정!
W = torch.zeros(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)
# prediction
y_pred = x_train * W + b
# loss & optimizer
loss = torch.mean((y_pred - y_train) ** 2)
optimizer = optim.SGD([W, b], lr=0.01)
# z/b/s
optimizer.zero_grad()
loss.backward()
optimizer.step()
[ Summary ]
- [z/b/x] 매 epoch마다, backward & optimize하기 이전에 zero_grad() 해주기
nb_epochs=1999
for epoch in range(nb_epochs + 1):
y_pred = x_train * W + b
loss = torch.mean((y_pred - y_train) ** 2)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print('Epoch {:4d}/{} W: {:.3f}, b: {:.3f} Cost: {:.6f}'.format(
epoch, nb_epochs, W.item(), b.item(), loss.item()))
16. Linear Regression (nn.Module)
- 이미 구현되어져 제공되고 있는 함수들을 사용
- model :
nn.Linear()
- loss :
nn.functional.mse_loss()
- model :
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(1)
x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])
model = nn.Linear(3,1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
nb_epochs = 2000
for epoch in range(nb_epochs+1):
y_pred = model(x_train)
loss = F.mse_loss(y_pred, y_train)
optimizer.zero_grad()
loss.backward() # backward 연산
optimizer.step()
if epoch % 100 == 0:
print('Epoch {:4d}/{} Cost: {:.6f}'.format(
epoch, nb_epochs, cost.item()))
new_var = torch.FloatTensor([[73, 80, 75]])
pred_y = model(new_var)
print(pred_y)
print(list(model.parameters()))
#------------------------------------------
tensor([[151.2305]], grad_fn=<AddmmBackward>)
[Parameter containing:
tensor([[0.9778, 0.4539, 0.5768]], requires_grad=True), Parameter containing:
tensor([0.2802], requires_grad=True)]
17. Linear Regression (Class)
class MultivariateLinearRegressionModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(3, 1)
def forward(self, x):
return self.linear(x)
model = MultivariateLinearRegressionModel()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-5)
18. Mini Batch & Data Loader
dataset=TensorDataset(x_train, y_train)
DataLoader(dataset, batch_size=2, shuffle=True)
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])
dataset = TensorDataset(x_train, y_train)
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
for epoch in range(nb_epochs + 1):
for batch_idx, samples in enumerate(dataloader):
xxxxx
19. Custom Dataset
torch.utils.data.Dataset
을 상속받아 직접 커스텀 데이터셋(Custom Dataset)을 만들기- 아래의 method들을 override 하여 Custom Dataset 만들기
class CustomDataset(torch.utils.data.Dataset):
def __init__(self):
# 데이터셋의 전처리를 해주는 부분
def __len__(self):
# 데이터셋의 길이. 즉, 총 샘플의 수를 적어주는 부분
def __getitem__(self, idx):
# 데이터셋에서 특정 1개의 샘플을 가져오는 함수
20. Linear Regression (with Custom Dataset)
class CustomDataset(Dataset):
def __init__(self):
self.x_data = [[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]]
self.y_data = [[152], [185], [180], [196], [142]]
def __len__(self):
return len(self.x_data)
def __getitem__(self, idx):
x = torch.FloatTensor(self.x_data[idx])
y = torch.FloatTensor(self.y_data[idx])
return x, y
dataset = CustomDataset()
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
21. Softmax
F.softmax(xxx, dim=0)
z = torch.rand(3, 5, requires_grad=True)
y_pred = F.softmax(z, dim=1) # (행,열)에서 "열" 기준이므로, "행"의 합이 1
print(y_pred)
#--------------------------
tensor([[0.2645, 0.1639, 0.1855, 0.2585, 0.1277],
[0.2430, 0.1624, 0.2322, 0.1930, 0.1694],
[0.2226, 0.1986, 0.2326, 0.1594, 0.1868]], grad_fn=<SoftmaxBackward>)
22. One-hot Encoding ( scatter_
)
y = torch.randint(5, (3,)).long()
print(y)
#--------------------------
tensor([0, 2, 1])
[ One-hot Encoding 하기 ]
y_one_hot = torch.zeros_like(y_pred) # 크기 : (3x5)
y_one_hot.scatter_(1, y.unsqueeze(1), 1)
print(y_one_hot)
#--------------------------
tensor([[1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 1., 0., 0., 0.]])
23. Softmax의 loss function 구하기
F.log_softmax()
- F.softmax() + torch.log() = F.log_softmax()
a=torch.log(F.softmax(z, dim=1))
b=F.log_softmax(z, dim=1)
a==b
F.cross_entropy()
- F.log_softmax() + F.nll_loss() = F.cross_entropy()
a=(y_one_hot * -torch.log(F.softmax(z, dim=1))).sum(dim=1).mean()
b=(y_one_hot * - F.log_softmax(z, dim=1)).sum(dim=1).mean()
c=F.nll_loss(F.log_softmax(z, dim=1), y)
d=F.cross_entropy(z, y)
a==b==c==d
24. Softmax Regression (nn.Module)
x_train = [[1, 2, 1, 1],
[2, 1, 3, 2],
[3, 1, 3, 4],
[4, 1, 5, 5],
[1, 7, 5, 5],
[1, 2, 5, 6],
[1, 6, 6, 6],
[1, 7, 7, 7]]
y_train = [2, 2, 2, 1, 1, 1, 0, 0]
x_train = torch.FloatTensor(x_train)
y_train = torch.LongTensor(y_train)
- One-hot 인코딩하기
y_one_hot = torch.zeros(8, 3)
y_one_hot.scatter_(1, y_train.unsqueeze(1), 1)
model = nn.Linear(4, 3)
optimizer = optim.SGD(model.parameters(), lr=0.1)
nb_epochs = 1000
for epoch in range(nb_epochs + 1):
y_pred = model(x_train)
loss = F.cross_entropy(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print('Epoch {:4d}/{} Cost: {:.6f}'.format(
epoch, nb_epochs, cost.item()))
25. Softmax Regression (Class)
class SoftmaxClassifierModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(4, 3) # Output이 3!
def forward(self, x):
return self.linear(x)
model = SoftmaxClassifierModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)
26. MNIST Classification ( Single NN )
import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import torch.nn as nn
import matplotlib.pyplot as plt
import random
- GPU 연산이 가능하다면 GPU를사용
USE_CUDA = torch.cuda.is_available()
device = torch.device("cuda" if USE_CUDA else "cpu")
- Random Seed 고정
random.seed(777)
torch.manual_seed(777)
if device == 'cuda':
torch.cuda.manual_seed_all(777)
- Hyperparameter
training_epochs = 15
batch_size = 100
-
Dataset
-
drop_last =True
-
1000 = 128 x 7개의 batch + 104
( 이 104개를 버리기! 상대적으로 과대평가 되는 것 방지 )
-
mnist_train = dsets.MNIST(root='MNIST_data/',
train=True,
transform=transforms.ToTensor(),
download=True)
mnist_test = dsets.MNIST(root='MNIST_data/',
train=False,
transform=transforms.ToTensor(),
download=True)
data_loader = DataLoader(dataset=mnist_train,
batch_size=batch_size,
shuffle=True,
drop_last=True) # 마지막 batch를 버리기
- model (
to()
: 연산을 어디서 수행할지 결정 )
linear = nn.Linear(784, 10, bias=True).to(device)
- Loss Function & Optimizer
nn.CrossEntropyLoss()
: 내부적으로 softmax 이미 포함torch.nn.functional.cross_entropy()
와 동일
criterion = nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.SGD(linear.parameters(), lr=0.1)
-
Train
-
여기서 y는 one-hot encoding 되지 않은 label이다 ( 0 ~9 중 하나 )
(
nn.CrossEntropyLoss()
가 알아서 내재잭으로 one-hot encoding 해준 뒤 연산 )
-
for epoch in range(training_epochs):
avg_cost = 0
total_batch = len(data_loader) # ( = 전체 data 개수 / batch 1개 당 개수 )
for X, Y in data_loader:
X = X.view(-1, 28 * 28).to(device) # (100,784)
Y = Y.to(device)
#------------------------------
y_pred = linear(X)
loss = criterion(y_pred, Y)
#------------------------------
optimizer.zero_grad()
loss.backward()
optimizer.step()
#------------------------------
avg_cost += cost / total_batch
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))
- Test
torch.no_grad()
: gradient 계산 안함
with torch.no_grad():
X_test = mnist_test.test_data.view(-1, 28 * 28).float().to(device)
Y_test = mnist_test.test_labels.to(device)
y_pred = linear(X_test)
prediction = (torch.argmax(y_pred, 1) == Y_test)
accuracy = prediction.float().mean()
print('Accuracy:', accuracy.item())
27. MNIST Classification ( MLP 1 )
import torch
import torch.nn as nn
from torch import optim
from sklearn.datasets import load_digits
digits = load_digits() # 1,979개의 이미지 데이터 로드
X = digits.data
Y = digits.target
X = torch.tensor(X, dtype=torch.float32)
Y = torch.tensor(Y, dtype=torch.int64)
model = nn.Sequential(
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 16),
nn.ReLU(),
nn.Linear(16, 10)
)
loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters())
losses = []
for epoch in range(100):
y_pred = model(X)
loss = loss_fn(y_pred, Y)
#---------------------------
optimizer.zero_grad()
loss.backward()
optimizer.step()
#---------------------------
if epoch % 10 == 0:
print('Epoch {:4d}/{} Cost: {:.6f}'.format(
epoch, 100, loss.item()))
losses.append(loss.item())
28. MNIST Classification ( MLP 2 )
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/7, random_state=0)
X_train = torch.Tensor(X_train)
X_test = torch.Tensor(X_test)
y_train = torch.LongTensor(y_train)
y_test = torch.LongTensor(y_test)
ds_train = TensorDataset(X_train, y_train)
ds_test = TensorDataset(X_test, y_test)
loader_train = DataLoader(ds_train, batch_size=64, shuffle=True)
loader_test = DataLoader(ds_test, batch_size=64, shuffle=False)
from torch import nn
model = nn.Sequential()
model.add_module('fc1', nn.Linear(28*28*1, 100))
model.add_module('relu1', nn.ReLU())
model.add_module('fc2', nn.Linear(100, 100))
model.add_module('relu2', nn.ReLU())
model.add_module('fc3', nn.Linear(100, 10))
loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01, weight_decay=1e-6)
train 함수
def train(epoch):
model.train()
for data, targets in loader_train:
outputs = model(data)
loss = loss_fn(outputs, targets)
#-------------------------
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("epoch{}:완료\n".format(epoch))
test 함수
def test():
model.eval()
num_correct = 0
with torch.no_grad():
for X, y in loader_test:
y_pred = model(X)
_, y_pred_class = torch.max(y_pred.data, 1) ( value, value index )
num_correct += predicted.eq(y.data.view_as(y_pred_class)).sum()
data_num = len(loader_test.dataset)
print('\n테스트 데이터에서 예측 정확도: {}/{} ({:.0f}%)\n'.format(num_correct,
data_num, 100. * num_correct / data_num))
- train
num_epoch=10
for epoch in range(num_epoch):
train(epoch)
test()
29. Batch Normalization & Layer Normalization
(1) Batch Normalization
.
(2) Layer Normalization
.
30. basics of CNN
(1) Conv2d
- input channel = 1
- output channel = 32
- kernel size = 3 ( = 3x3 )
- padding = 1
conv1 = nn.Conv2d(1, 32, 3, padding=1)
print(conv1)
#-----------------------------------------
Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(2) MaxPool2d
- 정수 하나를 인자로 넣으면, kernel size & stride 모두 해당 값
pool = nn.MaxPool2d(2)
print(pool)
#-----------------------------------------
MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(3) Basic Model & MNIST
import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
device = 'cuda' if torch.cuda.is_available() else 'cpu'
torch.manual_seed(777)
if device == 'cuda':
torch.cuda.manual_seed_all(777)
- hyperparameter
learning_rate = 0.001
training_epochs = 15
batch_size = 100
- dataset & dataloader
mnist_train = dsets.MNIST(root='MNIST_data/',
train=True,
transform=transforms.ToTensor(),
download=True)
mnist_test = dsets.MNIST(root='MNIST_data/',
train=False,
transform=transforms.ToTensor(),
download=True)
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
batch_size=batch_size,
shuffle=True,
drop_last=True)
- CNN
- 기본 구조 : [ (1) Convolution - (2) ReLU - (3) Max Pooling ] x n + [ FC Layer ]
- input : ( batch size 개수, h=28, w=28, c=1 )
class CNN(torch.nn.Module):
def __init__(self):
super(CNN, self).__init__()
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))
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))
self.fc = torch.nn.Linear(7 * 7 * 64, 10, bias=True)
torch.nn.init.xavier_uniform_(self.fc.weight)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = x.view(x.size(0), -1) # Flatten
out = self.fc(x)
return out
model = CNN().to(device)
- Loss Function & Optimizer
criterion = torch.nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
- Train
total_batch = len(data_loader)
for epoch in range(training_epochs):
avg_cost = 0
for X, Y in data_loader:
X = X.to(device)
Y = Y.to(device) # One-hot encoding 되지 "않은" 상태
#---------------------------
y_pred = model(X)
loss = criterion(y_pred, Y)
#---------------------------
optimizer.zero_grad()
loss.backward()
optimizer.step()
avg_cost += cost / total_batch
print('[Epoch: {:>4}] cost = {:>.9}'.format(epoch + 1, avg_cost))
- Test
with torch.no_grad():
X_test = mnist_test.test_data.view(len(mnist_test), 1, 28, 28).float().to(device)
Y_test = mnist_test.test_labels.to(device)
y_pred = model(X_test)
prediction = (torch.argmax(y_pred, 1) == Y_test)
accuracy = prediction.float().mean()
print('Accuracy:', accuracy.item())
31. NLP의 basic
tokenize
- 주어진 텍스트를 단어/문자 단위로 나누는 것
- 영어 package :
spacy
,nltk
- 한글 package :
- 띄어쓰기 기준 :
split
함수
1) 영어 : spaCy
- 예시 문장
english_text = "A Dog Run back corner near spare bedrooms"
- package & tokenizer 불러오기
import spacy
spacy_en = spacy.load('en')
eng_tokenizer = spacy_en.tokenizer
- tokenize하는 함수
def tokenize(text):
return [x.text for x in eng_tokenizer(text)]
- 결과
tokenize(english_text)
#---------------------------------------------------
['A', 'Dog', 'Run', 'back', 'corner', 'near', 'spare', 'bedrooms']
2) 영어 : nltk
- package & tokenizer 불러오기
import nltk
nltk.download('punkt')
from nltk.tokenize import word_tokenize
- 결과
word_tokenize(english_text)
#---------------------------------------------------
['A', 'Dog', 'Run', 'back', 'corner', 'near', 'spare', 'bedrooms']
3) 띄어쓰기로 tokenize
english_text.split()
#---------------------------------------------------
['A', 'Dog', 'Run', 'back', 'corner', 'near', 'spare', 'bedrooms']
4) 한글 : mecab
- 예시 문장
korean_text = "사과의 놀라운 효능이라는 글을 봤어. 그래서 오늘 사과를 먹으려고 했는데 사과가 썩어서 슈퍼에 가서 사과랑 오렌지 사왔어"
-
Mecab
: 형태소(morpheme) 분석기( 한국어는 일반적으로 띄어쓰기가 아닌, “형태소” 단위로 분석 )
!git clone https://github.com/SOMJANG/Mecab-ko-for-Google-Colab.git
%cd Mecab-ko-for-Google-Colab
!bash install_mecab-ko_on_colab190912.sh
from konlpy.tag import Mecab
tokenizer = Mecab()
tokenizer.morphs(korean_text)
#------------------------------------------------
['사과', '의', '놀라운', '효능', '이', '라는', '글', '을', '봤', '어', '.', '그래서', '오늘', '사과', '를', '먹', '으려고', '했', '는데', '사과', '가', '썩', '어서', '슈퍼', '에', '가', '서', '사과', '랑', '오렌지', '사', '왔', '어']
32. 네이버 영화 리뷰 전처리
- 1) pakcage 불러오기
import urllib.request
import pandas as pd
from konlpy.tag import Mecab
from nltk import FreqDist
import numpy as np
- 2) data 다운로드
urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings.txt", filename="ratings.txt")
data = pd.read_table('ratings.txt')
전처리 ( 규불 )
( “규”칙 제거 - “불”용어 제거 - )
-
3-1) 한글, 공백 제외하고 전부제거
( = 영어, 숫자, 특수문자 제거 )
- ”[\^ 여기에 포함시키고 싶은 규칙만 남기기 ]”
- 남길 것 1 :
ㄱ-ㅎ
- 남길 것 2 :
ㅏ-ㅣ
- 남길 것 3 :
가-힣
- 남길 것 1 :
- ”[\^ 여기에 포함시키고 싶은 규칙만 남기기 ]”
data['document'] = data['document'].str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]","")
- 3-2) 불용어 제거
- step 1) 불용어 list 생성
- step 2)
Mecab()
형태소 분석기 사용하여 모든 문장 tokenize - step 3) 각 문장 별로 for loop 돌면서, tokenize한 뒤, 불용어에 속하지 않으면 추가
stopwords=['의','가','이','은','들','는','좀','잘','걍','과','도','를','으로','자','에','와','한','하다']
tokenizer = Mecab()
morphs_tokenizer = tokenizer.morphs
tokenized=[]
for sentence in data['document']:
temp = morphs_tokenizer(sentence) # 토큰화
temp = [word for word in temp if not word in stopwords]
tokenized.append(temp)
- 4) Vocabulary 만들기
FreqDist
로 등장하는 모든 (고유 단어 & 등장 빈도) 확인하기- 등장 빈도 상위 Top N개의 “N”을 설정해주기 ( 여기서는 N = 500 )
from nltk import FreqDist
vocab = FreqDist(np.hstack(tokenized))
vocab_size = 500
vocab = vocab.most_common(vocab_size)
33. Torchtext (1) 영어
pip install torchtext
[ Torchtext가 제공하는 기능들 ]
- File Load
- Tokenizing (토크나이징)
- Vocabulary 생성
- Integer Encoding (정수 인코딩)
- Vector Representation ( 단어를 고유한 embedding vector로 )
- random initialized vector
- pre-trained vector
- Batch ( + Padding )
# from torchtext.data import TabularDataset ( before )
from torchtext.legacy.data import TabularDataset
- 1) data 다운받기 & 불러오기 ( IMDB dataset )
urllib.request.urlretrieve("https://raw.githubusercontent.com/LawrenceDuan/IMDb-Review-Analysis/master/IMDb_Reviews.csv", filename="IMDb_Reviews.csv")
df = pd.read_csv('IMDb_Reviews.csv', encoding='latin1')
- 2) train / test 나누기
train_df = df[:25000]
test_df = df[25000:]
train_df.to_csv("train_data.csv", index=False)
test_df.to_csv("test_data.csv", index=False)
- 3) Field 정의하기 ( 일종의 객체라고 생각하면 됨 )
- 역할 : 각종 텍스트 전처리
- 2개의 Field를 정의한다 ( Text(X) & Label(Y) )
[ 인자 소개 (default)]
- sequential : sequence 데이터 여부 (True)
- use_vocab : vocabulary 집합 만들 지 여부 (True)
- tokenize : 어떤 tokenize 함수를 사용 할지 (string.split)
- lower : 영어 텍스트 소문자화 여부 (False)
- batch_first : batch의 “dimiension”을 맨 앞으로 할 지 (False)
- is_target : y값인지의 여부 (False)
- fix_length : 최대 허용 길이
from torchtext import data
TEXT = data.Field(sequential=True,
use_vocab=True,
tokenize=str.split,
lower=True,
batch_first=True,
fix_length=20)
LABEL = data.Field(sequential=False,
use_vocab=False,
batch_first=False,
is_target=True)
-
4) Dataset 생성
(
TabularDataset
: data를 불러오면서, field에서 정의한 방법대로 tokenize )
[ 인자 소개 ]
- path : file이 위치한 경로
- format : data의 format
- fields : 위에서 정의한 field를 pair ( = (A,B) )로써 지정
- A : field의 호칭
- B : 위에서 생성한 field
- skip_header : data의 first row를 skip
from torchtext.data import TabularDataset
train_data, test_data = TabularDataset.splits(
path='.',
train='train_data.csv', test='test_data.csv',
format='csv',
fields=[('text', TEXT), ('label', LABEL)],
skip_header=True)
- 5) Data 확인하기
print('훈련 샘플의 개수 : {}'.format(len(train_data)))
print('테스트 샘플의 개수 : {}'.format(len(test_data)))
#------------------------------------------------------------
훈련 샘플의 개수 : 25000
테스트 샘플의 개수 : 25000
( 특정 idx의 data 확인하기 )
vars(train_data[0])
#------------------------------------------------------------
{'text': ['my', 'family', 'and', 'i', 'normally', 'do', 'not', 'watch', 'local', 'movies', 'for', 'the', 'simple', 'reason',
... 중략 ...
'movie?', 'congratulations', 'to', 'star', 'cinema!!', 'way', 'to', 'go,', 'jericho', 'and', 'claudine!!'],
'label': '1'}
- 6) Vocabulary 생성
- 위의 1)~4)의 과정으로, tokenize는 완료되었다
- 이제 vocabulary를 생성해보자
[ 인자 소개 ]
- min_freq : vocabulary 사전에 등록되기 위한 최소 등장 횟수
- max_size : vocabulary 사전의 최대 크기
TEXT.build_vocab(train_data, min_freq=10, max_size=10000)
print(len(TEXT.vocab)))
#----------------------------------------------
10002
10,000개가 아니라, 10,0002개인 이유는?
- 10,000개 : 일반적인 vocabulary
- 2개 : special token, <unk>와 <pad>
- <unk> : 단어 집합에 없는 단어 ( 최소 등장횟수 자격요건 충족 X )
- <pad> : 패딩
- 7) Data Loader 생성 (
Iterator
)- 인자 1)
dataset
- 인자 2)
batch_size
- 인자 1)
from torchtext.data import Iterator
batch_size = 5
train_loader = Iterator(dataset=train_data, batch_size = batch_size)
test_loader = Iterator(dataset=test_data, batch_size = batch_size)
( 25000개의 단어 / 배치당 5개 = 5000개의 배치 )
len(train_loader),len(test_loader)
#-----------------------------------
5000,5000
( 첫 번째 mini-batch 뽑아내기 )
- 총 5개의 data가 있음을 알 수 있다 ( \(\because\) batch size = 5 )
- 그 중 첫번째 data를 상세히 확인해보면 뒷부분에 padding (<pad>, index로는 1)이 됨을 알 수 있다.
batch = next(iter(train_loader))
print(batch.text)
print(batch.text[0])
#------------------------------------
tensor([[ 248, 39, 0, 0, 55, 7701, 0, 174, 701, 34, 3, 403,
8, 0, 1480, 0, 2595, 1499, 0, 9],
[ 50, 9, 82, 2294, 2, 0, 26, 6, 1130, 44, 10, 265,
54, 28, 450, 16, 55, 5506, 18, 94],
[ 10, 7, 5302, 2, 119, 25, 206, 0, 0, 95, 309, 1578,
3, 8885, 269, 1373, 0, 8, 0, 4],
[ 2, 256, 122, 5, 10, 0, 0, 3588, 0, 0, 4750, 19,
386, 0, 0, 996, 135, 68, 0, 2],
[ 10, 14, 61, 3, 0, 5, 3, 3536, 9, 202, 11, 42,
3589, 182, 1193, 19, 2608, 269, 4, 641]])
tensor([ 248, 39, 0, 0, 55, 7701, 0, 174, 701, 34, 3, 403,
8, 0, 1480, 0, 2595, 1499, 0, 9, 388, 5068, 6, 73,
... 중략 ...
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
34. Torchtext (2) 한글
( Mecab은 위에 나온대로 설치가 되었다는 가정 하에 )
from konlpy.tag import Mecab
- 1) dataset 다운로드 & 불러오기
urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt", filename="ratings_train.txt")
urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt", filename="ratings_test.txt")
train_df = pd.read_table('ratings_train.txt') # 15만개
test_df = pd.read_table('ratings_test.txt') # 5만개
- 2) Field 정의하기
( 주의 : 전처리를 위한 객체를 마련한 것일 뿐, 아직 전처리를 수행한 것은 아니다 )
from torchtext import data
( 총 3개의 field를 정의한다 )
- 1) ID ( 필수적 X )
- 2) TEXT
- 3) LABEL
tokenizer = Mecab()
morphs_tokenizer = tokenizer.morphs
# 필드 정의
ID = data.Field(sequential = False,
use_vocab = False)
TEXT = data.Field(sequential=True,
use_vocab=True,
tokenize=morphs_tokenizer,
lower=True,
batch_first=True,
fix_length=20)
LABEL = data.Field(sequential=False,
use_vocab=False,
is_target=True)
- 3) Dataset 만들기
- data 불러온 뒤, 위에서 정의한 field대로 전처리(+tokenize)
from torchtext.data import TabularDataset
train_data, test_data = TabularDataset.splits(
path='.',
train='ratings_train.txt', test='ratings_test.txt',
format='tsv',
fields=[('id', ID), ('text', TEXT), ('label', LABEL)],
skip_header=True)
len(train_data),len(test_data)
#------------------------------------
150000,50000
vars(train_data[0])
#-------------------------------------
{'id': '9976970', 'text': ['아', '더', '빙', '.', '.', '진짜', '짜증', '나', '네요', '목소리'], 'label': '0'}
- 4) Vocabulary 생성
TEXT.build_vocab(train_data, min_freq=10, max_size=10000)
- 5) Dataloader 생성 (
Iterator
)
from torchtext.data import Iterator
batch_size = 5
train_loader = Iterator(dataset=train_data, batch_size = batch_size)
test_loader = Iterator(dataset=test_data, batch_size = batch_size)
( 30000,10000 = 15만/5 , 5만/5 )
len(train_loader),len(test_loader)
#------------------------------------
30000,10000
35. Torchtext의 batch_first
batch_first =True
-
따라서, batch size=5가 먼저 나와서
\(\rightarrow\) 1개의 minibatch의 차원은 (5,20)
batch = next(iter(train_loader)) # 1번째 mini-batch
print(batch.text)
#-----------------------------
tensor([[ 31, 191, 24, 133, 445, 115, 42, 10, 149, 2, 3581, 6601,
0, 12, 172, 74, 358, 806, 6, 425],
[ 9, 98, 12, 10, 20, 7, 157, 2520, 285, 11, 1384, 46,
921, 4255, 16, 10, 0, 702, 82, 5],
[ 9, 323, 148, 10, 25, 17, 110, 3109, 80, 44, 291, 4427,
3, 778, 3286, 17, 0, 2, 1308, 193],
[ 10, 7, 49, 8950, 18, 189, 184, 5, 2, 1890, 17, 10,
0, 118, 24, 62, 141, 2, 162, 16],
[ 9, 574, 4312, 1147, 64, 2621, 3, 283, 499, 16, 21, 138,
0, 5, 0, 5994, 2, 1462, 12, 2]])
print(batch.text.shape)
#-----------------------------
torch.Size([5, 20])
batch_first = False
따라서, batch size=5가 뒤에 나와서
\(\rightarrow\) 1개의 minibatch의 차원은 (20,5)
batch = next(iter(train_loader)) # 1번째 mini-batch
print(batch.text)
#-----------------------------
tensor([[ 31, 9, 9, 10, 9],
[ 191, 98, 323, 7, 574],
[ 24, 12, 148, 49, 4312],
[ 133, 10, 10, 8950, 1147],
[ 445, 20, 25, 18, 64],
[ 115, 7, 17, 189, 2621],
[ 42, 157, 110, 184, 3],
[ 10, 2520, 3109, 5, 283],
[ 149, 285, 80, 2, 499],
[ 2, 11, 44, 1890, 16],
[3581, 1384, 291, 17, 21],
[6601, 46, 4427, 10, 138],
[ 0, 921, 3, 0, 0],
[ 12, 4255, 778, 118, 5],
[ 172, 16, 3286, 24, 0],
[ 74, 10, 17, 62, 5994],
[ 358, 0, 0, 141, 2],
[ 806, 702, 2, 2, 1462],
[ 6, 82, 1308, 162, 12],
[ 425, 5, 193, 16, 2]])
print(batch.text.shape)
#-----------------------------
torch.Size([20,5])
36. nn.Embedding()
Embedding vector를 사용하는 2가지 방법
-
1) Embedding Layer를 만든 뒤, 학습하기
\(\rightarrow\)
nn.Embedding()
-
2) pre-traeind Word Embedding Vector 사용하기
알아야 할 것들
-
Embedding Layer의 input이 되기 위해선, 모든 단어들이 Integer Encoding (정수 인코딩)이 되어 있어야!
( 단어 \(\rightarrow\) 단어 정수 idx\(\rightarrow\) Embedding Layer 통과 \(\rightarrow\) Dense Vector )
..
- 1) data 준비하기 & Integer Encoding
train_data = 'you need to know how to code'
vocab_list = set(train_data.split())
vocab = {tkn: i+2 for i, tkn in enumerate(vocab_list)}
vocab['<unk>'] = 0
vocab['<pad>'] = 1
- 2) Embedding Table 만들기 ( 아직 학습되지 않은 상태 )
[ 인자 소개 ]
-
num_embeddings : input dimension의 크기 ( = vocabulary 고유 단어 개수 )
-
embedding_dim : output dimension의 크기
( 원하는 embedding vector의 dimension )
-
padding_idx : <pad>의 인덱스를 알려줌
import torch.nn as nn
embedding_layer = nn.Embedding(num_embeddings = len(vocab),
embedding_dim = 3,
padding_idx = 1)
embedding_layer.weight
#------------------------------------------------------------
Parameter containing:
tensor([[-0.1778, -1.9974, -1.2478],
[ 0.0000, 0.0000, 0.0000],
[ 1.0921, 0.0416, -0.7896],
[ 0.0960, -0.6029, 0.3721],
[ 0.2780, -0.4300, -1.9770],
[ 0.0727, 0.5782, -3.2617],
[-0.0173, -0.7092, 0.9121],
[-0.4817, -1.1222, 2.2774]], requires_grad=True)
37. Pre-trained Word Embedding
nn.Embedding()
을 사용하는 것보다,
다른 data로 이미 사전 훈련되어 있는 Embedding vector를 사용하는 것이 더 나을 수도!
-
1) 사전학습된 weight 불러오기 ( = Embedding vector )
( 확인으로 수행한 것일 뿐, 꼭 이렇게 불러올 필요는 없다 )
from gensim.models import KeyedVectors
pretrained_w2v = KeyedVectors.load_word2vec_format('eng_w2v')
- 2) 데이터 불러오기
from torchtext import data, datasets
TEXT = data.Field(sequential=True, batch_first=True, lower=True)
LABEL = data.Field(sequential=False, batch_first=True)
trainset, testset = datasets.IMDB.splits(TEXT, LABEL)
- 3) 사전 학습된 weight를 초기값으로 설정하기
build_vocab(vectors=xxx)
nn.Embedding.from_pretrained
from torchtext.vocab import Vectors
pretrained_vectors = Vectors(name="eng_w2v")
TEXT.build_vocab(trainset,
vectors=pretrained_vectors,
max_size=10000,
min_freq=10)
embedding_layer = nn.Embedding.from_pretrained(TEXT.vocab.vectors, freeze=False)
( example : “this”의 Embedding Vector는? )
TEXT.vocab.vectors[10]
#------------------------------------------------------------------------
tensor([-0.4860, 2.4053, -0.8451, -0.6362, -0.0984, 0.9017, -1.8017, -2.4730,
... 중략 ...
0.0685, 2.3219, -1.2140, -1.2776])
embedding_layer(torch.LongTensor([10])
#------------------------------------------------------------------------
tensor([[-0.4860, 2.4053, -0.8451, -0.6362, -0.0984, 0.9017, -1.8017, -2.4730,
... 중략 ...
0.0685, 2.3219, -1.2140, -1.2776]], grad_fn=<EmbeddingBackward>)
38. Pre-trained Word Embedding 종류들
- fasttext.en.300d
- fasttext.simple.300d
- glove.42B.300d
- glove.840B.300d
- glove.twitter.27B.25d
- glove.twitter.27B.50d
- glove.twitter.27B.100d
- glove.twitter.27B.200d
- glove.6B.50d
- glove.6B.100d
- glove.6B.200d
- glove.6B.300d
39. RNN basic
.
\(\begin{aligned} &h_{t}=\tanh \left(W_{x} x_{t}+W_{h} h_{t-1}+b\right) \\ &y_{t}=f\left(W_{y} h_{t}+b\right) \end{aligned}\).
[ 차원 정리 ]
\(\begin{aligned} &x_{t}:(d \times 1) \\ &W_{x}:\left(D_{h} \times d\right) \\ &W_{h}:\left(D_{h} \times D_{h}\right) \\ &h_{t-1}:\left(D_{h} \times 1\right) \\ &b:\left(D_{h} \times 1\right) \end{aligned}\).
40. Pytorch RNN ( LSTM )
LSTM은 , nn.RNN
대신 nn.LSTM
만 사용하면 전부 동일하다!
import torch
import torch.nn as nn
input_size = 5 # d
hidden_size = 8 # Dh
Example
- 크기: (batch_size, time_steps, input_size)
inputs = torch.Tensor(1, 10, 5)
RNN
cell_shallow = nn.RNN(input_size, hidden_size, batch_first=True)
cell_deep = nn.RNN(input_size, hidden_size, num_layers = 2, batch_first=True)
cell_deep_bi = nn.RNN(input_size, hidden_size, num_layers = 2,
batch_first=True,bidirectional = True)
Result
y, h = cell_shallow(inputs)
print(y.shape)
print(h.shape)
#-------------------
torch.Size([1, 10, 8]) # 모든 time step에서의 output ( hidden state들 )
torch.Size([1, 1, 8]) # 마지막 time step에서의 output ( hidden state )
y, h = cell_deep(inputs)
print(y.shape)
print(h.shape)
#-------------------
torch.Size([1, 10, 8]) # 모든 time step에서의 output ( hidden state들 ) ... 불변
torch.Size([2, 1, 8]) # 마지막 time step에서의 output ( hidden state ) ... 1x(2)
y, h = cell_deep_bi(inputs)
print(y.shape)
print(h.shape)
#-------------------
torch.Size([1, 10, 16]) # 모든 time step에서의 output ( hidden state들 ) .. 16=8x2
torch.Size([4, 1, 8]) # 마지막 time step에서의 output ( hidden state ) ... 1x(2x2)
41. Pytorch CharRNN ( 텍스트 생성 )
- 1) import packages
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
- 2) dataset
input_str = 'apple'
label_str = 'pple!'
vocab = sorted(list(set(input_str+label_str)))
vocab_size = len(char_vocab)
- 3) hyperparameter
input_size = vocab_size
hidden_size = 5
output_size = 5
learning_rate = 0.1
- 4) Integer Encoding ( + inverse 버전)
char_to_index = dict((char, idx) for idx, char in enumerate(vocab))
index_to_char={}
for key, value in char_to_index.items():
index_to_char[value] = key
x_data = [char_to_index[c] for c in input_str]
y_data = [char_to_index[c] for c in label_str]
print(x_data)
print(y_data)
#---------------------------------------
[1, 4, 4, 3, 2] # a, p, p, l, e에 해당
[4, 4, 3, 2, 0] # p, p, l, e, !에 해당
( Pytorch는 3차원 tensor를 input으로 받기 때문에 ( 맨 앞에 batch size) , batch dimension을 추가해준다 & one-hot encoding해준다 )
x_data = [x_data]
y_data = [y_data]
x_one_hot = [np.eye(vocab_size)[x] for x in x_data]
print(x_one_hot)
#---------------------------------------
[array([[0., 1., 0., 0., 0.],
[0., 0., 0., 0., 1.],
[0., 0., 0., 0., 1.],
[0., 0., 0., 1., 0.],
[0., 0., 1., 0., 0.]])]
X = torch.FloatTensor(x_one_hot)
Y = torch.LongTensor(y_data)
X.shape,Y.shape
#---------------------------------------
torch.Size([1, 5, 5]), torch.Size([1, 5])
- 5) 모델 생성
class Net(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(Net, self).__init__()
self.rnn = torch.nn.RNN(input_size, hidden_size, batch_first=True)
self.fc = torch.nn.Linear(hidden_size, output_size, bias=True)
def forward(self, x):
x, _status = self.rnn(x)
x = self.fc(x)
return x
net = Net(input_size, hidden_size, output_size)
outputs = net(X)
print(outputs.shape)
print(outputs.view(-1, input_size).shape)
#-----------------------------
torch.Size([1, 5, 5]) # 3차원 ( batch 차원 O )
torch.Size([5, 5]) # 2차원 ( batch 차원 X )
위에서 size(5,5)의 의미?
- 앞의 5 : time step
- 뒤의 5 : 출력의 dimension
- 2) loss function & optimizer
loss_fn = torch.nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), learning_rate)
- 3) train
view
: Batch 차원 제거 위해
for i in range(100):
outputs = net(X)
loss = loss_fn(outputs.view(-1, input_size), Y.view(-1))
#----------------------
# zbs
optimizer.zero_grad()
loss.backward()
optimizer.step()
#----------------------
print(i, "loss: ", loss.item())
42. Pytorch Word RNN ( 텍스트 생성 )
RNN의 입력 단위가 “문자” 가 아닌 “단어” 로
\(\rightarrow\) pytorch의 nn.Embedding()
을 사용하기!
- 1) dataset
sentence = "Repeat is the best medicine for memory".split()
vocab = list(set(sentence))
print(vocab)
#----------------------------------------------
['best', 'memory', 'the', 'is', 'for', 'medicine', 'Repeat']
- 2) Integer Encoding
word2index = {tkn: i for i, tkn in enumerate(vocab, 1)}
word2index['<unk>']=0
index2word = {v: k for k, v in word2index.items()}
- 3)
build_data
함수- word \(\rightarrow\) integer 인코딩
- X,y반환
unsqueeze(0)
하는 이유 : batch 차원 추가 위해- 정수 encoding이기 때문에,
torch.LongTensor
를 사용
def build_data(sentence, word2index):
encoded = [word2index[token] for token in sentence]
X, Y = encoded[:-1], encoded[1:]
X = torch.LongTensor(input_seq).unsqueeze(0)
Y = torch.LongTensor(label_seq).unsqueeze(0)
return X, Y
X, Y = build_data(sentence, word2index)
- 4) hyperparameter
vocab_size = len(word2index) # vocabulary 개수 ( 고유 단어 개수 + 1)
input_size = 5
hidden_size = 20
- 5) 모델
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):
y = self.embedding_layer(x)
y, h = self.rnn_layer(output)
y = self.linear(y)
return y.view(-1, y.size(2))
model = Net(vocab_size, input_size, hidden_size, batch_first=True)
loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adam(params=model.parameters())
- 6) 정수 list \(\rightarrow\) 단어 list로 변환해주는 함수
decode = lambda y: [index2word.get(x) for x in y]
- 7) train
for step in range(201):
Y_pred = model(X)
loss = loss_fn(Y_pred, Y.view(-1))
optimizer.zero_grad()
loss.backward()
optimizer.step()
if step % 40 == 0:
print("[{:02d}/201] {:.4f} ".format(step+1, loss))
pred = output.softmax(-1).argmax(-1).tolist()
print(" ".join(["Repeat"] + decode(pred)))
print()
[01/201] 2.0184
Repeat the the the the medicine best
[41/201] 1.3917
Repeat is the best medicine for memory
[81/201] 0.7013
Repeat is the best medicine for memory
[121/201] 0.2992
Repeat is the best medicine for memory
[161/201] 0.1552
Repeat is the best medicine for memory
[201/201] 0.0964
Repeat is the best medicine for memory
43. Pytorch Sentiment Classification (다대일)
- 1) import packages
import os
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchtext import data, datasets
import random
SEED = 5
random.seed(SEED)
torch.manual_seed(SEED)
- 2) hyperparameters
BATCH_SIZE = 64
lr = 0.001
EPOCHS = 10
USE_CUDA = torch.cuda.is_available()
DEVICE = torch.device("cuda" if USE_CUDA else "cpu")
-
3) Field 정의하기
-
torchtext.data
의 Field클래스 사용( 전처리를 위한 객체 사용 )
-
TEXT = data.Field(sequential=True, batch_first=True, lower=True)
LABEL = data.Field(sequential=False, batch_first=True)
-
4) dataset 불러오기
-
torchtext.datasets
에서 제공하는 IMDB 데이터셋 아용 -
default 비율 = (8:2)
-
trainset, testset = datasets.IMDB.splits(TEXT, LABEL)
( 첫 번째 sample 확인해보기 )
vars(trainset[0])
#------------------------------------------------------------
{'text': ['if', 'you', 'like', 'jamie', 'foxx,(alvin', 'sanders),"date', 'from', 'hell",\'01,', 'you', 'will', 'love', 'his', 'acting', 'as', 'a', 'guy', 'who', 'never', 'gets', 'an', 'even', 'break', 'in', 'life', 'and', 'winds', 'up', 'messing', 'around', 'with', 'shrimp,', '(jumbo', 'size)', 'and', 'at', 'the', 'same', 'time', 'lots', 'of', 'gold', 'bars.', 'alvin', 'sanders', 'has', 'plenty', 'of', 'fbi', 'eyes', 'watching', 'him', 'and', 'winds', 'up', 'getting', 'hit', 'by', 'a', 'brick', 'in', 'the', 'jaw,', 'and', 'david', 'morse,(edgar', 'clenteen),', '"hack"', "'02", 'tv', 'series,', 'decides', 'to', 'zero', 'in', 'on', 'poor', 'alvin', 'and', 'use', 'him', 'as', 'a', 'so', 'called', 'fish', 'hook', 'to', 'attract', 'the', 'criminals.', 'there', 'is', 'lots', 'of', 'laughs,', 'drama,', 'cold', 'blood', 'killings', 'and', 'excellent', 'film', 'locations', 'and', 'plenty', 'of', 'expensive', 'cars', 'being', 'sent', 'to', 'the', 'junk', 'yard.', 'jamie', 'foxx', 'and', 'david', 'morse', 'were', 'outstanding', 'actors', 'in', 'this', 'film', 'and', 'it', 'was', 'great', 'entertainment', 'through', 'out', 'the', 'entire', 'picture.'],
'label': 'pos'}
- 5) Vocabulary 만들기
TEXT.build_vocab(trainset, min_freq=5) # 단어 집합 생성
LABEL.build_vocab(trainset)
vocab_size = len(TEXT.vocab)
n_classes = 2
- 6) Data Loader 생성
- train : val : test = 0.8x0.8 : 0.8x0.2 : 0.2
trainset, valset = trainset.split(split_ratio=0.8)
( 단어를 index로 대체하여 사용하는 BucketIterator
)
train_iter, val_iter, test_iter = data.BucketIterator.splits(
(trainset, valset, testset),
batch_size=BATCH_SIZE,
shuffle=True, repeat=False)
( 크기 확인 )
print('훈련 데이터의 미니 배치의 개수 : {}'.format(len(train_iter)))
print('테스트 데이터의 미니 배치의 개수 : {}'.format(len(test_iter)))
print('검증 데이터의 미니 배치의 개수 : {}'.format(len(val_iter)))
#----------------------------------------------------------------
훈련 데이터의 미니 배치의 개수 : 313
테스트 데이터의 미니 배치의 개수 : 391
검증 데이터의 미니 배치의 개수 : 79
- 7) 첫 번째 minibatch 확인하기
- size = ( batch size x 해당 배치 내에서 최대 길이 )
- “해당 배치 내에서 최대 길이”이므로, batch별로 크기가 다를 수 있다
# 1번째
batch = next(iter(train_iter))
print(batch.text.shape)
#----------------------------------------------------------------
torch.Size([64, 968])
# 2번째
batch = next(iter(train_iter))
print(batch.text.shape)
#----------------------------------------------------------------
torch.Size([64, 873])
- 8) 모델
_init_state
: 특정 state를 0으로 초기화
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))
x, _ = self.gru(x, h_0) # GRU output의 shape : (batch size, seq length, hidden dim)
h_t = x[:,-1,:] # 마지막 time step것만 가져오기
h_t=self.dropout(h_t)
logit = self.out(h_t) # (배치 batch, hidden dim) -> (배치 batch, output dim)
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_()
model = GRU(1, 256, vocab_size, 128, n_classes, 0.5).to(DEVICE)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
- 9) train & evaluate 함수
def train(model, optimizer, train_iter):
model.train()
for _, batch in enumerate(train_iter):
x, y = batch.text.to(DEVICE), batch.label.to(DEVICE)
y.data.sub_(1) # label을 0/1로 치환
#-------------------------------
logit = model(x)
loss = F.cross_entropy(logit, y)
#-------------------------------
optimizer.zero_grad()
loss.backward()
optimizer.step()
def evaluate(model, val_iter):
model.eval()
corrects, total_loss = 0, 0
for batch in val_iter:
x, y = batch.text.to(DEVICE), batch.label.to(DEVICE)
y.data.sub_(1)
#-------------------------------
logit = model(x)
loss = F.cross_entropy(logit, y, reduction='sum')
#-------------------------------
total_loss += loss.item()
corrects += (logit.max(1)[1].view(y.size()).data == y.data).sum()
size = len(val_iter.dataset) # batch의 개수
avg_loss = total_loss / size
avg_accuracy = 100.0 * corrects / size
return avg_loss, avg_accuracy
- 10) 학습하기 & best weight 저장하기
best_val_loss = None
for e in range(1, EPOCHS+1):
# (1) train
train(model, optimizer, train_iter)
# (2) evaluate
val_loss, val_accuracy = evaluate(model, val_iter)
print("[Epoch: %d] val loss : %5.2f | val accuracy : %5.2f" % (e, val_loss, val_accuracy))
# (3) save models
if not best_val_loss or val_loss < best_val_loss:
if not os.path.isdir("snapshot"):
os.makedirs("snapshot")
torch.save(model.state_dict(), './snapshot/txtclassification.pt')
best_val_loss = val_loss
- 11) best weight 불러오기
# model = GRU(1, 256, vocab_size, 128, n_classes, 0.5).to(DEVICE)
model.load_state_dict(torch.load('./snapshot/txtclassification.pt'))
test_loss, test_acc = evaluate(model, test_iter)
44. Pytorch Sequence Labeling (다대다)
- 입력 시퀀스 \(\mathrm{X}=\left[x_{1}, x_{2}, x_{3}, \ldots, x_{n}\right]\)
- 레이블 시퀀스 \(\mathrm{y}=\left[y_{1}, y_{2}, y_{3}\right.\) \(\left.\ldots, y_{n}\right]\) 를 각각 부여
.
task : 품사 태깅(PoS tagging)
- 1) packages 불러오기
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchtext import data
from torchtext import datasets
import time
import random
SEED = 1234
random.seed(SEED)
torch.manual_seed(SEED)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- 2) Field 정의하기
TEXT = data.Field(lower = True)
UD_TAGS = data.Field(unk_token = None)
PTB_TAGS = data.Field(unk_token = None)
- 3) Dataset 만들기
torchtext.datasets
에서 제공하는 UDPOS 데이터셋- train/valid/test로 나눈다
fields = (("text", TEXT), ("udtags", UD_TAGS), ("ptbtags", PTB_TAGS))
train_data, valid_data, test_data = datasets.UDPOS.splits(fields)
print(f"훈련 샘플의 개수 : {len(train_data)}")
print(f"검증 샘플의 개수 : {len(valid_data)}")
print(f"테스트 샘플의 개수 : {len(test_data)}")
#-----------------------------------------
훈련 샘플의 개수 : 12543
검증 샘플의 개수 : 2002
테스트 샘플의 개수 : 2077
- 4) label ( = 품사 ) 확인하기
vars(train_data.examples[0])['udtags']
#----------------------------------------------------
['PROPN', 'PUNCT', 'PROPN', 'PUNCT', 'ADJ', 'NOUN', 'VERB', 'PROPN', 'PROPN', 'PROPN', 'PUNCT', 'PROPN', 'PUNCT', 'DET', 'NOUN', 'ADP', 'DET', 'NOUN', 'ADP', 'DET', 'NOUN', 'ADP', 'PROPN', 'PUNCT', 'ADP', 'DET', 'ADJ', 'NOUN', 'PUNCT']
- 5) Vocabulary 만들기
- pre-trained Glove 사용
TEXT.build_vocab(train_data, min_freq = 5, vectors = "glove.6B.100d")
UD_TAGS.build_vocab(train_data)
PTB_TAGS.build_vocab(train_data)
- 6) Data Loader 만들기
BATCH_SIZE = 64
train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
(train_data, valid_data, test_data),
batch_size = BATCH_SIZE,
device = device)
- 7) 첫 번째 batch 확인
- size = (46,64)
- 46 : 해당 batch내의 최대 문장 길이
- 64 :
batch_first=False
이므로, 두 번째 차원이 batch size(=64)이다
- size = (46,64)
batch = next(iter(train_iterator))
batch.text.shape
#----------------------------------------
torch.Size([46, 64])
batch.text
#----------------------------------------
tensor([[ 732, 167, 2, ..., 2, 59, 668],
[ 16, 196, 133, ..., 2991, 46, 1],
[ 1, 29, 48, ..., 1582, 12, 1],
...,
[ 1, 1, 1, ..., 1, 1, 1],
[ 1, 1, 1, ..., 1, 1, 1],
[ 1, 1, 1, ..., 1, 1, 1]], device='cuda:0')
- 8) Model
class RNNPOSTagger(nn.Module):
def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers, bidirectional, dropout):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embedding_dim)
self.rnn = nn.LSTM(embedding_dim, hidden_dim, num_layers = n_layers, bidirectional = bidirectional)
self.fc = nn.Linear(hidden_dim * 2 if bidirectional else hidden_dim, output_dim)
self.dropout = nn.Dropout(dropout)
def forward(self, text):
# (크기) text = [sent len, batch size]
# (크기) embedded = [sent len, batch size, emb dim]
embedded = self.dropout(self.embedding(text))
# (크기) output = [sent len, batch size, hid dim * n directions]
outputs, (hidden, cell) = self.rnn(embedded)
# (크기) predictions = [sent len, batch size, output dim]
predictions = self.fc(self.dropout(outputs))
return predictions
- 9) Hyperparameters
INPUT_DIM = len(TEXT.vocab) # vocabulary의 개수
EMBEDDING_DIM = 100
HIDDEN_DIM = 128
OUTPUT_DIM = len(UD_TAGS.vocab)
N_LAYERS = 2
BIDIRECTIONAL = True
DROPOUT = 0.25
model = RNNPOSTagger(INPUT_DIM,
EMBEDDING_DIM,
HIDDEN_DIM,
OUTPUT_DIM,
N_LAYERS,
BIDIRECTIONAL,
DROPOUT)
- 10) pre-trained embedding 사용하기
pretrained_embeddings = TEXT.vocab.vectors
model.embedding.weight.data.copy_(pretrained_embeddings)
# unknown(0) & padding(1) 토큰 추가하기
UNK_IDX = TEXT.vocab.stoi[TEXT.unk_token]
PAD_IDX = TEXT.vocab.stoi[TEXT.pad_token]
model.embedding.weight.data[UNK_IDX] = torch.zeros(EMBEDDING_DIM) # 0번 임베딩 벡터에는 0값을 채운다.
model.embedding.weight.data[PAD_IDX] = torch.zeros(EMBEDDING_DIM) #
- 11) Loss Function & Optimizer
- padding token은 loss 계산에서 제외!
loss_fn = nn.CrossEntropyLoss(ignore_index = TAG_PAD_IDX)
optimizer = optim.Adam(model.parameters())
model = model.to(device)
loss_fn = loss_fn.to(device)
- 12) example prediction
- size (46,64,18)
- 46 : 1번째 batch의 sequence 길이 ( = 최대 문장 길이 )
- 64 : batch size
- 18 : num_classes
- size (46,64,18)
prediction = model(batch.text)
print(prediction.shape)
#------------------------------------
torch.Size([46, 64, 18])
prediction = prediction.view(-1, prediction.shape[-1])
print(prediction.shape)
print(batch.udtags.view(-1).shape)
#------------------------------------
torch.Size([2944, 18])
torch.Size([2944])
- 13) accuracy 계산 함수
def categorical_accuracy(y_pred, y_real_idx, tag_pad_idx):
y_pred_idx = y_pred.argmax(dim = 1, keepdim = True)
mask = (y_real != tag_pad_idx).nonzero()
y_pred_idx=y_pred_idx[mask]
y_real_idx=y_real_idx[mask]
correct = y_pred_idx.squeeze(1).eq(y_real_idx)
return correct.sum() / torch.FloatTensor([y_real_idx.shape[0]])
- 14) train & evaluation 함수
[size]
- text = [sent len, batch size]
-
predictions = [sent len, batch size, output dim] \(\rightarrow\) predictions = [sent len * batch size, output dim]
- tags = [sent len, batch size] \(\rightarrow\) [sent len * batch_size]
def train(model, iterator, optimizer, loss_fn, tag_pad_idx):
epoch_loss = 0
epoch_acc = 0
model.train()
for batch in iterator:
X = batch.text
Y = batch.udtags
#-----------------------------------------
Y_pred = model(X)
Y_pred = Y_pred.view(-1, Y_pred.shape[-1])
Y = Y.view(-1)
loss = loss_fn(Y_pred, Y)
#-----------------------------------------
optimizer.zero_grad()
loss.backward()
optimizer.step()
#-----------------------------------------
acc = categorical_accuracy(Y_pred, Y, tag_pad_idx)
epoch_loss += loss.item()
epoch_acc += acc.item()
return epoch_loss / len(iterator), epoch_acc / len(iterator)
def evaluate(model, iterator, loss_fn, tag_pad_idx):
epoch_loss = 0
epoch_acc = 0
model.eval()
with torch.no_grad():
for batch in iterator:
X = batch.text
Y = batch.udtags
#-----------------------------------------
Y_pred = model(X)
Y_pred = Y_pred.view(-1, Y_pred.shape[-1])
Y = Y.view(-1)
loss = loss_fn(predictions, tags)
#-----------------------------------------
# NO UPDATE
#-----------------------------------------
acc = categorical_accuracy(Y_pred, Y, tag_pad_idx)
epoch_loss += loss.item()
epoch_acc += acc.item()
return epoch_loss / len(iterator), epoch_acc / len(iterator)
- 15) 학습하기
N_EPOCHS = 10
best_valid_loss = float('inf')
for epoch in range(N_EPOCHS):
train_loss, train_acc = train(model, train_iterator, optimizer, loss_fn, TAG_PAD_IDX)
valid_loss, valid_acc = evaluate(model, valid_iterator, loss_fn, TAG_PAD_IDX)
if valid_loss < best_valid_loss:
best_valid_loss = valid_loss
torch.save(model.state_dict(), 'tut1-model.pt')
print(f'Epoch: {epoch+1:02}')
print(f'\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc*100:.2f}%')
print(f'\t Val. Loss: {valid_loss:.3f} | Val. Acc: {valid_acc*100:.2f}%')