Posts
All the articles I've posted.
rnn = torch.nn.RNN(input_size, hidden_size)
outputs, _status = rnn(input_data)
print(outputs)
print(outputs.size())
'''output
tensor([[[-0.7497, -0.6135],
[-0.5282, -0.2473],
[-0.9136, -0.4269],
[-0.9136, -0.4269],
[-0.9028, 0.1180]],
[[-0.5753, -0.0070],
[-0.9052, 0.2597],
[-0.9173, -0.1989],
[-0.9173, -0.1989],
[-0.8996, -0.2725]],
[[-0.9077, -0.3205],
[-0.8944, -0.2902],
[-0.5134, -0.0288],
[-0.5134, -0.0288],
[-0.9127, -0.2222]]], grad_fn=<StackBackward>)
torch.Size([3, 5, 2])
'''RNN Basics
PyTorch에서 RNN은 in/output size만 잘 맞춰주면 바로 사용이 가능하다. "h, e, l, o" 4개의 알파벳으로 이루어진 데이터셋을 통해 2차원의 output(class가 2개)을 내는 RNN을 만들어볼 것이다.
activation과 weight를 명시하여 표현하면 다음과 같다.
Usages of RNN
이런 RNN의 구조를 응용하여 다음과 같은 구조들로 사용할 수 있다.

-
one to many : 하나의 입력을 받아 여러 출력을 내는 구조이다. 하나의 이미지를 받아 그에 대한 설명을 문장(여러개의 단어)으로 출력하는 것을 예로 들 수 있다.
-
many to one : 여러 입력을 받아 하나의 출럭을 내는 구조이다. 문장을 입력받아 그 문장이 나타내는 감정의 label을 출력하는 것을 예로 들 수 있다.
-
many to many : 2가지의 구조가 있는 것을 볼 수 있다.
- 입력이 다 끝나는 지점부터 여러 출력을 내는 구조로, 문장을 입력받아 번역하는 모델을 예로 들 수 있다. 이 경우 문장의 중간에 번역을 진행하면 다 끝나고 나서 문장의 의미가 달라질 수 있기 때문에 먼저 입력 문장을 다 듣고 번역을 진행하게 된다.
- 입력 하나하나를 받으면서 그때마다 모델의 출력을 내는 구조이다. 영상을 처리할 때 frame 단위의 이미지로 나눠 입력을 받은 후 각 frame을 입력 받을 때마다 처리하는 것을 예로 들 수 있다.
RNN intro
RNN은 sequential data를 잘 학습하기 위해 고안된 모델이다. Sequential data란 단어, 문장이나 시게열 데이터와 같이 데이터의 순서도 데이터의 일부인 데이터들을 말한다.
# self.inplanes = 64
# self.layer1 = self._make_layer(block=Bottleneck, 64, layers[0]=3)
def _make_layer(self, block, planes, blocks, stride=1):
downsample = None
# identity 값을 낮춰서 shape을 맞춰주기 위함. channel도 맞춰주기.
if stride != 1 or self.inplanes != planes * block.expansion: # 64 != 64 * 4
downsample = nn.Sequential(
conv1x1(self.inplanes, planes * block.expansion, stride), #conv1x1(256, 512, 2) #conv1x1(64, 256, 2)
nn.BatchNorm2d(planes * block.expansion), #batchnrom2d(512) #batchnrom2d(256)
)
layers = []
layers.append(block(self.inplanes, planes, stride, downsample))
# layers.append(Bottleneck(64, 64, 1, downsample))
self.inplanes = planes * block.expansion #self.inplanes = 128 * 4
for _ in range(1, blocks):
layers.append(block(self.inplanes, planes)) # * 3
return nn.Sequential(*layers)ResNet
Plain network는 skip connection을 사용하지 않은 일반적인 CNN 신경망을 의미한다. 이러한 plain net이 깊어지면 깊어질수록 backpropagation을 할 때 기울기 소실이나 폭발이 발생할 확률이 높아진다.
criterion = nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.SGD(vgg16.parameters(), lr = 0.005,momentum=0.9)
# 학습이 진행됨에 따라 lr 조절
lr_sche = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.9) # optimizer의 step이 5번 진행될 때마다 gamma만큼 곱함
기존과 다른 점은 학습된 정도에 따라 learning rate를 줄이는 코드가 추가되었다는 것이다.

