호기심 많은 분석가

[BoostCamp] Week4_Day17. 여러번의 실패와 깊은 이해 본문

Coding/BoostCamp

[BoostCamp] Week4_Day17. 여러번의 실패와 깊은 이해

DA Hun 2021. 8. 30. 16:16
 

부스트캠프

개발자의 지속 가능한 성장을 위한 학습 커뮤니티

boostcamp.connect.or.kr

🕵🏻‍♂️마스크상태_분류_대회

  • torchvision.transforms는 100개가 있으면 그 이미지에 적용을 해줘서 200개가 되는 걸까?
    • 그렇지 않다. 그 이미지 자체에 값을 입혀서 변환시키는 것으로 개수는 같다. Resize, ToTensor와 같은 확정적인 것들은 모든 이미지에 입혀지고, HoriaontalFlip(p=0.5) 같은 랜덤으로 적용되는 것은 p의 확률을 기준으로 적용이 되거나 되지 않거나 한다
      transforms.Compose([ ToTensor(), 
      		Resize((512, 384)), 
      		HoriaontalFlip(p=0.5)] # default가 0.5 )
  • VS code에서는 작업을 돌려놓고 종료할 수 없을까?
  • 왜 항상 datetime.datetime.now()를 쓰면 현재 시간과 다를까?
    • UTC 시간 기준이기 때문, 우리는 UTC+9시간을 따르기 때문에 아래와 같이 해결할 수 있다
    • from pytz import timezone
      import datetime as dt
      
      now = (dt.datetime.now().astimezone(timezone("Asia/Seoul")).strftime("%Y-%m-%d_%H%M%S"))
  • Early Stopping을 구현하기 위해 지나간 모델을 pred_model = resnet18로 할당해주었는데, 제대로 된 할당이 되지 않음. 모델은 deepcopy로 할당해주어야 한다고 하는데, 그러기보다 가장 확실한 건 같은 이름으로 checkpoint를 계속 저장해주다가, EarlyStopping Point에서 끊어주면 된다.
  • transforms.Compose는 매번 적용하기 위해서는 epoch안에 위치시켜줘야 하는가?
    • 그렇지 않다. Epoch안의 아래 코드에서 dataloader를 호출할 때마다 배치 사이즈를 뽑아주면서 transform 시켜주기 때문에 밖에 위치해두어도 괜찮음
      for ind, (images, labels) in enumerate(dataloader):
  • 모델에 더 깊은 층을 쌓고, 함수화는 어떤 식으로 작업할까?
    • 모델을 print 해보니 구조가 나와서 조금 더 쉽게 이해하고, 여러 함수들을 적용할 수 있었다.
def resnet_finetune(model, classes):
    # pretrained된 모델을 불러옴
    model = model(pretrained=True)
    # resnet은 원래 512 -> 1000을 출력하는 모델인데 내가 128로 바꿔주고 한층 더 쌓아줌
    model.fc = nn.Linear(in_features=512, out_features=128, bias=True)
    model.bc = nn.BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    model.relu = nn.ReLU(inplace=True)
    # 마지막 
    model.fc2= nn.Linear(in_features=128, out_features=classes, bias=True)

    print("네트워크 필요 입력 채널 개수", model.conv1.weight.shape[1])
    print("네트워크 출력 채널 개수 (예측 class type 개수)", model.fc2.weight.shape[0])

    torch.nn.init.xavier_uniform_(model.fc2.weight)
    stdv = 1.0 / math.sqrt(model.fc2.weight.size(1))
    model.fc2.bias.data.uniform_(-stdv, stdv)

    return model
  • 깃헙을 서버 자체에 clone 할 수 있음을 배움 → 이것 때문에 얼마나 고생하였는가...
  • parameter.requires = False로 freeze 작업 가능

추후 시도할 것

  • albumentations Library 및 Transforms 더 적용
  • 배치 사이즈 키워보기
  • 다른 모델 적용해보기

📙개인학습

(5강) Model 1

  • 모델이 뭔가요?
    • In general, a model is an informative representation of an object, person or system
    • 모델은 object나 사람, 시스템의 정보의 표현이다.

Design Model with Pytorch

Open Source Machine Learning Framework → 연구나 공부에 굉장히 좋은 프레임워크

  • Low-level, Pythonic, Flexibility
    • High-level 제품처럼 굉장히 사용히 간단하기보다 내부 로직까지 조정할 수 있는 시각화로 치면 Seaborn보다 matplotlib에 가까운 느낌이다

nn.Module

  • Pytorch 모델의 모든 레이어는 nn.Module 클래스를 따른다
  • Super로 부모 클래스의 initalize들을 가져옴
    • Convolution도 위로 타고 타고 올라가면 ConNd라는 nn.Module 같은 클래스가 존재해서 같은 역할을 수행할 수 있게 도와준다.

modules

  • init에서 정의한 또 다른 nn.Module
    • self라는 본인의 member로 conv1, conv2를 정의해서 넣어주면 모델 자체가 새롭게 정의가 된다.
    • a라는 모델의 객체를 만들었으니 print를 하게 되면 모델의 설명이 나오게 되는데 방금 정의해준 initialize 해준 모듈들임
    • modules라는 함수는 a에 존재하는 여러 가지 모듈들을 하나씩 generation 해준다
      • 안에 있는 모듈도 나오고, 그 모듈의 child도 나오게 되는데, MyModel이라는 모듈이 nn.Module이라는 모듈을 할당했으니까 붙어서 같이 나오게 되는 것

forward

  • 이 모델(모듈)이 호출되었을 때 실행되는 함수

nn.Module Family

  • nn.Module을 상속받은 모든 클래스의 공통된 특징
    • 모든 nn.Module은 child modules를 가질 수 있다
    • 내 모델을 정의하는 순간, 그 모델에 연결된 모든 module을 확인할 수 있다.
      • Ex. backward 과정을 nn.Module에 정의된 방법을 사용할 것
    • 모든 nn.Module은 forward() 함수를 가진다
      • 내가 정의한 모델의 forward()를 한 번만 실행한 것으로 그 모델의 forward에 정의된 모듈 각각의 forward()가 실행된다.
      • 하나의 모델을 정의하는 것만으로도 전체적인 모듈들의 forward 함수들을 연결시킬 수 있고 실행할 수 있다.

Parameters

  • 모델에 정의되어 있는 module가 가지고 있는 계산에 쓰일 Parameter

  • 각 모델 파라미터 들은 data, grad, requires_grad 변수 등을 가지고 있다.
    • requires_grad : [True, False], False로 하면 특정 layer를 freeze 시켜서 트레이닝에 이용하지 않을 수 있음
    • grad : 각각의 parameter가 어떤 gradient를 가지고 있어서 순 전파가 거쳐갈 수 있는지 gradient를 저장하는 값

Pytorch의 Pythonic

  • Pythonic 하다는 것의 장점
    • 우리가 이러한 형식과 구조를 미리 알고 있다면 여러 가지 응용이 가능할뿐더러, 발생할 수 있는 에러들도 핸들링할 수 있다!


(6강) Model 2

일반적으로, 모델을 새로 설계 하는 데는 시간이 걸립니다. 
나는 당장 서비스를 해야 하는데, 모델 설계에 시간을 많이 쏟고 있다면 비효율적일 
수 있습니다. 따라서, 기존에 검증된 우수한 모델 구조와 미리 학습된 weight를 
재사용하는 방법에 대해서 다룹니다.

ImageNet

이미지넷이라는 데이터 셋이 만들어지면서 컴퓨터 비전이 급격히 떠올랐다

  • 획기적인 알고리즘 개발과, 검증을 위해 높은 품질의 데이터 셋은 필수적입니다.

Pretrained Model

배경

  • 모델 일반화를 위해 매번 수많은 이미지를 학습시키는 것은 까다롭고 비효율적
  • timn이라는 라이브러리에서도 더 다양한 pretrained model을 사용할 수 있다

Transfer Learning

1. CNN base 모델 구조 (simple)

  • Input + CNN Backbone(ResNet, VGG 등등) + Classifier → Output

2. Code Check

  • Torchvision model 구조
    • fc == fully connected layer == classifier

3. 내 데이터, 모델과의 유사성

  • Ex) ImageNet Pretraining
    • 실생활에 존재하는 이미지를 1000개의 다른 Class로 구분하자
    • Ex) 강아지, 고양이, 사과, 휴대폰, 의자, 화분, etc.

  • 내가 설정한 문제와 비교
    • 과연 ImageNet에 구름 위성사진이 있었을까, 그리고 강아지, 고양이처럼 확연히 다른 물체를 구분했던 CNN Backbone이 미세한 차이를 지니는 구름의 종류를 구분할 수 있을까
    • Pretraining 할 때 설정했던 문제와 현재 문제와의 유사성을 고려

