0
1

Keras3 にしたら古いモデルが読み込めなくなった話

Posted at

背景

Ubuntu22.04 から 24.04 に更新して、以前作成したトレーニング済みモデルをロードしようとしたら、読み込めなくなったので、その試行錯誤と解決方法をまとめる。

動作確認環境

LinuxOS Ubuntu 24.04.1 LTS
Python 3.12.3

免責事項

その前に、このスクリプトの実行は自己責任でお願いします。本スクリプトを実行することにより生じるいかなる問題に関しましても、筆者は一切責任を負いません。予めご了承ください。

from tensorflow.keras.callbacks import ModelCheckpoint でチェックポイントを登録しようとしたら失敗した。

from tensorflow.keras.callbacks import ModelCheckpoint

checkpoint = ModelCheckpoint(filepath='MODELS/model{epoch:02d}')

ValueError: The filepath provided must end in `.keras` (Keras model format). Received: filepath=MODELS/model{epoch:02d}

どうやら、Keras3から、チェックポイントの登録、モデルの保存には、 .keras を付けなければいけなくなったようだ。

pip freezekerastensorflow のバージョンを調べる

(venv) % pip freeze

keras==3.5.0
tensorflow==2.17.0

確かに、 Keras のバージョンが 3.5.0 に上がっている。

以前の Tensorflow のバージョン 2.15.1 のインストールを試みる

(venv) % deactivate
% rm -rf venv
% python -m venv venv
% source venv/bin/activate
(venv) % pip install tensorflow==2.15.1

ERROR: Could not find a version that satisfies the requirement tensorflow==2.15.1 (from versions: 2.16.0rc0, 2.16.1, 2.16.2, 2.17.0rc0, 2.17.0rc1, 2.17.0)
ERROR: No matching distribution found for tensorflow==2.15.1

2.16.0rc0 以上でないとインストールできないようだ。

取り敢えずチェックポイントに拡張子 .keras を付けてトレーニングしてみる

取り敢えず拡張子 .keras 付きのモデルが作成された。

checkpoint = ModelCheckpoint(filepath='MODELS/model{epoch:02d}.keras')

history = model.fit(x_train, y_train, epochs=1, batch_size=32, validation_split=0.2, callbacks=[checkpoint])

Keras3 ではトレーニング終了後 MODELS/model01.keras という zip 形式のトレーニング済みモデルが作成されたようだ。中身を見てみる。

model01.keras
├─ config.json
├─ metadata.json
└─ model.weights.h5

Keras2 以前のトレーニング済みモデルと中身が異なっている。因みに以前のトレーニング済みモデルはこんな感じ。

model01
├+ assets
│  └─ 空
├─ keras_metadata.pb
├─ saved_model.pb
└+ variables
   ├─ variables.data-00000-of-00001
   └─ variables.index

拡張子 .keras をつけてロードしてみる

from tensorflow import keras

model = keras.models.load_model('MODELS/model01.keras')

TypeError: Could not locate class 'Bias'. Make sure custom classes are decorated with `@keras.saving.register_keras_serializable()`.

During handling of the above exception, another exception occurred:

TypeError: <class 'keras.src.models.sequential.Sequential'> could not be deserialized properly. Please ensure that components that are Python object instances (layers, models, etc.) returned by `get_config()` are explicitly deserialized in the model's `from_config()` method.

カスタムクラス Bias が配置されていないというエラー。
もう一つが、 get_config() で返されたコンポーネントが from_config() で逆シリアライズ化されていないというエラー。

カスタムクラスが配置されていないということなので、トレーニング済みモデルをロードする前にモデルを定義・コンパイルする

from tensorflow import keras
from tensorflow.keras import layers

class Bias(keras.layers.Layer):
    # 省略  

model = keras.Sequential()
model.add(Bias(""" 省略 """))
model.compile(""" 省略 """)

コンパイルしたモデルに、チェックポイントで保存したウェイトをロードする

import shutil

