-
패스트캠퍼스 환급챌린지 42일차 미션 (3월 13일) : 딥러닝·인공지능 Signature 초격차 패키지 Online. 강의 후기패스트캠퍼스 챌린지 2024. 3. 13. 14:04
자, 오늘은 학습할 것이 매우매우매우매우매우매우매우매우 많으므로
스크롤 압박이 있을 예정
CH11-01. GAN 실습&CH12-01. ResNet을 사용한 이미지 분류기 실습_모듈 이해하기
CH11-01. GAN 실습
# 실습목표# GAN을 사용하여 이미지 생성 모델을 만듭니다.(데이터셋: CIFAR10)GAN?
기억을 복기해보면 GAN은 2개의 신경망으로 구성되어있다.
1. Generator
2. Discriminator
제너레이터는 입력으로 노이즈를 받고, 이미지를 생성하는 역할을 하고,
디스크리미네이터는 생성된 이미지를 입력으로 받고, 각각의 이미지가 진짜인지/가짜인지 판단하는 역할을 한다.

둘다 모두 학습을 시키는 것이 GAN이다.
하나의 신경망을 학습시키는 것은 익숙한데, 2개를 학습시킨다? 어려울 것 같은데, 한번 알아보자
1. Libraries Load
#Step1. Load libraries & Datasetsimport osimport numpy as npimport mathimport matplotlib.pyplot as plt
import torchvision.utils as utilsimport torchvision.transforms as transformsfrom torchvision.utils import save_imagefrom torchvision import datasets
from torch.utils.data import DataLoaderimport torchimport torch.nn as nnimport torch.nn.funtional as Fimage_size = 64dataset = datasets.CIFAR10(root = 'data', download = True,transform = transforms.Compose([transforms.Resize(image_size),transforms.CenterCrop(image_size),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5),(0.5, 0.5, 0.5)),]))이미지를 64,64로 변환해서 다운받을꺼고,
자. 그렇담 두번째는 하이퍼파라미터 설정이다.
2. Set hyperparameters
#Step2. Set hyperparameters
n_epochs = 5batch_size = 128lr = 0.0002b1 = 0.5b2 = 0.999latent_dim = 100channels = 1sample_interval = 400device = torch.device("cuda" if(torch.cuda.is_available()) else "cpu")에폭은 5로 설정하고, 배치사이즈는 128 그리고 필요한 변수들을 사전에 선언해 두었다.
3.DataLoader
# Step3. DataLoaderdataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle =True)이번은 데이터셋을 가지고 데이터로더를 만들껀데, 뭔가 이상하지 않은감?
원래 맨날 트레인셋, 테스트셋으로 만들어놓고 데이터로더도 2개만들어 줬던 것 같은데?....
GAN의 학습은 입력데이터와 그것의 타겟데이터로 구성된게 아니다.
진짜 데이터만 있으면 되고, 그것을 학습용/테스트 용으로 분할할 필요가 없다.
나중에 디스크리미네이터가 잘 판별하고 있는지, 제너레이팅된 데이터와 실제 데이터를 분간할 수 있는지
그 때 사용할 데이터이기 때문에 데이터 로더 하나뿐인 것이다.

학습에 사용될 데이터셋을 출력해보면 10개의 컬러 클래스 이미지다.
def weights_init(w):classname = w.__class__.__name__if classname.find('conv') != -1:nn.init.normal_(w.weight.data, 0.0, 0.02)elif classname.find('bn') != -1:nn.init.normal_(w.weight.data, 1.0, 0.02)nn.init.constant_(w.bias.data, 0)신경망을 설계하기 전에, 각각의 신경망을 구성하고 있는 w 값을 초기화 할 수 있는 함수를 만들었다.
컨볼루션이냐, 배치노말라이제이션이냐에 따라 신경망이 구성하고 있는 웨이트 값들을 다른 형태로
초기화 할 수 있는 형태로 만들어 주었다.

먼저 제너레이터부분.
노이즈를 입력을 받고,
이 노이즈를 리쉐입 하고,
트랜스포즈 콘블루션 -> 배치 노말라이제이션 -> 렐루 를 반복해서 거치고,
마지막에는 트랜스포즈 콘불루션은 배치노말라이제이션 없고 하이퍼볼릭 탄젠트를 통과하는 신경망을 제안하였다.

