P Stage 1 : Project Day 5-6
Day 5-6 list
- Baseline code로 좋은 나만의 코드 템플릿 만들기
Baseline code 분석
dotenv
- 서버와 관련된 접속 정보를 숨길 때 사용
- 서버상에 환경변수로 설정하거나 설정된 값을 가져올 때 사용
- python 뿐 아니라 javascript에서도 사용가능
- 일반적으로 많이 쓰는 방법은
.env
파일에 다양한 환경변수를 설정하고.gitignore
에 파일 추가해서 깃허브 업로드는 막지만 로컬에서는 동작할 수 있게 하는듯 - 개인적으로 프로젝트 진행할 때마다 이 부분에 대한 고민이 많았는데 이런 방법이 있었군….
argument 대한 고찰
- 파이썬 머신러닝 코드는
argparse
를 통해 argument를 받아서 실행함 - 코드가 생각보다 길어지지만 불필요한 내용이므로
utils.py
에 따로 빼서 관리하는 것이 좋아보임 - 개인적으로 가끔 사용하는 경우인데 그때그때 생각나는 argument가 있을때마다 새로 추가하는 경우도 많아서 사용처에 따라 묶어서 적어두는 것이 좋다고 생각
- 예를 들면 모델, 데이터는 같이 적어두고 모델의 hyperparameter 세팅끼리 묶어두는 것이 좋다고 생각
$\rightarrow$ 이후 코드를 받아보는 다른 사람이 읽기 쉬울듯
- 예를 들면 모델, 데이터는 같이 적어두고 모델의 hyperparameter 세팅끼리 묶어두는 것이 좋다고 생각
lr_scheduler
에서 사용되는 learning rate decay 값은lambda
로 지정되어 있는데 이는lr_decay
랑lambda
중 개인적으로는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
을 활용한importlib
의import_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를 통해 처리했음
int
는float
보다 훨씬 엄격하게 타입 체크가 들어가므로 우선int
통과여부를 확인했고 만약 둘 중 1개의 타입이라도 통과된다면 바로 type casting을 진행하고 멈춤- 만약 모든 타입 체크에 실패하면 무조건 문자열이므로 그대로 적용
학습경과 출력 문구 (f-string)
- 원래도 f-string을 자주 썼지만 좀 더 잘 활용하고자 f-string을 추가로 알아봄
- 문자정렬 $\rightarrow$ 각 옵션 넣고 자릿수 설정
- 좌측 정렬 :
f"{s1:<10}"
- 가운데 정렬 :
f"{s1:^10}"
- 우측 정렬 :
f"{s1:>10}"
- 좌측 정렬 :
:
은 최소문자 폭을 의미하고 열을 줄 맞춤할 때 편리
Comments powered by Disqus.