ROS2 自作 Turtlebot3 による 草刈りロボット開発。#9 LSTM で経路計画をする。

ROS2 自作 Turtlebot3 による 草刈りロボット開発。#9 LSTM で経路計画をする。

--- ROS2 ロボット自律走行の経路計画の補助に、機械学習(Transformer、LSTM)を使う。 ----

ROS2 自作 Turtlebot3 による 草刈りロボット開発。#8 Transformer で経路計画をする。 の続きです。

Transformer で、学習データ 1000個作って、学習させてみたが、1000個では、まるっきり足りないようで、 val=0.7 を切らない。

業を煮やして、それならと、 Speech to text の LSTM を同じ様に学習させてみました。

こちらは。1000件ほどのデータで、うまく学習できました。
これは、凄い!!
こんなにうまく行くとは、予想できませんでした。
本当に、うまく予測できているのか、今も、半信半疑です。
余りの感激に、涙がちょちょでるぞね!!

github に公開しました。
tosa-no-onchan/opp_with_lstm

1. 開発環境
PC: Ubuntu Mate 22.04
Python 3.10.12
virtual_env
tensorflow 2.16.2
keras 3.6.0

2. 学習。

$ python train.py

3. モデルのfreeze。
$ python test-model-freeze.py

注) 後で、TensorFlow 2.16.2 C++ で、使うために、モデルをフリーズします。
Frozen Graph TensorFlow 2.x だと、
The frozen models are also fully compatible with inference using TensorFlow 1.x, TensorFlow 2.x, ONNX Runtime, and TensorRT.
だそうです。

4. predict

$ python inferencModel.py
で、コース予測ができます。


v_6.jpg


上記で、コース予測をして、コースをプロットした画像を、下記に幾つか上げておきました。

tosa-no-onchan/opp_with_lstm/work
注) ロボットは、画像の左 Center から、右 Center へ移動します。常の画像のCenter を通る事を予定しています。

5. 学習データの用意。
ちょっと話が長いので、少しずつ書いていきます。

手抜きで、下記に書きました。
cource_classgen.cpp
大体わかると思います。

学習データ・セットは、下記に公開しました。
huggingface.co/datasets/tosa-no-onchan/opp

6. 参照。
Speech to Text LSTM のオリジナル。
Introduction to speech recognition with TensorFlow

7. Youtube に公開しました。
ROS2 Obstacle Path Planner with LSTM

8. 開発時のトラブル。

1) オリジナルの、 Speech to Tex Lstm のモデルが、 Keras 2.x 対応だったので、
それをそのまま使っていたら、Keras model の Save and Load でかなり手こずってしまった。
特に、inferencModel.py で、
model = keras.models.load_model(configs.model_path+'/a.model.keras',safe_mode=False)
でロードして、predict を実行すると、
input = layers.Lambda(lambda x: tf.expand_dims(x, axis=-1), output_shape=(input_dim[0], input_dim[1],1),dtype=tf.float32)(inputs)
で、tf. が undefined になって困った。
結局、
keras.ops.expand_dims(x, axis)
で書き換えることにした。

model.py

これで、Keras Saved model で、 predict がやっとできるようになったぞね。

2. CudnnRNNV3 が、ディフォルトで使われるので、GPU 対応にならざるを得ないし、ONNX に変換できない件。
model.py

じょうきで、keras.layers.LSTM が使われていて、ディフォルトで、GPU が有効だと、CudnnRNNV3 が使われるのが問題みたい。
LSTM layer
のオプションで、していできるみたい。

use_cudnn=False でできるのか?


けっかは、まだ同じじゃ。
原因が、解った。
上記の場合、layers.Bidirectional() が、1回のオペレーションで、layers.LSTM() を3回コールするが、その際に、
use_cudnn=False になるのが、最初の1 回のみみたい。

use_cudnn=False <-- 1回目、OK
use_cudnn=auto <-- 2回目、NG
use_cudnn=auto <-- 3回目、NG

今の所の対策は、~/kivy_env/lib/python3.10/site-packages/keras/src/layers/rnn/lstm.py
の パラメータの初期値をいじるしかない。

後、Model.compile() のオプションで、jit_compile=False を追加する。


これで、CudnnRNNV3 を組み込まずに train.py を実行できると思うが、やはり、結構遅い。
下の、方法よりは、速いかもしれない。
学習精度は、CudnnRNNV3 を使うときより、結構落ちる。トレードオフになる。
もし、ONNX が使えれば、Orange Pi 5 で、こちらを使えそうだが、現状、
ONNX のロードでエラーになる。
今は、Transformer 版で、学習データを増やして、精度が上がれば、Transformer 版が、ONNX で使える分、有効かもしれない。

TensorFlowでGPU学習させるためにCUDA周りではまったときの対処法
を参考に、cudnn を不可にしてみる。
$ export CUDA_VISIBLE_DEVICES=-1
$ python train.py
これは、めちゃくちゃ時間がかかるが、しかたがないか!!
これは、OK ぞね。