디스크리미네이터를 봐보자.
입력을 이미지로 받고(64,64) 이 이미지를 받고
콘불루션 연산을 반복 수행하고 최종적으로 시그모이드를 수행해 진짜인지 가짜인지 확률을 0과 1사이로 내뱉어준다.
구현한 구조 그대로 코드를 쭉 봐보자.
class Generator(nn.Module):def __init__(self):super().__init__()self.tconv1 = nn.ConvTranspose2d(100, 64*8, kernel_size=4, stride=1, padding=0, bias=False)self.bn1 = nn.BatchNorm2d(64*8)self.tconv2 = nn.ConvTranspose2d(64*8, 64*4, 4, 2, 1, bias=False)self.bn2 = nn.BatchNorm2d(64*4)self.tconv3 = nn.ConvTranspose2d(64*4, 64*2, 4, 2, 1, bias=False)self.bn3 = nn.BatchNorm2d(64*2)self.tconv4 = nn.ConvTranspose2d(64*2, 64, 4, 2, 1, bias=False)self.bn4 = nn.BatchNorm2d(64)self.tconv5 = nn.ConvTranspose2d(64, 3, 4, 2, 1, bias=False)
def forward(self, x):x = F.relu(self.bn1(self.tconv1(x)))x = F.relu(self.bn2(self.tconv2(x)))x = F.relu(self.bn3(self.tconv3(x)))x = F.relu(self.bn4(self.tconv4(x)))x = F.tanh(self.tconv5(x))
return xclass Discriminator(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(3, 64, 4, 2, 1, bias=False) # 3 x 64 x 64self.conv2 = nn.Conv2d(64, 64*2, 4, 2, 1, bias=False)self.bn2 = nn.BatchNorm2d(64*2)self.conv3 = nn.Conv2d(64*2, 64*4, 4, 2, 1, bias=False) # 64 x 2 x 16 x 16self.bn3 = nn.BatchNorm2d(64*4)self.conv4 = nn.Conv2d(64*4, 64*8, 4, 2, 1, bias=False)# 64 x 4 x 8 x 8self.bn4 = nn.BatchNorm2d(64*8)self.conv5 = nn.Conv2d(64*8, 1, 4, 1, 0, bias=False)# 64 x 4 x 4 x 4
def forward(self, x):x = F.leaky_relu(self.conv1(x), 0.2, True)x = F.leaky_relu(self.bn2(self.conv2(x)), 0.2, True)x = F.leaky_relu(self.bn3(self.conv3(x)), 0.2, True)x = F.leaky_relu(self.bn4(self.conv4(x)), 0.2, True)x = F.sigmoid(self.conv5(x))
return x각각의 신경망을 설계했으면 모델의 인스턴스를 만들어보자.
# Create Model instancegenerator = Generator().to(device)discriminator = Discriminator().to(device)
generator.apply(weights_init)discriminator.apply(weights_init)
print(generator)print(discriminator)wieght.init 함수를 적용해서 각각의 레이어를 구성하는 웨이터,파람 초기값을 설정해준다.
7. model Compile
# Loss functionadversarial_loss = nn.BCELoss()
# Optimizersoptimizer_G = torch.optim.Adam(generator.parameters(), lr=lr, betas=(b1, b2))optimizer_D = torch.optim.Adam(discriminator.parameters(), lr=lr, betas=(b1, b2))제너레이터, 디스크리미네이터는 각각 아담을 사용하지만, 옵티마이저는 각각 다르게 선언해줘야 한다.
fixed_noise = torch.randn(64, 100, 1, 1, device=device)
real_label = 1.fake_label = 0.진짜데이터는 1, 가짜데이터 0을 출력하도록 레이블을 선언하고,
값에 대해 나중에 비교하는데 활용할 것이다.
# Step8 Training Model# Discriminator 학습# real data로 학습# fake data로 학습# Generator 학습디스크리미네이터를 학습하고 그다음 제너레이터를 학습해보자.
디스크리미네이트 학습
1. 리얼 학습
: 이미지에 대해서 진짜일 경우 1, 가짜일 경우 0으로 신경망을 업데이트 해야한다.그 예측값을 진짜 답이랑 로스값을 비교해서 웨잇 파람을 업데이트 한다.
2. 페이크 학습
: 디스크리미네이터를 여전히 학습시키고, 입력으로 64,64로 들어간다.(출력은 와이햇)
이 아이햇은 레이블이 0이 되도록 학습이 되어야 한다.
64바이 64는 가짜이미지가 들어가야하는데, 제너레이터가 만든 이미지가 들어가야 한다.
그래서 제너레이터가 먼저 수행되어야하고.
제너레이터의 출력으로 나온 것이 페이크 이미지인것이다.
제너레이터 학습
제너레이터의 입력은 노이즈가 들어가고, 출력은 64바이 64 이미지다.
디스크리미네이터에서 학습한 그 결과값이 원하는 형태가 되어야 한다

CH12-01. ResNet을 사용한 이미지 분류기 실습_모듈 이해하기
이번시간에는 레즈넷을 사용하여 이미지를 학습하고 10개의 카테고리를 갖는 이미지 분류기 생성해보자.
레즈넷이란?
"이번시간에는 레즈넷을 깊게 알아보고자 하는 것이 아니다 신경망을 만들어서 계속적으로 재학습 시킬 때
파라미터를 직접 만지는게 아니고 여러가지 파일을 나눠서 만드는데 전체적인 파일 구조를 알아보는 시간이다."
레즈넷에 대해 보통 파인튜닝을 해서 사용하는 사람들이 많은데,
이렇게 내가 튜닝을 할 때 파라미터들을 어떻게 조정할 수 있는가에 대해 초점을 맞춰서 얘기해보자.
ResNet은 깊은 신경망이고 스킵커넥션 구조다.
배치노말라이제이션을 적용하고,
마지막에는 분류기학습을 위해 FC를 구현하지 않고 GAP를 수행한다.
신경망을 만들다보면 계속 반복되는 부분들이 있다.
변하는 것들은 데이터 셋, 하이퍼 파라미터 같이 바뀌는 부분은 한정적이다.
그래서 하나의 파일에 대해 바뀌는 부분만 폴더를 따로 만들어서 관리면 좋지 않을까? 라는 개념으로 모듈관리가 생겼다.
(OOP!)
강의에서는 탬플릿을 하나 보여주는데,

앞으로 이런식으로 메인과 데이터 트레인 테스트로 나눠서 하는 실습을 진행해보도록 하자.
42일차 끝.
본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
'패스트캠퍼스 챌린지' 카테고리의 다른 글