shutil.unpack_archive('MODELS/model01.keras', 'MODELS/model01')

shutil.ReadError: Unknown archive format 'MODELS/model01.keras'

shutil.unpack_archive では、拡張子 zip 以外のファイルを解凍できないようだ。
zipfile.ZipFile に変更してみる。

import zipfile

with zipfile.ZipFile('MODELS/model01.keras') as zf:
    zf.extractall('MODELS/model01')

無事に MODELS フォルダの下に model01 フォルダが作成され、その配下にモデルデータが解凍された。

MODELS
└+ model01
   ├─ config.json
   ├─ metadata.json
   └─ model.weights.h5

zf.extractall の解凍先を MODELS にすると MODELS フォルダの直下に、 config.jsonmetadata.jsonmodel.weights.h5 が解凍されてしまう。

with zipfile.ZipFile('MODELS/model01.keras') as zf:
    zf.extractall('MODELS')
MODELS
├─ config.json
├─ metadata.json
└─ model.weights.h5

モデルが複数個存在する場合、上書きされてしまうので、モデル毎に別フォルダで管理するのが無難。
解凍が終わったら、 model.weights.h5 のウェイトをロードして、モデルのフォルダ毎削除。

import shutil

model.load_weights('MODELS/model01/model.weights.h5')
shutil.rmtree('MODELS/model01')

別にモデルのフォルダを削除する必要はないが、 MODELS/model01.keras があるので、 MODELS/model01 を置いておく必要はない。
MODELS フォルダの直下に解凍しても良いが、後始末が面倒なので、モデル毎のフォルダを作成し、そのフォルダ毎削除するのが無難。

余談、ウェイトをロードして生成した Keras3 形式のモデルから、 Keras2 形式のモデルを生成できる

model.export('MODELS/model01')

トレーニング済みウェイトをロードして生成した Keras3 形式のモデルから model.export を使用すると、 Keras2 形式のモデルを生成できるが、 Keras2 形式のモデルを生成したところで、 Keras3 では使い道がない。

ロードしたウェイトでトレーニング

checkpoint = ModelCheckpoint(filepath='MODELS/model{epoch:02d}.keras')

history = model.fit(x_train, y_train, initial_epoch=1, epochs=2, batch_size=32, validation_split=0.2, callbacks=[checkpoint]

チェックポイントを定義し、無事に途中からでもトレーニングに成功。チェックポイントを定義していることで、 Keras3 形式のトレーニング済みウェイトが生成される。

Keras2 と Keras3の比較

• トレーニング済みモデルをロードする時 Keras2 では、 keras.models.load_model でモデルをロードできていたが、 Keras3 ではトレーニング済みモデルをロードできなくなった。 Keras3 でもトレーニング済みモデルをロードできるかもしれないが、その方法がわからない。
• 代わりに Keras3 では、モデルを再定義・コンパイルし、そのモデルにトレーニング済みウェイトをロード load_weights('モデルのパス/model.weights.h5') することで、トレーニング済みモデルを生成するような感じになっている。
Keras2 では、トレーニングを途中から再開する際、トレーニング済みモデルを読み込めば、トレーニングを途中から再開できたが、 Keras3 では、トレーニングを途中から再開する場合は、毎回モデルの定義・コンパイルを行い、そのモデルにトレーニング済みウェイトを読み込まなければならない。

最後に

今回 Ubuntu の最新 LTS 版がリリースされてから約半年が経ち、 22.04 から 24.04 に更新してみたところ、以前 Tensorflow でトレーニングしたトレーニング済みモデルが読み込めないという問題に遭遇しました。
長年ソフトウェア開発に身を置いていますが、 Keras に限らずモジュールが更新されると今まで動いていたモジュールが使えなくなるということがよくあります。ソフトウェア開発をする上で、この問題は永遠のテーマと言えます。
こういう問題に遭遇すると、問題解決のために、あっという間に時間が過ぎてしまいます。何とかしてもらいたいところです。
最後まで、この記事を読んでいただき、ありがとうございました。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1