🐛

[C#]Visual Studio 2022で任意のオブジェクトの変更を通知させるテク

2025/01/08に公開

みなさん、こんばんは。ボイラーです。
今回は趣味の作業中に気づいたVisual Studio 2022の便利機能について紹介したいと思います。

※なお、記事の最初の方にディープラーニングの内容を書きましたが、そこは重要ではないので流し読みしてもらっていいと思います。あくまで物語の導入として、書いたことをわかってもらえれば幸いです。

背景

書籍「ゼロから作るDeep Learning (3) フレームワーク編」に掲載されている、著者の斎藤 康毅さんがサンプルとして作られたディープラーニングフレームワークであるDeZeroがあります。私はそれをC#コードベースに移植したDeZero.NETというライブラリを作っています。

そのDeZero.NETの開発中に、畳み込みレイヤーの入力値がバックプロパゲーション時にはDisposeされていてNullReferenceExceptionが発生してしまうという現象が起きていました。

今回はこれをデバッグしている時に、Visual Studio 2022の便利機能を発見し使用したら見事にバグの原因に気づけたという話です。

本編

ディープラーニングにおいては、モデルの学習時にモデルに定義されているアーキテクチャに従って、トレーニングが行われていきます。今回でいうと動画にラベル付けをしてそれを回帰モデルとしてトレーニングします。

今回のモデルのアーキテクチャの主要なコンポーネントは、DCNNModel、BottleneckBlock、ResNet50です。詳細は省きます。

トラブル発生

それでこのモデルのトレーニングを安定稼働させるために、デバッグしては動作確認し、デバッグしては動作確認しというのを繰り返しました。その中のバグの1つに、ResNet50の中には畳み込み層があります。この畳み込み層の入力は、モデルに対する1回の「入力から出力、バックプロパゲーションが完了するまで」の間は記憶されているはずでした。しかし、今回のバグではこれが破棄(Dispose)されていました。

そこで、畳み込み層の入力を代入して保持するタイミングで、バグによって破棄される予定のオブジェクトを見つけました。

arg.Through[0]が今回のバグによって破棄される予定のオブジェクト
arg.Through[0]が今回のバグによって破棄される予定のオブジェクトです。

どうやって、このオブジェクトに対してDisposeメソッドが呼ばれるタイミングを知ることができるでしょうか?

バグの原因調査

私はVisual Studioのローカルウィンドウをぽちぽち右クリックをしてコンテキストメニューに何か有用な機能はないか調べました。

すると、ありました!!!!

値が変更されたときに中断メニュー

「値が変更されたときに中断」というメニューがあるではないですか!!!

これで args.Through[0].NDarraynull を代入されるタイミング、すなわちDisposeメソッドが呼ばれる時がわかりそうです。
「値が変更されたときに中断」をクリックします。

漆黒のブレークポイント設定

すると、args.Through[0].NDarray が漆黒の●がつきましたね。これで追跡してくれるようです。

その後は「続行」(F5)をしました。

データのブレークポイントのヒット

なにやら「データのブレークポイントのヒット」という小窓が出てきましたね。なるほど、これでオブジェクトのプロパティやフィールドに対する代入のタイミングが検知できるというわけですね!これは便利だ!!!

データのブレークポイントのヒット後

呼び出し履歴を確認

その後は簡単です。代入のタイミングがわかったところで、呼び出し履歴ウィンドウを確認して、どの処理によって、悪影響のある代入行為が指図されたかを調べれば良いのです。

呼出履歴の中に...ありますねこれ↓

DisposeAllInputs、、、貴様何者じゃ!?

DisposeAllInputs()。そう、今回の犯人はこのメソッドです。

トレーニング処理中に呼ばれている

しっかり、トレーニング処理中に呼ばれるように仕組まれていました。

これだから、既存のコードのコピペ利用は良くないんだなぁ。

まとめ

Visual Studio 2022の便利機能、「値が変更されたときに中断」機能を物語調で紹介しました。

いかがだったでしょうか。

この機能は役に立ちそうな場面というのは多そうなので、ぜひ使ってあげてください。

そして、知らない人がいたら、この記事を紹介してもらえると私は舞います。

ラグザイア

Discussion