【Pytorch 실습】 AutoEncoder를 사용한, Fashion Mnist data를 활용

아래의 코드는 Kaggle 및 Git의 공개된 코드를 적극 활용한, 과거의 공부한 내용을 정리한 내용입니다.

Fashion MNIST train, test 데이터셋을 미리 다운로드 할 필요 없음. PS.

  1. jupyter 실행결과도 코드 박스로 출력되어 있습니다.
  2. matplot을 이용해서 이미지를 출력하는 이미지는 첨부하지 않았습니다.

1. Data 다운 받고 torch에 Load 하기.

# torchvision 모듈을 이용해서 데이터 셋을 다운 받을 것이다. 
import torch
from torchvision import transforms, datasets  
BATCH_SIZE = 64

trainset = datasets.FashionMNIST(
    root      = './data/FASHIONMNIST/', 
    train     = True,
    download  = True,
    transform = transforms.ToTensor()
)
train_loader = torch.utils.data.DataLoader(
    dataset     = trainset,
    batch_size  = BATCH_SIZE,
    shuffle     = True,
    num_workers = 2
)

2. 모델 설계하기

from torch import nn, optim

class AE(nn.Module):
    def __init__(self):
        super(AE, self).__init__()

        # 데이터 Feature 뽑기
        self.encoder = nn.Sequential(
            nn.Linear(28*28, 128),
            nn.ReLU(),
            nn.Linear(128, 64),
        )
        
        # Feature를 이용해서 데이터 확장 해보기
        self.decoder = nn.Sequential(
            nn.Linear(64, 128),
            nn.ReLU(),
            nn.Linear(128, 28*28),
        )

    def forward(self, x):
        encoded = self.encoder(x)
        decoded = self.decoder(encoded)
        return encoded, decoded

USE_CUDA = torch.cuda.is_available()
DEVICE = torch.device("cuda" if USE_CUDA else "cpu")

model = AE().to(DEVICE)
optimizer = optim.Adam(model.parameters(), lr = 0.005)
criterion = nn.MSELoss()

print("Model: ", model)
print("Device: ", DEVICE)
Model:  AE(
  (encoder): Sequential(
    (0): Linear(in_features=784, out_features=128, bias=True)
    (1): ReLU()
    (2): Linear(in_features=128, out_features=64, bias=True)
  )
  (decoder): Sequential(
    (0): Linear(in_features=64, out_features=128, bias=True)
    (1): ReLU()
    (2): Linear(in_features=128, out_features=784, bias=True)
  )
)
Device:  cuda
# encoder decoder를 모두 통과한 후의 데이터를 출력해보기 위해서 다음과 같이 데이터 후처리
view_data = trainset.data[:5].view(-1, 28*28)
view_data = view_data.type(torch.FloatTensor) / 255.
# Definite Train & Evaluate
def train(model, train_loader, optimizer):
    model.train()
    for step, (x, label) in enumerate(train_loader):
        x = x.view(-1, 28 * 28).to(DEVICE)
        y = x.view(-1, 28 * 28).to(DEVICE)
        label = label.to(DEVICE)
        
        encoded, decoded = model(x)
        # AutoEncoder를 지나서 자기자신이 되도록 학습된다. 
        # loss값을 y와 'decoded를 정규화한 후'의 값과의 차이로 구했다면 더 좋았을 것 같다. 
        loss = criterion(decoded, y)  
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if step % 100 == 0:
            print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format(epoch, step * len(x), len(train_loader.dataset), 100. * step / len(train_loader), loss.item()))

4. Train 시키기. Train 하면서 중간결과도 출력해보기

''' Training'''
import numpy as np
import matplotlib.pyplot as plt

EPOCHS = 10
for epoch in range(1, EPOCHS + 1):
    train(model, train_loader, optimizer)
    test_x = view_data.to(DEVICE)
    encoded_data, decoded_data = model(test_x)
    f, a = plt.subplots(2, 5, figsize = (10, 4))
    print("[Epoch {}]".format(epoch))

    # 원래 이미지의 사진 출력
    for idx in range(5):
        img = np.reshape(view_data.data.numpy()[idx], (28, 28))
        a[0][idx].imshow(img, cmap = "gray")
        a[0][idx].set_xticks(())
        a[0][idx].set_yticks(())
        
    # Encoder와 Decoder를 모두 통화한 후 사진 출력
    for idx in range(5):
        img = np.reshape(decoded_data.to("cpu").data.numpy()[idx], (28, 28))
        a[1][idx].imshow(img, cmap = "gray")
        a[1][idx].set_xticks(())
        a[1][idx].set_yticks(())
    plt.show()

5. 위에서 압축한 Feature를 가지고 Classification해보자!

  • encodered 데이터를 사용함으로 feature수가 작아지고, Classification 속도가 빨라짐을 알 수 있다.
  • 위에서는 Input과 동일한 Output을 만드는 Autoencoder를 설계했다.
  • 여기서는 Supervised Learnging을 할것이다. Fashion 옷의 Class가 뭔지 예측한다.
# 굳이 모델을 설계하지 않고도, lightgbm이라는 모듈을 사용해서 모델을 학습시킬 수 있다. 이런게 있구나.. 정도로만 알아두기.
# 여기서는 학습이 오래 걸린다. 

import time
import lightgbm as lgb
from sklearn.metrics import accuracy_score
start = time.time() 
lgb_dtrain = lgb.Dataset(data = trainset.train_data.view(-1, 28 * 28).numpy(), label = list(trainset.train_labels.numpy()))
lgb_param = {'max_depth': 10,
            'learning_rate': 0.001,
            'n_estimators': 20,
            'objective': 'multiclass',
            'num_class': len(set(list(trainset.train_labels.numpy()))) + 1}

num_round = 10000
lgb_model = lgb.train(params = lgb_param, num_boost_round = num_round, train_set = lgb_dtrain)              # 여기서 학습을 진행한다. 모델의 파라메터를 학습 완료!
lgb_model_predict = np.argmax(lgb_model.predict(trainset.train_data.view(-1, 28 * 28).numpy()), axis = 1)   # TestDataset은 없고, 그냥 Traindata로 Inference!
print("Accuracy: %.2f" % (accuracy_score(list(trainset.train_labels.numpy()), lgb_model_predict) * 100), "%") 
print("Time: %.2f" % (time.time() - start), "seconds")
c:\users\justin\venv\lib\site-packages\torchvision\datasets\mnist.py:53: UserWarning: train_data has been renamed data
  warnings.warn("train_data has been renamed data")
c:\users\justin\venv\lib\site-packages\torchvision\datasets\mnist.py:43: UserWarning: train_labels has been renamed targets
  warnings.warn("train_labels has been renamed targets")
c:\users\justin\venv\lib\site-packages\lightgbm\engine.py:148: UserWarning: Found `n_estimators` in params. Will use it instead of argument
  warnings.warn("Found `{}` in params. Will use it instead of argument".format(alias))


Accuracy: 82.84 %
Time: 19.64 seconds
# 여기서는 학습이 빨리 이뤄지는 것을 확인할 수 있다.
# 왜냐면, Encoder한 값, 즉 작은 Feature Map Data(784 -> 64)를 사용하기 때문이다.  
# 하지만 낮은 차원의 Feature를 이용해서 학습을 시키므로, 정확도가 떨어지는 것을 확인할 수 있다. 
 
train_encoded_x = trainset.train_data.view(-1, 28 * 28).to(DEVICE)
train_encoded_x = train_encoded_x.type(torch.FloatTensor)
train_encoded_x = train_encoded_x.to(DEVICE)
encoded_data, decoded_data = model(train_encoded_x) # 위에서 만든 모델로 추론한 결과를 아래의 학습에 사용한다! 
encoded_data = encoded_data.to("cpu")

start = time.time() 
lgb_dtrain = lgb.Dataset(data = encoded_data.detach().numpy(), label = list(trainset.train_labels.numpy()))
lgb_param = {'max_depth': 10,
            'learning_rate': 0.001,
            'n_estimators': 20,
            'objective': 'multiclass',
            'num_class': len(set(list(trainset.train_labels.numpy()))) + 1}

num_round = 10000
lgb_model = lgb.train(params = lgb_param, num_boost_round = num_round, train_set = lgb_dtrain)   # 여기서 학습을 진행한다. 모델의 파라메터를 학습 완료!
lgb_model_predict = np.argmax(lgb_model.predict(encoded_data.detach().numpy()), axis = 1)        # TestDataset은 없고, 그냥 Traindata로 Inference!
print("Accuracy: %.2f" % (accuracy_score(list(trainset.train_labels.numpy()), lgb_model_predict) * 100), "%") 
print("Time: %.2f" % (time.time() - start), "seconds") 
Accuracy: 76.07 %
Time: 1.96 seconds

【Pytorch 실습】 Mnist 데이터셋 MLP, CNN으로 학습 및 추론

Mnist 데이터 셋을 다운받고 pytorch를 사용해서 학습 및 추론을 합니다. 아래의 코드는 Kaggle 및 Git의 공개된 코드를 적극 활용한, 과거의 공부한 내용을 정리한 내용입니다.

train, test 파일 다운받는 경로 :
https://www.kaggle.com/oddrationale/mnist-in-csv

PS.

  1. jupyter 실행결과도 코드 박스로 출력되어 있습니다.
  2. matplot을 이용해서 이미지를 출력하는 이미지는 첨부하지 않았습니다.

MLP 이용하기

1. 데이터 로드하기

