Saving model architecture only

目录

<!DOCTYPE html>

Saving model architecture only

Saving model architecture only

In this reading you will learn how to save a model's architecture, but not its weights.

In [1]:
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import json
import numpy as np

In previous videos and notebooks you have have learned how to save a model's weights, as well as the entire model - weights and architecture.

Accessing a model's configuration

A model's configuration refers to its architecture. TensorFlow has a convenient way to retrieve a model's architecture as a dictionary. We start by creating a simple fully connected feedforward neural network with 1 hidden layer.

In [12]:
# Build the model

model = Sequential([
    Dense(units=32, input_shape=(32, 32, 3), activation='relu', name='dense_1'),
    Dense(units=10, activation='softmax', name='dense_2')
])

A TensorFlow model has an inbuilt method get_config which returns the model's architecture as a dictionary:

In [13]:
# Get the model config

config_dict = model.get_config()
print(config_dict)
{'name': 'sequential_1', 'layers': [{'class_name': 'Dense', 'config': {'name': 'dense_1', 'trainable': True, 'batch_input_shape': (None, 32, 32, 3), 'dtype': 'float32', 'units': 32, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'class_name': 'GlorotUniform', 'config': {'seed': None}}, 'bias_initializer': {'class_name': 'Zeros', 'config': {}}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}}, {'class_name': 'Dense', 'config': {'name': 'dense_2', 'trainable': True, 'dtype': 'float32', 'units': 10, 'activation': 'softmax', 'use_bias': True, 'kernel_initializer': {'class_name': 'GlorotUniform', 'config': {'seed': None}}, 'bias_initializer': {'class_name': 'Zeros', 'config': {}}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}}]}

Creating a new model from the config

A new TensorFlow model can be created from this config dictionary. This model will have reinitialized weights, which are not the same as the original model.

In [14]:
# Create a model from the config dictionary

model_same_config = tf.keras.Sequential.from_config(config_dict)

We can check explicitly that the config of both models is the same, but the weights are not:

In [18]:
model_same_config.weights[0].numpy()
Out[18]:
array([[ 0.32018784, -0.31203708,  0.3884084 ,  0.39815035,  0.12277231,
         0.06283128, -0.00181133,  0.08204165, -0.06520784, -0.10535648,
         0.39801124, -0.3096236 , -0.33124626, -0.31795335,  0.269681  ,
         0.24391034,  0.32666877, -0.00207666,  0.11548647, -0.2982181 ,
         0.31595084, -0.32893732, -0.30951422,  0.3557584 , -0.31345037,
         0.24872544, -0.11665457,  0.19354698, -0.11421189,  0.379513  ,
        -0.09874538,  0.2733228 ],
       [-0.2701029 ,  0.41010258, -0.1029301 , -0.02907029,  0.01467118,
         0.32845995,  0.34112146,  0.04987955,  0.38121513,  0.02638358,
        -0.05360454, -0.08132905, -0.04201573,  0.31915244,  0.14087483,
        -0.00317615,  0.21524486,  0.34127113,  0.28162268, -0.05328548,
         0.23954645,  0.28847113, -0.26524216,  0.36938587,  0.2056348 ,
        -0.2901024 , -0.3059608 , -0.12417072,  0.14442006,  0.052432  ,
        -0.03236201,  0.2414712 ],
       [ 0.3244333 , -0.3292396 , -0.3979982 , -0.00870386, -0.02531084,
         0.26804635,  0.4129431 , -0.25866443,  0.14658073,  0.19640723,
        -0.228521  ,  0.1976535 ,  0.27944073,  0.05383909, -0.10119686,
         0.13287422,  0.19376644, -0.3658268 , -0.21895793, -0.29340154,
         0.22373989,  0.1382505 , -0.21012336, -0.31165347,  0.11762276,
         0.1420804 ,  0.38724568, -0.01395234,  0.18652275, -0.3718098 ,
        -0.23927805,  0.12664637]], dtype=float32)