3) ONNX への変換 と実行。
上記方法で、CudnnRNNV3 を使わなければ、ONNX への変換ができるが、
これを、onnxruntime からロードしようとすると、エラーがでて、さきに進まない。
いまは、ここまでか!!

ONNX のロードエラー時は、
下記コードでチェックできるみたいじゃ。
  onnx_model = onnx.load("a.model.onnx")
  onnx.checker.check_model(onnx_model)

4) tensorflow-onnx / support_status.md を見ていると、CudnnRNN はあるみたい。ないのは、CudnnRNNV3 のようだ。
/home/nishi/kivy_env/lib/python3.10/site-packages/keras/src/backend/tensorflow/rnn.py のなかで、
outputs, h, _, _, _ = tf.raw_ops.CudnnRNNV3() を使っている所為みたいだ。
outputs, h, _, _, _ = tf.raw_ops.CudnnRNN() にかえれれば、よいのだろうが、パラメータがかなり違うからむりか?
tf.raw_ops.CudnnRNNV3
tf.raw_ops.CudnnRNN
Keras 3 の問題か。
でもやっぱり、ONNX が未対応なのがもんだいか。

Example of converting TensorFlow model with custom op to ONNX を参考に、自分で、custom_op をつくらないといけないみたい。

5) 別の方法を見つけた。
i) python train.py は、CudnnRNNV3 版で、学習させる。
ii) test-model-freeze.py を実行させるときに、
LOAD_3=True で、 use Keras saved model を使うが、
その前に、
$ export CUDA_VISIBLE_DEVICES=-1
を叩いて、cudnn を禁止にする。
$ python test-model-freeze.py
で、Keras saved model から、 a.model_frozen.pb に変換する。
これで、CudnnRNNV3 を使わない、a.model_frozen.pb ができる。
一応、上記 a.model_frozen.pb を、 Tensorflow 2.16 CPP library and C++ (cpu版) プログラムで試したが、OK でした。
最後に、tf2onnx.convertを行う。

$ python -m tf2onnx.convert --input ./Models/test_opp/a.model_frozen.pb --output a.model.onnx --outputs Identity:0 --inputs x:0

これで、 ONNX model に変換はできる。
この場合は、CudnnRNNV3 は、入ってこないみたい。
しかし、 ONNX model のロードは、エラーになる。
下記コードで、原因がわかる。
onnx_model = onnx.load("a.model.onnx")
onnx.checker.check_model(onnx_model)


今度は、TensorArrayV2 が未対応みたいだ。

6) tflite への変換を試す。
tf.lite.TFLiteConverter の使い方に関して、新しい知見を得たので、それで、再度 tflite への変換をためしてみた。
今回は、うまく行った。
google で検索すると、
AssertionError when Saving Model as SavedModel Format with image augmentation layers #19100 に下記、記述を見つけた。


Migrating Keras 2 code to multi-backend Keras 3


下記コードで、できたみたい。
ただし、CudnnRNNV3 は、未対応なので、 train.py する時に、CudnnRNNV3が入らないようにする必要がある。
その方法は、後で書くぞね。
test-convert2tflite.py


7) tf-lite 変換で、もっと良い方法があった。
Keras saved model を使うと簡単だった。
この方法の手順は、
i) trainning を GPU モードで行う。こうすると、lstm で、cudnnRNNV3 が入ってくる。
しかし、cudnn を使ったほうが、学習が、早いし、精度もよい。
ii) model freez あるいは、tf-lite 変換の時に、
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
あるいは、
$ export CUDA_VISIBLE_DEVICES=-1
にして、cudnn を無効にして実行すれば、cudnnRNNV3 を取り除ける。
具体的には、
test-model-freeze.pytest-convert2tflite.py を、
LOAD_3=True のときの処理をみとうせ。

注) Keras saved model と、 Tensorflow saved model の違いみたい。
Keras saved model は、saved model の中には、class のシンボルが入っているだけで、load する時に、class 本体を、外部から取り込んでいるように思う。
方や、Tensorflow seaved model は、saved model の中に 保存時の class のインスタンスがすべて保存されていいて、
load するときは、外部から取り込んだりしない様に思う。

9. 総括。
Keras saved model を使えば、with cudnn で学習ができて、model freeze 、tf-lite 変換は、 without cudnnRNNV3 ができる。
なので、Orange pi 5 では、c++ tensorflow with cpu、c++ tf-lite で、実現できそうぞね。
ただ、もう少し、学習データを増やして、精度を上げないといかん。
やれやれ、やっと方針がまとまった。by nishi 2024.12.8

10. 参照。
モデルのフリーズ。
1) 具象関数の生成
2) How to freeze graph in TensorFlow 2.X

下記は、最初に目を通したほうがよかった。
Migrating Keras 2 code to multi-backend Keras 3

このブログ記事について

このページは、おんちゃんが2024年11月 7日 12:41に書いたブログ記事です。

ひとつ前のブログ記事は「ROS2 自作 Turtlebot3 による 草刈りロボット開発。#8 Transformer で経路計画をする。」です。

次のブログ記事は「TensorFlow 2.16.2 C++ library build」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

カテゴリ

ウェブページ

サイトナビ