paint-brush
探索用ソフトウェア: 発見のバランスを実現する@sinavski
331 測定値
331 測定値

探索用ソフトウェア: 発見のバランスを実現する

Oleg SInavski10m2024/03/21
Read on Terminal Reader

長すぎる; 読むには

次のことを主張する投稿: - 研究中に過剰な生産技術を避ける。生産と研究は目的が異なります - コードの大部分は消滅するので、研究において「技術的負債」を受け入れることは問題ありません。たとえば、コードを再利用しようと努めるべきではありません。 - しかし、研究者としては、高速な探索、高速な分岐、クリーンでシンプルなコードに投資する必要があります。
featured image - 探索用ソフトウェア: 発見のバランスを実現する
Oleg SInavski HackerNoon profile picture

私は生涯研究に携わってきたので、研究者は醜いコードを書くという固定観念を知っています (例:ここここ、またはここ を参照)。でも、私はこう思いました。それは直せるんじゃないでしょうか?そこで、私は何度も素晴らしい研究フレームワークを設計しようと試みました。私は、好きで読んでいたソフトウェア エンジニアリングの本やブログを使用して、インターフェイスを導入し、優れた抽象化を作成しようとしました。


しかし、何度も何度もそれらの努力は無駄になりました。私が取り組んだ研究ソフトウェアの大部分は、実際に運用されることはありませんでした (一部は運用されましたが)。誰かが私に単純な真実を教えてくれたら、私の精神衛生上は素晴らしいだろう:研究コードの死は実際に起こるべきことである。研究者は、そもそもそのエンジニアリングに多くの時間を費やすべきではありません。


プロのソフトウェア エンジニアは、ソフトウェアのベスト プラクティスを使用していない研究者を常に見下しています。リサーチ コードの水準を引き上げようとしている投稿がいくつかあります (たとえば、この素晴らしい投稿リサーチ コード ハンドブック)。しかし、この投稿は逆の方向に進んでいます。つまり、ソフトウェアのベストプラクティスをやりすぎず、代わりに高速探索のみに投資する方法を論じています。これは、多くのアイデアを迅速に試すことを目標とする研究志向の企業を対象としています。

1. 戦略的な技術的負債を負う

企業における研究プロジェクトの成功には、探索と活用という 2 つのフェーズがあります。 「探索」では、できるだけ多くの多様な解決策を試してみる必要があります。 「エクスプロイト」中は、最適なソリューションを強化し、それを有用な製品に変える必要があります。

探査中に多くのプロジェクトが消滅します。堅牢なソリューションを構築する必要があるのは、悪用中のみです。

ソフトウェアの最適な実践方法は、両者の間で大きく異なります。企業が研究部門と製品部門を別々に持つことが多いのはそのためです。ソフトウェア設計に関して一般的に読まれている書籍はすべて、主に 2 番目の「搾取」フェーズに関するものです。このフェーズでは、スケーラブルな製品の基盤を構築します。ここで、優れた API、ロギング、エラー処理など、すべての設計パターンが登場します。


しかし、最初の「探索」段階では、永遠に存続する基盤を構築しているわけではありません。実際、あなたの努力の大部分が生き残った場合、(当然のことながら) 十分な探索ができていないことになります。


この記事で紹介する多くの実践例は、通常であれば「技術的負債」となるものの例です。これは、再利用可能で抽象化されたクリーンなコードを書かないことで得られるものです。借金は常に悪なのでしょうか?私たちはローンや住宅ローンを借りないことを好みますが、お金を借りることは人生において良い戦略であることがよくあります。早く行動して後で利益を上げるために借金をしても大丈夫です。

研究でソフトウェア負債を抱えても大丈夫です。すべてを返済する必要はありません。研究で成功した少数の人に対してのみ返済する必要があります。

同様に、技術的負債を負わないと、研究の速度が低下する可能性があります。幸いなことに、ほとんどの場合、返済する必要はありません。いずれにせよ、研究コードのほとんどは消滅する可能性があります。したがって、平均すると、テクノロジー関連の負債全体に苦しむことはありません。

