2021/08/15

UnitVでも load_flashなら MobileNet V1 1000 class 動くね

maix_train は何とか動いたけれど結果が0,1しか出ないのはやはりつまらないです。
探してたら、MaxiPy_scripts に1000クラス分類できるやつあるじゃないですか。
この中の machine_vision/mobilenet_1000_class です。

ただ、ここには本体はなく説明だけです。目当てのkmodelは、説明にある通り https://dl.sipeed.com/MAIX/MaixPy/model に mobilenet_0x300000.kfpkg が入っているのでダウンロードします。

これをkflashで焼いて使うわけですが、でかいのでファームをminimunにして、GCヒープサイズも半分の256kbにしろとドキュメントには書いてあります。動くんでしょうけど、それは辛いです。。

そこで kpu.load()ではなく、kpu.load_flash()なら動くんじゃないかな?と試してみました。
ダウンロードした mobilenet_0x300000.kfpkg をただ焼いても動きません。
ここがポイントです!
load_flash()はメモリーにロードすることなくkpuが直接モデルのアドレスを見に来るようにするものらしいので、モデルデータをビッグエンディアンに変換しておく必要があります。

まずこのkfpkgをunzipで解凍します。すると flash-list.json と m.kmodel が得られます。
このm.kmodelをビッグエンディアンに変換します。
$ ../model_le2be.py m.kmodel
いきなり出てきたmodel_le2be.pyですが、MaixPy_scripts/machie_vision に入っているスクリプトです。これを実行すると m_be.kmodel が作成されます。

で、flash-list.jsonのbinをm_be.kmodelに書き換えて、zipしてkfpkgにしてkflashします。
手作業でこれを何度もやるのが辛かったので、簡単なfpkgツクールスクリプト kfpkg.py 書きました。
import sys
import json
import zipfile

MODEL_LOAD_ADDRESS = 0x300000
FLASH_LIST_JSON = '{"version":"0.1.0","files":[{"address":0,"bin":null,"sha256Prefix":false}]}'

def kfpkg(fname):
    f = json.loads(FLASH_LIST_JSON)
    f["files"][0]["address"] = MODEL_LOAD_ADDRESS
    f["files"][0]["bin"] = fname + ".kmodel"
    j = json.dumps(findent=2separators=(','': '))
    n = fname + ".kfpkg"
    print(n)
    with zipfile.ZipFile(n"w"compression=zipfile.ZIP_DEFLATEDas z:
        z.writestr("flash-list.json"j)
        z.write(f["files"][0]["bin"])

kfpkg(sys.argv[1])
$ python kfpkg.py m_be
一発で m_be.kfpkg を作ってくれます。そしたらこれを kflash します。
maixPyコードは以下のようなシンプルコード
import sensor
import KPU as kpu
import gc
gc.collect()

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224224))
sensor.set_hmirror(False)
sensor.set_vflip(False)
sensor.run(1)

model = kpu.load_flash(0x30000010x400060000000)

while(True):
    img = sensor.snapshot()
    fmap = kpu.forward(model, img)
    plist = fmap[:]
    pmax = max(plist)
    max_index = plist.index(pmax)
    print("%.2f : %d" % (pmax, max_index))

これでほぼ準備は整いました。

ファームは maixpy_v0.6.2_57_gae955b706_m5stickv.bin を使いました。フル機能ファームってことです。だめでした。メモリ不足エラーが出ました。そこで、
model = kpu.load_flash(0x30000010x400060000000)

model = kpu.load_flash(0x30000000x400060000000)
に変更

動きました!
今一度、load_flash()の確認 https://en.bbs.sipeed.com/t/topic/1811 によると
task=kpu.load_flash(model_addr, is_dual_buf(0/1), batch_size, spi_speed)
  1. model_addr: flash addr store your model, note, you need flip the model endian, use convert_le.py to convert normal model. and only support V3 model now.
  2. is_dual_buf: 0, single buf, use less ram and slower speed; 1, dual buf, more ram and faster speed.
  3. batch_size: when choose dual_buf, you need set load batch_size, suggestion value is 0x4000~0x10000, you can test out best value for your model.
  4. spi_speed: when use flash runner, we will temporary set flash to high speed mode, set the spi speed you want. the value should <= 80000000
内部バッファをシングルバッファにしてギリ入ったということですね。
ちなみにファームを minimum_with_ide_support.bin にすればダブルバッファでも動きました。
パフォーマンスの違いはちゃんと調べてないけれど、体感ではそんなに大きく変わらなかった。
これで、M5StickCと繋げればちょっと楽しくなるかな。

0 件のコメント:

コメントを投稿