4. Case by Case

Case 1. 문제를 해결하기 위한 학습 데이터가 충분하다.

  • CNN Backbone은 Input 데이터의 Feature를 추출해줌
  • Classifier는 추출된 Embedding을 바탕으로 Class를 새로 정의해줌
  • High Simiarity의 경우 이미 비슷한 이미지이므로 새로 Feature를 추출해줄 필요가 없다 → Freeze
  • 하지만 실험적으로 Similarity가 떨어지더라도 ImageNet Pretrained 된 Backbone 위에서 Trainable 하게 학습을 시키는 게 조금 더 좋다
  • CNN Backbone을 Freeze 하고 Classifier만 바꿔서 나오는 형태를 바꾸는 것을 Feature Extraction이라 함
  • CNN Backbone까지 미세 조정하는 방식을 Fine tuning이라 한다

Case 2. 학습 데이터가 충분하지 않은 경우

  • 가장 어려운 경우
  • High Similarity의 경우 다행히도 CNN Backbone을 Freeze 하고 Classifier를 바꿔주면 학습이 되지만 Low Similarity의 경우 좋지 않은 결과(Overfitting, Underfitting)를 낼 확률이 높다.

  • 그래서 우리의 주제와 Pretrained model이 만들어진 주제를 비교하고, 그 연관성과 Similarity를 가지고 우리의 데이터양까지 고려했을 때 어느 전략을 따를 것인가가 중요하다!

