0
1

バージョン管理とログ管理を楽にするサンプルコード

Last updated at Posted at 2024-06-14

研究をしているときにgitでバージョン管理をすることは少なくないと思います。

  • 複数人で開発を行っている場合
  • 同じファイル構造をローカルPCとリモートサーバーなど2箇所に保存し、実行する場所(サーバー・GPUなど)とコードを書く場所(PC)を分けて開発する場合

などでお世話になる機会が多く、gitに足を向けて寝られないエンジニアがほとんどなのではないでしょうか。

ある日、筆者はこのようなケースにぶち当たりました。

  • かなり前の学習モデルの動作確認をしようとしたが、モデル構造が以前と今では変更されており、どのバージョンまで戻せばいいのか分からない
  • nohup実行したときにnohup.outのどの部分にログが残っているのか分からない

このとき、git resetgit reflog,git revertを駆使して頑張ってバージョンを戻すことも可能ですが、間違えて今のファイルを全部消してしまうリスクもありますし、元のバージョンに戻すのが面倒くさいケースもあります。

極論言えば、タイムスタンプ付きのログ用フォルダを用意して、そこに移動すれば元のファイルを実行できる、というような環境を作りたいと考えました。

たとえばdatasetmodelsを外部からインポートしている場合、こうすれば当時の実行環境を再現できると思います。

  • フォルダ構造
-root
    -models
        -model_hogehoge.py
    -datasets
        -dataset_hogehoge.py
    -main.py
    -logs
  • コマンドライン、main.pyの実行例
.../root$ python main.py #実行コマンド
  • main.pyの書き方の例、このような形式で実行すると後で実行ログを振り返るのが楽ちんに。
main.py
from models import model_hogehoge
from datasets import dataset_hogehoge

import shutil
import os
import sys
from datetime import datetime, UTC, timedelta

if __name__ == "__main__":
    utc_time = datetime.now(UTC)
    #タイムスタンプ
    execution_time_str = (utc_time + timedelta(hours=9)).strftime('%Y%m%d_%H%M')
    log_folder = f"./logs/{execution_time_str}"
    #タイムスタンプを基にログフォルダを作成
    os.makedirs(log_folder, exist_ok=True)
    print(f"logs saved to {log_folder}") #この行だけ普通に標準出力

    # stdoutとstderrをログファイルに出力
    # このとき、実行ファイル名("main.py")はsys.argv[0]に格納されている
    out_f = open(f"{log_folder}/{sys.argv[0]}.log","w",encoding="utf-8")
    sys.stdout = out_f
    sys.stderr = out_f

    # 実行ファイルをログフォルダにコピー
    new_path = shutil.copy(f"{sys.argv[0]}",log_folder)
    parent_directory = '.'

    # 別ディレクトリからmain.pyを走らせていた場合
    # ただし兄弟ディレクトリとか(`../`)のケースは想定してないので注意
    if '/' in sys.argv[0]:
        parent_directory = '/'.join(sys.argv[0].split('/')[:-1])

    # importが必要なモジュールも入れておく
    datasets_path = shutil.copytree(f"{parent_directory}/datasets",f"{log_folder}/datasets")
    models_path = shutil.copytree(f"{parent_directory}/models",f"{log_folder}/models")

    #### ここに実行したいことを書く ####

    out_f.close()

できれば外部モジュールからimportしたものを自動でlog_folderにコピってくれるものも作りたいけど、やり方が分からず断念。

もしやり方が分かれば追記します

※このコードを応用してログを保存する場合、gitと併用するならばgitignoreするのを忘れずに(2024/6/21追記)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1