コードの再利用に反対するケース

多くのソフトウェア アーキテクチャとリファクタリング手法は、特にコードの再利用性を向上させることを目的としています。コードの再利用には一般的な欠点があります。しかし、運用環境では、よく知られている利点がそれを上回ります (たとえば、この典型的な投稿を参照してください)。研究プロジェクトでは、コードの大部分は忘れ去られる運命にあります。コードを再利用しようとすると、実際には速度が低下する可能性があります。


コードの再利用を制限することは、研究において許容される技術的負債の一種です。コードの再利用には、不必要な依存関係の追加、コードのコピーペースト、多数の共有研究コードの維持、時期尚早な設計投資など、いくつかのパターンについて説明したいと思います。

新しいものを輸入する前によく考えてください

速度を向上させる、適切に管理され、バージョン管理されたライブラリを知っている場合は、それを試してください。ただし、新しい依存関係を取り入れる前に、それが価値があるかどうかを判断してください。追加されるたびに依存地獄に近づきます。そのため、学習とトラブルシューティングに時間を費やすことができます。依存関係の落とし穴については、この簡潔な投稿を参照してください。


次の場合は、何かに依存してもおそらく問題ありません。

  • すでに使っているはずです。学ぶべきことはあまりありません。大規模なコミュニティがあり、優れたドキュメントとテストがあります。
  • バージョン管理されており、インストールが簡単です
  • そして最後に、それを自分で実装する方法はありません。

ただし、次の場合は依存関係に注意してください。

  • 使い方がすぐに分からない、非常に新しい (または非常に古い) か、誰も知らないようです。ドキュメントやテストはありません

  • これはあなたのモノリポジトリからのものであり、他のチームによって常に変更されています

  • 他の多くの依存関係やツールを取り込みます。それとも単にインストールが難しいだけですか

  • そして最後に、あなた (または一部の LLM) はこのコードを数時間で書けると感じます。


明示的な依存関係の代わりに、Go の優れた格言に従うことができます。「 少しの依存関係よりも少しのコピーのほうが優れています」。これは次のトピックです。

コピーペーストで自由に実験できる

コピーペーストは高速であり、調査中に最適なツールとなる場合があります。

コピペは違法であるべきだ」という意見もあります。しかし驚いたことに、私はそれを支持する議論を頻繁に行っていることに気づきました。探索段階では、コピーペーストが最適な選択となる可能性があります。


コードベースの別の部分から頻繁に使用される関数に依存している場合、それを簡単に変更することを忘れてしまう可能性があります。誰かのために何かを壊してしまい、コードのレビューと修正に貴重な時間を費やさなければならない可能性があります。ただし、必要なコードをコピーしてフォルダーに貼り付ければ、そのコードを自由に使用できます。これは、実験が例外ではなく標準である研究プロジェクトにおいては大きな問題です。特に、変更がすべての人にとって有益であるかどうかがわからない場合はそうです。


ディープラーニングのコードベースはコピーペーストに最も適していると思います。通常、モデルとそのトレーニングを記述するために必要なコードの量はそれほど多くありません。しかし同時に、それは非常に微妙であり、一般化するのは難しいかもしれません。共有可能なトレーニング スクリプトは、管理できないサイズに大きくなる傾向があります。たとえば、Hugging Face transformersトレーナーには +4k 行があります。興味深いことに、トランスフォーマーはモデル レベルでコピーペーストを選択しました。 「単一ファイル モデル」ポリシーの背後にある理由を記載した投稿を確認してください。コピーペーストの美しさについては、最後にあるリソースを参照してください。


コピーペーストの代わりに、ブランチ上に留まるという方法もあります。しかし、それはチームワークにあまりにも大きなオーバーヘッドをもたらしているように感じます。また、コピーペーストの美しさに関する投稿を他にもいくつか見つけました。結論の他の投稿を参照してください。

共有研究コードを維持するのは難しい

