Home [BoostCamp AI Tech / P Stage 1] Day27 - Project Day 5-6
Post
Cancel

[BoostCamp AI Tech / P Stage 1] Day27 - Project Day 5-6

P Stage 1 : Project Day 5-6


Day 5-6 list

  1. Baseline code로 좋은 나만의 코드 템플릿 만들기

Baseline code 분석

dotenv

  • 서버와 관련된 접속 정보를 숨길 때 사용
  • 서버상에 환경변수로 설정하거나 설정된 값을 가져올 때 사용
  • python 뿐 아니라 javascript에서도 사용가능
  • 일반적으로 많이 쓰는 방법은 .env 파일에 다양한 환경변수를 설정하고 .gitignore에 파일 추가해서 깃허브 업로드는 막지만 로컬에서는 동작할 수 있게 하는듯
  • 개인적으로 프로젝트 진행할 때마다 이 부분에 대한 고민이 많았는데 이런 방법이 있었군….

argument 대한 고찰

  • 파이썬 머신러닝 코드는 argparse를 통해 argument를 받아서 실행함
  • 코드가 생각보다 길어지지만 불필요한 내용이므로 utils.py에 따로 빼서 관리하는 것이 좋아보임
  • 개인적으로 가끔 사용하는 경우인데 그때그때 생각나는 argument가 있을때마다 새로 추가하는 경우도 많아서 사용처에 따라 묶어서 적어두는 것이 좋다고 생각
    • 예를 들면 모델, 데이터는 같이 적어두고 모델의 hyperparameter 세팅끼리 묶어두는 것이 좋다고 생각
      $\rightarrow$ 이후 코드를 받아보는 다른 사람이 읽기 쉬울듯
  • lr_scheduler에서 사용되는 learning rate decay 값은 lambda로 지정되어 있는데 이는 lr_decaylambda 중 개인적으로는 lambda가 좋다고 생각하는데 겹치는 문제가 있을 수 있음
  • argument에 리스트를 입력하는 경우가 있을 수 있는데, 이때는 인자를 다음과 같이 주면 된다.
1
parser.add_argument("--resize", nargs="+", type=int, default=[512, 384])
  • argument에서 boolean type은 잘 안 받아지는데 이때는 다음과 같이 작성하자
1
2
3
from disutils.util import strtobool
parser.add_argument('--record' type=lambda x: bool(strtobool(x)),
                    defulat=False)

docstring과 typing, annotation

  • docstring을 사용하는 것이 좋아보임. 나 혼자 쓰거나 많은 사람들이 쓰진 않아도 버릇을 미리 들여놓는게 좋을듯
  • 부캠에서 프로덕트 서빙 조교님께서 typing 모듈과 annotation의 활용을 버릇화 하는게 좋다고 하셨다. 참고해서 연습해야겠음
  • 파이참은 이걸 자동 지원해줘서 넘 좋다 ㅎㅎ 난 구글 갈 거니까 Google Style로 했음

Dataset과 DataLoader에 대한 구조적 이해

  • Dataset의 인자로는 data_dir, mean, std, val_ratio가 존재
  • data_dir은 데이터(이미지)가 존재하는 최상위 폴더
  • 데이터 파일을 다루는 부분에 있어서 os 라이브러리를 잘 활용하는 쪽으로 가는 것이 좋을 것 같음. 단순 string 연산으로는 좀 무리가 있을 듯
    • os.path.join
    • os.path.splittext
  • class에 Enum 타입을 활용하는 경우가 있음
  • annotation을 사용하는 경우가 많음
    • @classmethod : 클래스 내에 공유되는 변수와 class method, static method에 접근 가능하게 해줌
    • 클래스 내부에 있을 필요는 없지만 연관성에 대한 가독성을 높이고자 클래스 내부에 작성
    • @staticmethod를 활용해서 클래스의 encoding, decoding을 해주는 메서드를 구현함
      $\rightarrow$ 이건 잘 기억해두자 : 모든걸 외부 함수로 할 필요없이 클래스 내부에 메서드로 만들어도된다.
  • 나는 데이터 셋에 모든 데이터를 데이터 프레임가 같은 통합적 형태로 다룰려고 했는데 baseline을 보면 ‘이미지 경로’, ‘마스크 라벨’, ‘성별 라벨’, ‘연령 라벨’로 따로 분리해서 핸들링하고 있다는 것을 알 수 있음
    • 사실상 순서만 같으면 무관하므로 이렇게 관리하는게 더 좋을듯
  • 네이밍 컨벤션은 보통 데이터는 단수, 데이터를 담는 리스트는 복수로 작성하는 것이 좋음
  • 옛날엔 훈련과정이랑 validation 과정에서 동일한 변수명을 썼는데 train, val은 구분해서 변수를 해주는 것이 좋을 것 같음

