Layer-wise Relevance Propagation を Chainer で実装する
1. Layer-wise Relevance Propagation(LRP)
元論文が これ で、詳しいことは以下参照。
私はLRPを
一度データを順伝搬させて、出力層から各層の出力と重みを元に貢献度を求めていく手法
だと理解しています。
2. Chainer
国産のニューラルネットワーク用のフレームワークです。
一度、順伝搬させるとデータが数珠つなぎ的に残るので、個人的には使いやすくて好きです。
Chainer: A flexible framework for neural networks
3. 実装 (chainer v2.0.0)
Chainerは一度、順伝搬させるとデータと生成された層の種類を参照できるので、それを利用して実装します*1。
現在は最低限、線形結合と畳込み、プーリングのみに対応しています。 また、入力zのshapeは(データ数, 出力ニューロン数)を想定しています。
import chainer import numpy as np def LRP(z, epsilon=0): creator = z.creator var = z # relevance value r = np.zeros(z.data.shape) for i, d in enumerate(z.data): r[i, d.argmax()] = d.max() while(creator is not None): x = creator.inputs[0].data y = creator.outputs[0]().data if len(creator.inputs) > 1: w = creator.inputs[1].data if creator.label == "LinearFunction": _y = y + epsilon*np.sign(y) r = x.reshape(r.shape[0], -1) * (np.dot(r/_y, w)) elif creator.label == "Convolution2DFunction": _y = y + epsilon*np.sign(y) r = x * chainer.functions.deconvolution_2d(r.reshape(y.shape)/_y, w).data elif creator.label == "MaxPooling2D": r = chainer.functions.unpooling_2d( r.reshape(y.shape), ksize=creator.kh, stride=creator.sy, outsize=x.shape[2:]).data var = creator.inputs[0] creator = var.creator return r
一応、出力層のデータが消えないように以下のhookを順伝搬の際に追加しました。
from chainer.function import FunctionHook class RetainOutputHook(FunctionHook): def forward_postprocess(self, function, in_data): function.retain_outputs([0]) ''' Example with RetainOutputHook(): z = model.predict(x) '''
使用例はgithubに上げます。
*1:バグなどがあるかもしれません