chainerのimagenetサンプルで好きな画像サイズで入力する方法
chainerのサンプルにあるimagenetは,1000クラスの大規模画像分類用に設計されたネットワークである,Network In Network や,AlexNet, GoogLeNetなどを使うことが出来ます。
入力画像のサイズは256×256となっており,train_imagenet.pyの学習プログラムの内部でランダムにクリッピングをすることで,学習データを増やし,多少のズレに頑健なネットワークの学習が可能となっています。
このサンプルソースを使って,自分で用意した学習データを使って学習させたい場合,入力画像のサイズや,アスペクト比が違うこともあると思います。
そういう場合に、どこを変更すれば簡単に動くようになるかを紹介したいと思います。
まず、train_imagenet.pyのプログラムから
PreprocessedDatasetクラスの変更部分がこちらです。
class PreprocessedDataset(chainer.dataset.DatasetMixin): def __init__(self, path, root, mean, crop_size_x, crop_size_y random=True): self.base = chainer.datasets.LabeledImageDataset(path, root) self.mean = mean self.crop_size_x = crop_size_x self.crop_size_y = crop_size_y self.random = random def __len__(self): return len(self.base) def get_example(self, i): # It reads the i-th image/label pair and return a preprocessed image. # It applies following preprocesses: # - Cropping (random or center rectangular) # - Random flip # - Scaling to [0, 1] value crop_size_x = self.crop_size_x crop_size_y = self.crop_size_y image, label = self.base[i] _, h, w = image.shape if self.random: # Randomly crop a region and flip the image top = random.randint(0, h - crop_size_y - 1) left = random.randint(0, w - crop_size_x - 1) if random.randint(0, 1): image = image[:, :, ::-1] else: # Crop the center top = (h - crop_size_y) // 2 left = (w - crop_size_x) // 2 bottom = top + crop_size_y right = left + crop_size_x image = image[:, top:bottom, left:right] image -= self.mean[:, top:bottom, left:right] image /= 255 return image, label
このクラスは、初期化を行う部分と,データセットを読み込む際にデータをクリッピングする操作が含まれています。
元のプログラムは正方形の256×256ピクセルの画像が入力される前提となっているため,縦長や横長の画像に対応するために
crop_sizeにcrop_size_xとcrop_size_yを加え、修正しています。
次はTestModeEvaluatorクラスです。
まず、meanファイルとデータセット読み込みの部分で、先ほどcrop_size_xとcrop_size_yを加えた部分の修正をこちらでも行います。
model.insizeは、モデルファイルの中に書かれている入力画像のサイズを取得している部分です。
縦横違うサイズの場合は変更、もしくは追加する必要があります。
# Load the datasets and mean file mean = np.load(args.mean) train = PreprocessedDataset(args.train, args.root, mean, model.insize_x, model.insize_y) val = PreprocessedDataset(args.val, args.root, mean, model.insize_x, model.insize_y False)
次にモデルファイルです。
今回は例としてNetwork In Networkを用います。
import math import chainer import chainer.functions as F import chainer.links as L class NIN(chainer.Chain): """Network-in-Network example model.""" insize_x = 227 #横の入力画像サイズ(クリッピング後のサイズ) insize_y = 227 #縦の入力画像サイズ(クリッピング後のサイズ) #入力画像サイズに合わせて、畳み込みなどのフィルタサイズを変更してください def __init__(self): w = math.sqrt(2) # MSRA scaling super(NIN, self).__init__( mlpconv1=L.MLPConvolution2D( None, (96, 96, 96), 11, stride=4, wscale=w), mlpconv2=L.MLPConvolution2D( None, (256, 256, 256), 5, pad=2, wscale=w), mlpconv3=L.MLPConvolution2D( None, (384, 384, 384), 3, pad=1, wscale=w), mlpconv4=L.MLPConvolution2D( None, (1024, 1024, 1000), 3, pad=1, wscale=w), ) self.train = True def __call__(self, x, t): h = F.max_pooling_2d(F.relu(self.mlpconv1(x)), 3, stride=2) h = F.max_pooling_2d(F.relu(self.mlpconv2(h)), 3, stride=2) h = F.max_pooling_2d(F.relu(self.mlpconv3(h)), 3, stride=2) h = self.mlpconv4(F.dropout(h, train=self.train)) h = F.reshape(F.average_pooling_2d(h, 6), (x.data.shape[0], 1000)) loss = F.softmax_cross_entropy(h, t) chainer.report({'loss': loss, 'accuracy': F.accuracy(h, t)}, self) return loss