Translate

ラベル TensorFlow の投稿を表示しています。 すべての投稿を表示
ラベル TensorFlow の投稿を表示しています。 すべての投稿を表示

2022年12月2日金曜日

Raspberry PiにUSBマイクをつけて音声異常検知をためす



 数年前からやっている Donkeycarを使った自律走行カーですが、もうすこし機能を拡張しようかなと、音声で相手の接近を検知できないかを試してみました。

音声を考えたのは現在使っている Donkeycar のカメラが前にしか向いていないので、後方からの追い抜きをブロックしたらウケるおもしろいのではないか..というのが最初の動機です。

とりあえずはいきなりDonkeycarに実装しないで、単体のRaspberry Piにマイクをつけて試してみました。

なお、今回紹介する内容の Python コードは以下のGitHubリポジトリにおいてあります。
 


環境構築

Raspberry Pi は4B/8GB を使用してます。
 

近年すっかり手に入りにくくなったRaspberry Pi、一瞬去年作った スパコンもどきで使用していたRaspberry Piを使おいかと思ったのですが、たまたまスイッチサイエンスで1箱買うことができたので、壊さずにすみました..


Raspberry Pi OSは当時最新(今でもかな) Bullseye 64bitを使っています。

今回使用したのは Amazonでみつけてきたこの安いUSBマイク。選択の理由は、自分の車体はちょうど後方にRaspberry PiのUSBコネクタが向いているので、この小ささならアクセサリのじゃまにならず欲しい方向に設置できるからです。



 

必要なライブラリのインストール


DonkeycarはそもそもPythonベースで、Donkeycarのフレームワーク上に組み込むにはPythonでPartクラスを作成することになります。

sudo apt-get install -y build-essential python3 python3-dev python3-pip python3-virtualenv python3-numpy python3-pandas python3-pillow


Donkeycar アプリケーションはvirtualenv環境下で作成するので、実際には環境を作ってその中でライブラリをセットアップしました。

また音声異常検知にはRaspberry Pi用のTensorFlow 2.8.0を使っています。whlファイルは こちら からダウンロードしました。


:
sudo apt-get install -y libhdf5-dev libc-ares-dev libeigen3-dev gcc gfortran libgfortran5 libatlas3-base libatlas-base-dev libopenblas-dev libopenblas-base libblas-dev liblapack-dev git cython3 openmpi-bin libopenmpi-dev
:
pip install keras_applications==1.0.8 --no-deps
pip install keras_preprocessing==1.1.0 --no-deps
pip install numpy==1.22.1 -U
pip install h5py==3.6.0
pip install pybind11
pip install python_speech_features
pip install six wheel mock -U
pip install sklearn
:
wget "https://raw.githubusercontent.com/PINTO0309/Tensorflow-bin/main/previous_versions/download_tensorflow-2.8.0-cp39-none-linux_aarch64_numpy1221.sh"
chmod +x ./download_tensorflow-2.8.0-cp39-none-linux_aarch64_numpy1221.sh
./download_tensorflow-2.8.0-cp39-none-linux_aarch64_numpy1221.sh
pip install tensorflow-2.8.0-cp39-none-linux_aarch64.whl
:


Pythonからこのマイクを操作できないと意味がありません。マイクから音声データを取得するPythonライブラリは PyAudio を使いました。

PyAudioは内部でPortAudioを使用しているので、こちらもインストールします。

sudo apt-get install -y libportaudio2 libportaudiocpp0 portaudio19-dev

USBマイクの検出


PyAudioからUSBマイクを操作するには、まず搭載したUSBマウスのインデックス番号を知らないといけません。

USBマウスを挿した状態で、以下のプログラムを実行して表示内容からUSBマイクの番号をメモします。

import pyaudio
audio = pyaudio.PyAudio()
for i in range(audio.get_device_count()):
    print(audio.get_device_info_by_index(i))



先のUSBマイクではありませんが、Sound Blasterを指した状態だと次のような表示がでてきます。

aultHighOutputLatency': 0.034829931972789115, 'defaultSampleRate': 44100.0}
{'index': 1, 'structVersion': 2, 'name': 'Sound Blaster Play! 3: USB Audio (hw:1,0)', 'hostApi': 0, 'maxInputChannels': 2, 'maxOutputChannels': 2, 'defaultLowInputLatency': 0.008684807256235827, 'defaultLowOutputLatency': 0.008684807256235827, 'defaultHighInputLatency': 0.034829931972789115, 'defaultHighOutputLatency': 0.034829931972789115, 'defaultSampleRate': 44100.0}
:

