CNNのパラメータの可視化

2,162 views
Skip to first unread message

t.iwa...@gmail.com

unread,
Dec 19, 2016, 8:30:26 AM12/19/16
to Chainer Japanese User Group
とても初歩的な質問ですいません。
MNISTの画像データをconvolution_2dを用いて学習し、重みパラメータの可視化を試みたのですが、
パラメータのデータがどこに格納されているのかがわかりません。
modelという変数内にあると思うのですが、どうやって呼び出すのかわからない状態です。

どなたかご教示頂けないでしょうか?

Taiki Nomura

unread,
Dec 20, 2016, 1:56:47 AM12/20/16
to Chainer Japanese User Group
model.(自分が決めたレイヤーの名前).W

に格納されています




pickleで保存したモデルの重みを画像で保存させるコードです.
良かったらご利用ください

import cPickle
import matplotlib.pyplot as plt
import numpy as np
import chainer.links
import os


class visualize_filter():
    def __init__(self, model_path):
        self.model = cPickle.load(open(model_path, "rb"))
        self.model.set_train_state(True)

    def visualize_all(self, outdir):
        if not os.path.exists(outdir):
            os.makedirs(outdir)

        self.convs = self.__getConv()
        for conv in self.convs:
            self.__visualize(self.model.__dict__[conv], outdir + "/" + conv)

    def __getConv(self):
        convs = []
        for key in self.model.__dict__.keys():
            if isinstance(self.model.__dict__[key], chainer.links.connection.convolution_2d.Convolution2D):
                convs.append(key)
        return convs

    def __visualize(self, filter, outname):
        weights = filter.W
        out_n, in_n, h, w = weights.shape

        fig = plt.figure()
        fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)
        self.weights = []

        for i in range(out_n):
            for j in range(in_n):
                weight = weights[i, j].data
                self.weights.append(weight)
                ax = fig.add_subplot(out_n, in_n, in_n * i + j + 1, xticks=[], yticks=[])
                ax.imshow(weight, cmap=plt.cm.gray_r, interpolation='nearest')

        self.weights = np.asarray(self.weights, np.float)
        plt.savefig(outname + ".png")

    vf = visualize_filter.visualize_filter(model.pklのパス)
    vf.visualize_all(可視化したフィルタの出力先ディレクトリ)


2016年12月19日月曜日 22時30分26秒 UTC+9 t.iwa...@gmail.com:
Message has been deleted

t.iwa...@gmail.com

unread,
Dec 20, 2016, 5:06:18 PM12/20/16
to Chainer Japanese User Group
回答ありがとうございます。

__getConv関数のところでうまく名前を取得できないです。

試しに model.__dict__keys() を実行したところ、

['accfun', 'loss', '_persistent', 'name', '_children', '_uninitialized_params', '_cpu', 'lossfun', 'y', 'predictor', '_params', 'accuracy']

これだけしか出力されません。層の構成は以下のように指定しました。

class MLP(chainer.Chain):

    def __init__(self):
        super(MLP, self).__init__(
            # the size of the inputs to each layer will be inferred
            conv1 = F.Convolution2D(1,32,5),
            conv2 = F.Convolution2D(32,64,5),
            l1=L.Linear(1024, O_UNIT),  # n_in -> n_units
        )

    def __call__(self, x):
        h1 = F.max_pooling_2d(F.relu(self.conv1(x)),2)
        h2 = F.max_pooling_2d(F.relu(self.conv2(h1)),2)
        return self.l1(h2)


model.conv1.Wと入力すれば、第1層目のCNNのパラメータを取得することができるということでよろしいですか?

Taiki Nomura

unread,
Dec 21, 2016, 4:58:46 AM12/21/16
to Chainer Japanese User Group
model.__dict__keys() の結果を確認したところ,おそらくpickleによる保存の段階で学習したモデルではなく,classifierを保存しているのではないかと思います.
そのため,関数内で確認しているconvolution_2dの値が見つからないためうまく機能しないのかと.

model.conv1.Wと入力すれば、第1層目のCNNのパラメータを取得することができるということでよろしいですか?
その認識で問題ありません.


2016年12月21日水曜日 7時06分18秒 UTC+9 t.iwa...@gmail.com:

t.iwa...@gmail.com

unread,
Dec 29, 2016, 8:25:19 AM12/29/16
to Chainer Japanese User Group
回答ありがとうございます。

現在、以下のプログラムを使ってモデルを保存しているのですが、前回のままの出力になってしまいます。
保存方法が違うのかと思い、2種類の方法で保存したのですが、2つとも前回のままでした。

以下プログラムです。

import chainer
import chainer.functions as F
import chainer.links as L
from chainer import training
from chainer.training import extensions
import cPickle

