¿¬»êµéÀÇ µ¿ÀÛ ¿ø¸®¸¦ ÃæºÐÈ÷ ÀÌÇØÇÑÈÄ ´Ù½Ã º¸¼Åµµ ´ÊÁö ¾Ê½À´Ï´Ù.
2014 ILSVRC 2nd place
# ·±Å¸ÀÓ À¯Çü GPU ¸ðµå·Î º¯°æ
!pip install torch torchvision
Requirement already satisfied: torch in /usr/local/lib/python3.6/dist-packages (1.1.0) Requirement already satisfied: torchvision in /usr/local/lib/python3.6/dist-packages (0.3.0) Requirement already satisfied: numpy in /usr/local/lib/python3.6/dist-packages (from torch) (1.16.4) Requirement already satisfied: pillow>=4.1.1 in /usr/local/lib/python3.6/dist-packages (from torchvision) (4.3.0) Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from torchvision) (1.12.0) Requirement already satisfied: olefile in /usr/local/lib/python3.6/dist-packages (from pillow>=4.1.1->torchvision) (0.46)
!rm -r images
import os
# À̹ÌÁö ÆÄÀÏÀ» ÀúÀåÇÒ Æú´õ¸¦ »ý¼ºÇÕ´Ï´Ù.
try:
os.mkdir("images")
os.mkdir("images/dogs")
os.mkdir("images/cats")
except:
pass
# À̹ÌÁöµéÀ» ÁöÁ¤ÇÑ À§Ä¡¿¡ ´Ù¿î·ÎµåÇÕ´Ï´Ù.
# images/dogs ¹Ø¿¡ 2°³
!wget https://i.kinja-img.com/gawker-media/image/upload/s--WFkXeene--/c_scale,f_auto,fl_progressive,q_80,w_800/ol9ceoqxidudap8owlwn.jpg -P images/dogs
!wget https://www.rspcansw.org.au/wp-content/uploads/2017/08/50_a-feature_dogs-and-puppies_mobile.jpg -P images/dogs
# images/cats ¹Ø¿¡ 2°³
!wget https://www.catster.com/wp-content/uploads/2018/05/A-gray-cat-crying-looking-upset.jpg -P images/cats
!wget https://www.scarymommy.com/wp-content/uploads/2018/01/c1.jpg?w=700 -P images/cats
rm: cannot remove 'images': No such file or directory --2019-08-26 07:56:09-- https://i.kinja-img.com/gawker-media/image/upload/s--WFkXeene--/c_scale,f_auto,fl_progressive,q_80,w_800/ol9ceoqxidudap8owlwn.jpg Resolving i.kinja-img.com (i.kinja-img.com)... 151.101.194.166, 151.101.130.166, 151.101.2.166, ... Connecting to i.kinja-img.com (i.kinja-img.com)|151.101.194.166|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 32099 (31K) [image/jpeg] Saving to: ¡®images/dogs/ol9ceoqxidudap8owlwn.jpg¡¯ ol9ceoqxidudap8owlw 100%[===================>] 31.35K --.-KB/s in 0.005s 2019-08-26 07:56:10 (5.82 MB/s) - ¡®images/dogs/ol9ceoqxidudap8owlwn.jpg¡¯ saved [32099/32099] --2019-08-26 07:56:15-- https://www.rspcansw.org.au/wp-content/uploads/2017/08/50_a-feature_dogs-and-puppies_mobile.jpg Resolving www.rspcansw.org.au (www.rspcansw.org.au)... 101.0.77.122 Connecting to www.rspcansw.org.au (www.rspcansw.org.au)|101.0.77.122|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 130940 (128K) [image/jpeg] Saving to: ¡®images/dogs/50_a-feature_dogs-and-puppies_mobile.jpg¡¯ 50_a-feature_dogs-a 100%[===================>] 127.87K 157KB/s in 0.8s 2019-08-26 07:56:17 (157 KB/s) - ¡®images/dogs/50_a-feature_dogs-and-puppies_mobile.jpg¡¯ saved [130940/130940] --2019-08-26 07:56:19-- https://www.catster.com/wp-content/uploads/2018/05/A-gray-cat-crying-looking-upset.jpg Resolving www.catster.com (www.catster.com)... 192.124.249.102 Connecting to www.catster.com (www.catster.com)|192.124.249.102|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 165145 (161K) [image/jpeg] Saving to: ¡®images/cats/A-gray-cat-crying-looking-upset.jpg¡¯ A-gray-cat-crying-l 100%[===================>] 161.27K --.-KB/s in 0.03s 2019-08-26 07:56:19 (5.12 MB/s) - ¡®images/cats/A-gray-cat-crying-looking-upset.jpg¡¯ saved [165145/165145] --2019-08-26 07:56:22-- https://www.scarymommy.com/wp-content/uploads/2018/01/c1.jpg?w=700 Resolving www.scarymommy.com (www.scarymommy.com)... 104.18.166.96, 104.18.164.96, 104.18.168.96, ... Connecting to www.scarymommy.com (www.scarymommy.com)|104.18.166.96|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 2169547 (2.1M) [image/jpeg] Saving to: ¡®images/cats/c1.jpg?w=700¡¯ c1.jpg?w=700 100%[===================>] 2.07M --.-KB/s in 0.03s 2019-08-26 07:56:23 (67.4 MB/s) - ¡®images/cats/c1.jpg?w=700¡¯ saved [2169547/2169547]
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.init as init
import torch.utils.data as data
import torchvision.datasets as dset
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
batch_size= 1
learning_rate = 0.0002
num_epoch = 100
ex)
root/dog/xxx.png
root/dog/xxy.png
root/cat/123.png
root/cat/nsdf3.png
# ¶óº§(ȤÀº Ŭ·¡½º) º°·Î Æú´õ°¡ ÀúÀåµÇ¾î ÀÖ´Â ·çÆ® µð·ºÅ丮¸¦ ÁöÁ¤ÇÕ´Ï´Ù.
img_dir = "./images"
# ÇØ´ç ·çÆ® µð·ºÅ丮¸¦ ImageFolder ÇÔ¼ö¿¡ Àü´ÞÇÕ´Ï´Ù.
# À̶§ À̹ÌÁöµé¿¡ ´ëÇÑ º¯Çüµµ °°ÀÌ Àü´ÞÇØÁÝ´Ï´Ù.
img_data = dset.ImageFolder(img_dir, transforms.Compose([
transforms.Resize(256), # À̹ÌÁö Å©±â¸¦ 256x256À¸·Î ¹Ù²ãÁÝ´Ï´Ù.
transforms.RandomResizedCrop(224), # 256x256 À̹ÌÁöÀÇ ·£´ýÇÑ À§Ä¡¿¡¼ 224x224 Å©±â¸¸Å »ùÇøµ ÇÕ´Ï´Ù.
transforms.RandomHorizontalFlip(), # ·£´ýÇÑ È®·ü·Î À̹ÌÁö¸¦ Á¿ì¹ÝÀü ÇÕ´Ï´Ù.
transforms.ToTensor(), # À̹ÌÁö µ¥ÀÌÅ͸¦ ÅÙ¼·Î º¯ÇüÇÕ´Ï´Ù.
]))
train_loader = data.DataLoader(img_data, batch_size=batch_size,
shuffle=True, num_workers=2)
# ÄÁº¼·ç¼Ç ¿¬»êÀÌ 2¹ø ¿¬¼ÓÇÏ´Â °æ¿ì
# ÄÁº¼·ç¼Ç-È°¼ºÈÇÔ¼ö-ÄÁº¼·ç¼Ç-È°¼ºÈÇÔ¼ö-Ç®¸µ
def conv_2_block(in_dim,out_dim):
model = nn.Sequential(
nn.Conv2d(in_dim,out_dim,kernel_size=3,padding=1),
nn.ReLU(),
nn.Conv2d(out_dim,out_dim,kernel_size=3,padding=1),
nn.ReLU(),
nn.MaxPool2d(2,2)
)
return model
# ÄÁº¼·ç¼Ç ¿¬»êÀÌ 3¹ø ¿¬¼ÓÇÏ´Â °æ¿ì
# ÄÁº¼·ç¼Ç-È°¼ºÈÇÔ¼ö-ÄÁº¼·ç¼Ç-È°¼ºÈÇÔ¼ö-ÄÁº¼·ç¼Ç-È°¼ºÈÇÔ¼ö-Ç®¸µ
def conv_3_block(in_dim,out_dim):
model = nn.Sequential(
nn.Conv2d(in_dim,out_dim,kernel_size=3,padding=1),
nn.ReLU(),
nn.Conv2d(out_dim,out_dim,kernel_size=3,padding=1),
nn.ReLU(),
nn.Conv2d(out_dim,out_dim,kernel_size=3,padding=1),
nn.ReLU(),
nn.MaxPool2d(2,2)
)
return model
# À§¿¡¼ Á¤ÀÇÇÑ ºí·ÏµéÀ» ÀÌ¿ëÇØ VGG ³×Æ®¿öÅ©¸¦ ¸¸µé¾îº¸°Ú½À´Ï´Ù.
# ÇÊÅÍÀÇ °³¼ö°¡ 2ÀÇ n½ÂÀÇ °ªÀ» °¡Áö±â ¶§¹®¿¡ base_dimÀ̶õ º¯¼ö¸¦ Ãß°¡Çؼ ´Ü¼øÈ Çß½À´Ï´Ù.
# ÇöÀç dog, cat µÎ °¡Áö Ŭ·¡½º¸¦ ±¸ºÐÇÏ·Á°í Çϱ⠶§¹®¿¡ num_classes=2·Î ¼³Á¤Çß½À´Ï´Ù.
class VGG(nn.Module):
def __init__(self, base_dim, num_classes=2):
super(VGG, self).__init__()
self.feature = nn.Sequential(
conv_2_block(3,base_dim),
conv_2_block(base_dim,2*base_dim),
conv_3_block(2*base_dim,4*base_dim),
conv_3_block(4*base_dim,8*base_dim),
conv_3_block(8*base_dim,8*base_dim),
)
self.fc_layer = nn.Sequential(
nn.Linear(8*base_dim * 7 * 7, 100),
nn.ReLU(True), # True ´Â inplace ¿¬»êÀ» ÇÏ°Ú´Ù´Â Àǹ̸¦ °¡Áý´Ï´Ù. inplace ¿¬»êÀº °á°ú°ªÀ» »õ·Î¿î º¯¼ö¿¡ °ªÀ» ÀúÀåÇÏ´Â ´ë½Å ±âÁ¸ÀÇ µ¥ÀÌÅ͸¦ ´ëüÇϴ°ÍÀ» ÀǹÌÇÕ´Ï´Ù.
#nn.Dropout(),
nn.Linear(100, 20),
nn.ReLU(True),
#nn.Dropout(),
nn.Linear(20, num_classes),
)
def forward(self, x):
x = self.feature(x)
x = x.view(x.size(0), -1) # x.size(0)¸¦ batch size·Î ¹Ù²ãµµ °°Àº °ªÀÔ´Ï´Ù.
x = self.fc_layer(x)
return x
# gpu°¡ »ç¿ë °¡´ÉÇÑ °æ¿ì¿¡´Â device¸¦ 0¹ø gpu·Î ¼³Á¤ÇÏ°í ºÒ°¡´ÉÇϸé cpu·Î ¼³Á¤ÇÕ´Ï´Ù.
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
# ¾Õ¼ Á¤ÀÇÇÑ´ë·Î vGG Ŭ·¡½º¸¦ ÀνºÅϽºÈ ÇÏ°í ÁöÁ¤ÇÑ ÀåÄ¡¿¡ ¿Ã¸³´Ï´Ù.
model = VGG(base_dim=16).to(device)
# ¼Õ½ÇÇÔ¼ö ¹× ÃÖÀûÈÇÔ¼ö¸¦ ¼³Á¤ÇÕ´Ï´Ù.
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# ¸ðµ¨ ÀÚ³à ³ëµåÀÇ À̸§°ú ¸ðµâÀ» Ãâ·ÂÇÕ´Ï´Ù.
for i in model.named_children():
print(i)
cuda:0 ('feature', Sequential( (0): Sequential( (0): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (1): Sequential( (0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (2): Sequential( (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() (4): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (5): ReLU() (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (3): Sequential( (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() (4): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (5): ReLU() (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (4): Sequential( (0): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() (4): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (5): ReLU() (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) )) ('fc_layer', Sequential( (0): Linear(in_features=6272, out_features=100, bias=True) (1): ReLU(inplace) (2): Linear(in_features=100, out_features=20, bias=True) (3): ReLU(inplace) (4): Linear(in_features=20, out_features=2, bias=True) ))
for i in range(num_epoch):
for j,[image,label] in enumerate(train_loader):
x = image.to(device)
y_= label.to(device)
optimizer.zero_grad()
output = model.forward(x)
loss = loss_func(output,y_)
loss.backward()
optimizer.step()
if i % 10 ==0:
print(loss)
tensor(0.6225, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.6045, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.5143, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.4301, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.4345, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.4101, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.4734, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.4204, device='cuda:0', grad_fn=<NllLossBackward>) tensor(0.6140, device='cuda:0', grad_fn=<NllLossBackward>) tensor(1.0608, device='cuda:0', grad_fn=<NllLossBackward>)