手習ひデジタル信号処理(173) Scilab、{IPCV}、Lenetのパラメータの表示

Joseph Halfmoon

ScilabのIPCV「ツールボックス」の関数を練習中。前回から「Deep Learning」突入、ありがちな「手書き文字認識」(モデルはLenet-5)ができることを確認済。今回は御供の関数どもを使って、モデルのパラメータの様子などをビジュアライズ?いつものようにHelp例がそのまま動くと思うなよ、と。トホホ。

※「手習ひデジタル信号処理」投稿順 Indexはこちら

※Windows11上の    Scilab2024.0.0およびScilab上のScilab IPCVツールボックスを使用させていただいております。

モデルからのパラメータの取り出し

付属のサンプルでは、Tensorflow上で実装され学習済(多分 MNISTデータを使って)のLenet-5であるとの触れこみのファイル、 lenet5.pb を使ってます。AI業界における古典中の古典、Lenet-5であることを疑うわけではないですが、バイナリファイルがポロリンと付属しているだけで、どんなレイヤがどのようなパラメータを持っているのかHelpファイルには何も書かれておりませぬ。Lenetだから皆知っているだろ~ということ?

しかし、以下の関数を使えば、読み込んだモデルから、パラメータを抽出することが可能。

dnn_getparam(net, レイヤ名, …)

そして抽出したパラメータをビジュアライズする関数どもも「建前」そろっております。

    1. dnn_showparam
    2. dnn_showparamf2d
    3. dnn_showparamf3d

ただ、今回Helpファイルの用例に従って動作させてみたのですが、dnn_showparam関数では表示ができませなんだ。どして? 一方dnn_showparamf2dとdnn_showparamf3d関数では表示ができました。なお、dnn_showparam関数はspatial domain、~f2dと~f3dの両関数はfrequency domainの関数デス。

お惚け老人が悩んでもなんともならなかったので、今回はspatial domainについてはパス。毎度だな。

モデル内のレイヤ名のとりだし

さて、dnn_getparam関数でモデルのパラメータが抽出できるといっても、レイヤ名を指定しないとダメです。バイナリファイルがポロリンではレイヤ名などわからないじゃん。プンプン。

と思ったらバイナリファイルを読み込んだ先の変数に問えば良かったのです。まずは、

dnn_unloadallmodels();
dnn_path = fullfile(getIPCVpath(),'images','dnn');
net = dnn_readmodel(fullfile(dnn_path,'lenet5.pb'),'','tensorflow');

変数 net の中を眺めれば、こんな感じ。Lenet5_net

すると一番下に layernameを発見。それを列挙すれば以下のごとし。Lenet5_layerNames

Lenet自体は、コンボリューションー>プーリングー>コンボリューションー>プーリングー>全結合ー>全結合ー>全結合という7段構えらしいので、上記はちょっち細かく分かれておりますな。これはTensorFlow上での実装を反映したものでしょう。眺めているとだんだん7段に見えてくる?

なお実際に dnn_getparam関数にレイヤ名を与えてみると

    • なんたら/Conv2Dは取り出し可能
    • なんたら/MatMulは取り出し可能
    • なんたら/MaxPoolはエラー
    • なんたら/Reluはエラー
    • なんたら/transposeはエラー
    • なんたら/Reshapeはエラー

となります。コンボリューション・レイヤと全結合レイヤのパラメータのみ取り出し可能ってことみたい。

コンボリューション・レイヤのパラメータのビジュアライズ

上記で判明したLayer Nameを使いパラメータを取り出してビジュアライズするコード例が以下に。

最初のコンボリューションレイヤは、1枚の入力画像に5x5のカーネルサイズのパラメータをコンボリューションするものなので、パラメータ的には5x5の「2次元フィルタが6枚」になる筈。第2のコンボリューションレイヤは、その出力がプーリング層を通って「小さく」なった後にやはり5x5のカーネルサイズでコンボリューションするもの。入力が6枚に増えており、それぞれに16種のフィルタをかける勘定なので、フィルタ的には6x16枚です。

dnn_unloadallmodels();
dnn_path = fullfile(getIPCVpath(),'images','dnn');
net = dnn_readmodel(fullfile(dnn_path,'lenet5.pb'),'','tensorflow');
p1 = dnn_getparam(net,"conv2d/Conv2D");
scf(1);dnn_showparamf2d(p1);

p2 = dnn_getparam(net,"conv2d_2/Conv2D");
scf(11);dnn_showparamf2d(p2(:,:,1,:));
scf(12);dnn_showparamf2d(p2(:,:,2,:));
scf(13);dnn_showparamf2d(p2(:,:,3,:));
scf(14);dnn_showparamf2d(p2(:,:,4,:));
scf(15);dnn_showparamf2d(p2(:,:,5,:));
scf(16);dnn_showparamf2d(p2(:,:,6,:));

dnn_unloadallmodels();

1番目のレイヤは3次元なので、dnn_showparamf2dはそのままかけられました。しかし2番目のレイヤは4次元のためか、これをそのままかけてもサッパリでした。しかたがないので、取り出した4次元のパラメータのうち3番目のところを指定してそれぞれをビジュアライズしてみたら描くことができました。何かもっと良い方法があるのかしら?

1番目のレイヤのビジュアライズ結果が以下に。Conv2d

実際のパラメータが以下に。conv2d_5x5_6

実パラメータは5x5サイズですが、ビジュアライズ結果は周波数ドメインです。

2番目のコンボリューションレイヤのビジュアライズ結果が以下に。Conv2d_2_6x16

ビジュアライズしても、お惚け老人には何が何やらサッパリぜよ。

手習ひデジタル信号処理(172) Scilab、{IPCV}、Deep Learning? へ戻る

手習ひデジタル信号処理(174) Scilab、{IPCV}、Lenetの特徴マップ表示 へ進む