頻繁に使用される共有コードのメンテナンスには多大な労力が必要です。 torch.nn.Moduleのファイル行数をPytorchバージョンに対してプロットしたものを見てください。最も先進的な研究チームでさえ、複雑さを抑えるのに苦労していることがわかります。

torch.nn.Module ファイルの長さは PyTorch のバージョンに応じて異なります。それはますます単純になっていません。

大規模な共有研究コードを維持するために必要な時間とリソースを過小評価しないでください。研究ライブラリは使用すればするほど複雑になります。研究の方向ごとにユースケースが若干異なるため、一般的なライブラリよりも迅速に実行されます。何を寄付できるかについて非常に厳格なルールを確立します。そうしないと、共有コードが脆弱になり、多数のオプション、バグの多い最適化、エッジケースによって肥大化してしまいます。研究コードの大部分は消滅するため、この余分な複雑さはすべて再び使用されることはありません。共有コードの一部を削除すると、実際の調査に時間を割くことができます。

コードの再利用ではなく、探索を目的とした設計

実稼働環境であっても、 コードの将来性をあまり保証したくないというのは、ある程度真実です。要件を満たす最も単純なソリューションを実装するようにしてください。しかし、実稼働コードでは常に保守性の側面を考慮する必要があります。たとえば、通常はエラー処理、速度、ログ、モジュール化などを考慮する必要があります。


研究コードでは、それは何も重要ではありません。アイデアの良し悪しをできるだけ早く証明して次に進みたいだけです。したがって、モジュールや API を使用せずにそれを実現する非常にシンプルな点はまったく問題ありません。


次のような時期尚早なソフトウェア投資に貴重な時間を無駄にしないでください。

  • プロジェクトの初期段階でコンポーネント インターフェイスを作成しすぎている。自分で作った人為的な制約に合わせることに多くの時間を費やすことになる
  • ディープ ラーニング ソリューションを導入する前に、ディープ ラーニング トレーニング インフラストラクチャを最適化する
  • 運用構成/ファクトリー/シリアル化システムまたは基本クラスを使用します。多くの場合、プロトタイピング中にその機能は必要ありません。
  • 厳しすぎるリンティングおよび型チェック システム。急速に変化する使い捨ての研究コードを遅らせる理由はありません。

2. 迅速な探索に投資する

研究プロジェクトの目標は、新しい解決策を見つけることです。それがどのようなものであるかを(定義上)誰も知りません。これは、情報が限られた複雑な研究環境における最適化プロセスに似ています。適切な最小値を見つけるには、多くのパスを試し、良いパスと悪いパスを認識し、極小値にとらわれないようにする必要があります。これらすべてを迅速に行うには、技術的な負債を負う代わりにソフトウェアへの投資が必要になる場合があります。

共通パスの高速化

研究プロジェクトの共通部分のスピードアップに投資してください。

試してみたいさまざまな研究パスがいくつかあります。大部分のパスの時間を短縮する設計、ライブラリ、または最適化はありますか?これから試そうとしているすべてのアイデアを常に知っているとは限らないため、何かを過剰に設計しないように注意する必要があります。これはすべてのプロジェクトで非常にカスタムですが、いくつかの例を次に示します。


  • ディープネットワークをトレーニングする場合は、トレーニングインフラストラクチャに投資してください。トレーニング中に迅速かつ確実に収束できるハイパーパラメータを把握します。
  • すべての実験で異なるモデルを使用する必要がある場合は、それらをすばやく交換する方法を考えてください (たとえば、単純なファクトリ システムを使用するか、単にコピーペーストするなど)。
  • すべての実験にパラメータが多すぎて管理が難しい場合は、優れた構成ライブラリに投資してください。

すぐに分岐する

新しい研究パスを開始する速度に投資します。解決策を見つけるには、さまざまな方向性が必要です。

