PyTorch の開発者は、PyTorch の哲学は即時のタスクを解決すること、つまり計算グラフをその場で構築して実行することであると述べています。現在、PyTorch はこの即時実行コンセプトのおかげで最も人気のあるフレームワークの 1 つになっています。開発者は、ニューラル ネットワーク交換形式 ONNX を通じて、モデルをすばやく構築してアイデアを検証し、複数のフレームワーク間ですばやく移行できます。この記事では、基本的な概念から始めて、PyTorch の使用方法、トレーニング経験、テクニックを紹介し、起こりうる問題と解決策を示します。
プロジェクトアドレス: https://github.com/Kaixhin/grokking-pytorch PyTorch は、動的ニューラル ネットワーク (if ステートメントや while ループなどの動的制御フローを活用するネットワークなど) による自動微分化を可能にする柔軟なディープラーニング フレームワークです。また、GPU アクセラレーション、分散トレーニング、さまざまな最適化タスクもサポートしており、さらに多くの簡潔な機能を備えています。以下は、PyTorch の使い方に関する著者からのメモです。ライブラリの詳細やベスト プラクティスがすべて含まれているわけではありませんが、誰にとっても役立つ可能性があります。 ニューラル ネットワークは計算グラフのサブクラスです。計算グラフは入力データを受け取り、そのデータはデータ処理を実行するノードにルーティングされ、それらのノードによって変換される場合があります。ディープラーニングでは、ニューラル ネットワーク内のニューロン (ノード) は通常、パラメーターまたは微分可能な関数を使用してデータを変換し、勾配降下法によって損失を最小限に抑えるように最適化できます。より一般的には、関数はランダムであり、グラフ構造は動的になる可能性があります。したがって、ニューラル ネットワークはデータフロー プログラミングに適しているかもしれませんが、PyTorch の API は、より一般的に考えられているプログラミング形式である命令型プログラミングに重点を置いています。これにより、不必要なパフォーマンスを浪費することなく、コードを読みやすくし、複雑なプログラムについて推論することができます。PyTorch は高速で、多くの最適化が施されているため、エンドユーザーは心配する必要はありません。 この記事の残りの部分は、MINIST 公式 Web サイトの例に基づいて PyTorch を理解する方法について説明しており、公式の初心者向けチュートリアルを完了した後に閲覧する必要があります。コードは読みやすくするためにコメント付きのブロックで提示されるため、純粋にモジュール化されたコードのように異なる関数やファイルに分割されることはありません。 Pytorch の基本 PyTorch は、いわゆる命令型/積極的パラダイムを使用します。このパラダイムでは、コードの各行でグラフを構築して、完全な計算グラフの一部を定義する必要があります。完全な計算グラフがまだ構築されていない場合でも、これらの小さな計算グラフをコンポーネントとして独立して実行できます。この動的な計算グラフは、「define-by-run」方式と呼ばれます。 PyTorch テンソル PyTorch のドキュメントにあるように、NumPy の多次元配列に精通していれば、Torch テンソルの多くの操作を簡単に習得できます。 PyTorch は CPU テンソルと GPU テンソルを提供し、計算速度を大幅に向上させます。 テンソルの構築と操作から、TensorFLow と比較して、PyTorch でのテンソルの宣言と初期化がはるかに簡単であることがわかります。たとえば、torch.Tensor(5, 3) ステートメントを使用すると、5×3 の 2 次元テンソルをランダムに初期化できます。PyTorch は動的グラフであるため、宣言と実際の割り当ては同時に実行されます。 PyTorch では、torch.Tensor は各要素が単一のデータ型である多次元行列であり、コンストラクターのデフォルトは torch.FloatTensor です。具体的なテンソルの種類は次のとおりです。 次元を直接定義するだけでなく、一般に Python リストや NumPy 配列からテンソルを作成することもできます。また、Python のリストやタプルなどのデータ構造を使用する習慣に応じて、同様のインデックス方法を使用して値を取得または割り当てることができます。 PyTorch はブロードキャスト操作もサポートしています。これは通常、配列の異常な次元を別の演算子の次元と一致するように暗黙的に調整し、次元の互換性を実現します。 自動微分化モジュール TensorFlow、Caffe、CNTK などのほとんどのフレームワークは静的計算グラフを使用しており、開発者はニューラル ネットワークを構築または定義し、同じ構造を再利用してモデル トレーニングを実行する必要があります。ネットワーク モデルを変更するということは、関連するモジュールを最初から設計および定義する必要があることを意味します。 しかし、PyTorch で使用される手法は自動微分です。このメカニズムでは、システムには実行した操作を記録するレコーダーがあり、対応する勾配を逆計算します。この手法は、順方向伝播中にパラメータの微分を計算することで時間を節約できるため、ニューラル ネットワークを構築するときに非常に強力です。 概念的には、Autograd はグラフを維持し、変数に対して実行されたすべての操作を記録します。これにより、リーフ ノードが入力ベクトル、ルート ノードが出力ベクトルである有向非巡回グラフが生成されます。グラフのルートからリーフまでのパスをトレースすることで、連鎖律を使用して勾配を自動的に計算することが簡単にできます。 内部的には、Autograd はこのグラフを Function オブジェクトのグラフとして表現し、apply() を使用してグラフの評価結果を計算できます。計算の順方向伝播では、Autograd が要求された計算を実行するときに、勾配計算を表すグラフも構築され、各 Variable の .grad_fn 属性がこのグラフの入力単位になります。順方向伝播が完了したら、逆方向伝播でこの動的グラフに基づいて勾配を計算できます。 PyTorch には、学習プロセスを制御するためのオプティマイザー、ディープモデルを構築するためのニューラル ネットワーク モジュール、データの読み込みと処理など、多くの基本モジュールもあります。このセクションで紹介するテンソルと自動微分モジュールは、PyTorch のコア概念の 1 つです。詳細については、PyTorch のドキュメントを参照してください。 以下では、著者は MNIST を例に挙げて、データの読み込みからモデルのテストまでの PyTorch の使用、思考スキル、落とし穴について説明します。 PyTorch 実践ガイド 1. インポート
これらは、コンピューター ビジョンの問題に使用される torchvision モジュールを除き、標準化されたインポートです。 2. セットアップ
argparse は、Python でコマンドライン引数を処理する標準的な方法です。 デバイスに依存しないコード (利用可能な場合は GPU アクセラレーションを活用し、利用できない場合は CPU にフォールバックする) を記述する場合は、テンソルを保存する場所を決定する適切な torch.device を選択して保存することをお勧めします。デバイスに依存しないコードの詳細については、公式 Web サイトのドキュメントを参照してください。 PyTorch のアプローチは、ユーザーにデバイスの制御権を与えることです。これは単純な例では少し面倒ですが、テンソルがどこにあるかを見つけやすくなります。これは、a) デバッグや b) 手動デバイスを効率的に使用する場合に役立ちます。 再現可能な実験を行うには、乱数を使用して生成されたデータ (乱数を使用する random または numpy を含む) に対してランダム シードを設定する必要があります。 cuDNN は非決定論的なアルゴリズムを使用することに注意してください。これは、torch.backends.cudnn.enabled = False を設定することで無効にできます。 3. データ
torchvision.transforms には、切り抜きや正規化など、単一の画像用の便利な変換ツールが多数あります。 DataLoader には多くのパラメータが含まれています。batch_size と shuffle に加えて、num_workers と pin_memory も効率的なデータ読み込みに非常に重要です。たとえば、num_workers > 0 を設定すると、1 つのメイン プロセスを使用してブロックでデータをロードするのではなく、サブプロセスを使用してデータを非同期的にロードします。パラメーター pin_memory は、固定された RAM を使用して RAM から GPU への転送を高速化し、CPU のみを使用する場合は計算を実行しません。 4. モデル
ニューラル ネットワークの初期化は、通常、変数、トレーニング可能なパラメーターを含むレイヤー、場合によっては独立したトレーニング可能なパラメーター、およびトレーニング不可能なバッファーで構成されます。次に、フォワード パスはこれらの初期化パラメーターを、パラメーターのない純粋関数である F 内の関数と組み合わせます。開発者の中には、完全に機能するネットワーク (すべてのパラメータを独立させ、nn.Conv2d ではなく F.conv2d を使用するなど)、または完全にレイヤー関数で構成されたネットワーク (F.relu ではなく nn.ReLU を使用するなど) を使用することを好んでいる人もいます。 .to(device) は、デバイスが GPU に設定されている場合にデバイス パラメーター (およびバッファー) を GPU に送信する便利な方法です。デバイスが CPU に設定されている場合は何も行いません。ネットワーク パラメータをオプティマイザに渡す前に適切なデバイスに渡すことが非常に重要です。そうしないと、オプティマイザはパラメータを正しく追跡できなくなります。 ニューラル ネットワーク (nn.Module) とオプティマイザー (optim.Optimizer) はどちらも内部状態を保存および読み込むことができます。これを行うには、.load_state_dict(state_dict) を使用することをお勧めします。以前に保存した状態辞書から両方の状態を読み込み、トレーニングを再開できます。また、オブジェクト全体の保存が失敗する可能性があります。 ここで説明されていないいくつかの注意点は、フォワード パスでは制御フローを使用できることです。たとえば、メンバー変数またはデータ自体が if ステートメントの実行を決定できます。さらに、フォワードパス中にテンソルを印刷することも可能で、デバッグが容易になります。最後に、フォワードパスは複数のパラメータを取ることができます。断続的なコード ブロックを使用してこれを実証する方法は次のとおりです。
5. トレーニング
ネットワーク モジュールはデフォルトでトレーニング モードに設定されており、一部のモジュールの動作に影響します。特に、ドロップアウトとバッチ正規化に影響します。 .train() を使用して手動で設定する方が適切です。これにより、トレーニング フラグがすべてのサブモジュールに伝播されます。 loss.backward() を使用して新しい勾配セットを収集し、optimiser.step() を使用してバックプロパゲーションを実行する前に、optimiser.zero_grad() によって最適化されたパラメーターの勾配を手動でゼロにする必要があります。デフォルトでは、PyTorch は勾配を蓄積します。これは、1 回の反復で必要なすべての勾配を計算するためのリソースが不足している場合に便利です。 PyTorch は、テンソルに対して実行される操作を順番に収集し、それらを逆順に再生して逆モード微分を実行する、テープベースの自動勾配 (autograd) システムを使用します。これがまさに、PyTorch が非常に柔軟で、任意の計算グラフの実行を可能にする理由です。テンソルが勾配更新を必要としない場合 (このプロセスのためにテンソルを構築する必要がある場合は、requires_grad=True を設定する必要があります)、グラフを保存する必要はありません。ただし、ネットワークには勾配の更新を必要とするパラメータが含まれる傾向があるため、ネットワーク出力中に実行される計算はすべてグラフに保存されます。したがって、プロセスで取得したデータを保存する場合は、勾配の更新を手動で無効にするか、より一般的には、Python 数値 (Python スカラーの .item() 経由) または NumPy 配列として保存する必要があります。 autograd の詳細については、公式ドキュメントを参照してください。 計算グラフを切り捨てる 1 つの方法は、.detach() を使用することです。これは、時間の経過に伴う切り捨てバックプロパゲーションを介して RNN をトレーニングするときに、データが隠し状態を通過するときに適用できます。また、コンポーネントの 1 つが別のネットワークの出力である損失関数を微分するときにも便利です。しかし、他のネットワークは、GAN トレーニングでジェネレーターの出力から識別子をトレーニングしたり、値関数をベースライン (A2C など) として使用してアクター クリティック アルゴリズムの戦略をトレーニングしたりするなど、「損失例」モデルを使用して最適化されるべきではありません。 GAN トレーニング (識別器からジェネレーターをトレーニングする) での勾配計算を効果的に防止する別の方法は、微調整でもよく使用されますが、ネットワーク全体のパラメーターに対してループを構築し、param.requires_grad=False を設定することです。 コンソール/ログ ファイルに結果を記録するだけでなく、モデル パラメーター (およびオプティマイザーの状態) を確認することも重要です。通常の Python オブジェクトを保存するために torch.save() を使用することもできますが、他の標準的な選択肢としては組み込みの pickle があります。 6. テスト
.train() に早く応答するには、.eval() を使用してネットワークを明示的に評価モードにする必要があります。 前述したように、計算グラフは通常、ネットワークを使用するときに生成されます。 torch.no_grad() で no_grad コンテキスト マネージャーを使用すると、このような事態を防ぐことができます。 7. その他 メモリに問題がありますか? 公式 Web サイトのドキュメントでヘルプを確認してください。 CUDA エラーですか? これらはデバッグが難しく、通常は CPU 上でよりわかりやすいエラー メッセージを生成するロジックの問題です。 GPU を使用する予定の場合は、CPU と GPU を簡単に切り替えられると便利です。より一般的な開発のヒントとしては、適切なプロジェクトを起動する前に、すべてのロジックをすばやく実行してチェックできるようにコードを設定することです (たとえば、小さな/合成データセットを準備し、トレーニング + テスト エポックを実行するなど)。これが CUDA のバグである場合、または CPU に切り替えることができない場合は、CUDA_LAUNCH_BLOCKING=1 を設定すると、CUDA カーネルが同期的に起動し、より詳細なエラー情報が提供されます。 torch.multiprocessing、または複数の PyTorch スクリプトを一度に実行することに関するメモ。 PyTorch は、CPU 上での線形代数計算を高速化するためにマルチスレッド BLAS ライブラリを使用するため、多くの場合、複数のコアの使用が必要になります。複数のプロセスまたは複数のスクリプトの場合に、一度に複数のタスクを実行するには、環境変数 OMP_NUM_THREADS を 1 または別の小さい数値に設定して、手動でスレッド数を減らします。これにより、CPU スラッシングが発生する可能性が減ります。公式ドキュメントには、特にマルチプロセスに関するその他の注意事項も記載されています。 [この記事は51CTOコラム「Machine Heart」、WeChatパブリックアカウント「Machine Heart(id:almosthuman2014)」によるオリジナル翻訳です] この著者の他の記事を読むにはここをクリックしてください |
<<: AIファイナンスブームの背後にはアリババとスタートアップ企業独自の狙いがある
>>: 教育省:100 以上の AI 専門専攻を構築し、500 万人の AI 人材のギャップを埋めます。
歴史は、人々に気づかれずに何度も同じ冗談を繰り返す、昔のいたずらっ子のようなものです。歴史は単なるジ...
[[188839]]ビッグデータの概念が普及するにつれ、ビールとおむつの話は広く知られるようになり...
この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...
オープンソースの AI ディープラーニングを適用して、顔の表情の特徴に基づいて画像のキャプションを生...
ソラの登場はAI界全体に熱狂を巻き起こしたが、ルカンは例外だった。 OpenAI による Sora ...
この記事は、プログラマーの質問と回答のコミュニティである stackexchange.com の質問...
サプライ チェーンは、生産におけるあらゆるリンクの源です。原材料から製造、流通まで、各ステップで最も...
チャットボットの無限ループや同じ質問の繰り返しにイライラしていませんか? これは顧客にとってよくある...
最近、視覚合成というタスクが大きな注目を集めています。 NVIDIA の GauGAN は数日前にバ...
海外メディアNeowinによると、マイクロソフトが取得した最新の一連の特許の中に、潜在的な新しい配信...
生成 AI は、インターネット上の重要なコンテンツ ソースとなっています。AI によって生成されたテ...