最近私が意識していることを書いてみたいと思います。この内容が役に立つかもしれない人は、機械学習のプログラミングをする人で、あまりPythonを書いたことが無い仕事でプログラミングしたことがあまりないいつもプログラムの構成で悩んで、スッキリ書けないことが多いという人です。設計は「何に備えるか」を考える事に近いと思います。通常私が機械学習プロジェクトで意識しているのは以下のような点です。Production環境毎に異なる「データソースの場所」や「権限情報などの機密データ」の指定、のようなものまで色々あります。基本的にはこれらは「設定」により切り替えられるようにします。ログはちゃんと残すバッチ的に動くことが多いので、ログは非常に重要です。時刻付きで出力したり、ログレベル(どれだけ詳細にログを出力するか)が調整できることが大事です。機械学習モデルの切り替えができるようにする大抵はある程度性能を出すために、まだまだ人手によるモデルの試行錯誤が必要です。昨日とは全く違った新しい構造のモデルが発表され、試したくなることも多いでしょう。いう時に、新しい部分だけ記述することで、動作するようになっていると幸せです。他のプログラムから起動しやすいようにする特にハイパーパラメータの探索などの場合、複数のハイパーパラメータでの学習と評価を何度も行うことが多いです。そのような場合は、別プロセスで起動する方が何かと影響が少なくて良い気がします。いうケースを想定して、学習や評価を他のプログラムから別プロセスで実行しやすいようにしておくと便利です。設定周り設定を保持するClassを作ってデフォルト値を定義する設定はFlatなKey-Valueで持つよりは、JSONのような構造化できるように持っておくほうが表現力が高く、まとまりが良いので何かと便利です。...というように多少面倒でもClassを定義して、デフォルト値などを定義しておきます。Hintなどを上手く使うことでPyCharmなどのIDEが補完してくれるようになることです。すると、たくさんある設定の名前を正確に覚える必要もなくなり、タイプミスによる不具合をなくすことができます。設定ファイルを読み込んで、デフォルト値を上書きできるようにする次に少し実装が必要ですが、YAMLのような人間が読み書きし易いフォーマットで設定を定義して、デフォルト値を上書きできるようにしておくと便利です。今回はその実装は示しませんが色々な設定を1つのYAMLファイルに書いて、それを引数として与えることで、どの設定で実行したかがわかりやすくなります。環境についての設定は環境変数から取得するようにする例えば、権限情報やデータソースの設定は環境によって変わることがあります。最近だと、GPUの数やメモリサイズなどが違う場合こともあるでしょう。それらの設定はYAMLファイルからではなく、環境変数から読み込むと上記のYAMLを書き換えずに別の環境で動作させることが簡単にできます。いうファイルにKey-Value形式で書いておくことで読み込んでくれます(後述します)。.envというファイルはGitなどにコミットしてはいけないファイルなので、.gitignoreなどに書いておくようにしましょう。いう標準packageがありますが、なんか使い方がよくわからないので、私は最近まで使っていませんでした。ログレベルやログの出力先などを制御する仕組みを今更自分で再発明するのも無駄です。getLogger(__name__)と書いてlogger.info("message")というように使っています。getLogger().addHandler(stream_handler)というようにして、起動時に1回実行しておくと、ログファイルと標準出力に時刻付きで吐き出してくれます。後々、環境別にログレベルを変えたい場合も簡単にできます(ちょっと書き足せば)。さんの「機械学習で泣かないためのコード設計」を参考にしています。各種設定を保持します。以降のクラスは、インスタンス生成時にこのConfigを渡して保持しておくと便利です。DataProcessor主にデータの読み込みと前処理を担当します。前処理は、訓練の時と、予測の時に両方使うことがあるので、分離しておくと良いです。いうのがあって、この辺りの標準的になりそうな仕組みを活用できるようにした方がより良くなるような気がしています。ModelDL系のModelをWrapします。モデルの保存と読み込みを行うようにします。Trainerモデルの訓練を担当します。Methodを持たせます。ModelAPIモデルによる予測を担当します。Methodをもたせます。Modelによっては、InputやOutputの形状が変わったりするので、その辺りを吸収することがよくあります。モデルの切り替え例えば、同じタスクでも、RNNを使うモデルやCNNを使うモデルがあります。それらを切り替えたい場合に、設定だけで切り替えると、Modelの中にIF文が大量発生して、可読性が悪くなります。Training時の工夫もモデルの構造で変わってくることが多いので、大変です。ModelAPI)の3つを1つのセットとして増やしていくと、たぶん破綻せずにすみます。model_dog/model_api.pyというような構成にします。基底クラスを作っておいても良いかもしれません。しておけば、設定ファイルのmodel_catを使うと書けばmodel_catを使うようにしておくことで、簡単にモデルを切り替えることができるようになります。このような構成で1年以上運用していて、何パターンも新しいモデルを追加していますが、今のところ破綻せずに済んでいます。プログラムの起動周りここは色々な方法がありそうですが、私は以下のような方法に決めています。だいたい以下のようなコードになります。sys.exit(manager.start())以下の処理をしています。別ファイルにしておくと、相対PATHによるimportができるので少し便利です。いう相対指定のimportができない。毎回毎回実行時に環境変数PYTHONPATHを指定したりしなくて済みます。manager.py例えば、以下のようなコードになります。実際に行いたいコマンドに応じて、Configを引数とした関数の呼び出し。他のプログラムから呼び出しやすい?一応、YAMLファイルを一時ディレクトリに書き出して、引数で与えることでプログラムの振る舞いを変えることができます。入力や出力も、その一時ディレクトリに書き出すようにそのYAMLファイルで指示しておけば、並列に独立に実行することが一応できます。Dockerなどのコンテナに入れて実行する場合も大きな問題はないです(そりゃまあ、そうか)。さいごに以前、他の人から質問を受けたので書いてみました。参考になれば幸いです。