TensorFlow, Kerasでモデルのレイヤー名を取得

Posted: | Tags: Python, TensorFlow, Keras, 機械学習

TensorFlow, Kerasで構築したモデルからレイヤー名を取得する方法について、以下の内容を説明する。

  • 全てのレイヤー名を取得
  • 条件を満たすレイヤーの名前を抽出
  • レイヤーのインデックスを指定して名前を取得

レイヤーの名前からインデックスを取得したい場合や、レイヤーのオブジェクト自体を取得したい場合は以下の記事を参照。

以下のサンプルコードのTensorFlowのバージョンは2.1.0。TensorFlowに統合されたKerasを使う。

import tensorflow as tf
import pprint

print(tf.__version__)
# 2.1.0

Kerasに同梱されているVGG16のモデルを例とする。自分で構築したモデルでもやり方は同じ。

model = tf.keras.applications.VGG16(weights=None)

model.summary()
# Model: "vgg16"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_1 (InputLayer)         [(None, 224, 224, 3)]     0         
# _________________________________________________________________
# block1_conv1 (Conv2D)        (None, 224, 224, 64)      1792      
# _________________________________________________________________
# block1_conv2 (Conv2D)        (None, 224, 224, 64)      36928     
# _________________________________________________________________
# block1_pool (MaxPooling2D)   (None, 112, 112, 64)      0         
# _________________________________________________________________
# block2_conv1 (Conv2D)        (None, 112, 112, 128)     73856     
# _________________________________________________________________
# block2_conv2 (Conv2D)        (None, 112, 112, 128)     147584    
# _________________________________________________________________
# block2_pool (MaxPooling2D)   (None, 56, 56, 128)       0         
# _________________________________________________________________
# block3_conv1 (Conv2D)        (None, 56, 56, 256)       295168    
# _________________________________________________________________
# block3_conv2 (Conv2D)        (None, 56, 56, 256)       590080    
# _________________________________________________________________
# block3_conv3 (Conv2D)        (None, 56, 56, 256)       590080    
# _________________________________________________________________
# block3_pool (MaxPooling2D)   (None, 28, 28, 256)       0         
# _________________________________________________________________
# block4_conv1 (Conv2D)        (None, 28, 28, 512)       1180160   
# _________________________________________________________________
# block4_conv2 (Conv2D)        (None, 28, 28, 512)       2359808   
# _________________________________________________________________
# block4_conv3 (Conv2D)        (None, 28, 28, 512)       2359808   
# _________________________________________________________________
# block4_pool (MaxPooling2D)   (None, 14, 14, 512)       0         
# _________________________________________________________________
# block5_conv1 (Conv2D)        (None, 14, 14, 512)       2359808   
# _________________________________________________________________
# block5_conv2 (Conv2D)        (None, 14, 14, 512)       2359808   
# _________________________________________________________________
# block5_conv3 (Conv2D)        (None, 14, 14, 512)       2359808   
# _________________________________________________________________
# block5_pool (MaxPooling2D)   (None, 7, 7, 512)         0         
# _________________________________________________________________
# flatten (Flatten)            (None, 25088)             0         
# _________________________________________________________________
# fc1 (Dense)                  (None, 4096)              102764544 
# _________________________________________________________________
# fc2 (Dense)                  (None, 4096)              16781312  
# _________________________________________________________________
# predictions (Dense)          (None, 1000)              4097000   
# =================================================================
# Total params: 138,357,544
# Trainable params: 138,357,544
# Non-trainable params: 0
# _________________________________________________________________

上のコードのようにsummary()で出力される情報にレイヤーの名前も含まれているが、以降のサンプルコードでは、文字列のリストなどでレイヤーの名前を取得する方法を示す。

全てのレイヤー名を取得

以下のように、すべてのレイヤーの名前をリストで取得できる。出力を見やすくするためにpprintを使っている。

names = [l.name for l in model.layers]
pprint.pprint(names, compact=True)
# ['input_1', 'block1_conv1', 'block1_conv2', 'block1_pool', 'block2_conv1',
#  'block2_conv2', 'block2_pool', 'block3_conv1', 'block3_conv2', 'block3_conv3',
#  'block3_pool', 'block4_conv1', 'block4_conv2', 'block4_conv3', 'block4_pool',
#  'block5_conv1', 'block5_conv2', 'block5_conv3', 'block5_pool', 'flatten',
#  'fc1', 'fc2', 'predictions']

