Skip to content
CatBus

Posts

All the articles I've posted.

PYTORCHLAB 11-1
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을 만들어볼 것이다.

2022.06.05·5분·rnn
PYTORCHLAB 11-0
ht=f(ht1,xt)h_t=f(h_{t-1}, x_t)

activation과 weight를 명시하여 표현하면 다음과 같다.

ht=tanh(Whht1,Wxxt)h_t=tanh(W_h h_{t-1}, W_x x_t)

Usages of RNN

이런 RNN의 구조를 응용하여 다음과 같은 구조들로 사용할 수 있다.

Usages of RNN

  • one to many : 하나의 입력을 받아 여러 출력을 내는 구조이다. 하나의 이미지를 받아 그에 대한 설명을 문장(여러개의 단어)으로 출력하는 것을 예로 들 수 있다.

  • many to one : 여러 입력을 받아 하나의 출럭을 내는 구조이다. 문장을 입력받아 그 문장이 나타내는 감정의 label을 출력하는 것을 예로 들 수 있다.

  • many to many : 2가지의 구조가 있는 것을 볼 수 있다.

    • 입력이 다 끝나는 지점부터 여러 출력을 내는 구조로, 문장을 입력받아 번역하는 모델을 예로 들 수 있다. 이 경우 문장의 중간에 번역을 진행하면 다 끝나고 나서 문장의 의미가 달라질 수 있기 때문에 먼저 입력 문장을 다 듣고 번역을 진행하게 된다.
    • 입력 하나하나를 받으면서 그때마다 모델의 출력을 내는 구조이다. 영상을 처리할 때 frame 단위의 이미지로 나눠 입력을 받은 후 각 frame을 입력 받을 때마다 처리하는 것을 예로 들 수 있다.

RNN intro

RNN은 sequential data를 잘 학습하기 위해 고안된 모델이다. Sequential data란 단어, 문장이나 시게열 데이터와 같이 데이터의 순서도 데이터의 일부인 데이터들을 말한다.

2022.06.03·3분·rnn
PYTORCHLAB 10-6
    # 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을 할 때 기울기 소실이나 폭발이 발생할 확률이 높아진다.

2022.05.26·25분·cnn
PYTORCHLAB 10-5
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를 줄이는 코드가 추가되었다는 것이다.

Train 설명 그림

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에서 만든 모델이다.

2022.05.25·20분·cnn
PYTORCHLAB 10-4
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 하여 데이터로 만들어 준다. 우리가 찍은 사진을 학습하는데 사용할 때 아주 좋은 기능이다.

2022.05.22·10분·imagefolder
PYTORCHLAB 10-3
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")

MNIST 설명 그림

두꺼비(?)와 숫자 5가 잘 나온다. 또한 이런 이미지들도 당연히 vis.images()를 통해 한번에 많은 이미지도 출력할 수 있다.

Visdom

Visdom은 Meta 사(facebook)에서 제공하는 PyTorch에서 사용할 수 있는 시각화 도구이다. 실시간으로 데이터를 시각화하면서 바뀌는 점을 확인할 수 있다는 장점이 있다.

2022.05.22·8분·visdom
PYTORCHLAB 10-1
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)을 이동시키면서 겹쳐지는 부분의 각 원소의 값을 곱해서 더한 값을 출력으로 하는 연산'이라고 나와있다. 자세히 어떤 과정의 연산인지 확인해 보자.

2022.05.21·10분·convolution
PYTORCHLAB 9-4
# 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(기울기 폭주)는 정상적인 학습을 할 수 없게 만드는 요인들이다.

2022.05.14·6분·batch-normalization
PYTORCHLAB 9-3
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)되는 경우가 발생한다.

2022.05.14·7분·dropout