gcloud run deploy captcha --source . --function hello --base-image python312 --region asia-northeast1cd /workspaces/captcha-cloudrun
python -m pip install tensorflowjspython - <<'PY'
import tensorflow as tf
model = tf.keras.models.load_model('xserver_captcha.keras')
model.save('xserver_captcha.h5')
print('saved h5')
PY/usr/local/python/3.12.1/bin/tensorflowjs_converter \
--input_format=keras \
xserver_captcha.h5 \
web_model生成物:
web_model/model.jsonweb_model/group1-shard1of3.binweb_model/group1-shard2of3.binweb_model/group1-shard3of3.bin
Keras 3 の出力をそのままブラウザで使うと互換性エラーが出ることがあるため、今回の web_model/model.json は TensorFlow.js 互換になるよう追加調整しています。
Keras 3 から変換した直後の model.json は、そのままだとブラウザ側の tf.loadLayersModel() で読み込めない箇所がありました。今回行った主な調整は以下です。
Keras 3 側では次のように出力されることがありました。
{
"class_name": "InputLayer",
"config": {
"batch_shape": [null, 60, 300, 3]
}
}しかし TensorFlow.js 側は batch_shape ではなく、batch_input_shape または inputShape を期待します。
そのため以下のように変更しています。
{
"class_name": "InputLayer",
"config": {
"batch_input_shape": [null, 60, 300, 3]
}
}これをしないと、次のエラーが発生しました。
An InputLayer should be passed either a `batchInputShape` or an `inputShape`.
Keras 3 の JSON では dtype が DTypePolicy オブジェクトとして出力されることがあります。
例:
"dtype": {
"module": "keras",
"class_name": "DTypePolicy",
"config": { "name": "float32" }
}TensorFlow.js ではこの形式をそのまま扱えないことがあるため、単純な文字列に変換しています。
"dtype": "float32"Keras 3 ではレイヤー接続情報がオブジェクト形式で出力されることがあります。
例:
"inbound_nodes": [
{
"args": [
{
"class_name": "__keras_tensor__",
"config": {
"keras_history": ["input_image", 0, 0]
}
}
],
"kwargs": {}
}
]TensorFlow.js の tfjs-layers は、より古い配列表現を期待するため、以下の形式に変換しています。
"inbound_nodes": [
[
["input_image", 0, 0, {}]
]
]これを行わないと、次のようなエラーが発生しました。
Corrupted configuration, expected array for nodeData
Keras 3 が付与する以下のような情報は、TensorFlow.js 側で不要または互換性問題の原因になることがありました。
moduleregistered_namebuild_config
そのため、modelTopology 内から不要なメタ情報を整理しています。
変換直後の weightsManifest には、例えば以下のような名前が入っていました。
"forward_lstm/lstm_cell/kernel"一方、TensorFlow.js が実際に期待していた名前は次のような形式でした。
"bilstm1/forward_forward_lstm/kernel"この差異があると、次のエラーが発生しました。
Provided weight data has no target variable: forward_lstm/lstm_cell/kernel
そのため、weightsManifest.weights[].name を TensorFlow.js 側の実際の変数名に合わせて修正しています。
主な対応例:
forward_lstm/lstm_cell/kernel→bilstm1/forward_forward_lstm/kernelbackward_lstm/lstm_cell/kernel→bilstm1/backward_forward_lstm/kernelforward_lstm_1/lstm_cell/kernel→bilstm2/forward_forward_lstm_1/kernelbackward_lstm_1/lstm_cell/kernel→bilstm2/backward_forward_lstm_1/kernel
ブラウザが古い model.json をキャッシュしてしまうと、修正後の内容が反映されないことがあります。
そのため index.html 側では次のようにクエリ文字列付きで読み込むようにしています。
await tf.loadLayersModel('./web_model/model.json?v=20260407-2')最終的に以下の内容を確認できました。
tf.loadLayersModel()が成功する- 入力 shape が
[null, 60, 300, 3] - 出力 shape が
[null, 19, 11] - ダミー入力
tf.zeros([1, 60, 300, 3])でpredict()が成功する
つまり、現在の web_model はブラウザ側だけで推論できる TensorFlow.js 用モデルとして利用可能です。