# Load Dataset
import pandas as pd
train_dataset = pd.read_csv("./mnist_train.csv")
test_dataset = pd.read_csv("./mnist_test.csv")
# Check Train Set
train_dataset.head()
# Split to Image & Label
train_images = (train_dataset.iloc[:, 1:].values).astype("float32")
train_labels = train_dataset["label"].values
test_images = (test_dataset.iloc[:, 1:].values).astype("float32")
# Check Train Data's Image
print(train_images)
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]
# Check Train Data's Label
print(train_labels)
[5 0 4 ... 5 6 8]
# Check Test Data's Image
test_images
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
# Split into Train, Valid Dataset 분리 비율은 8:2
from sklearn.model_selection import train_test_split
train_images, valid_images, train_labels, valid_labels = train_test_split(train_images,
                                                                          train_labels,
                                                                          stratify = train_labels,
                                                                          random_state = 42,
                                                                          test_size = 0.2)
# Check Train, Valid, Test Image's Shape
print("The Shape of Train Images: ", train_images.shape)
print("The Shape of Valid Images: ", valid_images.shape)
print("The Shape of Test Images: ", test_images.shape)
The Shape of Train Images:  (48000, 784)
The Shape of Valid Images:  (12000, 784)
The Shape of Test Images:  (10000, 784)
# Check Train, Valid Label's Shape
print("The Shape of Train Labels: ", train_labels.shape)
print("The Shape of Valid Labels: ", valid_labels.shape)
The Shape of Train Labels:  (38400,)
The Shape of Valid Labels:  (9600,)
# Reshape image's size to check for ours
train_images = train_images.reshape(train_images.shape[0], 28, 28)
valid_images = valid_images.reshape(valid_images.shape[0], 28, 28)
test_images = test_images.reshape(test_images.shape[0], 28, 28)
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-18-f37841568d28> in <module>
      2 train_images = train_images.reshape(train_images.shape[0], 28, 28)
      3 valid_images = valid_images.reshape(valid_images.shape[0], 28, 28)
----> 4 test_images = test_images.reshape(test_images.shape[0], 28, 28)


ValueError: cannot reshape array of size 7850000 into shape (10000,28,28)
# Check Train, Valid, Test Image's Shape after reshape
print("The Shape of Train Images: ", train_images.shape)
print("The Shape of Valid Images: ", valid_images.shape)
print("The Shape of Test Images: ", test_images.shape)
The Shape of Train Images:  (38400, 28, 28)
The Shape of Valid Images:  (9600, 28, 28)
The Shape of Test Images:  (10000, 785)
# Visualize Train, Valid, Test's Images
import matplotlib.pyplot as plt
for idx in range(0, 5):
    plt.imshow(train_images[idx], cmap = plt.get_cmap('gray'))
    plt.title(train_labels[idx])
    plt.show()
for idx in range(0, 5):
    plt.imshow(valid_images[idx], cmap = plt.get_cmap('gray'))
    plt.title(valid_labels[idx])
    plt.show()
for idx in range(0, 5):
    plt.imshow(test_images[idx], cmap = plt.get_cmap('gray'))
    plt.show()

2. Torch를 이용한 데이터 로드, 모델 생성

지금까지 로드한 데이터를 torch.tensor형태로 데이터를 변환해준다.

# Make Dataloader to feed on Multi Layer Perceptron Model
# train과 test 셋을 batch 단위로 데이터를 처리하기 위해서. _loader를 정의 해준다.
import torch
from torch.utils.data import TensorDataset, DataLoader
train_images_tensor = torch.tensor(train_images)
train_labels_tensor = torch.tensor(train_labels)
train_tensor = TensorDataset(train_images_tensor, train_labels_tensor)
train_loader = DataLoader(train_tensor, batch_size = 64, num_workers = 0, shuffle = True)

valid_images_tensor = torch.tensor(valid_images)
valid_labels_tensor = torch.tensor(valid_labels)
valid_tensor = TensorDataset(valid_images_tensor, valid_labels_tensor)
valid_loader = DataLoader(valid_tensor, batch_size = 64, num_workers = 0, shuffle = True)

test_images_tensor = torch.tensor(test_images)
# Create Multi Layer Perceptron Model
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class MLP(nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        self.input_layer = nn.Linear(28 * 28, 128)
        self.hidden_layer = nn.Linear(128, 128)
        self.output_layer = nn.Linear(128, 10)

    def forward(self, x):
        x = x.view(-1, 28 * 28)
        x = F.relu(self.input_layer(x))
        x = F.relu(self.hidden_layer(x))
        x = self.output_layer(x)
        x = F.log_softmax(x, dim = 1)
        return x

USE_CUDA = torch.cuda.is_available()
DEVICE = torch.device("cuda" if USE_CUDA else "cpu")

model = MLP().to(DEVICE)
optimizer = optim.Adam(model.parameters(), lr = 0.001)  # optimization 함수 설정

print("Model: ", model)
print("Device: ", DEVICE)
Model:  MLP(
  (input_layer): Linear(in_features=784, out_features=128, bias=True)
  (hidden_layer): Linear(in_features=128, out_features=128, bias=True)
  (output_layer): Linear(in_features=128, out_features=10, bias=True)
)
Device:  cpu

3. 여기까지 모델 설계. 이제 학습 시작

# Definite Train & Evaluate
# 이제 학습키자!
def train(model, train_loader, optimizer):
    model.train()  # "나 모델을 이용해서 학습시킬게! 라는 의미"
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(DEVICE), target.to(DEVICE)
        optimizer.zero_grad()
        output = model(data)
        loss = F.cross_entropy(output, target)  # criterion
        loss.backward()
        optimizer.step()

        if batch_idx % 100 == 0:
            print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format(epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item()))

def evaluate(model, valid_loader):
    model.eval()  # "나 모델을 이용해서 학습시킬게! 라는 의미"
    valid_loss = 0  # just Loss를 확인하기 위해서.
    correct = 0

    with torch.no_grad():
        for data, target in valid_loader:
            data, target = data.to(DEVICE), target.to(DEVICE)
            output = model(data)
            valid_loss += F.cross_entropy(output, target, reduction = "sum").item()
            prediction = output.max(1, keepdim = True)[1]
            correct += prediction.eq(target.view_as(prediction)).sum().item()

    valid_loss /= len(valid_loader.dataset)
    valid_accuracy = 100. * correct / len(valid_loader.dataset)
    return valid_loss, valid_accuracy
''' Training'''
EPOCHS = 10
for epoch in range(1, EPOCHS + 1):
    train(model, train_loader, optimizer)
    valid_loss, valid_accuracy = evaluate(model, valid_loader)
    print("[EPOCH: {}], \tValidation Loss: {:.4f}, \tValidation Accuracy: {:.2f} %\n".format(epoch, valid_loss, valid_accuracy))
Train Epoch: 9 [0/38400 (0%)]	Loss: 0.005890
Train Epoch: 9 [6400/38400 (17%)]	Loss: 0.054453
Train Epoch: 9 [12800/38400 (33%)]	Loss: 0.017136
Train Epoch: 9 [19200/38400 (50%)]	Loss: 0.004437
Train Epoch: 9 [25600/38400 (67%)]	Loss: 0.150551
Train Epoch: 9 [32000/38400 (83%)]	Loss: 0.177758
[EPOCH: 9], 	Validation Loss: 0.2030, 	Validation Accuracy: 95.92 %

Train Epoch: 10 [0/38400 (0%)]	Loss: 0.075817
Train Epoch: 10 [6400/38400 (17%)]	Loss: 0.075776
Train Epoch: 10 [12800/38400 (33%)]	Loss: 0.010031
Train Epoch: 10 [19200/38400 (50%)]	Loss: 0.056201
Train Epoch: 10 [25600/38400 (67%)]	Loss: 0.056001
Train Epoch: 10 [32000/38400 (83%)]	Loss: 0.103519
[EPOCH: 10], 	Validation Loss: 0.2131, 	Validation Accuracy: 95.54 %

4. Test 하고 Test 결과를 출력해보자.

# Predict Test Dataset
# Validation 과 Test 같은 경우에 다음과 같이 torch.no_grad를 꼭 사용하니 참고하자.
def testset_prediction(model, test_images_tensor):
    model.eval()  # test모드 아니고, validation모드를 사용한다.
    result = []
    with torch.no_grad():
        for data in test_images_tensor:
            data = data.to(DEVICE)
            output = model(data)
            prediction = output.max(1, keepdim = True)[1]
            result.append(prediction.tolist())
    return result
test_predict_result = testset_prediction(model, test_images_tensor)
test_predict_result[:5]
[[[7]], [[2]], [[1]], [[0]], [[4]]]
import numpy as np
from collections import Counter
Counter(np.squeeze(test_predict_result)).most_common()
[(1, 1139),
 (3, 1115),
 (9, 1113),
 (7, 991),
 (0, 979),
 (8, 959),
 (6, 949),
 (4, 938),
 (2, 934),
 (5, 883)]
for idx in range(0, 10):
    plt.imshow(test_images[idx], cmap = plt.get_cmap('gray'))
    plt.title("Predict: " + str(test_predict_result[idx]))
    plt.show()

CNN 이용하기

1. Data Load 하기

# Load Dataset
import pandas as pd
train_dataset = pd.read_csv("./Mnist_train.csv")
test_dataset = pd.read_csv("./Mnist_test.csv")
# Check Train Set
train_dataset.head()
# Split to Image & Label
train_images = (train_dataset.iloc[:, 1:].values).astype("float32")
train_labels = train_dataset["label"].values
test_images = (test_dataset.values).astype("float32")
# Check Train Data's Image 
train_images
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
# Check Train Data's Label
train_labels
array([1, 0, 1, ..., 7, 6, 9], dtype=int64)
# Check Test Data's Image
test_images
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]], dtype=float32)
# Split into Train, Valid Dataset
from sklearn.model_selection import train_test_split
train_images, valid_images, train_labels, valid_labels = train_test_split(train_images, 
                                                                          train_labels, 
                                                                          stratify = train_labels, 
                                                                          random_state = 42, 
                                                                          test_size = 0.2)