👨‍👨‍👦‍👦피어세션

굿모닝 세션 😉

  • 각자 작업내용 공유
    • 오주영
      • train, inference method 생성
      • transformer 추가 구현
      • lr_scheduler 추가함
    • 허정훈
      • 5-fold 나눠서 5개 모델 앙상블 → batch
      • freeze 성능이 안 나왔다.
      • data argumentation 시도해볼 예정
    • 이준혁
      • loss 가 계속 튄다(acc 95% ~ 15%로 많은 폭의 차이를 보인다)
      • model 추가
      • train, test, valid를 각 fold 마다 초기화가 되도록 구현
      • densenet을 사용하는 image size를 load 할 때 바꿔서 앞단의 layer를 사용하는 게 좋아 보인다.
        • 굳이 바꾸지 말고 어차피 마지막 fully-connected-layer 만 input에 의존적이니
    • 조현동
      • 이미지 자르는 걸 추가적으로 작업 중
    • 황원상
      • 아직 train 은 못 돌림
      • loss까지 구현(클래스별 loss algorithm을 각 class에 맞게 구한 후 더한 값을 출력)
      • 오늘 중에 train 하는 것이 목표
    • 임성민
      • dataloader 부분까지 작업 진행됨
  • freeze 하기 위해 참고한 블로그가 있는가?
  • num_worker를 몇으로 주었는지?
    • batch_size에 따라 다름 batch 가 크면 좀 작게 함
    • 8로 주었을 때 높은 성능 폭을 체감되어서 사용 중
  • 과적합을 시키는 게 결과가 더 잘 나오는 듯
    • 테스트 데이터와 학습 데이터가 크게 차이 나지 않는 듯
  • loss를 구하는 방법이 각 class 마다 다른데 그게 학습이 되는가?
    • class : 마스크, 젠더, 나이를 측정
    • 각 클래스 별로 backward() 하면 돼서 될 것 같다.
  • transforms.normalize 는 꼭 하자
  • 기존 model에서 layer를 빼는 방법은?
    • model.features 하면 conv, model.classifier 하면 linear
  • labeling

