はじめに
アルゴリズム開発者とシステム実装者の間で、ときとして考え方の行き違いが生じることもあるようだ。
システム実装者の視点で、アルゴリズム開発者の書いたコードをみたとき、「使えないコード」とみなされたり、アルゴリズム開発者は、「まともなコードの書けないエンジニア」と即断されてしまうことがあったりする。
その理由の1つとして、それぞれの業務の性質によるソースコードの美意識の違いがあるのではないかと思い始めた。
どちらが正しいとか間違っているというものではなく、ソフトウェアのフェーズが違うので、その時点での着目する部分が異なるので、コードの美意識の違いになっているのではないかと推測する。
この文章では、一方の文化の人が他方の文化の人がどのように物事を考えるのかについて、相互理解につなげることがのぞみである。
前提
- ソースコードの品質・設計には、コードがどうあるべきかについての美意識が影響する。
- どのように機能を切り分け、APIをどう設計するのかが、ライブラリの使い勝手に影響するので、コードをどのように設計するのかは、重要な項目である。
「リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック」
システム構築者のコーディングの美意識
- 処理の入出力が明確であれば、それ以上のことは隠すのがよい。
- 依存しているライブラリが隠れている方がいい。
- 組み込みに使う範囲の必要かつ十分な範囲の最小限の機能をしかもってはならない。
- 想定している使い方以外の使い方ができてはならない。
- 常に一定の条件で動作するようにすること。データメンバーを直接いじってカスタマイズすることは嫌われる。
- アルゴリズムの性能のテストについては、既に検証されていることを前提として考えられることが多く、性能のテストコードと大量のテストデータをリポジトリに含むことは嫌われる。
システム構築者にとってのぞましいあり方
- 抽象クラスによってAPIが設計されている。
- その抽象クラスを実装するように個別の実装が存在する。
- 抽象クラスで設計されているAPIだけ、public メソッドが存在している。
- それ以外のメソッドはprivateメソッドとして存在している。
- データメンバーはprivateにする。
アルゴリズム構築者のコーディングの美意識
- どの段階で何をやっているのかが明示的な方がいい。
- 依存しているライブラリが見えやすいほうがいい。
- アルゴリズムのテストをするためのスクリプトとデータを適度にリポジトリに含めておきたい。
- アルゴリズムを設計するうえで、妥当性を検証するための動作を検証できる仕組みを必要とする。
- アルゴリズムを設計するうえで、カスタマイズが可能なことが求められる。
- コーディング上の自由度を減らしたくない。
- 以下のテストが必要
- 機能テスト
- 性能テスト
- 処理速度テスト
アルゴリズム構築者にとって初期の段階でのぞましいあり方
- データメンバーはpublicにする。
- setterのメソッド、getterのメソッドを作らない。
- 必要なAPIの設計が見定まるまでは、全てのメソッドをpublic にする。
- 使い方が見定まるまでは、ベタなコーディングをあること。
アルゴリズム構築段階では必要な機能
- 機能テスト
- 性能テスト
- 実行速度テスト
- 性能を評価するための結果のグラフ作成
機械学習の推論コードの場合
アルゴリズム開発者の書くコード
- 推論エンジンへの入力・出力のインタフェースが明示的であるコードであることが多い。
- 物体検出の推論エンジン:
- 入力の画像サイズ
- 出力の座標
これらが、使用している深層学習の枠組みを明示的にしている場合が多い。
システムのモジュールとして利用するソフトウェアエンジニアの書くコードの場合
- 推論エンジンへの入力・出力のインタフェースを隠蔽している場合が多い
アルゴリズム開発者は、実装するコードの100倍以上のコードを書く。
-
学習用のコード
-
学習用のデータを作成する作業の中で使用するツール
- データのサンプリングのためのツール。
- データに正解のアノテーションを付けるためのツール(既存ツールを利用する場合も多い。)
- 学習のアノテーション後の結果を確認するツール。
- 独自のデータ拡張用のツール。
-
機能テストのコード
APIが実装されていて、入出力の型があっていることの確認。 -
性能評価のコード
- 推論の実行結果の性能がどうであるのかを評価するさまざまな性能評価用のコード
-
実行速度評価のコード
- 時刻差では、マルチコアのCPUでの処理を評価できない。
- time 評価用の実行コード
- userの時間は複数のコアの分を含んでいる。
- profilerの実行
- profiler では、正確な実行速度は評価できない。
- profiler では、内部の関数の呼び出し回数が適切かどうかを確認できる。
- 実行速度の評価では、初回の呼び出しの分だけ、極端に時間がかかることがある。
-
デモ用のコード
- カメラ入力で画面出力のデモスクリプト
- 動画ファイル入力で画面出力のデモスクリプト
アルゴリズム開発者とは、アルゴリズムの実行結果を信用しない人種
アルゴリズム開発者とは、アルゴリズムを信用しない人種だ。
アルゴリズムには、目的の動作を必ず動作できる種類のものと、そうでないものとが存在する。並び替えのアルゴリズムは、必ず並び替えができる種類のものであるのに対し、画像認識のアルゴリズム(例:人検出)は、必ず人を検出できるとは限らない。
だからこそ、アルゴリズム開発者は、アルゴリズムの実行結果を信用しない。
評価結果を可視化するための機能
画像認識アルゴリズムの問題
- 画像認識アルゴリズムは、従来のアルゴリズムと意味合いが違う。
- 従来のアルゴリズムの典型例として、sortアルゴリズムがある。
- sortアルゴリズムは常に期待値どおりの結果がでる。
- しかし、画像認識アルゴリズムでは期待値どおりの完璧な結果にすることがない。
- そのため、どの程度の比率が期待値に一致したのかを使って評価するしかない。
ソースコードのPRと承認プロセス
- 特に食い違いを生じやすいのが、ソースコードのPRと承認プロセスだ。
システム実装のエンジニアが常に気にしていること。
- システム実装者は、実装が劣化するのを恐れる。
- 不十分な品質のコードは、システムの劣化を引き起こす。
- 誤解を引き起こす関数名・変数名。
- 余分なimportによる、リソースの消費量の増大。
- 処理の遅い部分が入りこむことで、システムのレスポンスの低下。
- こういった可能性を常に意識している。
アルゴリズム構築者のエンジニアが気にしていること
- 目的の機能が実装されているか
- 目的の機能の推論の精度が出ているか
- 目的の機能を実現する際の各種パラメータが妥当な値になっているか
- さまざまなシーンでの性能はどうなっているか
- 無駄を排した実装になっているか。
- テストの自動化ができているか
- デモによって視覚的に確認できるようになっているか。
- こういった内容を早く実装していくこと。
- 影響の範囲はアルゴリズム構築のコードの範囲なので、その時点ではシステムに影響しない。
- コードを実装し、さっさとテストすること。
- 変数名がおかしくても、まずは、さっさと実装を進めること。
アルゴリズム構築者へのアドバイス
- アルゴリズムの構築の初期段階のコードと、システムに組み込む直前のコードはAPIの設計指針が異なるということを覚悟すること。
- アルゴリズムの構築用のリポジトリとは別に、組み込み用モジュールのリポジトリとは別になることも覚悟しよう。
- システムに組み込むモジュールを設計する際には、抽象クラスでAPIを設計して、それに対して実装を埋めていくようにしよう。
システム構築のエンジニアへのアドバイス
- アルゴリズム構築者も、モジュールのAPIの設計が重要なことを理解しています。
- アルゴリズム構築の初期段階と、システムに組み込む際とでは必要な作業が違っていることも理解しています。
- アルゴリズム構築者、動作して結果が妥当であること、設計の健全性の確認、動作速度の妥当性を意識して開発しています。
- そして、どういう使い方になるのかを考えながら、システムへの実装を考えています。
項目 | アルゴリズム構築(初期段階) | システム組み込み用モジュール |
---|---|---|
位置づけ | 実用になることを示すこと | 組み込んで利用すること |
立場 | アルゴリズムが実用になることを示すこと | 実用になることがわかっているアルゴリズムを使うこと |
利用するライブラリ | アルゴリズムの根幹のライブラリ | システムで利用する最小限のライブラリ |
利用する追加ライブラリ | 動作検証を支援するライブラリ・可視化ライブラリを含める | --- |
データ構造 | 必ずしも隠さない | 隠す |
使い方の自由度 | 制限しない | 想定する使い方に制約して、使い方の自由度を減らす |
クラスとしての実装 | 必ずしも必須ではない。場合によってはベタ書きのサンプルコードもある。 | モジュールとしての適切な設計。その中でクラスが妥当であればクラスを実装 |
抽象クラスによるAPI 設計 | しないことが多い | 抽象クラスによるAPIの明示がのぞましい |
コーディングスタイル | その分野の開発者ならば読める程度のコーディング | その部署で採用しているコーディングスタイル 例 Pythonにおけるtypehint, フォーマッタの利用 |
動作検証用のコード | 必ず含める | 必ずしも含めない |
動作検証用のログ出力 | 含めることがある | 基本含めない |
動作結果の可視化のためのグラフ作成 | 含めることがある | 含めない |
深層学習のモデルの場合の入力画像 | モデル自体の入力サイズを明示的に意識するコーディングの場合が多い | モデル自体の入力サイズを隠蔽している。 |
動作検証用のデータ | リポジトリそのもの、別リポジトリのどちらかで含める | 含めない |
デモプログラム | 必要になった様々な使い方のでもプログラム。例:静止画、複数の静止画、動画入力、カメラ入力など | ユースケースに近い1つのデモプログラム |
設定パラメータ | 設定の自由度が高いこと。推奨条件に対して裏付けの評価ができること | 推奨条件のパラメータだけあればいい |
PRの考え方 | 反映速度重視 | 品質重視 |