GPU = 0
UNIT = 1000
O_UNIT = 10
BACTHSIZE = 100
EPOCH = 3
OUT = 'result'
RESUME = ''



# Network definition
class MLP(chainer.Chain):

    def __init__(self):
        super(MLP, self).__init__(
            # the size of the inputs to each layer will be inferred
            conv1 = F.Convolution2D(1,32,5),
            conv2 = F.Convolution2D(32,64,5),
            l1=L.Linear(1024, O_UNIT),  # n_in -> n_units
        )

    def __call__(self, x):
        h1 = F.max_pooling_2d(F.relu(self.conv1(x)),2)
        h2 = F.max_pooling_2d(F.relu(self.conv2(h1)),2)
        return self.l1(h2)


def main():

    model = L.Classifier(MLP())
    if GPU >= 0:
        chainer.cuda.get_device(GPU).use()  # Make a specified GPU current
        model.to_gpu()  # Copy the model to the GPU

    # Setup an optimizer
    optimizer = chainer.optimizers.Adam()
    optimizer.setup(model)

    print "Set Optimizer - OK"

    # Load the MNIST dataset
    train, test = chainer.datasets.get_mnist(ndim=3)

    train_iter = chainer.iterators.SerialIterator(train, BACTHSIZE)
    test_iter = chainer.iterators.SerialIterator(test, BACTHSIZE,
                                                 repeat=False, shuffle=False)

    print "Set MNIST - OK"

    # Set up a trainer
    updater = training.StandardUpdater(train_iter, optimizer, device=GPU)
    trainer = training.Trainer(updater, (EPOCH, 'epoch'), out=OUT)

    trainer.extend(extensions.Evaluator(test_iter, model, device=GPU))

    trainer.extend(extensions.LogReport())

    trainer.extend(extensions.PrintReport(
        ['epoch', 'main/loss', 'validation/main/loss',
         'main/accuracy', 'validation/main/accuracy', 'elapsed_time']))

    # Print a progress bar to stdout
    trainer.extend(extensions.ProgressBar())

    print "Set Option - OK"

    if RESUME:
        # Resume from a snapshot
        chainer.serializers.load_npz(RESUME, trainer)

    

    # Run the training
    trainer.run()

    model.to_cpu()
    chainer.serializers.save_npz("after.model", model)
    cPickle.dump(model,open('model', 'wb'), -1)

if __name__ == '__main__':
    main()

Taiki Nomura

unread,
Dec 30, 2016, 7:44:17 AM12/30/16
to Chainer Japanese User Group
 model = L.Classifier(MLP())を

Model = MLP()
model = L.Classifier(Model)

cPickle.dump(model,open('model', 'wb'), -1)を
cPickle.dump(model,open('Model', 'wb'), -1)としてみてください

現状Classifierを保存しているので,MLPを保存すれば動くのではないかと思います

2016年12月29日木曜日 22時25分19秒 UTC+9 t.iwa...@gmail.com:

醬油

unread,
Jan 7, 2017, 10:41:25 AM1/7/17
to Chainer Japanese User Group
Nomura様

vf = visualize_filter.visualize_filter(model.pklのパス)

の「model.pklのパス」が理解できないでいます。
モデルを出力したファイルのディレクトリを指定して上記コードを更新したプログラムを実行たところ、
_pickle.UnpicklingError: A load persistent id instruction was encountered,
but no persistent_load function was specified.

と指摘されたので、ディレクトリのことではなく、モデル自身のことかと思っています。
モデルを予め定義しておく必要があるのでしょうか。
ご助言いただけると幸いです。

醬油

醬油

unread,
Jan 7, 2017, 8:02:05 PM1/7/17
to Chainer Japanese User Group
スレッドに書いた私のコードを再利用してモデルを生成してから
vp = visualize_param(classifier_model)
として渡してあげると、{train, name, _persistent, accfun, _params, y, accuracy, loss, _children, _uninitialized_params, lossfun, _device_id, _cpu, predictor}
が__getConv(self)のkeyとして与えられているようです。

MNISTが対象なのでこの関数内で
if isinstance(self.model.__dict__[key], chainer.links.connection.linear.Linear):
としています。

自分のレポジトリにアップしましたので出来ましたらご指摘をお願いいたします:

醬油

unread,
Jan 8, 2017, 9:44:06 AM1/8/17
to Chainer Japanese User Group
OpenCVが依存性の関係でインストールできないようなので、画像データとしてパラメータ画像を生成するのはあきらめました。
#パラメータ値をグレースケールで表示するためにOpenCVを必要としてました。

代わりに簡易統計プログラムを作成しました。
下記レポジトリに置きました。自由に使ってください。

ただ、パラメータの格納のされ方をきちんと理解していないため、統計から漏れているパラメータがあるかもしれません。

醬油
Reply all
Reply to author
Forward
0 new messages