lr_sche.step()이 추가된 것 말고 크게 다른 점은 없다.
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
images = images.to(device)
labels = labels.to(device)
outputs = vgg16(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
Accuracy of the network on the 10000 test images: 75 %VGG
VGG-net(이하 VGG)은 14년도 ILSVRC(Imagenet 이미지 인식 대회)에 나온 네트워크로 옥스포드의 Visual Geometry Group에서 만든 모델이다.
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader
from matplotlib.pyplot import imshow
%matplotlib inline
trans = transforms.Compose([
transforms.Resize((64,128))
])
train_data = torchvision.datasets.ImageFolder(root='custom_data/origin_data', transform=trans)
원본 데이터가 있는 곳을 root로 잡고 Compose를 통해 적용할 transforms들을 묶어 넣어준다. 원본 데이터가 265x512로 너무 커서 64x128로 바꾸어주는 과정을 거친다.
여기서는 하나의 transforms을 사용하지만 어러개를 사용해야할 때 Compose로 묶어 사용할 수 있다.
ImageFolder
torchvision.datasets에 있는 ImageFolder는 directory에 따라 category를 자동으로 labeling 하여 데이터로 만들어 준다. 우리가 찍은 사진을 학습하는데 사용할 때 아주 좋은 기능이다.
MNIST = dsets.MNIST(root="./MNIST_data",train = True,transform=torchvision.transforms.ToTensor(), download=True)
cifar10 = dsets.CIFAR10(root="./cifar10",train = True, transform=torchvision.transforms.ToTensor(),download=True)
#CIFAR10
data = cifar10.__getitem__(0)
print(data[0].shape)
vis.images(data[0],env="main")
# MNIST
data = MNIST.__getitem__(0)
print(data[0].shape)
vis.images(data[0],env="main")

두꺼비(?)와 숫자 5가 잘 나온다. 또한 이런 이미지들도 당연히 vis.images()를 통해 한번에 많은 이미지도 출력할 수 있다.
Visdom
Visdom은 Meta 사(facebook)에서 제공하는 PyTorch에서 사용할 수 있는 시각화 도구이다. 실시간으로 데이터를 시각화하면서 바뀌는 점을 확인할 수 있다는 장점이 있다.
class CNN(torch.nn.Module):
def __init__(self):
super(CNN, self).__init__()
# L1 ImgIn shape=(?, 1, 28, 28)
# Conv -> (?, 32, 28, 28)
# Pool -> (?, 32, 14, 14)
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))
# L2 ImgIn shape=(?, 32, 14, 14)
# Conv ->(?, 64, 14, 14)
# Pool ->(?, 64, 7, 7)
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))
# Final FC 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 them for FC
out = self.fc(out)
return out
model = CNN().to(device)Convolution
강의 자료에서는 '이미지(2차원 매트릭스) 위에서 stride 만큼 filter(kernel)을 이동시키면서 겹쳐지는 부분의 각 원소의 값을 곱해서 더한 값을 출력으로 하는 연산'이라고 나와있다. 자세히 어떤 과정의 연산인지 확인해 보자.
# nn layers
linear1 = torch.nn.Linear(784, 32, bias=True)
linear2 = torch.nn.Linear(32, 32, bias=True)
linear3 = torch.nn.Linear(32, 10, bias=True)
relu = torch.nn.ReLU()
bn1 = torch.nn.BatchNorm1d(32)
bn2 = torch.nn.BatchNorm1d(32)
nn_linear1 = torch.nn.Linear(784, 32, bias=True)
nn_linear2 = torch.nn.Linear(32, 32, bias=True)
nn_linear3 = torch.nn.Linear(32, 10, bias=True)
# model with Batch normalization
bn_model = torch.nn.Sequential(linear1, bn1, relu,
linear2, bn2, relu,
linear3).to(device)
# model without Batch normalization
nn_model = torch.nn.Sequential(nn_linear1, relu,
nn_linear2, relu,
nn_linear3).to(device)
# define cost/loss & optimizer
criterion = torch.nn.CrossEntropyLoss().to(device) # Softmax is internally computed.
bn_optimizer = torch.optim.Adam(bn_model.parameters(), lr=learning_rate)
nn_optimizer = torch.optim.Adam(nn_model.parameters(), lr=learning_rate)Batch Normalization
Gradient Vanishing(기울기 소실)과 Gradient Exploding(기울기 폭주)는 정상적인 학습을 할 수 없게 만드는 요인들이다.
model.train() # set the model to train mode (dropout=True)
for epoch in range(training_epochs):
avg_cost = 0
for X, Y in data_loader:
# reshape input image into [batch_size by 784]
# label is not one-hot encoded
X = X.view(-1, 28 * 28).to(device)
Y = Y.to(device)
optimizer.zero_grad()
hypothesis = model(X)
cost = criterion(hypothesis, Y)
cost.backward()
optimizer.step()
avg_cost += cost / total_batch
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))
print('Learning finished')
'''output
Epoch: 0001 cost = 0.308392197
Epoch: 0002 cost = 0.142623395
Epoch: 0003 cost = 0.113427199
Epoch: 0004 cost = 0.093490042
Epoch: 0005 cost = 0.083772294
Epoch: 0006 cost = 0.077040948
Epoch: 0007 cost = 0.067025252
Epoch: 0008 cost = 0.063156039
Epoch: 0009 cost = 0.058766391
Epoch: 0010 cost = 0.055902217
Epoch: 0011 cost = 0.052059878
Epoch: 0012 cost = 0.048243146
Epoch: 0013 cost = 0.047231019
Epoch: 0014 cost = 0.045120358
Epoch: 0015 cost = 0.040942233
Learning finished
'''Dropout
lab7-1에서 알아본 것처럼 학습을 하다보면 train set에 너무 과적합(overfitting)되는 경우가 발생한다.