PL Template for NLP (1)

City_Duck·2023년 4월 21일
0

PL Template

목록 보기
2/6

Hydra : 페이스북에서 복잡한 config를 관리하기 위해 사용하는 오픈소스

NLP Model의 성능을 높이기 위해서는 다양한 하이퍼 파라미터 혹은 기법의 조합을 실험하고 이를 관리해야합니다.
이를 config 없이 수행한다면 일일이 변경해야하는 수고스러움이 생기기에 율적인 config 관리는 효율적은 학습에 도움이 됩니다.

이를 위해 Hydra Docs를 살펴보고자 합니다.

Hydra

발췌 : Hydra Docs

Getting started

  • Key features
    • 다양한 소스로 구성된 계층적 configuration
    • configuration이 커맨드 라인에서 선언 혹은 override가 가능
    • tab을 통해 쉽게 커맨드 작성 가능
    • 로컬 혹은 원격으로 실행 가능
    • 하나의 커맨드로 다양한 조합을 수행 가능
  • example
    # Hydra tree
    ├── conf
    │   ├── config.yaml			# default 설정 
    │   ├── db					# Group db
    │   │   ├── mysql.yaml	    
    │   │   └── postgresql.yaml
    │   └── __init__.py
    └── my_app.py			    # 실행의 주체

Tutorials

A simple command-line application

from omegaconf import DictConfig, OmegaConf
import hydra

@hydra.main(version_base=None)
def my_app(cfg: DictConfig) -> None:
    print(OmegaConf.to_yaml(cfg))

if __name__ == "__main__":
    my_app()

해당 예시에서 Hydra는 empty cfg object를 만들고 @hydra.main에 이를 전달합니다.
커맨드 라인에서 새로운 config value를 추가할 수 있는데 이 때 +는 해당 field가 new라는 알려줍니다.

$ python my_app.py +db.driver=mysql +db.user=omry +db.password=secret
db:
  driver: mysql
  user: omry
  password: secret

Specifying a config file

from omegaconf import DictConfig, OmegaConf
import hydra

@hydra.main(version_base=None, config_path=".", config_name="config")
def my_app(cfg):
    print(OmegaConf.to_yaml(cfg))

if __name__ == "__main__":
    my_app()

이와 같이 config_path와 config_name을 데코레이터에 명시함으로써 config file을 지정할 수 있습니다.
이 때 config 파일은 yaml 파일이여야 합니다.

커맨드라인에서 지정된 config 파일을 override 할 수 있는데 이 때는 +를 사용하지 않습니다.

# 원본
$ python my_app.py
db:
  driver: mysql
  user: omry
  password: secret

# override
$ python my_app.py db.user=root db.password=1234
db:
  driver: mysql
  user: root
  password: 1234

또한 ++를 사용해 기존에 존재하는 config를 override하거나 기존에 존재하지 않는 config를 추가할 수 있습니다.

# Override an existing item
$ python my_app.py ++db.password=1234

# Add a new item
$ python my_app.py ++db.timeout=5

Grouping config files

directory를 통해 config group을 만들 수 있습니다.

├─ conf
│  └─ db
│      ├─ mysql.yaml
│      └─ postgresql.yaml
└── my_app.py

여기서 db directory 안에 있는 mysql, postgresql은 db group으로 묶였다고 할 수 있습니다.

from omegaconf import DictConfig, OmegaConf
import hydra

@hydra.main(version_base=None, config_path="conf")
def my_app(cfg: DictConfig) -> None:
    print(OmegaConf.to_yaml(cfg))

if __name__ == "__main__":
    my_app()

이와 같이 config 파일을 명시하지 않아도 +GROUP=OPTION을 통해 config group에서 특정 config를 지정할 수 있다.

$ python my_app.py +db=postgresql
db:
  driver: postgresql
  pass: drowssap
  timeout: 10
  user: postgres_user

# override도 가능하다.
$ python my_app.py +db=postgresql db.timeout=20
db:
  driver: postgresql
  pass: drowssap
  timeout: 20
  user: postgres_user  

Selecting default configs

config.yaml을 통해 default configs를 설정할 수 있습니다.

