오늘은 Machine Learning 코드를 보면 사용자가 편리하게 하이퍼파라미터 지정할 수 있도록 활용되는 파이썬 패키지인 argparse에 대해서 알아보겠습니다.
python train.py --epochs 30 --batch_size 4 --checkpoint ./path
깃허브를 통해 배포된 소스코드나 모델을 돌릴 때 Terminal에 위와 같은 방식으로 실행시키는 경우가 많이 있습니다. 위의 실행 코드 덕분에 우리는 편하게 원하는 에폭수, 배치사이즈를 변경시킬 수 있습니다.
이러한 방식으로 코드를 실행시키는 이유는 다른 사람이 짠 코드를 내가 활용할 때에는 각자 컴퓨터 환경에 따라 몇가지 설정을 바꿔줘야 하기 때문입니다. 이 때 모든 소스코드를 다 돌아보며 필요한 설정값을 바꿔주는 것은 사용자 입장에서 매우 불편할 것입니다. 이를 편리하게 python terminal에서 몇가지 인자만 바꿔서 옵션으로 추가해주면 실행될 수 있도록 기능을 제공하는 것이 오늘 설명하는 argparse 패키지 입니다.
주의할 점
argparse는 기본적으로 터미널 명령창에서 실행되는 것을 원칙으로 합니다. Jupyter Notebook이나 대화형 실행 framework에서는 제대로 실행되지 않을 수 있습니다. argparse 패키지는 기본적으로 내장되어 있는 패키지 입니다.
import argparse
argparse는 기본적으로 아래와 같은 방식으로 실행됩니다.
<예시>
parser = argparse.ArgumentParser(description='description for project')
parser.add_argument('--print_number', type=int, help="insert number for print")
args = parser.parse_args()
if __name__ == "__main__":
print(f'print number: {str(args.print_number)}')
<실행결과>
print number: 5
parser = argparse.ArgumentParser(description='description for project') 첫번째 줄은 parser를 생성하는 과정입니다.parser.add_argument('--print_number', type=int) 이후 생성된 parser에 argument를 추가해줍니다. 이때 --print_number는 parser의 첫번째 인자의 이름이며, type을 지정할 수 있습니다.args = parser.parse_args() parser의 인자들을 코드에서 활용할 수 있게 args라는 이름으로 변수화 한 것이며, args.인자이름을 통해 parser의 각 인자들의 값을 활용할 수 있습니다.--help, -h는 기본적으로 내장되어 있는 기능으로 이 인자를 넣고 python을 실행하면 python 파일에서 지정할 수 있는 인자들에 대한 설명이 나옵니다. parser에 인자를 추가할 때 help 통해 해당 인자에 대한 설명을 추가하였다면, -h를 실행할 때 해당 설명도 함께 나오게 됩니다.
<예시>
python parser_example.py -h
<실행결과>
usage: parser_example.py [-h] [--print_number]
description for project
options:
-h, --help show this help message and exit
--print_number PRINT_NUMBER insert number for print
위에서 print_number를 추가하는 과정에서 help를 지정해줬기 때문에 그 부분이 실행결과에 출력되는 것을 볼 수 있습니다. 이를 추가함으로써 새로운 사용자가 각 인자들에 대한 간략한 설명을 확인할 수 있습니다.
--help와 같은 full name과 -h와 같은 약자를 하나씩 지정합니다.-혹은 --가 붙어 있으면 optional, 인자 이름만 있으면 positional 인자입니다.--name gr0o0vy 혹은 --name=gr0o0vy와 같은 방식으로 가능하며, positional 인자의 값은 인자의 이름 없이 파이썬 실행코드 뒤에 값만 붙이면 됩니다.<예시>
parser.add_argument('-bar', default='default')
parser.add_argument('aespa')
<실행결과>
#-bar: star, aespa: supernova
> python parser_example.py -bar star supernova
bar: star
aespa: supernova
#-bar: 지정하지 않음, aespa: supernova
> python parser_example.py supernova
bar: defalt
aespa: supernova
#-bar: 지정하지 않음, aespa: 지정하지 않음 -> 오류 발생
> python parser_example.py
usage: parser_example.py [-h] [-bar BAR] aespa
parser_example.py: error: the following arguments are required: aespa
positional 인자와 optional 인자를 모두 지정할 때에는 optional 인자 이름을 통해 optional 인자의 값을 입력할 수 있기 때문에 순서가 바뀌어도 되지만, positional 인자가 2개 이상일 경우에는 positional 인자끼리는 순서를 맞춰서 값을 지정해줘야 합니다.
parse_args()는 기본적으로 모든 인자를 문자열로 취급합니다. 따라서 다른 데이터 타입으로 인자의 값을 처리하고 싶다면 type을 지정해줘야합니다. defautl type은 문자열입니다.
argument의 type으로는 str, int, float, bool의 형태로 지정이 가능합니다. 이때 list는 사용할 수 없기 때문에 추후 설명할 action에서 append를 통해 list 지정이 가능합니다.
<예시>
parser.add_argument('-bar', type=int, default='default')
parser.add_argument('aespa', type=str)
action은 add_argument 과정에서 어떤 방식으로 인자를 저장할 것인지에 대한 action을 나타냅니다. default action은 store로 해당 argument에 인자의 값을 저장하는 action을 수행합니다. action의 종류에는 다음과 같은 것들이 있습니다.
store: default action으로 해당 argument에 인자의 값을 저장하는 action을 수행합니다.
store const: optional argument의 경우 인자의 값을 지정하지 않으면 const의 값이 저장됩니다. 이때 인자의 값만 지정하지 않는 것이지, 실행문에 인자는 불러와져야합니다.
<예시>
parser.add_argument('--foo','-f', action='store_const',const='foo1',default="foo2")
<실행결과>
> python argparse_example.py --foo #실행문에 인자를 불러옴
foo1 #const
> python argparse_example.py --foo foo3 #--foo를 foo3로 지정
foo3
> python argparse_example.py #foo2 #실행문에 --foo를 불러오지 않음
foo2 #defalut
store_true, store_false: 인자를 적으면(값은 주지 않음) 해당 인자에 True혹은 false가 저장됩니다. 만일 인자를 적지 않으면 각각의 default 값인 false와 true가 반환됩니다.
<예시>
```
parser.add_argument('--foo1', action='store_true')
parser.add_argument('--foo2', action='store_true')
parser.add_argument('--foo3', action='store_false')
parser.add_argument('--foo4', action='store_false')
args = parser.parse_args()
print('args.foo1:', args.foo1)
print('args.foo2:', args.foo2)
print('args.foo3:', args.foo3)
print('args.foo4:', args.foo4)
> python argparseTest.py --foo1 --foo4 #foo1과 foo4를 인자로 적음
args.foo1: True #foo1 store true
args.foo2: False #foo2 default
args.foo3: True #foo3 default
args.foo4: False #foo4 store true
```
append: 값을 하나가 아닌 여러개 저장하고 싶을 때 활용합니다. 동일한 인자에 값을 다르게 여러개를 추가하면 해당 인자는 list가 되고, 각 값은 해당 list에 append 됩니다. 참고로 한 번만 호출해도 args.foo는 데이터 타입이 list가 되지만,호출하지 않으면 None이 됩니다.
<예시>
parser.add_argument('--foo', action='append')
> python argparseTest.py --foo 1 --foo 123 --foo=xyz
args.foo: ['1', '123', 'xyz']
```
Machine learning 소스 코드에서 많이 활용되는 parser와 이 parser를 쉽게 다루기 위한 argparse 라이브러리에 대해서 알아봤습니다. 이는 나중에 직접 모델을 제작하고 배포할 때도 유용하게 활용될 수 있으니 많이 연습해 봐야겠습니다.