Segmentationや、SSD, YOLO(v2)といったsingle shot系のベースネットワークとしてFully Convolutional Networks (FCN) を利用していると、入力画像サイズが可変なので、任意の入力画像サイズに対し出力されるfeature mapのサイズを明示的に知りたいときがある。
例えばstride=2にしたダウンサンプルを4回行うと、出力されるfeature mapのサイズは入力画像の大体1/16になる。入力サイズを16の倍数に制限してしまえば単純に16で割れば良いが、端数のケースも考慮したい。Paddingなしの2x2 maxpoolingとかであれば、単純に16で割って端数を切り捨てれば良い。
ResNet系では、paddingあり、stride=2の3x3の畳み込みでダウンサンプルするケースが多いので、そういうケースでfeature mapのサイズを明示的に求めたい。
Kerasで言えば、下記のような畳み込み。
Conv2D(32, 3, strides=2, padding="same")
x
を入力サイズ、count
をstride=2でダウンサンプルする回数とすると、出力されるfeature mapのサイズは下記で求められる。
def down_sample(x, count):
for _ in range(count):
x = (x + 1) // 2
return x
これは下記でも同じ。
def down_sample(x, count):
return (x + pow(2, count) - 1) // pow(2, count)
ランダムな入力サイズで確認(Keras実装)。
import numpy as np
from keras.models import Sequential
from keras.layers import Conv2D
def down_sample(x, count):
return (x + pow(2, count) - 1) // pow(2, count)
def main():
model = Sequential()
model.add(Conv2D(16, 3, strides=2, padding="same", activation="relu", input_shape=(None, None, 3)))
model.add(Conv2D(32, 3, strides=2, padding="same", activation="relu"))
model.add(Conv2D(64, 3, strides=2, padding="same", activation="relu"))
model.add(Conv2D(128, 3, strides=2, padding="same", activation="relu"))
for _ in range(10):
h, w = np.random.randint(300, 600), np.random.randint(300, 600)
data = np.ones((1, h, w, 3))
ch, cw = down_sample(h, 4), down_sample(w, 4)
result = model.predict(data)
print("result: {}, calculated: ({}, {})".format(result.shape[1:3], ch, cw))
if __name__ == '__main__':
main()