모듈 관리

  • 모듈을 관리하는 과정에서 getattr을 활용한 importlibimport_module을 자주 활용함
  • argument를 다량으로 받아올 수 있게 설정하고 다양한 optimizer, loss function, scheduler를 실험자가 마음대로 커스터마이징이 가능하게 함
  • 결과적으로 코드를 일반화하기에 아주 좋은 세팅임
  • 개인적으로 이번 베이스라인에서 가장 좋은 코드 일반화 소득

Scheduler Hyperparameter

  • 모델이랑 optimizer는 사용자가 실행시 argument로 자유롭게 설정이 가능함
  • Scheduler는 그렇지 않아서 이것도 가능하게 세팅 진행
  • 진행과정
    • 문제는 scheduler별로 가지고 있는 parameter가 다르다는 것
    • 처음에는 argparse에 모든 가능한 argument를 추가하려 했으나 이는 사실상 말이 안되는 과정 $\rightarrow$ 찾아보니까 내부 파라미터는 너무 많다.
    • 해결방법
      • 어차피 해당 스케쥴러 사용자는 들어가는 파라미터를 알고 있을 것이므로 사용자가 직접 파라미터를 입력하게 하면된다.
    • 따라서 argparse에는 딱 한줄만 추가
      1
      2
      
      parser.add_argument('--sch_params', dest='sch_params', action=StoreDictKeyPair, metavar="KEY1=VAL1,KEY2=VAL2",
                          help='Your scheduler parameters', required=True)
      
    • 여기서 사용된 StoreDictKeyPair는 커스텀 클래스로 코드는 다음과 같음
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
      class StoreDictKeyPair(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            my_dict = {}
            for kv in values.split(","):
                key, value = kv.split("=")
      
                for t in (int, float):
                    try:
                        value = t(value)
                    except ValueError:
                        pass
                    else:
                        break
      
                my_dict[key] = value
            setattr(namespace, self.dest, my_dict)
      
      • StoreDictKeyPair에서 문제는 argparse의 특성상 내부 인자를 문자열로 받아오는 것이었음
      • auto typcasting이 있었다면… 좋았겠지만 솔직히 어떤 언어가 문자열로 된 숫자가 int인지 float인지 구분 하는지…
      • 따라서 직접 type check를 통해 처리했음
      • intfloat보다 훨씬 엄격하게 타입 체크가 들어가므로 우선 int 통과여부를 확인했고 만약 둘 중 1개의 타입이라도 통과된다면 바로 type casting을 진행하고 멈춤
      • 만약 모든 타입 체크에 실패하면 무조건 문자열이므로 그대로 적용

학습경과 출력 문구 (f-string)

  • 원래도 f-string을 자주 썼지만 좀 더 잘 활용하고자 f-string을 추가로 알아봄
  • 문자정렬 $\rightarrow$ 각 옵션 넣고 자릿수 설정
    • 좌측 정렬 : f"{s1:<10}"
    • 가운데 정렬 : f"{s1:^10}"
    • 우측 정렬 : f"{s1:>10}"
  • :은 최소문자 폭을 의미하고 열을 줄 맞춤할 때 편리
This post is licensed under CC BY 4.0 by the author.

[BoostCamp AI Tech] Day26

[BoostCamp AI Tech / P Stage 1] Day28 - Project Day 8

Comments powered by Disqus.