ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 성능 최적화
    딥러닝/이것저것 2023. 4. 1. 15:05

    👩‍💻 성능 최적화 방식 

     

    💚 데이터를 이용한 성능 최적화

    - 최대한 많은 데이터 수집하기 

     

    딥러닝과 머신러닝의 성능 비교

    - 데이터 생성 

    (이미지 조작 코드 - 앞 5장 참고하여 작성하기)

     

    - 데이터 범위 조정하기(스케일링) 

     활성화 함수인 시그모이드를 사용한다면 데이터셋 범위를 0~1의 값을 갖도록 하고, 하이퍼볼릭 탄젠트를 사용한다면 데이터셋 범위를 -1~1의 값을 갖도록 조정하는 것이 가능하다. 

     

    알고리즘 튜닝을 위한 성능 최적화 

     

    알고리즘 성능 평가 방식 

    - accuracy, F1 score, AP 메트릭스 등의 정확도 검증을 통한 판별

     

    성능 비교 

    훈련(train) 성능 >>> 검증(test) 성능

    - 과적합 의심

    - 해결책으로 규제화하기 

     

    훈련과 검증 결과가 모두 성능이 좋지 않은 상황

    - 과소적합 의심

    - 에포크 수 줄이기

     

    가중치 

    - 가중치에 대한 초깃값은 작은 난수를 사용해보기

    - 비지도 학습을 이용하여 사전 훈련(가중치 정보를 얻기 위한 사전 훈련)을 진행한 후 지도 학습을 진행해보기 

     

    학습률

    - 학습률은 모델의 네트워크 구성에 따라 다르기 때문에 초기에 매우 크거나 작은 임의의 난수를 선택하여 학습 결과를 보고 조금씩 변경해보는 것

    - 네트워크의 층이 많다면 학습률이 높아야 하며, 네트워크의 층이 적다면 학습률이 적어야 된다. 

     

    활성화 함수 

    - 일반적으로는 활성화 함수로 시그모이드나 하이퍼볼릭 탄젠트를 사용한다면 출력층에서는 소프트맥스나 시그모이드 함수를 많이 선택해서 사용한다. 

     

    배치와 에포크

    -  큰 에포크와 작은 배치를 사용하기 

    - 훈련 데이터셋의 크기를 동일하게 하거나 하나의 배치로 실험삼아서 훈련 진행해보기 

     

    옵티마이저와 손실함수 

     - 일반적으로 확률적 경사하강법(로지스틱 회귀 방식)을 주로 사용함 

    -  손실함수로는 아담이나 RMSProp 사용함 

     

    네트워크 구성

    - 하나의 은닉층에 뉴런을 여러 개 포함시키거나(네트워크가 넓다고 표현), 네트워크 계층을 늘리되 뉴런 개수는 줄여 보면서(네트워크가 깊다고 표현) 최적의 네트워크를 구축해보기 

     

    앙상블을 이용한 성능 최적화

     

    앙상블이란?

    간단히 모델을 두 개 이상 섞어서 사용해보기 

     

     

    하이퍼 파라미터를 이용한 성능 최적화

    배치 정규화 , 규제화, 표준화 

     

    정규화란(normalization)?

    - 데이터 범위를 사용자가 원하는 범위로 제한하는 것을 의미한다. 

    - 이미지 데이터는 픽셀 정보로 0~255 사이의 값을 갖게 되는데, 이를 255로 나누어 0.1~1 사이로 조정하는 것 등을 의미

     

    - feature scaling(피처 스케일링)으로도 표현하기도 함 

    - MinMaxScaler() 를 주로 사용 

          MinMaxScaler 수식

    - 기울기 소멸, 기울기 폭발 문제를 해결하기 위함 

    - 물론 손실함수로 ReLU를 사용하는 방법이나 초깁갓 튜닝, lr 설정 등 역시 쓰이기도 하지만 이들과 다같이 쓰이는 것이 배치 정규화이다. 

     

     

    ** 내부 공변량 변화

    - 기울기 소멸과 폭발을 유발하는 원인

    - 네트워크의 각 층마다 활성화 함수가 적용되면서 입력 값들의 분포가 계속 바뀌게 만드는 것

     

    미니배치 정규화 과정

     

    ① 미니 배치 평균을 구하기

     

    ② 미니 배치의 분산과 표준편차를 구함

     

    ③ 정규화를 수행한다.

     

    ④ 스케일(scale)을 조정(데이터 분포 조정)한다.

     

    규제화(regulation)

    - 모델 복잡도를 줄이기 위해 제약을 두는 방법

    - 데이터가 네트워크에 들어가기 전에 필터를 적용한 것 

    - 드롭아웃

     

    드롭아웃

    - 훈련할 때 일정 비율의 뉴런만 사용하고 나머지 뉴런에 해당하는 가중치는 업데이트하지 않는 것

    - 은닉층에 배치한 노드를 임의로 끄면서 학습함

    - 어떤 노드를 비활성화할지는 학습할 때마다 무작위로 선정되며, 테스트 데이터로 평가할 때는 노드들을 모두 사용하여 출력하되 노드 삭제 비율(드롭아웃 비율)을 곱해서 성능을 평가한다.

     

    💚 FASHIONMNIST 데이터셋을 통하여 배치 정규화 구현하기 

     

    ✍ 라이브러리 호출

    import torch
    import matplotlib.pyplot as plt
    import numpy as np
    
    import torchvision
    import torchvision.transforms as transforms
    
    import torch.nn as nn
    import torch.optim as optim

     

    ✍ FashionMNIST 데이터셋(이미지 데이터) 불러오기 

    trainset = torchvision.datasets.FashionMNIST(
                                root='..data/', train=True,
                                download=True,
                                transform=transforms.ToTensor())
                                # root = '' : ''라는 디렉토리에 다운받은 데이터셋을 넣는다. 
                                #transform=transforms.ToTensor() : 다운받은 데이터셋을 텐서형식으로 변환한다.
                                #데이터셋은 trainset이라는 변수 안에 저장된다.

     

    ✍ 데이터셋을 메모리로 가져오기 

    batch_size = 4 # 데이터를 메모리로 가져올 때 한 번에 네 개씩(미니배치 크기) 쪼개서 가져옴
    trainloader = torch.utils.data.DataLoader(trainset, batch_size =batch_size, shuffle=True )
    # trainloader이라는 변수는 DataLoader로 데이터셋을 메모리로 가져오는 행위 자체를 넣은 것

     

    ✍ 데이터셋 분리하기

    dataiter = iter(trainloader) #trainloader에서 원소를 하나씩 꺼내오는 것을 dataiter에 저장시킴
    images, labels = dataiter.next() #dataiter.next()로 하나씩 꺼내온 것을 각각 images, labels로 나눠서 저장한다.
    
    print(images.shape)
    print(images[0].shape)
    print(labels[0].item())

    images.shape

    [batch_size, channels, height, width] 로 출력

    - batch_size : 배치에 포함된 이미지의 개수

    - channels : 이미지 채널 (흑백은 1개의 채널을 가지고, 컬러 이미지는 3개의 채널을 가진다.)

    - width : 이미지의 높이와 너비를 나타낸다. 

    print구문 출력결과

    ✍ 이미지 데이터 전처리하기

    def imshow(img, title):
        plt.figure(figsize=(batch_size * 4, 4)) #출력할 개별 이미지의 크기 지정
        plt.axis('off')
        plt.imshow(np.transpose(img, (1, 2, 0)))
        plt.title(title)
        plt.show()

    plt.figure(figsize=(batch_size * 4, 4))

    - 출력할 개별 이미지의 크기를 지정

    - batch_size : 이미지 배치 크기

    - *4 : 출력할 이미지의 가로 길이

     

    plt.axis('off')좌표축을 없앤다. 

     

    transpose(출력할 이미지, (배치사이즈, 가로 길이, 채널 수))

    - np.transpose() 함수를 사용하여 이미지 데이터의 차원 순서를 변경하는 것 

    - 저대로 행렬 차원을 변경하여 imshow() 함수에 img를 전달한다.

    - 저 순서대로 변경해야지 넘파이 형태로 matplotlib에서 출력이 가능하다. 

     

    plt.title(title)

    - 이미지에 제목을 추가한다.

    - title은 함수의 두 번째 인자로 전달된 제목

     

    ✍ 이미지 데이터 출력함수 정의하기 

    def show_batch_images(dataloader):
        images, labels = next(iter(dataloader)) #가져온 이미지의 크기는 (4, 28, 28, 1(배치 크기, 높이, 너비, 채널))이 됩니다.
    
        img = torchvision.utils.make_grid(images) #torchvision.utils.make_grid : 좌표에 이미지 픽셀을 대응시켜 그리드 형태로 출력한다.
        imshow(img, title=[str(x.item()) for x in labels]) #imshow 함수를 사용함으로써 데이터의 형태는 (채널, 높이, 너비)에서 (높이, 너비, 채널)로 변경된다.
    
        return images, labels

     

    ✍ 이미지 출력하기

    images, labels = show_batch_images(trainloader)

    이미지 출력 결과

     

    ✍ 배치 정규화가 적용되지 않은 모델 네트워크 만들기

    class NormalNet(nn.Module):
        def __init__(self):
            super(NormalNet, self).__init__()
            self.classifier = nn.Sequential(
                nn.Linear(784, 48), #(28, 28) 크기의 이미지로 입력은 784(28×28) 크기가 된다.
                nn.ReLU(),
                nn.Linear(48, 24),
                nn.ReLU(),
                nn.Linear(24, 10) # FashionMNIST의 클래스는 총 열 개
            ) #nn.Sequential을 사용하면 forward( ) 함수에서 계층(layer)별로 가독성 있게 코드 구현이 가능하도록 도와준다.
    
        def forward(self, x):
            x = x.view(x.size(0), -1)
            x = self.classifier(x) #nn.Sequential에서 정의한 계층 호출
            return x
            
      # 배치 정규화가 적용되지 않은 모델 선언하기
      
      model = NormalNet()
      print(model)

     

     

    ** 과적합

    - 훈련 데이터셋을 과하게 학습하는 것 

    - 일반적으로 훈련 데이터셋은 실제 데이터셋의 부분 집합이므로 훈련 데이터셋에 대해서는 오류가 감소하지만, 테스트 데이터셋에 대해서는 오류가 증가하는데 이 증가가 급격해지는 상태를 과적합이라고 부른다. 

    ✍ 배치 정규화가 적용된 모델 네트워크 만들기

    class BNNet(nn.Module):
        def __init__(self):
            super(BNNet, self).__init__()
            self.classifier = nn.Sequential(
                nn.Linear(784, 48),
                nn.BatchNorm1d(48), # 배치정규화가 적용되는 부분으로 48은 이전 계층의 출력채널과 똑같이 작성해줘야 함
                nn.ReLU(),
                nn.Linear(48, 24),
                nn.BatchNorm1d(24),
                nn.ReLU(),
                nn.Linear(24, 10)
            )
    
        def forward(self, x):
            x = x.view(x.size(0), -1)
            x = self.classifier(x)
            return x
    #모델 선언
    model_bn = BNNet()
    print(model_bn)

     

    ✍ 모델 학습하기 

    loss_arr = []
    loss_bn_arr = []
    max_epochs = 2
    
    for epoch in range(max_epochs):
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            opt.zero_grad() #배치 정규화가 적용되지 않은 모델의 학습
            outputs = model(inputs)
            loss = loss_fn(outputs, labels)
            loss.backward()
            opt.step()
    
            opt_bn.zero_grad() #배치 정규화가 적용된 모델의 학습
            outputs_bn = model_bn(inputs)
            loss_bn = loss_fn(outputs_bn, labels)
            loss_bn.backward()
            opt_bn.step()
    
            loss_arr.append(loss.item())
            loss_bn_arr.append(loss_bn.item())
    
        plt.plot(loss_arr, 'yellow', label='Normal')
        plt.plot(loss_bn_arr, 'blue', label='BatchNorm')
        plt.legend()
        plt.show()

     

    배치 정규화 위치

     

     

    ✍ 데이터셋 메모리로 불러오기

    - 앞에서 불러오기는 했지만 이번에는 크기를 다르게 해서 불러오자 

    batch_size = 512
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)

     

    ✍ 모델에서 사용할 옵티마이저와 손실함수 지정하기 

    loss_fn = nn.CrossEntropyLoss()
    opt = optim.SGD(model.parameters(), lr=0.01)
    opt_bn = optim.SGD(model_bn.parameters(), lr=0.01)

     

    💚 FASHIONMNIST 데이터셋을 통하여 드롭아웃 구현하기 

     

    ✍ 데이터셋 분포 출력을 위한 전처리 

    N = 50
    noise = 0.3
    
    x_train = torch.unsqueeze(torch.linspace(-1, 1, N), 1) 
    y_train = x_train + noise * torch.normal(torch.zeros(N, 1), torch.ones(N, 1)) 
    
    x_test = torch.unsqueeze(torch.linspace(-1, 1, N), 1)
    y_test = x_test + noise * torch.normal(torch.zeros(N, 1), torch.ones(N, 1))

     

     

     

    표준화

     

    기존 데이터를 평균은 0, 표준편차는 1인 형태의 데이터로 만드는 것 

    - standard scaling(= z-score normalization)

    StandardScaling() 수식

     

Designed by Tistory.