# Check Train, Valid, Test Image's Shape
print("The Shape of Train Images: ", train_images.shape)
print("The Shape of Valid Images: ", valid_images.shape)
print("The Shape of Test Images: ", test_images.shape)
The Shape of Train Images:  (33600, 784)
The Shape of Valid Images:  (8400, 784)
The Shape of Test Images:  (28000, 784)
# Check Train, Valid Label's Shape
print("The Shape of Train Labels: ", train_labels.shape)
print("The Shape of Valid Labels: ", valid_labels.shape)
The Shape of Train Labels:  (33600,)
The Shape of Valid Labels:  (8400,)
# Reshape image's size to check for ours
train_images = train_images.reshape(train_images.shape[0], 28, 28)
valid_images = valid_images.reshape(valid_images.shape[0], 28, 28)
test_images = test_images.reshape(test_images.shape[0], 28, 28)
# Check Train, Valid, Test Image's Shape after reshape
print("The Shape of Train Images: ", train_images.shape)
print("The Shape of Valid Images: ", valid_images.shape)
print("The Shape of Test Images: ", test_images.shape)
The Shape of Train Images:  (33600, 28, 28)
The Shape of Valid Images:  (8400, 28, 28)
The Shape of Test Images:  (28000, 28, 28)
# Visualize Train, Valid, Test's Images
import matplotlib.pyplot as plt
for idx in range(0, 5):
    plt.imshow(train_images[idx], cmap = plt.get_cmap('gray'))
    plt.title(train_labels[idx])
    plt.show()
for idx in range(0, 5):
    plt.imshow(valid_images[idx], cmap = plt.get_cmap('gray'))
    plt.title(valid_labels[idx])
    plt.show()
for idx in range(0, 5):
    plt.imshow(test_images[idx], cmap = plt.get_cmap('gray'))
    plt.show()
# Make Dataloader to feed on Multi Layer Perceptron Model
import torch
from torch.utils.data import TensorDataset, DataLoader
train_images_tensor = torch.tensor(train_images)
train_labels_tensor = torch.tensor(train_labels)
train_tensor = TensorDataset(train_images_tensor, train_labels_tensor)
train_loader = DataLoader(train_tensor, batch_size = 64, num_workers = 0, shuffle = True)

valid_images_tensor = torch.tensor(valid_images)
valid_labels_tensor = torch.tensor(valid_labels)
valid_tensor = TensorDataset(valid_images_tensor, valid_labels_tensor)
valid_loader = DataLoader(valid_tensor, batch_size = 64, num_workers = 0, shuffle = True)

test_images_tensor = torch.tensor(test_images)

2. 모델 생성

import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size = 5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size = 5)
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)

    def forward(self, x):
        x = x.view(-1, 1, 28, 28)
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2(x), 2))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        x = F.log_softmax(x)
        return x

USE_CUDA = torch.cuda.is_available()
DEVICE = torch.device("cuda" if USE_CUDA else "cpu")

model = CNN().to(DEVICE)
optimizer = optim.Adam(model.parameters(), lr = 0.001)

print("Model: ", model)
print("Device: ", DEVICE)
Model:  CNN(
  (conv1): Conv2d(1, 10, kernel_size=(5, 5), stride=(1, 1))
  (conv2): Conv2d(10, 20, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear(in_features=320, out_features=50, bias=True)
  (fc2): Linear(in_features=50, out_features=10, bias=True)
)
Device:  cuda

3. 학습

# Definite Train & Evaluate
def train(model, train_loader, optimizer):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(DEVICE), target.to(DEVICE)
        optimizer.zero_grad()
        output = model(data)
        loss = F.cross_entropy(output, target)
        loss.backward()
        optimizer.step()
        
        if batch_idx % 100 == 0:
            print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format(epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item()))

def evaluate(model, valid_loader):
    model.eval()
    valid_loss = 0
    correct = 0

    with torch.no_grad():
        for data, target in valid_loader:
            data, target = data.to(DEVICE), target.to(DEVICE)
            output = model(data)
            valid_loss += F.cross_entropy(output, target, reduction = "sum").item()
            prediction = output.max(1, keepdim = True)[1]
            correct += prediction.eq(target.view_as(prediction)).sum().item()

    valid_loss /= len(valid_loader.dataset)
    valid_accuracy = 100. * correct / len(valid_loader.dataset)
    return valid_loss, valid_accuracy
''' Training'''
EPOCHS = 10
for epoch in range(1, EPOCHS + 1):
    train(model, train_loader, optimizer)
    valid_loss, valid_accuracy = evaluate(model, valid_loader)
    print("[EPOCH: {}], \tValidation Loss: {:.4f}, \tValidation Accuracy: {:.2f} %\n".format(epoch, valid_loss, valid_accuracy))
Train Epoch: 9 [0/33600 (0%)]	Loss: 0.039682
Train Epoch: 9 [6400/33600 (19%)]	Loss: 0.002007
Train Epoch: 9 [12800/33600 (38%)]	Loss: 0.041496
Train Epoch: 9 [19200/33600 (57%)]	Loss: 0.047618
Train Epoch: 9 [25600/33600 (76%)]	Loss: 0.001618
Train Epoch: 9 [32000/33600 (95%)]	Loss: 0.191500
[EPOCH: 9], 	Validation Loss: 0.0745, 	Validation Accuracy: 98.02 %

Train Epoch: 10 [0/33600 (0%)]	Loss: 0.007429
Train Epoch: 10 [6400/33600 (19%)]	Loss: 0.077467
Train Epoch: 10 [12800/33600 (38%)]	Loss: 0.007383
Train Epoch: 10 [19200/33600 (57%)]	Loss: 0.009296
Train Epoch: 10 [25600/33600 (76%)]	Loss: 0.054614
Train Epoch: 10 [32000/33600 (95%)]	Loss: 0.032034
[EPOCH: 10], 	Validation Loss: 0.0807, 	Validation Accuracy: 98.23 %

4. 추론

# Predict Test Dataset
def testset_prediction(model, test_images_tensor):
    model.eval()
    result = []
    with torch.no_grad():
        for data in test_images_tensor:
            data = data.to(DEVICE)
            output = model(data)
            prediction = output.max(1, keepdim = True)[1]
            result.append(prediction.tolist())
    return result
test_predict_result = testset_prediction(model, test_images_tensor)
test_predict_result[:5]
c:\users\justin\venv\lib\site-packages\ipykernel_launcher.py:21: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.





[[[2]], [[0]], [[9]], [[9]], [[3]]]
import numpy as np
from collections import Counter
Counter(np.squeeze(test_predict_result)).most_common()
[(1, 3176),
 (7, 2910),
 (3, 2872),
 (2, 2803),
 (9, 2801),
 (4, 2781),
 (0, 2725),
 (8, 2718),
 (6, 2716),
 (5, 2498)]
for idx in range(0, 10):
    plt.imshow(test_images[idx], cmap = plt.get_cmap('gray'))
    plt.title("Predict: " + str(test_predict_result[idx]))
    plt.show()

【캡스톤1】 자율주행 RC카 만들기

캡스톤 수업을 위한 rpLidar + 라즈베리파이 기본 설정하기

캡스톤 수업을 위한 rpLidar + 라즈베리파이 기본 설정하기 1

1. REFERENCE

  1. 로스 패키지 구동 네이버 블로그

  2. 로스란? 아두이노란? 아두이노에 Lidar데이터를 가져오는 코드는 여기에

  3. ROS 홈페이지에서 rplidar를 검색했을 때 나오는 코드 목록

    image-20200524194150672

  4. 라이더 드라이버 로스 패키지 목록 (위의 3개 하나하나)

    1. rplidar (distros = kinetic, melodic)
    2. rplidar driver in python (distros = indigo, jade)
    3. rplidar_ros - 2016년 버전이라 읽을 글 많이 없음
  5. RPLIDAR and ROS programming - 블로그 설명

  6. ROS and Hector SLAM - 블로그 설명

  7. RPLidar_Hector_SLAM - 깃 코드


2. 읽은 내용 정리하기

Reference 읽기 순서 : 4.1 -> 5 -> 6 -> 7

(1) Ref 4.1 : rplidar

차례
1. Overview
2. ROS Nodes
   - rplidarNode
      - Published Topics
      - Services
      - Parameters
3. Device Settings
4. Launch File Examples
5. About Slamtec/RoboPeak
6. Distributor Links
7. Related Links
  1. Overview

    rplidar에 대한 기본적 설명. sensor_msgs/LaserScan형식 구조체의 메세지를 publish

    SLAM based on RPLIDAR and ROS Hector Mapping 동영상 속 ROS Hector

  2. ROS Nodes

    • rplidarNode - RPLIDAR 스캔 결과를 로스 메세지 형태로 publish하는 노드

      • Published Topics

        • ‘scan’ : 스캔된 데이터의 메세지
      • Services

        • start_motor, stop_motor 모터의 시작과 중지를 관리하는 서비스
      • Parameters

        • ```sh
          1. Parameter이름 (자료형, default 값)
          2. serial_port (string, default: /dev/ttyUSB0) serial port name used in your system.
          3. serial_baudrate (int, default: 115200) serial port baud rate.
          4. frame_id (string, default: laser_frame) frame ID for the device.
          5. inverted (bool, default: false) indicated whether the LIDAR is mounted inverted.뒤집혔나
          6. angle_compensate (bool, default: false) indicated whether the driver needs do angle compensation. 각도 보상 필요?
          7. scan_mode (string, default: std::string()) the scan mode of lidar. ```
  3. Device Setting

    • rplidar tutorial - rplidar-ros/wiki
      • rplidar basic document
      • rplidar sdk - slamtec에서 재공해 줌 - SDK Git Code과 연결됨
      • 위의 Ref1에서 봤던 내용이 좀더 간략히 나와 있다. 코드 실행 순서.. image-20200524204312223
      • 이 사진과 같이 라이더를, 자동차에 해야한다. theta와 d가 publish되는 메세지값에 나타나는 듯 하다.
      • remap the USB serial port name 했을 때의 방법도 나온다. 이건 건들지 말자.
  4. Launch File Examples

    $ ls -l /dev |grep ttyUSB
    $ sudo chmod 666 /dev/ttyUSB0
    1.
    $ roslaunch rplidar_ros view_rplidar.launch    #for rplidar A1/A2
    2. 
    $ roslaunch rplidar_ros rplidar.launch
    $ rosrun rplidar_ros rplidarNodeClient
    