研究者は、新しい多様なアイデアを迅速に開始できる必要があります。プロジェクトの開始時点では簡単そうに思えます。しかし、人々が自分の好きな研究の道に固執するにつれて、それは徐々に困難になっていきます。これに対処するには、文化的および組織的な変化が不可欠です。あまりにも多くの資金と感情を投入する前に、有望でない研究を中止するプロセスが必要です。定期的なデモデーと技術的なピアレビューは、この目的のための効果的な戦略として役立ちます。また、人々が新しい輝かしいアイデアに飛びつくか、現在のプロジェクトを適切に終了するかのバランスを見つけることも重要です。


ただし、これはソフトウェアに関する投稿なので、新しいプロジェクトの分岐を容易にするための実践方法をいくつか紹介します。

  • 評価コードをアルゴリズムから切り離してください。通常、評価は研究の方向性よりも安定しています。
  • 新しいプロジェクトを白紙の状態から始めることを歓迎しますが、どのコンポーネントが再利用されるかに注意してください。モジュール化してクリーンアップすることは良い投資です
  • 新しい研究プロジェクトでは、最も革新的でリスクの高いコンポーネントを最初に実装します。そうすることで、将来のソフトウェア設計を導くボトルネックの大部分が特定されます。

信号対雑音比を高める

バグと非決定論は研究プロジェクトを狂わせ、結果を決定的ではないものにする可能性があります

ノイズが多くバグのあるコードでは、結果が非常に曖昧で決定的ではないため、プロジェクト全体が時間の無駄になってしまいます。過度に設計すべきではありませんが、次の単純な経験則に従うと、コードが乱雑になることを避けることができます。


  • 副作用のあるコードを避ける

  • デフォルトではクラスではなく関数が使用されます。クラスの場合は、継承よりもカプセル化を優先します

  • 関数/クラス/モジュールの長さを最小限に抑えます。 if ステートメントの数を最小限に抑える

  • Python の知識は豊富ですが、簡単なテクニックを使用してください。メタクラス、デコレータ、関数型プログラミングなどの知的雑草への誘惑に抵抗してください。


実行ごとに異なる結果が生成されるソフトウェアは、扱いにくいものです。不運なシードに基づいて重要ではあるが間違った決定を下した場合、回復するために多くの時間を無駄にすることになります。非決定性ソフトウェアを扱う場合のヒントをいくつか紹介します。


  • ノイズがアルゴリズムから発生しているのか、それとも評価から発生しているのかを理解します。ノイズ源は複雑になるため、完全に決定論的な評価を目指す必要があります。
  • 本当に再現可能なスクリプトが得られるまで、ランダム性の原因を見つけることをやめないでください。すべてのランダム シードを見つけた後は、データまたは副作用のある汎用関数からノイズが発生する可能性があることに注意してください。
  • シードを変更し、結果のベースラインの分散を決定します。統計的に有意ではない結果に基づいて決定を下さないでください。

結論

オチはリサーチコードに関する次の投稿から来ています。


「コードは重要ではないので、[優れたソフトウェア設計] を気にする必要はありません。コードは、必要な答えを得るツールです。」


優れたコーディング基盤を持つことは非常に重要です。しかし、結局のところ、重要なのは探索と実際に役立つ製品です。研究でプロダクション ソフトウェアを使いすぎると、何か新しいものを発見するのに必要な時間が無駄になります。代わりに、探索プロセスを遅らせている原因を見つけてください。高速な分岐、結果までの時間、クリーンなノイズレス コードに投資することで、研究パスをスピードアップします。


コードの再利用に完全に反対するのはおかしいでしょう。コードの再利用はバランスのとれたアクティビティである必要があることだけを指摘したいと思います。研究では、本番環境よりも使い捨てコードの割合が高くなります。再利用に対してバランスはさらに傾いています。コード再利用の落とし穴を紹介する優れた投稿をさらにいくつか紹介します。


そして、コピーペーストの実践を主張する投稿がさらにいくつかあります。

読んでくれてありがとう!少し物議を醸している部分もあると思いますので、コメントでお知らせください。


ここにも登場します。