ビジネスパーソン・ガジェット置場 empty lot for business

営業や仕事、それに伴う生活を便利に楽にするツール、ガジェットを作ります。既にあるツールも自分用にカスタマイズ。

ディープラーニング: DeZeroで学習したモデルを保存する方法

備忘録です。DeZeroを使用して画像認識などをするときGPUを使用したいのでGoogle Colaboratoryを使用します。ただ、Google Colaboratoryは放っておくとセッションも切れてしまいますし、自分がチェックしたい画像を分類させるためにわざわざ学習から行うのも時間がかかってしまいます。学習済みのモデルは保存しておいていざ分類したいときはそのモデルを読み込むようにしたいです。今回はその方法をまとめておきます。

DeZeroのsave_weightsメソッド

こちらのメソッドはDeZeroのレイヤーを管理するクラスで実装されています。中身としてはnumpyのsavez_compressed()が呼び出され実行されます。

 

numpyのsavez_compressed()は1つのファイル(xxxx.npz)に、複数の配列を保存したり圧縮により、ファイルサイズを削減したりできるようです。

 

savez_compressed()はこちらに書かれている記事がとてもわかりやすかったです。

numpy.savez_compressed:複数のNumPy配列を圧縮&バイナリ保存 - Wizard Notes

 

メソッドの実装

実際に学習済みのモデルを保存するには下記のコードを追記すれば保存してくれます。

model.save_weights('ファイルのパス')

ファイル名を決めてそのパスを引数で渡します。

※modelはモデルのインスタンス変数です。

 

学習したモデルの読み込み

学習したモデルを簡単に読み込むには、自分でモデルを組むときにpretrainedというbooleanの変数を設定しておくと良いです。

 

例としては下記のような感じです。WEIGHTS_PATH に格納しているファイルのパスは上記の保存する時に使用したパスです。

 

__init__関数にある条件分岐でこのパスを読み込むかどうかを決めています。

 

class TestModel(Model):
    WEIGHTS_PATH = "ファイルのパス"
    def __init__(self, pretrained=False):
        super().__init__()
        self.conv1_1 = L.Conv2d(32, kernel_size=3, stride=1, pad=1)
        self.conv1_2 = L.Conv2d(32, kernel_size=3, stride=1, pad=1)
        self.conv2_1 = L.Conv2d(64, kernel_size=3, stride=1, pad=1)
        self.conv2_2 = L.Conv2d(64, kernel_size=3, stride=1, pad=1)
        self.conv3_1 = L.Conv2d(128, kernel_size=3, stride=1, pad=1)
        self.conv3_2 = L.Conv2d(128, kernel_size=3, stride=1, pad=1)
        self.conv4_1 = L.Conv2d(512, kernel_size=3, stride=1, pad=1)
        self.conv4_2 = L.Conv2d(512, kernel_size=3, stride=1, pad=1)
        self.fc5 = L.Linear(1024)
        self.fc6 = L.Linear(6)

                # ここで保存している学習済みのモデルを読み込むか決めている if pretrained: weights_path = TestModel.WEIGHTS_PATH self.load_weights(weights_path) def forward(self, x): x = F.relu(self.conv1_1(x)) x = F.relu(self.conv1_2(x)) x = F.pooling(x, 2, 2) x = F.relu(self.conv2_1(x)) x = F.relu(self.conv2_2(x)) x = F.pooling(x, 2, 2) x = F.relu(self.conv3_1(x)) x = F.relu(self.conv3_2(x)) x = F.pooling(x, 2, 2) x = F.relu(self.conv4_1(x)) x = F.relu(self.conv4_2(x)) x = F.pooling(x, 2, 2) x = F.reshape(x, (x.shape[0], -1)) x = F.dropout(F.relu(self.fc5(x))) x = self.fc6(x) return x @staticmethod def preprocess(data, size=(224, 224), dtype=np.float32): # dataにはDatasetクラスのprepareでpathを入れている image = Image.open(data) image = image.convert('RGB') if size: image = image.resize(size) image = np.asarray(image, dtype=dtype) image = image[:, :, ::-1] # image -= np.array([103.939, 116.779, 123.68], dtype=dtype) image = image.transpose((2, 0, 1)) return image

 

このようにしてモデルのクラスを作成した場合、下記のように条件付けで簡単に学習済みのモデル、または、学習前のモデルインスタンスを生成できます。

 


# 学習済みモデルを使用しない場合(初回の学習時など)
model = TestModel(pretrained=False)
# 学習済みモデルを使用する場合(再度学習をさせる時や実際にモデルを使って予測をする場合) model = TestModel(pretrained=True)