Pynote

Python、機械学習、画像処理について

Keras - Keras のファイルの形式について

試した環境

  • Keras 2

MNIST のクラス分類器を CNN で作成する。

サンプルの重みファイルを作成するために、MNIST の分類問題を解くためのモデルを作成し、学習を行う。

MNIST データセットを読み込み、前処理を行う。

import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Conv2D, Dense, Dropout, Flatten, MaxPooling2D
from keras import backend as K
import numpy as np

batch_size = 128
num_classes = 10
epochs = 12

# MNIST データセットを読み込む。
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 画像の前処理を行う。
img_rows, img_cols = 28, 28  # ネットワークの入力サイズ
x_train = x_train[...,np.newaxis].astype('float32') / 255.
x_test = x_test[...,np.newaxis].astype('float32') / 255.

# ラベルを one-hot 表現にする。
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

モデルを作成する。

# モデルを作成する。
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu',
                 input_shape=(img_rows, img_cols, 1)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D())
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer='adadelta',
              metrics=['accuracy'])

モデル構成を表示する。

model.summary()
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 26, 26, 32)        320       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 24, 24, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 64)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 12, 12, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 9216)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 128)               1179776   
_________________________________________________________________
dropout_2 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                1290      
=================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0

モデルの学習を行う。

# 学習する。
model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

save_weights() で保存した場合

save_weights() ではモデルの重みのみを保存できる。
これには、モデル構成等の情報は含まれない。

# モデルを保存する。
weights_path = 'mnist_classifier.h5'
model.save_weights(save_path)

HDF5 ファイルの中身を表示する。

HDF5 ファイルはツリー構造になっているので、可視化する。

import h5py

def traverse(node, depth):
    def indent(depth):
        # 階層に応じて、インデントする。
        for i in range(depth):
            print('    ', end='')
    
    indent(depth)
    if isinstance(node, h5py.File):
        print('File key:{}'.format(node.name))
    elif isinstance(node, h5py.Group):
        print('Group key:{}'.format(node.name))
    else:
        print('Dataset key:{}, type: {}, shape: {}'.format(
            node.name, node.dtype, node.shape))

    # attributes
    for key, value in node.attrs.items():
        indent(depth)
        print('attribute key: {}, value: {}'.format(key, value))

    # Traverse children
    if not isinstance(node, h5py.Dataset):
        for key, value in node.items():
            traverse(value, depth + 1)

h5file = h5py.File(weights_path, 'r')
traverse(h5file, 0)
File key:/
attribute key: layer_names, value: [b'conv2d_1' b'conv2d_2' b'max_pooling2d_1' b'dropout_1' b'flatten_1'
 b'dense_1' b'dropout_2' b'dense_2']
attribute key: backend, value: b'tensorflow'
attribute key: keras_version, value: b'2.1.2'
    Group key:/conv2d_1
    attribute key: weight_names, value: [b'conv2d_1/kernel:0' b'conv2d_1/bias:0']
        Group key:/conv2d_1/conv2d_1
            Dataset key:/conv2d_1/conv2d_1/bias:0, type: float32, shape: (32,)
            Dataset key:/conv2d_1/conv2d_1/kernel:0, type: float32, shape: (3, 3, 1, 32)
    Group key:/conv2d_2
    attribute key: weight_names, value: [b'conv2d_2/kernel:0' b'conv2d_2/bias:0']
        Group key:/conv2d_2/conv2d_2
            Dataset key:/conv2d_2/conv2d_2/bias:0, type: float32, shape: (64,)
            Dataset key:/conv2d_2/conv2d_2/kernel:0, type: float32, shape: (3, 3, 32, 64)
    Group key:/dense_1
    attribute key: weight_names, value: [b'dense_1/kernel:0' b'dense_1/bias:0']
        Group key:/dense_1/dense_1
            Dataset key:/dense_1/dense_1/bias:0, type: float32, shape: (128,)
            Dataset key:/dense_1/dense_1/kernel:0, type: float32, shape: (9216, 128)
    Group key:/dense_2
    attribute key: weight_names, value: [b'dense_2/kernel:0' b'dense_2/bias:0']
        Group key:/dense_2/dense_2
            Dataset key:/dense_2/dense_2/bias:0, type: float32, shape: (10,)
            Dataset key:/dense_2/dense_2/kernel:0, type: float32, shape: (128, 10)
    Group key:/dropout_1
    attribute key: weight_names, value: []
    Group key:/dropout_2
    attribute key: weight_names, value: []
    Group key:/flatten_1
    attribute key: weight_names, value: []
    Group key:/max_pooling2d_1
    attribute key: weight_names, value: []