# config.yaml
defaults:
  - db: mysql

이와 같이 defaults를 통해 간단히 default configs를 설정할 수 있습니다.
또한 _self_ 키워드를 통해 defaults의 override를 조정할 수 있습니다.

# config.yaml
defaults:
  - db: mysql
  - _self_

db:
  user: root
  
# result
db:
  driver: mysql  # db/mysql.yaml
  pass: secret   # db/mysql.yaml 
  user: root     # config.yaml

# config.yaml
defaults:
  - _self_
  - db: mysql

db:
  user: root
  
# result
db:
  driver: mysql # db/mysql.yaml
  pass: secret  # db/mysql.yaml
  user: omry    # db/mysql.yaml

_self가 아래에 있을 경우 config 파일이 override 하지만 _self가 위에 있을 경우에는 override되지 않는다.

Multi-run

>>> python my_app.py --multirun db=mysql,postgresql schema=warehouse,support,school
>>> python my_app.py -m db=mysql,postgresql schema=warehouse,support,school

해당 기능을 통해 여러개 조합의 config를 한번에 실행할 수 있다.
또한 sweeping을 할 수 있다.

# config.yaml
hydra:
  sweeper:
    params:
      db: mysql,postgresql
      schema: warehouse,support,school
      
# 다음과 같이 사용도 가능
x=range(1,10)                  # 1-9
schema=glob(*)                 # warehouse,support,school
schema=glob(*,exclude=w*)      # support,school

Logging

Hydra는 Python logging을 간편하게 설정할 수 있게한다.

import logging
from omegaconf import DictConfig
import hydra

# A logger for this file
log = logging.getLogger(__name__)

@hydra.main()
def my_app(_cfg: DictConfig) -> None:
    log.info("Info level message")
    log.debug("Debug level message")

if __name__ == "__main__":
    my_app()

$ python my_app.py
[2019-06-27 00:52:46,653][__main__][INFO] - Info level message

Common Patterns

Extending Configs

# config.yaml
defaults:
	- db : mysql

# db/mysql.yaml
defaults:
  - base_mysql

user: omry
password: secret
port: 3307
encoding: utf8

# db/base_mysql.yaml
host: localhost
port: 3306
user: ???
password: ???

이와 같이 순서대로 확장되는 경우 다음과 같이 output이 나온다.

>>> python my_app.py

db:
  host: localhost   # from db/base_mysql
  port: 3307        # overridden by db/mysql.yaml 
  user: omry        # populated by db/mysql.yaml
  password: secret  # populated by db/mysql.yaml
  encoding: utf8    # added by db/mysql.yaml

Configuring Experiments

├── config.yaml
├── db
│   ├── mysql.yaml
│   └── sqlite.yaml
└── server
    ├── apache.yaml
    └── nginx.yaml
    
>>> python my_app.py

db:
  name: mysql
server:
  name: apache
  port: 80

폴더 구조와 실행 결과값이 다음과 같을 때

# experiment/nglite.yaml

# @package _global_
defaults:
  - override /db: sqlite
  - override /server: nginx
  
server:
  port: 8080
  
>>> python my_app.py +experiment=nglite

db:
  name: sqlite
server:
  name: nginx
  port: 8080

다음과 같이 여러개의 설정을 한번에 바꿀 수 있다.
Key concepts:

  • #@package _global_ : config 파일과 sqlite, nginx가 서로 다른 폴더에 있기에 사용
  • The overrides of /db and /server are absolute paths : experiment 폴더 밖에 파일들이 존재하기에 절대 경로를 넣어줘야한다.

다음과 같이 간단하게 sweeping 할 수도 있다.

>>> python my_app.py --multirun +experiment=aplite,nglite

[HYDRA] Launching 2 jobs locally
[HYDRA]        #0 : +experiment=aplite
db:
  name: sqlite
server:
  name: apache
  port: 8080

[HYDRA]        #1 : +experiment=nglite
db:
  name: sqlite
server:
  name: nginx
  port: 8080

ETC.

Colorlog plugin

Optuna Sweeper plugin

profile
AI 새싹

0개의 댓글