굿에프터눈 세션 😊

  • 오후 작업 내역(변경사항이 있는 멤버만)
    • 조현동
      • 한번 제출해보았다
      • class 분류는 주영님 베이스로 하되, 이미지를 자르는 부분만 추가해서 수행함
        • cvlib로 자름 → 찾아봐야겠다(링크 첨부해야 함)
        • import cv2
          import sys
          import pandas as pd
          import numpy as np
          import matplotlib.pyplot as plt
          import seaborn as sns
          import os
          import shutil
          from PIL import Image
          import cvlib as cv
          
          def crop_face(imagePath):
              image = cv2.imread(imagePath)
              faces,confidence = cv.detect_face(image)
              H,W,C = image.shape
              if not faces:
                  print(imagePath)
                  return image , True
              for x,y,w,h in faces:
          				#좌표값에 50을 넣은 이유가 너무 얼굴에 딱 붙여서 잘리기 때문에 넣은 값
                  image = image[max(y-50,0):min(h+50,H), max(0,x-50):min(w+50,W)]
                  break;
              return image ,False
    • 황원상
      • 디버깅 진행했고 training 동작하기 시작함
      • 내일 중으로는 제출할 수 있을 것으로 보임
    • 허정훈
      • early stopping 걸어줘서 성능을 체크하고 있음(성능이 좋은 모델을 선택하기 위함)
    • 이준혁
      • 현재 Densenet161 사용하고 있는데 parameter 가 많아서 OOM을 마주칠 것 같음
        • 한번 제출해본 뒤 성능이 좋지 않으면 가벼운 모델 사용 계획 중
    • 오주영
      • 모델의 성능을 올리기 위한 hyperparameter 조정 중
        • input에 따른 성능 차이가 아닌가로 생각하고 접근 → 확신으로 바뀜
  • 사진을 자르는 기준은?
    • 얼굴을 인식하냐 안 하냐로 기준을 나눔
      • 그 기준은?
        • 라이브러리의 기준인 듯(얼굴에 사각형을 그려 각 좌표값을 구하고 그 좌표값이 존재하지 않는 경우를 인식하지 않았다고 판단)
        • 데이터가 괜찮아서 가능한 방법이라고 판단함
    • 잘리지 않은 사진 중 마스크를 쓴 사진의 비율이 높았다
  • transfrom.Centercrop 보다 cv로 자르는 것을 권장함
  • dataloader에서 파일을 나눠놓지 않고 원본 폴더를 접근하는 방식인데 가져올 때 transform을 사용하면 이미지가 변형이 된다.
  • augmentation을 하는 이유는?
    • robust 하게 할 수 있어서
    • 과적합 해결
  • epoch 안에서 image를 불러야 하나요?
    • 상관없다.
  • 모델을 copy 하는 방법은?
    • deepcopy 사용해야 함
      • copy.deepcopy(model.state_dict())
    • checkpoint를 정해서 pickle 저장
  • fold 마다 성능 차이가 많이 나는가?
    • 주영님 : 1% 내외로 차이가 난다
    • 준혁님 : 5% 정도 차이가 난다
  • 다음 주에는 어떻게 작업을 진행하는 게 좋을지
    1. 각자 만들어 놓은 코드를 합친 후
    2. 각 모듈별 성능이 좋은걸 체크하는 방식으로
  • 이미지 비율을 바꾸는 augmentation 하는 것도 좋아 보임
    • 그전에 이미지를 좀 잘라내야 함

    ✍🏻학습회고

  • 아침 7시, 3등을 찍었다.

이미지 데이터를 다룰 줄 모르던 Day1, 여러 코드와 아이디어로 간단한 모델을 만든 Day2, 추가 작업을 통해 Score를 높인 Day3였다. 우리 팀은 구글 시트에 작업 내용들을 기록하고 있는데,

  1. model을 pretrained=True
  2. Epoch ↑
  3. Ensemble, Batch_size ↑

등의 방법들을 사용하였다. 작업마다 성능이 높아짐을 확인할 수 있었고 모방은 창조의 어머니라 하였던가, 나는 완벽히 이해하지 못하더라도 꽤 좋은 성능의 모델을 만드는 데 역량이 있다. → 이러한 강점을 잘 이용해야겠다.

남은 시간은 Early Stopping을 직접 구현해주다가 베이스라인이 필요하다는 분들이 많아 한번 작성해보았다. 주석들도 더 깔끔하게 달아보았고, 전체적인 내 코드의 흐름을 다시 정리하는 느낌이라 좋았다. 나도 첫날 정말 앞이 깜깜했는데 지금 대회가 조금 막막하신 분들께 조금이나마 도움이 되길 바란다.

 

 

[AI Tech]Daily Report

Naver AI Tech BoostCamp 2기 캠퍼 허정훈 2021.08.03 - 2021.12.27 https://bit.ly/3zvJnSh

data-hun.notion.site