ルート以下にモデルを構成する各層の重みを内包する Gruop ノードが属している。
畳み込み層 conv2d_1 のカーネル、バイアスの値は以下のようにして取り出せる。

conv1_node = h5file['/conv2d_1/conv2d_1']  # conv2d_1 の Group ノード

kernel = conv1_node['kernel:0'].value
print(type(kernel), kernel.shape)

bias = conv1_node['bias:0'].value
print(type(bias), bias.shape)
<class 'numpy.ndarray'> (3, 3, 1, 32)
<class 'numpy.ndarray'> (32,)

save() で保存した場合

save() ではモデルの構造、重み、学習の設定、optimizer の状態が含まれる。

# モデルを保存する。
model_path = 'mnist_classifier_model.h5'
model.save(model_path)

# HDF5 ファイルを読み込む。
h5file = h5py.File(model_path, 'r')
traverse(h5file, 0)
File key:/
attribute key: keras_version, value: b'2.1.2'
attribute key: backend, value: b'tensorflow'
attribute key: model_config, value: b'{"class_name": "Sequential", "config": [{"class_name": "Conv2D", "config": {"data_format": "channels_last", "bias_initializer": {"class_name": "Zeros", "config": {}}, "strides": [1, 1], "use_bias": true, "dilation_rate": [1, 1], "batch_input_shape": [null, 28, 28, 1], "kernel_constraint": null, "kernel_size": [3, 3], "bias_regularizer": null, "activity_regularizer": null, "kernel_regularizer": null, "name": "conv2d_1", "dtype": "float32", "filters": 32, "bias_constraint": null, "activation": "relu", "padding": "valid", "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "distribution": "uniform", "seed": null, "mode": "fan_avg"}}, "trainable": true}}, {"class_name": "Conv2D", "config": {"data_format": "channels_last", "bias_initializer": {"class_name": "Zeros", "config": {}}, "strides": [1, 1], "use_bias": true, "dilation_rate": [1, 1], "kernel_constraint": null, "kernel_size": [3, 3], "bias_regularizer": null, "activity_regularizer": null, "kernel_regularizer": null, "name": "conv2d_2", "filters": 64, "bias_constraint": null, "activation": "relu", "padding": "valid", "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "distribution": "uniform", "seed": null, "mode": "fan_avg"}}, "trainable": true}}, {"class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_1", "data_format": "channels_last", "strides": [2, 2], "pool_size": [2, 2], "padding": "valid", "trainable": true}}, {"class_name": "Dropout", "config": {"name": "dropout_1", "rate": 0.25, "noise_shape": null, "trainable": true, "seed": null}}, {"class_name": "Flatten", "config": {"name": "flatten_1", "trainable": true}}, {"class_name": "Dense", "config": {"activity_regularizer": null, "use_bias": true, "kernel_constraint": null, "bias_regularizer": null, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "name": "dense_1", "units": 128, "bias_constraint": null, "activation": "relu", "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "distribution": "uniform", "seed": null, "mode": "fan_avg"}}, "trainable": true}}, {"class_name": "Dropout", "config": {"name": "dropout_2", "rate": 0.5, "noise_shape": null, "trainable": true, "seed": null}}, {"class_name": "Dense", "config": {"activity_regularizer": null, "use_bias": true, "kernel_constraint": null, "bias_regularizer": null, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "name": "dense_2", "units": 10, "bias_constraint": null, "activation": "softmax", "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "distribution": "uniform", "seed": null, "mode": "fan_avg"}}, "trainable": true}}]}'
attribute key: training_config, value: b'{"sample_weight_mode": null, "metrics": ["accuracy"], "loss_weights": null, "optimizer_config": {"class_name": "Adadelta", "config": {"epsilon": 1e-08, "rho": 0.95, "decay": 0.0, "lr": 1.0}}, "loss": "categorical_crossentropy"}'
    Group key:/model_weights
    attribute key: layer_names, value: [b'conv2d_1' b'conv2d_2' b'max_pooling2d_1' b'dropout_1' b'flatten_1'
 b'dense_1' b'dropout_2' b'dense_2']
    attribute key: backend, value: b'tensorflow'
    attribute key: keras_version, value: b'2.1.2'
        Group key:/model_weights/conv2d_1
        attribute key: weight_names, value: [b'conv2d_1_2/kernel:0' b'conv2d_1_2/bias:0']
            Group key:/model_weights/conv2d_1/conv2d_1_2
                Dataset key:/model_weights/conv2d_1/conv2d_1_2/bias:0, type: float32, shape: (32,)
                Dataset key:/model_weights/conv2d_1/conv2d_1_2/kernel:0, type: float32, shape: (3, 3, 1, 32)
        Group key:/model_weights/conv2d_2
        attribute key: weight_names, value: [b'conv2d_2_2/kernel:0' b'conv2d_2_2/bias:0']
            Group key:/model_weights/conv2d_2/conv2d_2_2
                Dataset key:/model_weights/conv2d_2/conv2d_2_2/bias:0, type: float32, shape: (64,)
                Dataset key:/model_weights/conv2d_2/conv2d_2_2/kernel:0, type: float32, shape: (3, 3, 32, 64)
        Group key:/model_weights/dense_1
        attribute key: weight_names, value: [b'dense_1_2/kernel:0' b'dense_1_2/bias:0']
            Group key:/model_weights/dense_1/dense_1_2
                Dataset key:/model_weights/dense_1/dense_1_2/bias:0, type: float32, shape: (128,)
                Dataset key:/model_weights/dense_1/dense_1_2/kernel:0, type: float32, shape: (9216, 128)
        Group key:/model_weights/dense_2
        attribute key: weight_names, value: [b'dense_2_2/kernel:0' b'dense_2_2/bias:0']
            Group key:/model_weights/dense_2/dense_2_2
                Dataset key:/model_weights/dense_2/dense_2_2/bias:0, type: float32, shape: (10,)
                Dataset key:/model_weights/dense_2/dense_2_2/kernel:0, type: float32, shape: (128, 10)
        Group key:/model_weights/dropout_1
        attribute key: weight_names, value: []
        Group key:/model_weights/dropout_2
        attribute key: weight_names, value: []
        Group key:/model_weights/flatten_1
        attribute key: weight_names, value: []
        Group key:/model_weights/max_pooling2d_1
        attribute key: weight_names, value: []
    Group key:/optimizer_weights
    attribute key: weight_names, value: [b'training_2/Adadelta/Variable:0' b'training_2/Adadelta/Variable_1:0'
 b'training_2/Adadelta/Variable_2:0' b'training_2/Adadelta/Variable_3:0'
 b'training_2/Adadelta/Variable_4:0' b'training_2/Adadelta/Variable_5:0'
 b'training_2/Adadelta/Variable_6:0' b'training_2/Adadelta/Variable_7:0'
 b'training_2/Adadelta/Variable_8:0' b'training_2/Adadelta/Variable_9:0'
 b'training_2/Adadelta/Variable_10:0' b'training_2/Adadelta/Variable_11:0'
 b'training_2/Adadelta/Variable_12:0' b'training_2/Adadelta/Variable_13:0'
 b'training_2/Adadelta/Variable_14:0' b'training_2/Adadelta/Variable_15:0']
        Group key:/optimizer_weights/training_2
            Group key:/optimizer_weights/training_2/Adadelta
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable:0, type: float32, shape: (3, 3, 1, 32)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_10:0, type: float32, shape: (3, 3, 32, 64)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_11:0, type: float32, shape: (64,)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_12:0, type: float32, shape: (9216, 128)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_13:0, type: float32, shape: (128,)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_14:0, type: float32, shape: (128, 10)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_15:0, type: float32, shape: (10,)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_1:0, type: float32, shape: (32,)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_2:0, type: float32, shape: (3, 3, 32, 64)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_3:0, type: float32, shape: (64,)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_4:0, type: float32, shape: (9216, 128)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_5:0, type: float32, shape: (128,)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_6:0, type: float32, shape: (128, 10)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_7:0, type: float32, shape: (10,)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_8:0, type: float32, shape: (3, 3, 1, 32)
                Dataset key:/optimizer_weights/training_2/Adadelta/Variable_9:0, type: float32, shape: (32,)