In [16]:
model.weights[0].numpy()
Out[16]:
array([[ 2.25344867e-01, -4.00846332e-01,  6.58946037e-02,
        -2.19083592e-01, -1.09725207e-01, -3.05240273e-01,
         6.52390420e-02,  1.06124908e-01, -3.80216032e-01,
         2.37855166e-01,  3.63039970e-02, -2.57415980e-01,
         3.64589423e-01, -1.00239307e-01, -1.17904902e-01,
         2.90944606e-01, -2.66889036e-02,  3.66890281e-01,
        -2.16333792e-01,  2.27825850e-01,  4.84699905e-02,
         6.82083964e-02, -4.10397261e-01,  3.85402411e-01,
        -6.74243867e-02, -3.19808185e-01, -3.28407615e-01,
        -4.01737124e-01, -1.42560869e-01, -2.42977679e-01,
        -1.76593542e-01, -3.67286295e-01],
       [ 3.45749527e-01, -9.82977152e-02, -2.72501558e-01,
         1.79233164e-01,  1.22059017e-01,  3.28419477e-01,
        -1.18748903e-01,  1.44381851e-01, -1.66147947e-04,
         6.86341524e-02, -2.61380166e-01,  2.37095982e-01,
        -2.09037602e-01,  2.20286995e-01,  2.68697739e-04,
        -1.65851906e-01,  4.51520979e-02, -7.18868971e-02,
        -4.94976938e-02,  3.01871330e-01,  3.11734587e-01,
         3.17297012e-01, -9.20674205e-02,  3.43128949e-01,
         3.64839882e-01,  1.41674310e-01, -2.65622824e-01,
         1.66677088e-01,  3.15773040e-01, -7.33288229e-02,
         1.89372897e-03, -1.18387610e-01],
       [ 9.19142067e-02,  1.04854256e-01, -1.62220180e-01,
        -2.49067843e-02,  3.78358036e-01, -4.31624949e-02,
        -1.65788621e-01,  2.20695138e-03,  3.22818786e-01,
         1.48884207e-01,  1.90474600e-01,  3.16670030e-01,
        -3.40526640e-01, -4.04169858e-01, -2.97709644e-01,
         3.66963774e-01, -1.71429813e-02, -3.82638395e-01,
         2.36696750e-01,  1.22457236e-01, -2.13849738e-01,
        -1.29857361e-01,  3.43173742e-02, -3.50103140e-01,
         1.04871184e-01, -1.13306969e-01, -3.56688976e-01,
         3.12692434e-01, -1.41811430e-01,  2.09401160e-01,
        -2.07413435e-02,  7.00601637e-02]], dtype=float32)
In [5]:
# Check the new model is the same architecture

print('Same config:', 
      model.get_config() == model_same_config.get_config())
print('Same value for first weight matrix:', 
      np.allclose(model.weights[0].numpy(), model_same_config.weights[0].numpy()))
Same config: True
Same value for first weight matrix: False

For models that are not Sequential models, use tf.keras.Model.from_config instead of tf.keras.Sequential.from_config.

Other file formats: JSON and YAML

It is also possible to obtain a model's config in JSON or YAML formats. This follows the same pattern:

In [6]:
# Convert the model to JSON

json_string = model.to_json()
print(json_string)
{"class_name": "Sequential", "config": {"name": "sequential", "layers": [{"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "batch_input_shape": [null, 32, 32, 3], "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 10, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}]}, "keras_version": "2.2.4-tf", "backend": "tensorflow"}

The JSON format can easily be written out and saved as a file:

In [7]:
# Write out JSON config file

with open('config.json', 'w') as f:
    json.dump(json_string, f)
del json_string
In [8]:
# Read in JSON config file again

with open('config.json', 'r') as f:
    json_string = json.load(f)
In [9]:
# Reinitialize the model

model_same_config = tf.keras.models.model_from_json(json_string)
In [10]:
# Check the new model is the same architecture, but different weights

print('Same config:', 
      model.get_config() == model_same_config.get_config())
print('Same value for first weight matrix:', 
      np.allclose(model.weights[0].numpy(), model_same_config.weights[0].numpy()))
Same config: True
Same value for first weight matrix: False

The YAML format is similar. The details of writing out YAML files, loading them and using them to create a new model are similar as for the JSON files, so we won't show it here.

In [11]:
# Convert the model to YAML

yaml_string = model.to_yaml()
print(yaml_string)
backend: tensorflow
class_name: Sequential
config:
  layers:
  - class_name: Dense
    config:
      activation: relu
      activity_regularizer: null
      batch_input_shape: !!python/tuple
      - null
      - 32
      - 32
      - 3
      bias_constraint: null
      bias_initializer:
        class_name: Zeros
        config: {}
      bias_regularizer: null
      dtype: float32
      kernel_constraint: null
      kernel_initializer:
        class_name: GlorotUniform
        config:
          seed: null
      kernel_regularizer: null
      name: dense_1
      trainable: true
      units: 32
      use_bias: true
  - class_name: Dense
    config:
      activation: softmax
      activity_regularizer: null
      bias_constraint: null
      bias_initializer:
        class_name: Zeros
        config: {}
      bias_regularizer: null
      dtype: float32
      kernel_constraint: null
      kernel_initializer:
        class_name: GlorotUniform
        config:
          seed: null
      kernel_regularizer: null
      name: dense_2
      trainable: true
      units: 10
      use_bias: true
  name: sequential
keras_version: 2.2.4-tf

Writing out, reading in and using YAML files to create models is similar to JSON files.