つまりなにしたの?
Caffe model zooのモデルを読み込んで使えるようにはなった。
転移学習のようなことをしようと思ったけど、モデルを好き放題付け替えてみたいと思った時に
自動的にやるスクリプトはちょっと自動過ぎて楽しめないので丁寧に重みとバイアスをコピーする方法を確認した。
前回まではこちら
Caffe Model Zooのモデルをとりあえず実行するまではこっちでできる
ensekitt.hatenablog.com
ensekitt.hatenablog.com
モデルを読み込むところ
ここは実行したときと同じ。
読み込んだモデルはmodelという名前の変数にいれることにした。
せっかくなのでBVLCのGoogLeNetのを使ってみた(これはちょっと後悔した→何故か?→モデルが複雑だった)
MODEL = 'model/bvlc_googlenet.caffemodel' PICKLE = 'model/ggnet.pkl' if os.path.exists(PICKLE): print("Load pickle") with open(PICKLE, 'rb') as pkl: model = pickle.load(pkl) else: print("Load caffemodel and make pickle") if os.path.exists(MODEL): model = CaffeFunction(MODEL) with open(PICKLE, 'wb') as pkl: pickle.dump(model, pkl) print(MODEL + " not found.")
自前のGoogLeNetのモデル
class GoogLeNet(Chain): insize = 224 def __init__(self): super(GoogLeNet, self).__init__() with self.init_scope(): self.conv1 = L.Convolution2D(3, 64, 7, stride=2, pad=3) self.conv2_reduce = L.Convolution2D(64, 64, 1) self.conv2 = L.Convolution2D(64, 192, 3, stride=1, pad=1) self.inception_3a = L.Inception(192, 64, 96, 128, 16, 32, 32) self.inception_3b = L.Inception(256, 128, 128, 192, 32, 96, 64) self.inception_4a = L.Inception(480, 192, 96, 208, 16, 48, 64) self.inception_4b = L.Inception(512, 160, 112, 224, 24, 64, 64) self.inception_4c = L.Inception(512, 128, 128, 256, 24, 64, 64) self.inception_4d = L.Inception(512, 112, 144, 288, 32, 64, 64) self.inception_4e = L.Inception(528, 256, 160, 320, 32, 128, 128) self.inception_5a = L.Inception(832, 256, 160, 320, 32, 128, 128) self.inception_5b = L.Inception(832, 384, 192, 384, 48, 128, 128) loss3_fc = L.Linear(1024, 1000) loss1_conv = L.Convolution2D(512, 128, 1) loss1_fc1 = L.Linear(2048, 1024) loss1_fc2 = L.Linear(1024, 1000) loss2_conv = L.Convolution2D(528, 128, 1) loss2_fc1 = L.Linear(2048, 1024) loss2_fc2 = L.Linear(1024, 1000) def __call__(self, x, train=True): h = F.relu(self.conv1(x)) h = F.max_pooling_2d(h, 3, stride=2) h = F.local_response_normalization(h, n=5, k=1, alpha=2e-05) h = F.relu(self.conv2_reduce(h)) h = F.relu(self.conv2(h)) h = F.local_response_normalization(h, n=5, k=1, alpha=2e-05) h = F.max_pooling_2d(h, 3, stride=2) h = self.inception_3a(h) h = self.inception_3b(h) h = F.max_pooling_2d(h, 3, stride=2) h = self.inception_4a(h) b = F.average_pooling_2d(h, 5, stride=3) b = F.relu(self.loss1_conv(b)) b = F.relu(self.loss1_fc1(b)) b = self.loss1_fc2(b) h = self.inception_4b(h) h = self.inception_4c(h) h = self.inception_4d(h) b = F.average_pooling_2d(h, 5, stride=3) b = F.relu(self.loss2_conv(b)) b = F.relu(self.loss2_fc1(b)) b = self.loss2_fc2(b) h = self.inception_4e(h) h = F.max_pooling_2d(h, 3, stride=2) h = self.inception_5a(h) h = self.inception_5b(h) h = F.average_pooling_2d(h, 7, stride=1) y = self.loss3_fc(F.dropout(h, 0.4, train=train)) return y ggn = GoogLeNet()
今回の目的だと最初のconv1だけあるモデルでいいけど後々どうせ使うので全部入れた。
各層の中身を見る
各層にアクセスするにはドットで層の名前を接続するか、[]に層の名前を指定することでできる。
# コピー先 ggn.conv1.W.shape # 実行例: (64, 3, 7, 7) # コピー元 model['conv1/7x7_s2'].W.shape # 実行例: (64, 3, 7, 7) # 一致していることを確認すればコピーできる
コピーする
普通に代入すればいい。
# コピーする ggn.conv1.W = model['conv1/7x7_s2'].W ggn.conv1.b = model['conv1/7x7_s2'].b