上記の表示ならインデックス番号は `1` であることがわかります。

## 録音

まず、対象音源を録音する必要がありますが、今回はwav形式で音声データを取得しました。

定期的にwavファイルを所定のディレクトリに保管するプログラムを別プロセスで実行しておき、音声異常検知は別のプロセスが保管先の最新音声ファイルを使って判断するしくみでつくりました。


import wave
import pyaudio
:
# 配列frames データをwavファイルにして保存
wavefile = wave.open('test_10.wav','wb')
wavefile.setnchannels(1) # チャネル:1
wavefile.setsampwidth(audio.get_sample_size(pyaudio.paInt16)) # ビットレート:int16ビット
wavefile.setframerate(44100) # サンプリングレート:44100kHz



チャネルの`1`はモノラルです。ステレオにするには`2`とします。
サンプリングレートはCDと同等の音質とものの本にはかかれている 44100 kHz にしています。
ビットレートは、wavファイルに格納される要素1つのサイズですが今回はint16ビットを使用しています(参考にしたコードもこの値だったので..)。


# PyAudio インスタンス化
audio = pyaudio.PyAudio()

# 引数情報に従って、PyAudio ストリーム生成
stream = audio.open(
    format=pyaudio.paInt16, # ビットレート:int16ビット,
    rate = 44100,           # サンプリングレート:44100kHz
    channels = 1,           # チャネル:1
    input_device_index = 1, # デバイスインデックス番号:1 ← 検出した数字
    input = True,
    frames_per_buffer=4096) # チャンク:4096

# 録音秒数
record_secs = 10

# 指定秒数の音声をchunkサイズごとに取得し、配列framesへ追加
max_count = int((44100 / 4096) * record_secs)
for i in range(0, max_count):
    frames = []
    # IOError対策 exception_on_overflow=False
    frames.append(stream.read(chunk, exception_on_overflow=False))
    wavefile.writeframes(b''.join(frames))
    if i != 0 and i % 100 == 0 and debug:
        print(f'wrote {i}/{max_count} frame(s).')

# ストリームの停止およびクロース
stream.stop_stream()
stream.close()
# PyAudioインスタンスの停止
audio.terminate()


上記コードでは10秒の音声を録音しています。

長時間録音するとIOErrorがたまに出てとまるので無視して続けるように`exception_on_overflow=False`を指定しています。
 

音声異常検知


音声異常検知は、古くから研究されている領域です。なので方法もある程度先人の方が考えてくれています。

特徴抽出


まず、音声データを音響特徴量というデータに加工します。
これにより巨大な音声データを検出したい特徴をなるべくそこなわないようにかつある程度操作しやすいサイズにしています。

以下の表は日本音響学会の学会誌より一部引用したものです。




検知したい対象に合わせて音響特徴量のアルゴリズムを変えています。今回はログフィルタバンクを使用しました。


フィルタバンクというのは音響学ではよく使われる用語で、元の音声にフィルタバンク行列のドット積をとり特徴を損なわないように次元を下げる方法です。
 

上表のようにさまざまな特徴量があるります。人の感性に近い音響特徴量を得たいという方はメルフィルタバンクをよくつかうそうですが、今回は`python_speech_features`の`logfbank`を使用しました。

from python_speech_features import logfbank
:
(rate,sig) = wav.read(eval_path)
input_data = logfbank(sig,44100,winlen=0.01,nfilt=20)


分類器


音響特徴量をもとに正常か異常かを判定する機能です。
むかしはOCSVNなどの数理最適化で使用されたアルゴリズムを使用していましたが、最近は機械学習モデルを使うようになってきました。

なので、音響特徴量でごりごりにサイズを落とすことはしなくて良くなっているそうです。

今回は全結合4層で真ん中で半分の次元に落としている簡単なエンコーダデコーダ型のモデルを使いました。



このモデルは入力データと出力データが同じ形式で、入力データをそのまま復元するように学習させます。