Ref 4.1.1 rplidar_ros 내용은 위의 rplidar tutorial 내용과 동일

(2) Ref 5 : RPLIDAR and ROS programming



3. 프로젝트 완수(중간과정 생략…)

안정적으로 프로젝트를 완수 했다.

  • 완성된 RC카 이미지.
    image

완성한 프로젝트의 소스코드는 깃에 Private로 저장해 두었다. (수업 과제이다 보니 공개적으로 오픈해두는 것은 좋지 않을 것 같아서…)

  • 나름 만족스러운 결과를 얻을 수 있어서 뿌듯하고 보람찼던 경험이었다.^^

【Python-Module】 argparse/yaml/logging python 모듈 공부 내용 정리

(위성Segment) argparse/yaml/logging python 모듈 공부 내용 정리 pytorch-semseg코드를 공부하면서 앞으로 계속 나오게 될 argparse/yaml 에 대해서 공부하고 정리한 내용을 기록해 놓는다.

참고 페이지 : https://github.com/meetshah1995/pytorch-semseg/issues/188

  1. http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html#data
  2. http://home.bharathh.info/pubs/codes/SBD/download.html

1. Referece for argparse

  1. http://blog.naver.com/PostView.nhn?blogId=cjh226&logNo=220997049388&parentCategoryNo=&categoryNo=17&viewDate=&isShowPopularPosts=false&from=section
  2. https://greeksharifa.github.io/references/2019/02/12/argparse-usage/
  3. https://brownbears.tistory.com/413

첫번쩨 Reference 공부내용 정리

  • arg+parse = argument(parameter) + parsing
# 예제코드
from __future__ import print_function
import argparse

def main():
	parser = argparse.ArgumentParser(description='This code is written for practice about argparse')
	parser.add_argument('X', type=float,
			metavar='First_number',
			help='What is the first number?')
	parser.add_argument('Y', type=float,
			metavar='Second_number',
			help='What is the second number?')
	parser.add_argument('--op', type=str, default='add',
			choices=['add','sub','mul','div'],
			help='What operation?')
	args = parser.parse_args()
	
	X = args.X
	Y = args.Y
	op = args.op
	print(calc(X,Y,op))

def calc(x, y, op):
	if op == 'add':
		return x + y
	elif op == 'sub':
		return x - y
	elif op == 'mul':
		return x * y
	elif op == 'div':
		return x / y

if __name__=="__main__":
	main()
  1. 기초 코드
    • argparse.ArgumentParser함수를 통해 parser를 생성한다.
    • parser.add_argument를 이용하여 입력받고자 하는 인자의 조건을 설정한다
    • parser.parse_args 함수를 통해 인자들을 파싱하여 args에 저장한다. 각 인자는 add_argument의 type에 지정된 형식으로 저장된다
  2. parser.add_argument에 들어갈 수 있는 옵션
    • type/ default/ choices/ help 등등
    • 여기서 choices를 사용함으로써 help에서 어떤 옵션이 가능한지 보여준다.
    • metavar는 필수 인자를 입력하지 않았을 때, 그 자리 변수가 무엇인지에 대한 이름이다.
    • nargs=’+’를 사용함으로써, 여러개의 (제한 없음) 변수를 리스트로 받을 수 있다.
  3. parser.parse_args()로 정의된 객체 args 사용방법
    • X = args.X // Y = args.Y
    • op = args.op 에서 처럼 –[]라고 add_argument를 했다면, args.[]라고 사용가능하다.

두번쨰 Reference 공부내용 정리

  1. 위의 기초 코드 3개 중, ArgumentParseradd_argument에 사용가능한 메소드들이 잘 정리되어 있다.
  2. image

세번쨰 Reference 공부내용 정리

  • 지금까지 한 것보다 조금 더 심화된 내용이 설명되어 있다.
  • 이 정도는 필요할 때마다 찾아보기로 하자.

2. Referece for yaml

  1. https://itholic.github.io/python-yaml/
  2. https://teeeeeeemo.tistory.com/39
  3. https://junho85.pe.kr/1451

기본 사용방법은 매우 간단하다.

  1. 이와 같은 파일이 있다고 치자

    # /home/info/yaml
    language: python
    test: pytes
    
  2. 이렇게 py파일에서 쓰면 된다.

    import yaml
       
    with open('info.yaml') as f:
        cfg = yaml.load(f)
       
       
    language = conf['language']
    test = cfg['pytest']
    

    즉, yaml 모듈의 load함수를 통해서 conf를 dictionary 객체로 만들어 준다.

  3. 추가 사용법

    • 모르겠으면 우선 yaml파일을 가져오고, type과 같은 함수를 이용해서 내가 가지고 있는 yaml.load로 선언한 객체에 대한 분석을 해보자.

    • 코드 예제

      # yaml 파일
      yaml_str = """
      Date: 2017-08-08
      ChampionList:
      - champion_id: 1000
       name: Teemo
       position: top
       skill: ap
      - champion_id: 1001
       name: Vayne
       position: bottom
       skill: ad
      - champion_id: 1002
       name: Ahri
       position: mid
       skill: ap
      """
           
      # .py 파일 내부 코드
      import yaml
           
      cfg = yaml.load(yaml_str)
      for champion in cfg['ChampionList']:
      	print(champion["name"], champion["skill"])
           
      

3. Reference for logging

  1. https://ourcstory.tistory.com/97
  2. https://minimin2.tistory.com/41
  3. https://snowdeer.github.io/python/2017/11/17/python-logging-example/

