실험 관리

개시하다


안녕하세요, fkubota(현재 Kaggle Expert 20210225).이번엔 트위터에서도 자주 화제가 되는 실험 관리 방법을 쓰려고 한다.이전에 쓴 적이 있다카글 일기라는 전투법. 이 문장은 그래도 약간 관련이 있으니 필요하면 한번 보세요.
그리고 마요네즈(KagleMaster 등)에게는 유용한 정보가 없을 수도 있다.더 좋은 방법이 있으면 알려주세요.
이번 보도는script(*.py)가 실험을 진행할 때 이렇게 한 것을 소개했다.
가장 먼저 출전한 대회개구리 시합는 다섯 번째다.과거를 돌아보면 매번 반성하고 매번 과제를 해결하기 위해 노력한다.다섯 번째 때 드디어 제가 좋아하는 스타일을 정형화할 수 있을 것 같아서 소개해 드릴게요.

실험 스크립트 관리 모드


실험 스크립트를 관리할 때 세 가지 모델을 고려했다.각각 간단히 소개하다.

모드 1


src
├ config.yml
└ exp.py
lib
├ model.py
└ train.py
스크립트의 버전 관리 모델끊임없이 각본을 키우는 인상을 준다.이전 버전git checkout으로 돌아가려면 특정commiit로 돌아가세요.이거 찢어졌어.이유는 다음과 같습니다.
  • exp035와exp022의 스크립트를 비교하고 싶을 때 바로 만들 수 없습니다.
  • 자신의git의commiit관리가 믿음직하지 않다.
  • 재현적인 의미에서 좀 불안하다.
  • .

    모드 2


    lib
    ├ model.py
    └ train.py
    exp
    ├ exp001
    │ ├ config.yml
    │ └ exp.py
    ├ exp002
    │ ├ config.yml
    │ └ exp.py
    └ ...
    
    각 실험을 위해 스크립트를 분리하는 모델.관측된 감각으로 보아 이 패턴은 매우 많은 것 같다.모든 expXXX가 공통lib/*을 참조하는 것이 특징입니다.이것도 폐품이 되었다.
  • 한 번의 실험lib/*을 거칠 때마다 끊임없이 변화하기 때문에 예를 들어exp020의 실험 후exp001은 이동을 보장할 수 없다.
  • 또는 이동성 보장(후방 호환성?)이 점을 감안하면 대본 쓰기가 힘들다
  • 결과, 어떤 실험을 재현할 때git checkout 그commiit
  • 로 되돌아가야 한다.
  • 다른expXXX의 스크립트를 비교하고 싶을 때 XXXlib/*에 따라 비교적 번거롭기 때문에(github 같은 것을 사용하나요?)

  • 파괴적인 변경에 소극적이다.공통적lib/*이 있기 때문에 싫더라도 다른expXXX의 존재를 의식해야 하며 파이프의 구조에 하기 싫은 변경이 존재한다."대담한 실험이 어렵다"
  • 여기까지 요약하면 실험 각본에 대한 관리 요구는 다음과 같다.
  • 재현성
  • 파괴성을 소극적으로 바꾸지 않는다
  • 과거의 실험 스크립트를 즉시 참조할 수 있음
  • 모드 3


    결과적으로 촌스러워 일에 쓰지 않는다.몇 달 경기라 긴장이 풀릴 것 같아요.
    exp
    ├ exp001
    │ ├ config.yml
    │ ├ exp.py
    │ ├ model.py
    │ └ train.py
    ├ exp002
    │ ├ config.yml
    │ ├ exp.py
    │ ├ model.py
    │ └ train.py
    └ ...
    
    실험마다 완전히 독립된 스크립트 관리.이것에 따라 얼마든지 에드성을 허용할 수 있는 코드다.과거의 실험을 고려하지 않고 버릴 수도 있는 생각을 실현할 수 있다.파괴적인 변경은 얼마든지 할 수 있고, 그 변경이 안 되면 버리고 계속 진행하는 것도 쉽다.exp033/train.pyexp134/train.py를 비교하고 싶을 때도 바로 할 수 있습니다.물론 재현성도 있다.찬반 의견이 있을 것 같지만 지금은 이 관리가 편해요.
    평소 인코딩에vim를 사용했는데 ↓ 같은 느낌으로 원하는 정보를 바로 방문하고 싶은데 이 관리가 편리해요.
    exp002와exp001을 비교하는 예 열기
    ↓비교의 경우

    ↓ diff(명령::vert diffsplit ../exp001/exp.py
    아, 혹시 모르니까 이 패턴과 소감은 도대체 제 의견이에요. 관리를 잘하는 사람이 있을 거예요. 패턴이 한두 개쯤 될 거예요.내 실력으로는 어려울 뿐이니 탓하지 마세요.

    실험 단위


    예를 들어 그림의 크기를 바꾸는 실험을 고려해 보자.img_size=100200300400과 4가지 모델 테스트 시exp001,exp002...그래도 되는데 이건 좀 아닌 것 같아.의미 있는 총결산expXXX을 더 작은 단위로 도입runXXX.
    exp001의 실험에서 [run001,run002,run003,run004]라는 인상이 있었다.
    runXXX는 Kagle이 말한 submission 파일 1부입니다.1_exp:n_run:n_sub 단위로 관리한다.

    간단한 예


    모두가 이 실험 관리 방법을 더욱 쉽게 이해하고 모방할 수 있도록 우리는 모두가 좋아하는 방법으로 샘플을 만들었다.여기..다음은 창고에 대한 간단한 설명입니다.
    본론으로 들어가다.
    런을 가져와도 스크립트의 구성은 바뀌지 않습니다.
    exp
    ├ exp001
    │ ├ config.yml
    │ ├ exp.py
    │ ├ model.py
    │ └ train.py
    ├ exp002
    │ ├ config.yml
    │ ├ exp.py
    │ ├ model.py
    │ └ train.py
    └ ...
    
    irisデータセット 중 몇 개exp.py가 달리고 있다.
    ↓ 데면데면한 인상.
    def run(i):
        hoge
      
    def exp():
        for i in len(runs):
             run(i)
    
    실제 설치 상황을 설명합니다.여기가 중요해.
    실장이 목계 모형을 결정할 때run를 예로 들자.
    path:
      dir_save: ../../data/output/exp/
    
    model:
      params:
        random_state: 42
        max_depth: 5
    
    split:
      random_state: 42
    
    이 실험exp001에서config.yml를 1,2,3으로 변경한다.거기에 다음과 같은 코드가 쓰여 있다.
    def exp():
        list_config_str = [
            '''
            model:
                params:
                    max_depth: 1
            ''',
            '''
            model:
                params:
                    max_depth: 2
            ''',
            '''
            model:
                params:
                    max_depth: 3
            ''',
        ]
    
        for i_run, config_str in enumerate(list_config_str, 1):
            config_update = yaml.safe_load(config_str)
            run_name = f'run{str(i_run).zfill(3)}'
            run(run_name, config_update)
    
    하고 있는 일로
  • config의 Param에서 변경하려는 섹션 목록
  • max_depth에서str를dictyaml.safe_load
  • 로 변환
  • config_update를run
  • 에게 건네주기
    run에서 config.ymlconfig_update를 불러오고 부분만 고쳐 쓰는 처리이런 느낌이에요.업데이트로 만든 팔람은 복수도 할 수 있어 유연하다.그림의 크기가 커지는 동시에 대량의 크기를 줄여야 하기 때문에 매우 편리하다.
    list_config_str = [
        '''
        model:
            params:
                img_size: 100
        dataset:
            batch_size: 50
        ''',
        '''
        model:
            params:
                img_size: 400
        dataset:
            batch_size: 20
            ''',
        ]
    
    좀 귀찮아요.아주 추상적인 느낌으로 쓰면 그렇지.
    def run(update_cfg):
        new_cfg = update(base_cfg, update_cfg)
        train(cfg)
    
    def exp():
        for update_cfg in [update_cfg1, update_cfg2, ...]:
            run(update_cfg)
    
    그리고 출력은 당연히exp,run 단위로 출력한다.결과는 다음과 같은 디렉토리로 구성됩니다.
    example-exp-iris/
    ├── data
    │   └── output
    │       └── exp
    │           ├── exp001
    │           │   ├── run001
    │           │   │   └── config_update.yml
    │           │   ├── run002
    │           │   │   └── config_update.yml
    │           │   └── run003
    │           │       └── config_update.yml
    │           └── exp002
    │               ├── run001
    │               │   └── config_update.yml
    │               ├── run002
    │               │   └── config_update.yml
    │               ├── run003
    │               │   └── config_update.yml
    │               └── run004
    │                   └── config_update.yml
    └── exp
        ├── exp001
        │   ├── config.yml
        │   ├── exp.py
        │   └── util.py
        └── exp002
            ├── config.yml
            ├── exp.py
            └── util.py
    
    통상적으로 output에는 모델,log,도표 등이 저장되어 있지만 이번에는 간단하게 보기 위해 업데이트의config가 저장되어 있다.그리고 wandb도 썼어요.잘 됐다.이번 생략은

    끝맺다


    이렇게 오래 썼는데 끝까지 읽어주셔서 감사합니다.나는 실험의 관리가 사람에 따라 다르다고 생각한다.가능하다면 다양한 사람들의 관리를 참고하여 자신에게 맞는 것을 찾는 것이 좋습니다. 그러니 제 예를 참고하세요.나도 1년 뒤에 관리가 완전히 달라질 수도 있어.
    그게 다야.감사합니다!

    좋은 웹페이지 즐겨찾기