リスト内包表記を使って、モデルのlayers属性からレイヤーのオブジェクトを取り出し、レイヤーのname属性で名前を取得している。

layers属性は各レイヤーのオブジェクトが格納されているリスト。

pprint.pprint(model.layers)
# [<tensorflow.python.keras.engine.input_layer.InputLayer object at 0x131c7a650>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x104ce6590>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x131aba910>,
#  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x131c5cdd0>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x12ab00e10>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x12aaf44d0>,
#  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x12aaef890>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x131ebc290>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x131ec0bd0>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x131ec6f50>,
#  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x131ec9e90>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x131ed8090>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x131edbdd0>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x132a21dd0>,
#  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x132a26950>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x132a2bd10>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x132a35f90>,
#  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x132a3cbd0>,
#  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x132a41f10>,
#  <tensorflow.python.keras.layers.core.Flatten object at 0x132a46ed0>,
#  <tensorflow.python.keras.layers.core.Dense object at 0x132a46f50>,
#  <tensorflow.python.keras.layers.core.Dense object at 0x132a51710>,
#  <tensorflow.python.keras.layers.core.Dense object at 0x132a59110>]

print(type(model.layers))
# <class 'list'>

レイヤーオブジェクトのname属性で名前を取得可能。

print(model.layers[0])
# <tensorflow.python.keras.engine.input_layer.InputLayer object at 0x131c7a650>

print(type(model.layers[0]))
# <class 'tensorflow.python.keras.engine.input_layer.InputLayer'>

print(model.layers[0].name)
# input_1

条件を満たすレイヤーの名前を抽出

リスト内包表記に条件を追加すると、条件を満たすレイヤーの名前のみを抽出できる。

'pool'が含まれている名前のみを抽出する例は以下の通り。

names_pool = [l.name for l in model.layers if 'pool' in l.name]
print(names_pool)
# ['block1_pool', 'block2_pool', 'block3_pool', 'block4_pool', 'block5_pool']

レイヤーの種類で条件を指定することもできる。クラスに対する条件を与える。

Denseレイヤーの名前のみを抽出する例は以下の通り。

names_dense = [l.name for l in model.layers
               if isinstance(l, tf.keras.layers.Dense)]
print(names_dense)
# ['fc1', 'fc2', 'predictions']

組み込み関数isinstance()を使うと複数の種類(クラス)のレイヤーを抽出するのも簡単。

names_dense_pool = [l.name for l in model.layers
                    if isinstance(l, (tf.keras.layers.Dense, tf.keras.layers.MaxPooling2D))]
pprint.pprint(names_dense_pool, compact=True)
# ['block1_pool', 'block2_pool', 'block3_pool', 'block4_pool', 'block5_pool',
#  'fc1', 'fc2', 'predictions']

否定notを使って、条件を満たさないレイヤーの名前を抽出することもできる。

names_not_conv = [l.name for l in model.layers
                  if not isinstance(l, tf.keras.layers.Conv2D)]
pprint.pprint(names_not_conv, compact=True)
# ['input_1', 'block1_pool', 'block2_pool', 'block3_pool', 'block4_pool',
#  'block5_pool', 'flatten', 'fc1', 'fc2', 'predictions']

レイヤーのインデックスを指定して名前を取得

上の例ですでに出てきているが、レイヤーのインデックス(何層目か)を指定して名前を取得したい場合は、layers属性から所望のインデックスのレイヤーを指定すればよい。

print(model.layers[0].name)
# input_1

print(model.layers[5].name)
# block2_conv2

print(model.layers[10].name)
# block3_pool

layers属性はただのリストなので、負の値で末尾からの位置を指定することもできる。最終レイヤーは-1

print(model.layers[-1].name)
# predictions

print(model.layers[-3].name)
# fc1

スライスで範囲を指定することも可能。

names_slice = [l.name for l in model.layers[5:10]]
print(names_slice)
# ['block2_conv2', 'block2_pool', 'block3_conv1', 'block3_conv2', 'block3_conv3']

反対に、レイヤーの名前を指定してインデックスを取得したい場合は以下の記事を参照。

関連カテゴリー

関連記事