なのでモデルの真ん中で絞らないとすぐに収束してしまいます。
ですが個のモデルでは真ん中で半分のサイズになるので、情報損失が必ず発生して完全にもとには戻せません。
なので他のモデル同様トレーニング時間は長くはないですが短くないです(私のPCだと10秒データで5~10分くらい)。

このモデルのメリットは、トレーニング用の学習データとして異常音声データをわざわざ収集しなくても良いところです。


工場とかの実際にシビアに使用される現場だと異常音を録音する機会はなかなかめぐってこないとおもいます。
先人の方々はよく考えておられます。
 

ちなみに 評価、テストのためには異常音声データは必要です。 むしろ正常動作ではないことを教えていない以上、すべての異常ケースの音声が必要になってきます。

IT企業のソリューションとして音声異常検知を掲げているところで、正常音声だけでできますとうたっている会社も一部ありますが、個人的にはそういう会社は信用しないほうがいいと思います。

モデルの実装はTensorFlow.. というかほぼ keras ですね。

from keras.layers import Dense, BatchNormalization, Activation
from keras.models import Sequential, load_model
:
input_size = 20
:
model = Sequential()
model.add(Dense(input_size,input_shape=(input_size,)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dense(int(input_size/2)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dense(input_size))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dense(input_size))
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()

損失関数

損失関数はどうするかというと、入力データとモデル出力データの距離(平均二乗誤差)をとります。
距離が0に近い、つまり入力データとほぼ同じ音響特徴量である、ということです。

算出された距離にしきい値を設けて、その値より小さい場合は「正常」、そうでない場合は「異常」と判断させます。

今回は`sklearn.metrics`の`mean_squared_error`を使用しています。

from sklearn.metrics import mean_squared_error
:
# 異常判定スコア計算
score = mean_squared_error(input_data, output_data)

 

学習データ


今回学習データとして10秒間の音声データ(wav形式)を使用しています。

wavファイルならどこで取ったものでもトレーニング用のデータとして使えますが、本番と同じ環境で収集したものが望ましいのはいうまでもありません。
 

評価データ

学習データは10秒だったのですが、評価は2秒データにしています。

Donkeycarはデフォルトで1秒間に20回ループが回るようになっています。なので音声データを2秒間取り続けるわけには行きません。なので別プロセスで音声を収集していて、Donkeycarアプリ側は最新の2秒データを評価しています。

なのでループの40回くらいは同じ音声データの結果で判断してしまいます。このあたりはしきい値を緩めて早めに検知するようにして対応することになりますね。
 

テスト


Donkeycarに実装せずにテストしたかったので、タミヤの高速・低速ギア変更可能な2輪駆動バギーをつかってテストしました。

定期的に録音した音声の異常検知スコアをFlaskでグラフ化するWebアプリを別途動かしておき、バギーを近づけたり遠ざけたりしてみました。
 

単独バギーの接近検知




バギーのギア変速検知(高速→低速)




チューニングの違うバギーを聞き分け




二輪駆動四輪駆動の聞き分け


 

上記いずれの動画では、どれも判別できている様子がわかるとおもいます。

..が、実は上記のモデルのうち「二輪駆動四輪駆動の聞き分け」で使用した分類器以外の3つのユースケースの学習データは、何も動いていない状態で録音した無音声データを使っています。

だからわざわざ機械学習モデルなんぞつかわなくてもwavファイルをそのまま評価するだけで、無音→音ありはすぐに判別できるのです。

音声異常検知モデルは、デモ検証ではいい成績を残すことが多いですが、実際の現場のデータの場合はそうはいきません。
Donkeycarレースであっても、参加者が徐々に増えるなど現場の環境音が常時変化する場合はそのたび学習し直すことになります。

現場に合わせて音響特徴量を磨く作業が必要になります。
結論を言うと、音声異常検知はDonkeycarレースのような常に環境音に変化のある場合は難しいのです。



 

超音波の送受信で距離をはかるセンサなども安く手に入るので、後方に向けて設置して於けばいいだけの話なのです。
(きちんと計測してませんが)そのほうがRaspberry Piのコンピュータリソースを食わないとおもいます。
 

【スイッチサイエンス】ベーシックモジュール用距離センサー







2022年1月12日水曜日

富岳上でTensorFlowサンプルを動かす



前記事

「富岳上に tkinter が使用可能な TensorFlow 2.2.0 をインストールする方法 」
https://fight-tsk.blogspot.com/2021/12/tkinter-tensorflow-220.html


では、TensorFlow2.2.0が動作する環境をPythonともども富士通提供のソースコードからコンパイルして構築した。

富士通提供の富岳でも動作する TensorFlow ソースコード(a64fxブランチ)
https://github.com/fujitsu/tensorflow/tree/fujitsu_v2.2.0_for_a64fx



では、ビルドした環境が正常に動作するのかを確認するにはどうすればいいか。

そのために(?)提供されているのが fcc_build_script/sample_script にあるサンプルコード群である。



ここには

  • 01_resnet
  • 02_OpenMNT
  • 03_Bert
  • 04_Mask-R-CNN

の4つのサンプルコードが用意されている。

これらのディレクトリ内にはバッチスクリプトが提供されており、順番に富岳の計算ノード上で動かせば実行できる


..と思ったのだが、なかなか動作しない。

ここでは、2022/1/12時点の環境で実行するために修正をいれた内容を紹介する。


全体共通


env.src の編集


サンプルコードのスクリプトは基本的に fcc_build_script/env.src を使用する。
このため、env.srcが富岳の環境に合致するように環境変数を変更しておく必要がある。

以下、前記事でも書いた2022/1/12時点で動作した修正箇所である。

PREFIX=${HOME}/.local/aarch64
TCSDS_PATH=/opt/FJSVxtclanga/tcsds-1.2.33
VENV_PATH=${HOME}/.local/aarch64/venv/tensorflow
PREFIXやVENV_PATHは各自のホームディレクトリの使い方で異なるので、それぞれに合わせて変更しておく。

01_resnet

10_setup_resnet.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "proc=1"
#PJM -S

11_train_resnet-single.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "proc=1"
#PJM -S
富岳のスレッドは8でそのうち0から3の4つは使用できないので、NUMA_NODEを修正する。
NUMA_NODE=4

12_train_resnet-4process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。
また、複数プロセスの実行となるのでmpiオプションなどが異なっていることに注意のこと。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S
#PJM -L "node=1:noncont"
#PJM --mpi "shape=1,proc=4"
#PJM -j

ステップジョブ実行

ログインノードで 01_resnet ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 10_setup_resnet.sh
pjsub --step --sparam "jid=XXXXXXX" 11_train_resnet-single.sh
pjsub --step --sparam "jid=XXXXXXX" 12_train_resnet-4process.sh

02_OpenNMT

20_setup_OpenNMT の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "proc=1"
#PJM -S

21_train_OpenNMT_Transformer-single.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -L "node=1"
#PJM -S
富岳のスレッドは8でそのうち0から3の4つは使用できないので、NUMA_NODEを修正する。
NUMA_NODE="4,5"

22_train_OpenNMT_Transformer-2process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "shape=1,proc=2"
#PJM -S
環境変数MPIには、並列プログラム実行プレフィックスが格納されている。
デフォルトではなぜか富岳上のmpirunではサポートされていないオプション --display-map 、 --display-allocation 、 --map-by が付いているのでこれらを除去する。

  MPI="mpirun -np 2"

ステップジョブの実行

ログインノードで 02_OpenNMT ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 20_setup_OpenNMT.sh
pjsub --step --sparam "jid=XXXXX" 21_train_OpenNMT_Transformer-single.sh
pjsub --step --sparam "jid=XXXXX" 22_train_OpenNMT_Transformer-2process.sh

03_Bert

300_setup_bert.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

311_create_pretraining_data.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

312_run_pretraining.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

numactl のオプションは変更しなくても良い(使われていないので)。

313_run_pretraining-2process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "shape=1,proc=2"
#PJM --mpi "max-proc-per-node=4"
#PJM -S
環境変数MPIから富岳上のmpirunに実装されていないオプションを除去する。
MPI="mpirun -np 2"

321_create_finetuning.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

322_run_finetuning.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S
環境変数NUMAは使用されていないのでそのままでもよい。

323_run_finetuning-2process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "shape=1,proc=2"
#PJM --mpi "max-proc-per-node=4"
#PJM -S
環境変数MPIから富岳上のmpirunに実装されていないオプションを除去する。
MPI="mpirun -np 2"

ステップジョブの実行

ログインノードで 03_bert ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 300_setup_bert.sh
pjsub --step --sparam "jid=XXXXX" 311_create_pretraining_data.sh
pjsub --step --sparam "jid=XXXXX" 312_run_pretraining.sh
pjsub --step --sparam "jid=XXXXX" 313_run_pretraining-2process.sh
pjsub --step --sparam "jid=XXXXX" 321_create_finetuning.sh
pjsub --step --sparam "jid=XXXXX" 322_run_finetuning.sh
pjsub --step --sparam "jid=XXXXX" 323_run_finetuning-2process.sh

04_Mask-R-CNN

libxml2/libxsltのコンパイル

Mask R CNN のトレーニング処理を実行するためには、contextlib2 というPythonパッケージが必要になる。その前提としてlibxml2/libxsltライブラリが必要となるため、先にホームディレクトリ内でコンパイル・インストールする。
http://xmlsoft.org/downloads.html からlibxml2とlibxsltのソースコードをダウンロード
富岳上へソースをコピーし展開(以下では ${HOME}/.tmp 直下に2つとも展開し${HOME}/.local/aarch64へインストールする前提での記述となる)する。
 
cd ${HOME}/.tmp/libxml2
make clean
source ${PYTHONHOME}/bin/activate
./autogen.sh --prefix=${HOME}/.local/aarch64 --with-python-install-dir=${HOME}/.local/aarch64/venv/tensorflow
make
make install
cd ../libxslt
./autogen.sh --prefix=${HOME}/.local/aarch64 --with-python-install-dir=${HOME}/.local/aarch64/venv/tensorflow
make
make install

40_setup_mask-r-cnn.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

41-0_download_traindata.sh の編集

スクリプト先頭のPJMコメントを以下のように追加する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

41-1_setup_traindata.sh の編集

スクリプト先頭のPJMコメントを以下のように編集する。
なお rscunit は各自の環境に合わせて編集すること。 

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

42_train_maskrcnn_single.sh の編集

スクリプト先頭のPJMコメントを以下のように編集する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

43_train_maskrcnn_multi.sh の編集

スクリプト先頭のPJMコメントを以下のように編集する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -L "node=1:noncont"
#PJM --mpi "shape=1,proc=2"
#PJM -S
環境変数MPIRUNから富岳上のmpirunに実装されていないオプションを除去する。
MPIRUN="mpirun -np 2"

ステップジョブの実行

ログインノードで 04_Mask-R-CNN ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 40_setup_mask-r-cnn.sh
pjsub --step --sparam "jid=XXXXX" 41-0_download_traindata.sh
pjsub --step --sparam "jid=XXXXX" 41-1_setup_traindata.sh
pjsub --step --sparam "jid=XXXXX" 42_train_maskrcnn_single.sh
pjsub --step --sparam "jid=XXXXX" 43_train_maskrcnn_multi.sh

以上

2019年8月14日水曜日

Windows10上でRaspberry Pi Zero用Tensorflow Lite 静的ライブラリのコンパイル方法

Donkeycarのバージョンが3.1.0にあがってしまいました..
3.1.0の目玉はTensorRT対応とTensorflow Lite対応です。
TensorRTはGPUがそもそもないのでどうでもいいですがLiteのほうは..Zeroで自動走行にすると内部エラーで落ちる問題が解決できるかもしれない..ということでRaspberry Pi ZeroにTensorflow Liteをインストールしなくてはなりません。

でもそんなwheelファイル誰も公開していない..TawnさんにSlackできいても知らないとの答え..

しょうがないので公式ドキュメントに従ってコンパイルをすることになったわけです。

----

Tensorflow LiteドキュメントにはDockerコンテナ上でクロスコンパイルする手順がかかれていますが、あくまでarmv7l(3B/3B+)用であり、get started に whlファイルのダウンロード元URLがかかれているので、正直コンパイルするひつようがありません。

でもなぜかZero用のarmv6用は置かれていないので、自分でコンパイルするしかありません。

以下、手順を紹介しますが、すべての機能のテストをしていませんので、動かなくてもごめんなさい。
Tensorflow本体のビルドは40時間以上かかるというブログ記事情報もあったりしますが、ここに書かれている手順はLiteの静的ライブラリ作成だけなので、Lenovo T470で20分くらいだったとおもいます。

----

Docker Desktopのインストール

  • Windows10上にDocker Desktopをインストール
  • Docker Desktop>Settings>Shared Drives
  • Cドライブをシェア

クロスコンパイル環境コンテナの起動

  • コマンドプロンプトを管理者として起動
  • cd c:/Users/ユーザ名
  • mkdir tmp
  • docker run -it -v c:/Users/ユーザ名/tmp:/projects tensorflow/tensorflow:nightly-devel /bin/bash
(Proxy指定が必要な場合)
  • cat >> /etc/apt/apt.conf <
  • Acquire::http::Proxy "http://proxy.server:XXXX";
  • Acquire::https::Proxy "http://proxy.server:XXXX";
  • Ctrl+D


  • apt-get update
  • apt-get install crossbuild-essential-armhf vim

リポジトリのチェックアウト

(Proxy指定が必要な場合)
  • git config --global http.proxy http://peoxy.server:XXXX
  • git config --global https.proxy http://peoxy.server:XXXX

  • cd /projects
  • git clone https://github.com/tensorflow/tensorflow
  • cd tensorflow
  • git checkout master


Raspberry Pi Zero用設定に書き換え

  • vi vi tensorflow/lite/tools/make/targets/rpi_makefile.inc
  • 5行目:TARGET_ARCH := armv6 に変更
  • 38行目:-fPIC の末尾に \ 追加
  • 39行目:-marc 挿入
  • 46行目:-fPIC の末尾に \ 追加
  • 47行目:-marc 挿入
  • 53行目:-Wl,--as-needed の末尾に \ 追加
  • 54行目:-latomic 挿入

コンパイル実行

  • ./tensorflow/lite/tools/make/download_dependencies.sh
  • ./tensorflow/lite/tools/make/build_rpi_lib.sh
  • exit


静的ライブラリファイルのデプロイ

  • WinSCPなどを使って以下のファイルをRaspberry Pi Zero上の/usr/local/libなどにコピー
C:\Users\89004\tmp\tensorflow\tensorflow\lite\tools\make\gen\rpi_armv6\lib\libtensorflow-lite.a

------

..公式サイトにwheelファイルリンクがないのはもしかしたらZeroでは動作しないということなのかもしれないなあ..

そのあたりは自己責任でお願いします...



ps

WinSCP後の後始末

クロスコンパイル環境コンテナの削除

  • docker container ls -a でコンテナID先頭3文字を確認
  • docker container rm コンテナID先頭3文字


イメージの削除

  • docker image rm tensorflow/tensorflow:nightly-devel


作業ディレクトリの削除

  • cd c:/Users/ユーザ名
  • del /f tmp でY選択

2019年2月25日月曜日

ブログ記事「Lingvo: A TensorFlow Framework for Sequence Modeling for Sequence Modeling」を勝手に翻訳してみた

今朝のタイムラインに流れていたブログ記事 Lingvo: A TensorFlow Framework for Sequence Modeling for Sequence Modeling を勝手に翻訳したものです。

--------

Lingvo: シーケンスモデリングのための TensorFlow フレームワーク

  • 2019年2月23日
  • Jonathan Shen

Lingvo とは、 国際語エスペラント語 で「言語」を表します。Lingvo と命名したことは、まさにLingvoフレームワークのルーツを暗示しています - Lingvoは、機械翻訳、音声認識、そして音声合成のような言語関連タスクのためのシーケンスモデルに焦点を合わせてTensorFlowを使った一般的なディープラーニングフレームワークとして開発されました。
内部的には、Lingvoフレームワークは勢いを増し、Lingvoを使用している研究者の数はバルーンのように膨らんでいます。その結果、Lingvoを使用して作成された最先端の結果を含む出版済みの 論文 が今では多数あります。サポートされているアーキテクチャは、従来のRNNシーケンスモデルからTransformerモデルおよびVAEコンポーネントを含むモデルまで多岐にわたります。私たちの研究コミュニティの支持を示し、再現可能な研究努力を奨励するために、私たちはフレームワークをオープンソース化し、私たちの論文で使われているモデルを公開し始めています。

図1:Lingvoフレームワークの概要。評価と提供のためにモデルをインスタンス化、トレーニング、およびエクスポートする方法を概説しています。

Lingvo は共同研究を念頭に置いて構築されており、さまざまなタスクで共通のレイヤの実装を共有することでコードの再利用を促進しています。さらに、すべてのレイヤが同じ共通のインタフェースを実装し、同じ方法でレイアウトされています。これにより、よりクリーンでわかりやすいコードが生成されるだけでなく、他の人が別のタスクに対して行った改善を自分のタスクに適用することが非常に簡単になります。この一貫性を強化するには、より多くの規律 (dicipline) と共通語 (boilerplate) が必要になりますが、 Lingvo では、これを最小限に抑えて研究中の反復時間を短縮することを試みています。

コラボレーションのもう1つの側面は、再現可能な結果を共有することです。Lingvoは、チェックインモデルのハイパーパラメータ設定を集中管理する場所を提供します。これは重要な実験を文書化するのに役立つだけでなく、同一のモデルを訓練することによってあなたの結果を簡単に再現する方法を他の人に与えることになります。

def Task(cls):
  p = model.AsrModel.Params()
  p.name = 'librispeech'

  # encoder パラメータの初期化
  ep = p.encoder
  # データは240次元フレーム(80x3フレーム)で構成されており、
  # それらを個々に80次元フレームとして再解釈します。
  # 詳細は LibrispeechCommonAsrInputParams も参照のこと。
  ep.input_shape = [None, None, 80, 1]
  ep.lstm_cell_size = 1024
  ep.num_lstm_layers = 4
  ep.conv_filter_shapes = [(3, 3, 1, 32), (3, 3, 32, 32)]
  ep.conv_filter_strides = [(2, 2), (2, 2)]
  ep.cnn_tpl.params_init = py_utils.WeightInit.Gaussian(0.001)
  # Conv LSTM レイヤを無効化
  ep.num_conv_lstm_layers = 0

  # decoder パラメータの初期化
  dp = p.decoder
  dp.rnn_cell_dim = 1024
  dp.rnn_layers = 2
  dp.source_dim = 2048
  # unrolling ベースに基づく間、機能を使用する。
  dp.use_while_loop_based_unrolling = False

  tp = p.train
  tp.learning_rate = 2.5e-4
  tp.lr_schedule = lr_schedule.ContinuousLearningRateSchedule.Params().Set(
      start_step=50000, half_life_steps=100000, min=0.01)

  # Setting p.eval.samples_per_summary を大きな値に設定すると、
  # dev, devother, test, testother は完全に評価され(これらの各セットの
  # num_samplesは5000未満なので)、トレーニングサマリは5000サンプルで計算される
  p.eval.samples_per_summary = 5000
  p.eval.decoder_samples_per_summary = 0

  # オーバーフィットを防ぐために、可変重量ノイズを使用
  p.vn.global_vn = True
  p.train.vn_std = 0.075
  p.train.vn_start_step = 20000

  return p


Lingvo は NLP に焦点を当てることから始めましたが、それは本質的に非常に柔軟性があり、画像セグメンテーションや点群分類などのタスクのためのモデルはフレームワークを使ってうまく実装されています。Distillation、GAN、およびマルチタスクモデルもサポートされています。同時に、このフレームワークはスピードを犠牲にすることはなく、最適化された入力パイプラインと高速分散トレーニングを特徴としています。最後に、Lingvoはプロダクションの容易さを目指してまとめられており、モバイル推論のためのモデルの移植への明確な道筋さえあります。

コードに直接ジャンプするには、GitHubページ と codelab を調べてください。Lingvoまたはそれがサポートする高度な機能の詳細については、私たちの 論文 を参照してください。
-----

個々に乗ってるコードを読む限りでは、自然言語処理系DLは基本エンコーダデコーダで、それぞれのレイヤ群をあらわすオブジェクトにパラメータをセットするだけでモデル構築ができるフレームワークのようだ。

でもね..機械学習やディープラーニングで苦労するのはモデルよりもデータの口金(くちがね)にあわせることであって、特に日本語などの分かち書きから始めないとだめな言語はとっても面倒になるのよ..そのあたりをカバーするフレームワークが本当はほしいんだけどなあ..

 

Google Colab相当の環境をローカルPC上のDocker Composeで実現する

 Docker Composeの有料版に、お金を払いたくない ^H^Hが使えない ため古いゲーミングPC(GeForce3080)にDocker Composeを入れてその上のコンテナでGoogle Colab相当のノート操作ができないかためしてみた: コンテナイメージとして a...