<기본사용법>

  1. 로그 출력을 위한 logging 모듈을 제공합니다. 아주 간단히 사용할 수 있으며, print 함수 등을 통해 콘솔창에 지저분하게 출력하는 것보다 logging 모듈을 사용하는 것을 추천한다. 콘솔창과 파일에 동시에 로그 남기는 것이 가능하다.

  2. 로그를 콘솔에도 출력하고 싶고, 파일에도 동시에 남기고 싶다면 아래와 같이 fileHandler, streamHandler를 생성해서 logger에 Handler를 추가해주면 된다

  3. 로그 포매팅이라고 하면, 내가 로그를 남길때 앞에 쓰여지는 형식의 포맷을 정하는 것을 말한다 로그 포매팅 : %(log_name)s 를 사용하고 중간에 문자를 자유롭게 첨가

    import logging
    import logging.handlers
       
    # logger 인스턴스를 생성 및 로그 레벨 설정
    logger = logging.getLogger("crumbs")
    logger.setLevel(logging.DEBUG)
       
    # formmater 생성 <***adding***>
    formatter = logging.Formatter('[%(levelname)s|%(filename)s:%(lineno)s] %(asctime)s > %(message)s')
       
    # fileHandler와 StreamHandler를 생성
    fileHandler = logging.FileHandler('./log/my.log')
    streamHandler = logging.StreamHandler()
       
    # handler에 fommater 세팅 <***adding***>
    fileHandler.setFormatter(formatter)
    streamHandler.setFormatter(formatter)
       
    # Handler를 logging에 추가
    logger.addHandler(fileHandler)
    logger.addHandler(streamHandler)
       
    # logging
    logger.debug("debug")
    logger.info("info")
    logger.warning("warning")
    logger.error("error")
    logger.critical("critical")
       
    '''
    출력결과
    [DEBUG|input.py:24] 2016-05-20 10:37:06,656 > debug
    [INFO|input.py:25] 2016-05-20 10:37:06,657 > info
    [WARNING|input.py:26] 2016-05-20 10:37:06,657 > warning
    [ERROR|input.py:27] 2016-05-20 10:37:06,657 > error
    [CRITICAL|input.py:28] 2016-05-20 10:37:06,657 > critical
    
  4. 다른 코드를 통해 좀 더 알아보자. setLevel(logging.DEBUG) -> setLevel(logging.INFO)

    import logging
       
    # 로그 생성
    logger = logging.getLogger()
       
    # 로그의 출력 기준 설정
    logger.setLevel(logging.INFO)
       
    # log 출력 형식 기본 포맷 
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
       
    # log 출력
    stream_handler = logging.StreamHandler()
    stream_handler.setFormatter(formatter)
    logger.addHandler(stream_handler)
       
    # log를 파일에 출력
    file_handler = logging.FileHandler('my.log')
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)
       
    for i in range(10):
    logger.info(f'{i}번째 방문입니다.')
    

【위성Segment】 Segmentation 공부할 코드 사이트 정리

공부할 코드를 찾아보고, 안 내용을 기록해 놓았습니다.

(위성Segment) Segmentation 공부할 코드 사이트 정리

1. 전체 Segmentation Models 정리 GIT

  1. semantic-segmentation-pytorch

    (3.2 star) 난이도 4.5 / PPM PSP Uper HRNet 같은 최신 Segmentation 코드

  2. pytorch-semseg

    (2.6 star) 난이도 3 / FCN PSP U-Net 같은 기초+좋은 코드와 DataLoaders가 있다. Config 만드는 것이 필수

  3. segmentation_models.pytorch

    (1.6 star) 난이도 5 / pip install로 Segmentation을 수행할 수 있다. UNet PSP DeepLabv3

  4. awesome-semantic-segmentation-pytorch

    (1.1 star) 난이도 2 / Segmentation 모델들 정말 많다. But 대부분 중요한것 아님..

따라서 나는 2번의 코드를 공부해보기로 결정했다. 하는 김에 전체 코드를 잘근잘근 씹어먹자

2. Pytorch-semseg GIT 내부 내용 정리

segmentation_models.pytorch에 구현되어 있는 코드들을 간략히 설명해주는 이 사이트를 공부한 내용을 아래에 정리해 놓는다.

<전체 목차>
1. Segmentation, Pytorch란?
2. FCN
3. SegNet
4. U-Net
5. DenseNet
6. E-Net & Link-Net
7. Mask-RCNN
8. PSP-Net
9. RefineNet
10. G-FR-Net
11. DeCoupleNet
12. GAN-Approach
13. Dataset

1. Segmentation, Pytorch란?


3.pytorch-semseg 돌려보기

  1. pip install -r requirements.txt
  2. Pascal voc를 FCN8을 통해서 돌려보기

【Paper】 Semantic Segmentation for AutoDriving/ 공부 계획 및 모델 핵심 정리

Image Segmentation for Autonomous Driving 논문 리뷰 및 정리

(위성Segment) Segmentation for Autonomous Driving 논문 정리 논문 원본 : 2019 (cite:10) A Brief Survey and an Application of Semantic Image Segmentation for Autonomous Driving

1. 논문 필기 및 정리 자료 다운로드 링크

2. 논문 전체 요약

  • 이 논문에서는 deep learning이 무엇이고 CNN이 무엇인지에 대한 아주 기초적인 내용들이 들어가 있다. 이미 알고 있는 내용들이라면 매우 쉬운 논문이라고 할 수 있다.
  • FCN에 대한 소개를 해주고, a virtual city Image인 SYNTHIA-Rand-CVPR16 Dataset을 사용해, FCN-AlexNet, FCN-8s, FCN-16s and FCN-32s 이렇게 4가지 모델에 적용해 본다.
  • 결론 :
    1. Maximum validation accuracies of 92.4628%, 96.015%, 95.4111% and 94.2595% are achieved with FCN-AlexNet, FCN-8s, FCN-16 and FCN-32s models
    2. Training times는 FCN-AlexNet이 다른 모델들에 비해 1/4시간이 걸릴 만큼 학습시간이 매우 짧다. 하지만 우리에게 중요한 것은 inference시간이므로, the most suitable model for the application is FCN-8s.
    3. 각 모델들에 대한 inference 시간 비교는 논문에서 해주지 않는다.

3. 앞으로 추가 공부 계획

4. 면접 준비 - 딥러닝 모델 핵심 정리

각 모델별 핵심 용어 정리(논문 level2 정도로만 읽은 상태. 빠르게 Skip. 핵심만 파악)

  1. 코드는 직접만드는 것보다는, 이미 만들어진 코드들을 수정하고 참고
    • FPN : bottomup[bottleNet+resnet], topdown[ upsample, leteral connection(sum)]
    • ResNet : self.shortcut = nn.sequential(); out += self.shortcut(input)
    • vgg : 신경망은 매우 간단. data, criterion, optimizer. zero_grad -> loss -> backword -> opti.step
  2. DQN – Q learning, Fixed Target Network, Experience Replay memory
  3. FPN – Bottom-up, Top-down, lateral-connection, multi-scale-detection
  4. Fast-RCNN – Selective search, ROI pooling, Bounding Box Regression
  5. Faster-RCNN – RPN(anchor개념을 사용해서 각 grid마다 객체의 유무/ Box location 정보를 뽑아낸다. RPN의 Loss function도 따로 있다. 객체유무/ Box coordinate 차이), 9개 anchor.
  6. FCN – FCN32 ->(upsampling) FCN16
  7. Mask-RCNN – Align pooling(각 픽셀 4등분+weighted sum), Binary Cross Entropy, 마지막단 FCN, Multi training(keypoint Detection), 최초 Instacne Segmentation
  8. DeepLab – Dilated Con(global fearture/contexts), CRP(Posterior, Energy), ASPP(atrous spatial pyramid pooling)
  9. PSPNet – Pyramid Pooing layer, concatenate
  10. ParsNet – Global context information, Global pooling,
  11. SegNet – Encoder/Decoder, maxpooling index
  12. HRNet – high resolution, low resolution의 information Exchange. BackboneNetwork
  13. Panotic-Network (PA-Net) – FPN + mask+rcnn
  14. Dilated Conv – 추가 비용없이, receptive field 확장
  15. RNN, LSTM, Attention, GAN 개념 사용 가능
  16. CRF – Posterior를 최대화하고 Energy를 최소화한다.
    Energy는 위치가 비슷하고 RGB가 비슷한 노드사이에서 라벨이 서로 다른것이라고 하면 Panalty를 부과함으로써 객체의 Boundary를 더 정확하게 찾으려고 하는 노력입니다.
    Energy공식에 비용이 너무 많이 들어서 하는 작업이 mean field approximation이라고 합니다.
  17. Yolo – 1stage detector, cheaper grid, 7730(5+5+20), confidence낮음버림, NMS -> Class 통합
  18. SSD – Anchor, 다양한 크기 객체, 작은 -> 큰 물체, Detector&classifier(3개 Anchor, locallization(x,y,w,h), class-softMax결과(20+1(배경)) ), NMS

【Algorithm】 게임 맵 최단거리 - 카카오 문제

프로그래머스 게임 맵 최단거리 알고리즘 풀이

문제링크 : 게임 맵 최단거리
주석을 참고해서 코드 이해에 도움을 받으시길 바랍니다.

image

from collections import deque

def bfs(start, maps):
    dirs = [(0,1),(1,0),(0,-1),(-1,0)]
    queue = deque()                     # https://excelsior-cjh.tistory.com/96
    queue.append(start)
    while queue:                        # 빈 list, 빈 que는 False가 된다.
        y, x, cnt = queue.popleft()
        maps[y][x] = 0                  # Point! 이미 방문한 곳 처리는 벽으로 만들어 버린다!
        for dy, dx in dirs:
            ny, nx = y + dy, x + dx
            # BFS를 사용하므로, 가장 처음 발견하면, 그 cnt를 return하면 된다.
            if ny == len(maps)-1 and nx == len(maps[0])-1:
                return cnt + 1

            # 빈 공간을 만났다면,
            elif 0 <= ny < len(maps) and 0 <= nx < len(maps[0]) and maps[ny][nx] == 1: 
                maps[ny][nx] = 0
                queue.append((ny, nx, cnt+1))
    return -1

def solution(maps):
    # 첫 위치는, map[0][0]이며, count=1로 시작한다. 
    return bfs((0,0,1), maps) 

【Pytorch】 Pytorch튜토리얼 6 - what is torch.nn really?

아래의 주석을 참고해서 공부하기 바랍니다. 차근히 공부해보기

WHAT IS TORCH.NN REALLY?

  1. MNIST 데이터 세트에서 기본 신경망을 학습
  2. 점진적에서 하나 개의 기능을 추가 할 것 -> torch.nn, torch.optim, Dataset, DataLoader
  3. 처음에는 정말 코드를 복잡하게 만들고, 그것을 torch 내부의 모듈과 함수(클래스)를 이용해서 코드를 점점 쉽게 구현해 나갈 것이다.

    1. 파일 및 이미지 다운. 파일을 torch.tensor로 변환하기

from pathlib import Path        # pathlib는 파일위치 찾기, 파일 입출력에 사용하는 모듈. 과거 os모듈. https://brownbears.tistory.com/415
import requests                 # 간편한 HTTP 요청처리를 위해 사용하는 모듈

# 1. 폴더를 만들고, MNIST 데이터 다운로드 하기
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"          # os.path.join 과 같은 느낌.
PATH.mkdir(parents=True, exist_ok=True)

URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"

if not (PATH / FILENAME).exists():  # os.path.join 과 같은 느낌.
        content = requests.get(URL + FILENAME).content
        (PATH / FILENAME).open("wb").write(content)



# 2. 다운한 파일의 압축을 풀고, 파일을 Load 하여, 하나의 변수에 넣는다.
import pickle                   # 파일 load하는데 많이 쓰이는 모듈
import gzip                     # 압축된 파일의 내용을(굳이 압축안 풀고) 바로 읽을 수 있게 해주는 모듈 : https://itholic.github.io/python-gzip/
with gzip.open((PATH / FILENAME).as_posix(), "rb") as f:
        ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")

# 3. 파일 다운로드가 잘 되었나 확인하보자. 
from matplotlib import pyplot
import numpy as np

print(x_train.shape, '\n', type(x_train))
pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")

(50000, 784) 
 <class 'numpy.ndarray'>





<matplotlib.image.AxesImage at 0x2930e3d3088>

svg

# 4. torch.tensor를 사용할 것이기 때문에, 
import torch

x_train, y_train, x_valid, y_valid = map(torch.tensor, (x_train, y_train, x_valid, y_valid)) # https://pytorch.org/docs/stable/tensors.html#torch.Tensor
n, c = x_train.shape

print(x_train.shape)
print(y_train.min(), y_train.max())  # 0 ~ 9까지 10개의 Class가 존재한다.
torch.Size([50000, 784])
tensor(0) tensor(9)

2. torch.nn을 사용하지 않고 신경망 구현해 보기.

nn을 이용해서, 매개변수를 정의한다면, 자동으로 requires_grad = True가 된다.
하지만 아래와 같이 매개변수를 직접 정의한다면, requires_grad = True를 직접해주어야한다.
그리고, _를 사용하면 the operation is performed in-place라는 것을 의미한다.

import math

weights = torch.randn(784, 10) / math.sqrt(784)     # 여기서 가중치 초기화 방법으로 Xavier initialisation 를 사용했다.
weights.requires_grad_()                            # Defalut =-> requires_grad=True : https://pytorch.org/docs/stable/tensors.html#torch.Tensor.requires_grad_
bias = torch.zeros(10, requires_grad=True)
# 1층 Fully connected Layer를 만든다.
def log_softmax(x):
    return x.exp().log() - x.exp().sum(-1).log().unsqueeze(-1)  
    # torch.tensor의 함수(math 모듈의 함수 NO)를 잘 이용하고 있다.  
    # x.exp().log() == x
def model(xb):
    return log_softmax(xb @ weights + bias)         # @내적 연산을 의미

image

# 64장을 하나의 배치로 하고, Forward를 진행해 나간다.
bs = 64  # batch size

xb = x_train[0:bs]      # a mini-batch from x
preds = model(xb)       # predictions
print(preds[0])
print(preds.shape)
tensor([-2.3311, -2.3437, -1.6287, -2.1573, -2.8016, -2.4115, -2.5137, -2.1718,
        -2.4900, -2.7065], grad_fn=<SelectBackward>)
torch.Size([64, 10])

loss function을 만들어 보자

image

def nll_loss(input, target):
    return -input[range(target.shape[0]), target].mean()

loss_func = nll_loss        # 함수 포인터는 이처럼 이용하면 된다.

yb = y_train[0:bs]
print(yb.shape) # torch.Size([64]) -> 64장의 이미지 각각의 class가 적혀 있다.
print(loss_func(preds, yb))
torch.Size([64])
tensor(2.3936, grad_fn=<NegBackward>)

accuracy function을 만들어보자.

def accuracy(preds_before, yb):
    # 각 예측에 대해 가장 큰 값을 가진 인덱스가 목표 값과 일치함을 판단합니다.
    preds = torch.argmax(preds_before, dim=1) 
    # dim : the dimension to reduce. If None, the argmax of the flattened input is returned.
    # preds_before -> shape : (64, 10) -> (64)
    return (preds == yb).float().mean()

    """
    print(preds) -> tensor([3, 3, 3, 6, 6, 3, 3.....  9, 3, 6])
    print(preds.shape) -> torch.Size([64])
    """
print(accuracy(preds, yb))
tensor(0.0312)

이제 훈련을 시켜보자.

loop를 통해서,
데이터 가져오기 -> forward -> loss계산 -> backward -> 가중치 갱신
이 되는 것을 확인하라.

from IPython.core.debugger import set_trace

lr = 0.5  # learning rate
epochs = 2  # how many epochs to train for

for epoch in range(epochs):
    # x_train.shape == (50000,784) 
    # n == 50000 , bs = 64
    for i in range((n - 1) // bs + 1):
        # set_trace()
        # 튜토리얼 문서에 의하면, 이 코드를 디버깅하면서 한줄한줄 확인하고 싶다면 위의 주석을 풀라 했다.
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        with torch.no_grad():
            weights -= weights.grad * lr
            bias -= bias.grad * lr
            weights.grad.zero_()
            bias.grad.zero_()
        # 여기서 x_train의 가장 마지막 16개의 사진은 학습에 사용 못 된다.
print(loss_func(model(xb), yb), "\n",accuracy(model(xb), yb)) # 가장 마지막 배치에 대한, loss와 accuracy를 확인해보자
tensor(0.0827, grad_fn=<NegBackward>) 
 tensor(1.)

3. Using torch.nn.functional

위에서 했던 동일한 작업을 수행하기 위해, PyTorch의 nn클래스를 활용하여보다 간결하고 유연한 코드를 만들어보자.
우선 torch.nn.functional를 사용해서 코드를 만들어 봅시다. 여기에는 torch.nn의 모든 기능이 포함되어 있습니다.

# 새로운 학습을 위해.. 다시!
xb = x_train[0:bs]      # a mini-batch from x
yb = y_train[0:bs]
weights = torch.randn(784, 10) / math.sqrt(784)     # 여기서 가중치 초기화 방법으로 Xavier initialisation 를 사용했다.
weights.requires_grad_()                            # Defalut =-> requires_grad=True : https://pytorch.org/docs/stable/tensors.html#torch.Tensor.requires_grad_
bias = torch.zeros(10, requires_grad=True)
import torch.nn.functional as F

loss_func = F.cross_entropy  # 위의 nll_loss 처럼, 함수 포인터는 이처럼 이용하면 된다.

def model(xb):
    return xb @ weights + bias

print(loss_func(model(xb), yb), accuracy(model(xb), yb))
tensor(2.4334, grad_fn=<NllLossBackward>) tensor(0.)

4. Refactor using nn.Module

nn.Module및 nn.Parameter를 적극적으로 이용합니다.

from torch import nn
# import torch.nn as nn

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
         # nn.Parameter(텐서) : 이 텐서를 parameter로 이용할 것을 명명한다. grad를 알아서 해준다.
        self.weights = nn.Parameter(  torch.randn(784, 10) / math.sqrt(784)  )
        self.bias = nn.Parameter(torch.zeros(10))

    def forward(self, xb):
        return xb @ self.weights + self.bias
model = Mnist_Logistic()
print(loss_func(model(xb), yb)) # loss값 구하기.
tensor(2.3004, grad_fn=<NllLossBackward>)
# 위에서는 weights -= weights.grad * lr -> weights.grad.zero_() 과 같은 과정을 bias에도 반복했었지만.. 여기서는 쉽게 할 수 있다.
with torch.no_grad():
    for p in model.parameters(): 
        p -= p.grad * lr
    model.zero_grad()
from IPython.core.debugger import set_trace

lr = 0.5  # learning rate
epochs = 2  # how many epochs to train for

def fit():
    for epoch in range(epochs):
        for i in range((n - 1) // bs + 1):
            start_i = i * bs
            end_i = start_i + bs
            xb = x_train[start_i:end_i]
            yb = y_train[start_i:end_i]
            pred = model(xb)
            loss = loss_func(pred, yb)

            loss.backward()
            with torch.no_grad():
                for p in model.parameters():  p -= p.grad * lr
                model.zero_grad()

fit()
print(loss_func(model(xb), yb))

5. Refactor using nn.Linear

위에서는 weight와 bias를 직접 정의했지만,
이제는 nn.Linear를 사용해서 코드를 구현해보자

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin = nn.Linear(784, 10)

    def forward(self, xb):
        return self.lin(xb)
model = Mnist_Logistic()
print(loss_func(model(xb), yb))
fit()  # 위에 있는 함수 그대로 사용해도 된다.

6. Refactor using optim

위에서 했던,

with torch.no_grad():
    for p in model.parameters(): p -= p.grad * lr
    model.zero_grad()

과정을 optim를 이용해서 쉽게 구현해보자. 그냥

opt.step()
opt.zero_grad()

를 하면 된다!

from torch import optim
# 더 아래에서도 사용하기 위해서, 굳이 이렇게 get_model이라는 함수를 구현했다. 
def get_model():
    model = Mnist_Logistic()
    return model, optim.SGD(model.parameters(), lr=lr)

model, opt = get_model()
"""
model = Mnist_Logistic()
opt = optim.SGD(model.parameters(), lr=lr)
"""
print(loss_func(model(xb), yb))

lr = 0.5 
epochs = 2

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

7. Refactor using Dataset

지금까지

start_i = i * bs
end_i = start_i + bs
xb = x_train[start_i:end_i]
yb = y_train[start_i:end_i]

를 했지만, 파이토치의 an abstract Dataset class인, TensorDataset를 이용해보자. (텐서의 첫 번째 차원을 따라 반복, 인덱싱 및 슬라이스하는 방법을 제공)
TensorDataset에는 len , getitem 이라는 좋은 함수가 있다.
* 자세한 사항은 이 홈페이지를 공부하자 **언젠간 공부해야 한다!! ***

from torch.utils.data import TensorDataset
train_ds = TensorDataset(x_train, y_train)
""" 위에서는 이렇게 했었다. 
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
""" 
# 이제는 이런 식으로 구현할 것이다. 
start_i = i * bs
end_i = start_i + bs
xb,yb = train_ds[start_i : end_i] # 처음에 train_ds정의를 튜플로 했으므로, 항상 output도 튜플로 해준다.
lr = 0.5 
epochs = 2

model, opt = get_model()

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        xb, yb = train_ds[i * bs: i * bs + bs]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

8. Refactor using DataLoader

이제는 [i * bs: i * bs + bs] 이렇게 하는 것도 싫다.
DataLoader를 사용함으로써 배치 관리를 쉽게 할 수 있다.

from torch.utils.data import DataLoader

train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs)
"""위에서는 이렇게 했었다. 
for i in range((n-1)//bs + 1):
    xb,yb = train_ds[i*bs : i*bs+bs]
    pred = model(xb)
"""
# 이제는 이런 식으로 구현할 것이다.
for xb,yb in train_dl:
    pred = model(xb)
    break
lr = 0.5 
epochs = 2

model, opt = get_model()
loss_func = F.cross_entropy

for epoch in range(epochs):
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))


9. Add validation

앞으로 우리는 a validation set을 사용할 것이다. in order to identify if you are overfitting. 유의사항

  1. train dataset은 suffling(섞거나, 랜덤하게 뽑아서) 이용했지만(오버피팅 막기 위해), validation set에서는 그런 작업이 필요없다.
  2. validation에서는 train보다 2배이상의 batch사이즈를 사용할 것이다. 역전파를 하지 않기 때문에 메모리 사용이 적기 때문이다.
  3. 큰 배치를 사용해서, 빠르게 Loss값을 구하고 validation 값을 확인한다.
# Train dataset
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)
# Validation dataset
valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)
lr = 0.5 
epochs = 2

model, opt = get_model()
loss_func = F.cross_entropy

# point 1 : validation (or inference)에서는 torch.no.grad() 로 처리한다
# point 2 : train, eval하기 전에, model.train() / model.eval()를 해준다. 배치Norm이나 DropOut과 같은 layer처리를 알아서 바꿔준다. torch.nn의 매소드라고 할 수 있다.

for epoch in range(epochs):
    model.train()
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

    model.eval()
    with torch.no_grad():
        # print((xb, yb) for xb, yb in valid_dl) -> <generator object <genexpr> at 0x000001A8AFF87848>
        # print(loss_func(model(xb), yb) for xb, yb in valid_dl)  -> { []를 치지 않아도, [변수_ for _ in _] 가 잘 동작한다...] } -> <generator object <genexpr> at 0x000001A89EC026C8>
        # print(list(loss_func(model(xb), yb) for xb, yb in valid_dl))  -> [tensor(0.3860), tensor(0.4615), tensor(0.4938), tensor(0.5899),  .... 
        # print(len(list(loss_func(model(xb), yb) for xb, yb in valid_dl)))   -> [79] 백터
        valid_loss = sum(loss_func(model(xb), yb) for xb, yb in valid_dl)

    print(epoch,"번째 epoch에서 valid_loss값은" ,valid_loss / len(valid_dl))

10. 지금까지 했던 것을 함수로 만들기!

loss_batch // fit // get_data 라는 이름의 함수를 만들지.

  1. loss_batch : one batch에 대해서 loss를 구해주는 함수
  2. fit : loss_batch함수를 이용해서, 모델 전체를 train, validation 해주는 함수.
  3. get_data :
def get_data(train_ds, valid_ds, bs):
    return (
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )
def loss_batch(model, loss_func, xb, yb, opt=None):
    loss = loss_func(model(xb), yb)  # 한 batch 즉 64장에 대한, 총 (평균) loss를 계산한다.

    if opt is not None:  # validation, inference를 위해서 만들어 놓는 옵션.
        loss.backward()
        opt.step()
        opt.zero_grad()

    return loss.item(), len(xb)  # train 과정 중, 이 값은 필요 없다. validation을 위해 return을 만들어 놓았다.
import numpy as np # 맨 아래 val_loss를 구하기 위해 numpy를 잠깐 쓴다.

def fit(epochs, model, loss_func, opt, train_dl, valid_dl):
    for epoch in range(epochs):
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)

        model.eval()
        with torch.no_grad():
            # [*,*,*,*,*,*,*],[+,+,+,+,+,+,+] <= zip( [*,+] , [*,+] , [*,+] , [*,+] ...)
            # print( list(zip( * [ loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl])) ) 
            # print( list([* [ loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]]) )
            # 여기서 [] for in 관계가 어떻게 되는 거지? 는 위의 주석을 풀어보면 된다.
            losses, nums = zip( * [ loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl] )  
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)

        print(epoch, val_loss)

# 자 이제 우리가 만든 함수를 돌려보자
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(epochs, model, loss_func, opt, train_dl, valid_dl)


11. nn.linear말고, CNN 사용하기

import torch.nn as nn
import torch.nn.functional as F
class Mnist_CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1)
        self.conv2 = nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1)
        self.conv3 = nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1)

    def forward(self, xb):
        xb = xb.view(-1, 1, 28, 28) # 첫 input size = [[이미지 장 수, 784]]
        xb = F.relu(self.conv1(xb))
        xb = F.relu(self.conv2(xb))
        xb = F.relu(self.conv3(xb))
        xb = F.avg_pool2d(xb, 4) # https://pytorch.org/docs/stable/nn.functional.html#pooling-functions
        return xb.view(-1, xb.size(1))

lr = 0.1
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
import torch.optim as optim

epochs = 2
bs = 64
train_ds = TensorDataset(x_train, y_train)
valid_ds = TensorDataset(x_train, y_train)

loss_func = F.cross_entropy
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)

# 하기 전 #10의 3개의 함수 선언 하기.
model = Mnist_CNN()
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
0 0.41726013900756836
1 0.27703515412330626

12. nn Sequential

nn의 하나의 클래스인 Sequential을 이용해 보자.
Sequential객체는 순차적으로 내부에 포함 된 각 모듈을 실행한다.
여기서 주의할 점은, Sequential을 정확하게 이용하기 위해서, view를 위한 layer를 하나 정의해주어야한다.
아래의 내용은 함수 포인터, 함수 input매개변수 등 다양한 사항을 고민해야한다.

class Lambda(nn.Module):
    def __init__(self, func):
        super().__init__()
        self.func = func

    def forward(self, x):
        return self.func(x)


def preprocess(x):
    return x.view(-1, 1, 28, 28)
# http://hleecaster.com/python-lambda-function/
# lambda input매개변수 : 함수내부 연산 
# 변수명_a = lambda ~~ : ~~  ; -> 변수명_a는 함수 포인터이다.

"""
    Mnist_CNN에서는 forward에서 xb = xb.view(-1, 1, 28, 28)를 쉽게 했지만, Sequential에서는 그렇게 하지 못한다.
    따라서 이러한 처리를 하는 방법은 바로 아래 코드처럼 구현을 하는 것이다.
    Lambda(preprocess) 에서 preprocess(x_input)이 들어가면서 Sequential aclass가 나중에 실행될 것이다. 
    Sequential에 순차적으로 넣는 매개변수 하나하나는 꼭! nn.Module로 정의된 Class 이여야 한다. # 이것이 view용 레이어 처리 방법이다.

"""
model = nn.Sequential(
    Lambda(preprocess),  
    nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.AvgPool2d(4),
    Lambda(lambda x: x.view(x.size(0), -1)), 
)
# 맨 아래에서도 preproces같은 함수 포인터가 들어가면 좋지만, 굳이 def preprocess: 하기 귀찮으므로...

lr = 0.5
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
0 0.8372452193450928
1 0.747732577419281

13. Wrapping DataLoader

모든 2d single channel image라면 input을 무조건 받을 수 있는, model을 구현해 보자.
위에서는 preprocess라는 함수를 정의하고, nn.Sequential(Lambda(preprocess), … ; 처럼 사용했었다.
그러지 말고, 아에 처음부터 train_dl, valid_dl을 view처리를 한 상태에서 model에 집어넣자.

def preprocess(x, y):
    return x.view(-1, 1, 28, 28), y                                         # 굳이 계속 none일 y를 새로 정의한 이유가 뭘까?????

class WrappedDataLoader:
    def __init__(self, dl, func):
        self.dl = dl
        self.func = func

    def __len__(self):
        return len(self.dl)

    # WrappedDataLoader클래스로 정의한 객체에서, iter함수를 사용하고 싶다면 이것을 정의한다.
    # yield == 생성기(generator) == https://python.bakyeono.net/chapter-7-4.html
    def __iter__(self): 
        batches = iter(self.dl)
        for b in batches:
            # print(type(b))                                                # list
            # print(len(b) , b[0].shape)                                    # 2(?) torch.Size([64, 784])
            # print(self.func(*b))                                          # 2장의 이미지가 view처리 되어 나온다.
            # print(len(self.func(*b)), self.func(*b)[0].shape)             # 2, torch.Size([64, 1, 28, 28])
            yield (self.func(*b))  # preprocess == func으로 동작한다. *b가 들어가는 것은.. 잘 모르겠다. 어째서지?

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)
# 위에서 train_dl을 잘 만져놓았으므로, model의 input은 무조건 적절한 사이즈의 input일 것이다.
model = nn.Sequential(
    nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.AdaptiveAvgPool2d(1),
    Lambda(lambda x: x.view(x.size(0), -1)),
)

opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
0 0.34880866147994993
1 0.2753501031970978

14. GPU사용해서 가속하기

print(torch.cuda.is_available())
dev = torch.device("cuda" if torch.cuda.is_available() else torch.device("cpu") )
# dev = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")  <- 홈페이지 방법. 둘다 된다.
def preprocess(x, y):
    return x.view(-1, 1, 28, 28).to(dev), y.to(dev)  # 핵심 포인트!!


train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)
model.to(dev)                                        # 이것도 핵심 포인트!!!
                                                     # 4Classifier에서 net.to(dev)를 검색해서 보자. <- 똑같은 방법 사용!
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
fit(epochs, model, loss_func, opt, train_dl, valid_dl)

【Paper】 Image Segmentation Using Deep Learning -A Survey [3]

Image Segmentation Using Deep Learning: A Survey 논문 리뷰 및 정리

(위성Segment) Segmentation Survey 논문 정리 3 논문 원본 : 2020 (cite:6) Image Segmentation Using Deep Learning: A Survey

Section 4: IMAGE SEGMENTATION DATASETS

  • 이 세션에서는 이미지 세그먼테이션 데이터 세트에 대한 요약을 제공한다
  • 2가지 범주로 분류 : 2D 이미지, 3D 이미지, 2.5 이미지(depth카메라)
  • 일부 데이터셋에서는 data augmentation을 하는 것이 좋다.(특히 의료 이미지에서) 그 방법으로는 reflection, rotation, warping, scaling, color space shifting, cropping, and projections onto principal components과 같은 방법이 있다.
  • data augmentation를 통해서 모델의 성능을 향상시키고, 수렴 속도를 높히고, Overfitting 가능성을 줄이며, 일반화 성능을 향상시키는데 도움이 될 수 있다.

4.1 - 2D Datasets

  1. PASCAL Visual Object Classes (VOC) [141]
    • 5가지 정보 : classification, segmentation, detection, action recognition, and person layout
    • 21가지 segmentation class
    • 각각 1,464, 1,449개의 Train, Validation 이미지
  2. PASCAL Context [142]
    • PASCAL VOC의 확장데이터
    • 400개의 segmentation class {divided into three categories (objects, stuff, and hybrids)}
    • 하지만 너무 희박하게 존제하는 data 때문에 사실상, 59개의 자주 나타나는 class로 일반적으로 적용된다.
  3. Microsoft Common Objects in Context (MS COCO) [143]
    • dataset : 91 objects types / 2.5 million labeled instances / 328k images
    • segmenting individual object instances
    • detection : 80 classes / 82k train images / 40.5k validation / 80k test images
  4. Cityscapes [144]
    • semantic understanding of urban street scenes에 집중되어 있다.
    • diverse set of stereo video sequences / 50 cities / 25k frames
    • 30 classes(grouped into 8 categories)
  5. ADE20K[134] / MIT Scene Parsing (SceneParse150)
    • scene parsing algorithms을 위한 training and evaluation platform
    • 20K images for training/ 2K images for validation / 150 semantic categories
  6. SiftFlow [145]
    • 2,688개의 정보 있는 이미지
    • 258*258이미지
    • 8 가지 풍경(산 바다 등.. ) / 33 semantic classes
  7. Stanford background [146]
    • 하나 이상의 forground(객체)가 있는 715 images
  8. BSD (Berkeley Segmentation Dataset) [147]
    • 1,000 Corel dataset images
    • empirical basis(경험적 기초) for research on image segmentation
    • 공개적으로 흑백이미지, 칼라이미지 각각 300개가 있다.
  9. Youtube-Objects [148], [149]
    • 10 개의 PASCAL VOC class에 대한 동영상 데이터(weak annotations) [148]
    • 10,167 annotated 480x360 pixel frame [149]
  10. KITTI [150]
    • mobile robotics and autonomous driving에서 자주 쓰이는 데이터 셋
    • hours of videos(high-resolution RGB, grayscale stereo cameras, and a 3D laser scanners)
    • original dataset에서는 ground truth for semantic segmentation를 제공하지 않는다.
    • 그래서 직접 annotation한 데이터 셋으로 [151]에서 323 images from the road detection challenge with 3 classes(road, vertical(빌딩, 보행자 같은), and sky)
  11. 그 외 추가 데이터 셋
    • Semantic Boundaries Dataset (SBD) [152]
    • PASCAL Part [153]
    • SYNTHIA [154]
    • Adobes Portrait Segmentation [155]

image

4.2 - 2.5D Datasets

  • RGB-D 이미지는 비교적 저렴한 방법으로 데이터를 얻을 수 있기 때문에 많은 분야에서 사용되고 있다.
  1. NYU-D V2 [156]
    • the RGB and depth cameras of the Microsoft Kinect
    • 1,449개의 labeled 이미지. 3개의 도시
    • instance number가 기록되어 있다.
    • 407,024 unlabeled frames
  2. SUN-3D [157]
    • RGB-D video dataset
  3. SUN RGB-D [158]
    • an RGB-D benchmark for the goal of advancing the state-of-the-art
    • four different sensors / 10,000 RGB-D images
    • 2D polygons / 3D bounding boxes
  4. UW RGB-D Object Dataset [159]
    • a Kinect style 3D camera.
    • 51 categories / 640 480 pixel RGB and depth images at 30 Hz
  5. ScanNet [160]
    • an RGB-D video dataset
    • nstance- level semantic segmentations
    • 3D scene understanding tasks에서 사용.
    • 3D object classification, semantic voxel labeling, and CAD model retrieval.에서도 사용된다.

image

4.3 - 3D Datasets

  • robotic, medical image analysis, 3D scene analysis, construction applications(공사 응용)에 사용되는 3D이미지 데이터셋을 살펴본다.
  • 3D datasets은 point clouds와 같이, meshes or other volumetric representations(표현법)으로 제공된다.
  1. Stanford 2D-3D [161]
    • instance-level semantic and geometric annotations from 2D, 2.5D and 3D
    • 6 indoor areas
    • 70,000 RGB images along with the corresponding depths, surface normals, semantic annotations, global XYZ images as well as camera information.
  2. ShapeNet dataset [162] [163]
    • single clean 3D models
    • 55 common object categories with about 51,300 unique 3D models
  3. Sydney Urban Objects Dataset [164]
    • urban road objects of Sydney, Australia.
    • vehicles, pedestrians, signs and trees

Section 5: PERFORMANCE REVIEW

  • segmentation models의 성능을 평가하기 위해서, 사용하는 popular metrics(업무 수행 결과를 보여주는 계량적 분석)을 몇가지 소개해준다.
  • 유망한 DL-based segmentation models에 대한 정량적 성능표도 제공한다.
  • 모델을 평가하기 위해서는 많은 요소를 보아야한다. Ex. quantitative accuracy, speed (inference time), and storage requirements (memory footprint)

5.1 Metrics For Segmentation Models

여기에서는 the accuracy of segmentation을 평가하기 위한 몇가지 metrics을 소개한다.

image
  1. Pixel accuracy - 식(2)
    • 모든 픽셀 중 잘 segmentation한 픽셀의 비율
    • 식에서 K는 클래스의 갯수. K+1은 forground 추가
    • ground truth : class j / 예측한 class : i
    • 이것을 모든 클래스에 대해서 평균낸 것이 MPA(Mean Pixel Accuracy)이다. - 식(3)
  2. Intersection over Union (IoU) == the Jaccard Index - 식(4)
    • Mean-IoU : the average IoU over all classes. Sementation모델의 성능을 평가하기 위해 많이 사용되고 있다.
    • Precision / Recall - 식(5) : 참조링크
      • TP : the true positive fraction (클래스를 맞게 예측한 갯수)
      • FP : the false positive fraction (클래스를 틀리게 예측한 갯수)
      • FN : the false negative fraction (한 클래스에 대해서, 틀리게 예측한 갯수)
    • F1 score - 식(6)
      • precision & recall를 조화롭게 해놓은 mean
  3. Dice coefficient - 식(7)
    • IOU와 비슷하지만 다른 식이다. 비교해서 확인해보기.
    • Dice coefficient about foreground - 식(8)
      • binary segmentation maps(배경이냐? 객체냐?)
      • a positive class로써 foreground라고 생각하고, Dice 식을 쓰면 F1과 같은 식이 된다.

5.2 Quantitative Performance of DL-Based Models

imgae

  • Table1 : the PASCAL VOC
  • Table2 : the Cityscape test dataset
  • Table3 : the MS COCO stuff test set
  • Table4 : the ADE20k validation set
  • Table5 : the NYUD-v2 and SUNRGBD datasets for RGB-D segmentation (논문 참조)

  • 대부분의 모델에서 코드를 제공하지 않기 때문에, 논문의 내용을 재현하기 위해 많은 노력을 투자했다.
  • 일부 논문에서는 1. performance on non-standard benchmarks, 2. performance only on arbitrary subsets of the test set from a popular benchmark를 발표하고, 적절하고 완벽한 설명을 제공하지 않기 때문에, 실험이 쉽지 않았다.

section 6: CHALLENGES AND OPPORTUNITIES

  • 앞으로 Image segmentation 기술을 향상시키기 위한, 몇가지 유망한 연구방향을 소개한다.

6.1 More Challenging Datasets

  • large-scale image datasets이 많이 있지만, 더 까다로운 조건과 다양한 종류의 데이터가 필요하다.
  • 객체가 매우 많고나 객체들이 overlapping되어 있는 이미지들이 매우 중요하다.
  • 의료 이미지에서 더 많은 3D이미지 데이터셋이 필요하다.

6.2 Interpretable Deep Models

  • 성능이 좋은 모델들은 많지만, what exactly are deep models learning? / How should we interpret the features learned by these models? 에 대한 답변을 정확히 하지 못하고 있다.
  • 모델들의 구체적인 행동을 충분히 이해하는 연구가 필요하다. 이러한 이해는 더 좋은 모델을 개발하는데 큰 도움을 줄 것이다.

6.3 Weakly-Supervised and Unsupervised Learning

  • Weakly-supervised (a.k.a. few shot learning)과 unsuper- vised learning은 매우 각광 받고 있는 연구이다. 이 연구를 통해서 Segmentation에서 labeled dataset을 받는데 큰 도움을 받을 수 있을 것이다(특히 의료 분야에서).
  • The transfer learning(유명한 데이터 셋을 이용해 학습시킨 모델을 이용해 나의 데이터 셋에 맞게 fine-tune하는 것) 과 같이, Self-supervised learning도 우리에게 크게 유용할 것 이다. Self-supervised learning을 통해서 훨씬 적은 수의 데이터셋을 이용해서 Segmentation 모델을 학습시킬 수 있다.
  • 지금은 강화학습을 기반한 Segmentation 모델이 나오고 있지 않지만, 미래에 좋은 기반 방법이 될 수 있을 것이다.

6.4 Real-time Models for Various Applications

  • 최소 25프레임 상의 segmentation 모델을 가지는 것이 중요하다.
  • 이것은 자율주행자동차와 같은 컴퓨터 vision 시스템에 매우 유용할 것이다.
  • 현재 많은 모델들은 frame-rate와 거리가 멀다.
  • dilated convolution은 the speed of segmentation models을 올리는데 큰 도움을 주지만, 그래도 여전히 개선시켜야할 요지는 많다.

6.5 Memory Efficient Models

  • 많은 모델들은 inference를 하는데도 많은 메모리를 필요로 한다.
  • 휴대폰과 같은 장치에도 적합한 모델을 만들려면 네트워크를 단순화해야한다.
  • simpler models/ model compression techniques/ knowledge distillation techniques등을 사용해서 더 작은 메모리로 더 효율적으로 복잡한 내트워크를 수정할 수 있다.

6.6 3D Point-Cloud Segmentation

  • 3D 포인트 클라우드 세그멘테이션을 다루는 사람은 훨씬 적다. 하지만 그 관심이 점점 높아지고 있다. 특히 3D modeling, self-driving cars, robotics, building modeling에서.
  • 3D unordered and unstructured data를 처리하기 위해서 CNNs and other classical deep learning architectures를 적용하는것이 가장 좋은 방법인지는 확실하지 않다.
  • Graph-based deep models이 3D point-cloud segmentation를 다루는데에 좋을 수도 있다.
  • point-cloud segmentation이 가능하다면 많은 산업적 응용이 가능할 것이다.

7 CONCLUSIONS

  • 우리는 100개 이상의 Image segmentation모델을 비교해보았다.

Pagination


© All rights reserved By Junha Song.