busyoucow が 2022年09月26日04時32分20秒 に編集
初版
タイトルの変更
NumTone
タグの変更
SPRESENSE
NeuralNetworkConsol
カメラボード
メイン画像の変更
記事種類の変更
製作品
ライセンスの変更
(CC BY 4+) Creative Commons Attribution CC BY version 4.0 or later
本文の変更
NumTone ~とりあえずAI使ってみよう!~ spresense、かっこいいですよね。 マイコンボード上で動くAI(エッジAI)を使って何かしたい! そう思って使い方調べてみても、動画見ているだけで頭がクラクラ… そう感じている人は、少なくないはずです! ちょいとお試しで、手っ取り早く何か作ってみよう! そんな人のための記事です。 AIを使って、演奏してみましょう! 必要なもの - spresenseメイン基板 - spresenseカメラボード - spresense拡張ボード(公式) - googleアカウント か Sony ID - 小さめのスピーカ(開発中はヘッドフォンの方がよい) - i5第四世代以上のCPUを搭載したWindowsパソコン(GPUがついているとよい) - 日本国内にてインターネットが使える環境 - MicroUSB to USBケーブル - MicroSDメモリーカード(4Gバイト以上を推奨) - メモ用紙10枚と筆記用具 それでは作ってみましょう! 〇spresenseを組み立て、カメラボードと拡張ボードがちゃんと接続されているか確認する まず、こちらを参考にしてArduinoIDEをインストールしてspresense用の開発環境を整えます LEDを光らせるところまで行ってください https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html スピーカかヘッドフォンも接続してしまいましょう  次にこちらを参考にしてMicroUSBケーブルをメインボードに接続し、拡張ボードが実際に接続されているか動作確認をします リチウムポリマーバッテリーのところは行わなくてよいです https://deviceplus.jp/mc-general/spresense-02/ 更にカメラボードが実際に接続されているか動作確認をします。 ボタンを押して操作する以降のところは行わなくてよいです https://deviceplus.jp/mc-general/spresense-05/ ここまできて何故、動作確認を行うのか疑問に思う方も多いと思います 他のマイコン入門デバイスと違って、spresennseはメインボードに何か接続した際きちんと繋がった感が薄いのです 差し込んでも接続されていないケースが多いため、手っ取り早く動作するもので確認をしないと 動作しなかった際何処に不具合があるのかわからなくなることが多いのです 面倒くさがらず、一歩一歩確認しながら行ってください 〇NeuralNetworkConsolを「インストール」する ここからNeuralNetworkConsol Windows版(アプリ)をダウンロードしてインストールしてください https://dl.sony.com/ja/app/ インストール方法はこちらを参考にしてください https://www.mgo-tec.com/blog-entry-nnc-introduction.html インストールにはGoogleアカウントかSony IDが必要ですが、日本国内であれば2022年9月現在無料で使えます クラウド版は従量課金であり無料枠が少ないため、試しに使う用途には推奨しません Windows版(アプリ)はインストールしたパソコン自体で機械学習を行い学習済みモデルを作成します 機械学習には比較的マシンパワーを必要とするため、できればGPUを搭載したパソコンで行うことを推奨します ゲーミングPCなどがお勧めです。ビジネス向けパソコンでも動作はしますが時間がかかります 学習済みモデルを一度作成すれば、あとはそれをspresenseに組み込んで単体にて動作します 〇サンプルプロジェクトで学習済みモデルファイルを生成する ここの手書き文字MNISTデータセットをダウンロードする以降を行ってください https://www.mgo-tec.com/blog-entry-nnc-introduction.html もしくは、ここからtutorial.image_classification.digitsをダウンロードし NeuralNetworkConsole Windows版でダウンロードしたファイルdigits.sdcprojをプロジェクトで開くで開いてください https://dl.sony.com/ja/project/ この場合、次の画面になります  digits.sdcprojをクリックすると、次の画面になります  右上のデータセットをクリックします  左のTrainingをクリックし、右上のデータセットから下のアイコンをクリックするとデータセットを開くことができます  右に一覧が出るのでmnist_training.csvをクリックします。  この画面が出るとトレーニング用のデータセットをセットされます 次にValidationをクリックします  右に一覧が出るのでmnist_test.csvをクリックします 左上の学習をクリックして右上の学習を確認して実行をクリックすると、機械学習が始まります ここは結構時間がかかり、RTX2060というGPUを使用して20分弱でした  終了したら、右上の評価を確認して実行をクリックします  終了したら、左上の結果を右クリックして、エクスポート→NNBを選択します  model.nnbという学習済みファイルが生成されるので、これをnumtone.nnbにリネームして MicroSDカードにコピーし、spresense拡張ボードに差し込みます。  〇spresense上で動作させる こちらのコードをspresense上にて実行してください ```arduino:Numtone本体 #include <Camera.h> #include <SPI.h> #include <EEPROM.h> #include <SDHCI.h> #include <NetPBM.h> #include <DNNRT.h> #include <Audio.h> AudioClass *theAudio; SDClass SD; #define DNN_IMG_W 28 #define DNN_IMG_H 28 #define CAM_IMG_W 320 #define CAM_IMG_H 240 #define CAM_CLIP_X 104 #define CAM_CLIP_Y 0 #define CAM_CLIP_W 112 #define CAM_CLIP_H 224 int data[10] = {0,262,294,330,349,392,440,494,523,552}; int count = 1; uint8_t buf[DNN_IMG_W*DNN_IMG_H]; DNNRT dnnrt; DNNVariable input(DNN_IMG_W*DNN_IMG_H); static uint8_t const label[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; void CamCB(CamImage img) { if (!img.isAvailable()) { Serial.println("Image is not available. Try again"); return; } CamImage small; CamErr err = img.clipAndResizeImageByHW(small , CAM_CLIP_X, CAM_CLIP_Y , CAM_CLIP_X + CAM_CLIP_W -1 , CAM_CLIP_Y + CAM_CLIP_H -1 , DNN_IMG_W, DNN_IMG_H); if (!small.isAvailable()){ putStringOnLcd("Clip and Reize Error:" + String(err), ILI9341_RED); return; } small.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565); uint16_t* tmp = (uint16_t*)small.getImgBuff(); float *dnnbuf = input.data(); float f_max = 0.0; for (int n = 0; n < DNN_IMG_H*DNN_IMG_W; ++n) { dnnbuf[n] = (float)((tmp[n] & 0x07E0) >> 5); if (dnnbuf[n] > f_max) f_max = dnnbuf[n]; } for (int n = 0; n < DNN_IMG_W*DNN_IMG_H; ++n) { dnnbuf[n] /= f_max; } String gStrResult = "?"; dnnrt.inputVariable(input, 0); dnnrt.forward(); DNNVariable output = dnnrt.outputVariable(0); int index = output.maxIndex(); if (index < 10) { gStrResult = String(label[index]) + String(":") + String(output[index]); } else { gStrResult = String("?:") + String(output[index]); } Serial.println(gStrResult); img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565); uint16_t* imgBuf = (uint16_t*)img.getImgBuff(); } void setup() { Serial.begin(115200); //while (!Serial) { // ; // wait for serial port to connect. Needed for native USB port only //} theSD.begin(); theAudio = AudioClass::getInstance(); theAudio->begin(); puts("initialization Audio Library"); theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP, 0, 0); File nnbfile = SD.open("numtone.nnb"); if (!nnbfile) { Serial.print("nnb not found"); return; } int ret = dnnrt.begin(nnbfile); if (ret < 0) { Serial.println("Runtime initialization failure."); if (ret == -16) { Serial.print("Please install bootloader!"); Serial.println(" or consider memory configuration!"); } else { Serial.println(ret); } return; } theCamera.begin(); theCamera.startStreaming(true, CamCB); //dnnrt.inputVariable(input, 0); //dnnrt.forward(); } void loop() { puts("loop!!"); DNNVariable output = dnnrt.outputVariable(0); int index = output.maxIndex(); //theAudio->setBeep(1,-40,262); theAudio->setBeep(1,-40,data[index]); usleep(500 * 1000); theAudio->setBeep(0,0,0); usleep(100000); } ``` メモ用紙に0~9までの数字を大きめに書いて、カメラに見せると数字によって音階が鳴ると思います 数字を入れ替えることによって演奏?できるので、これはもう新しい楽器!? 独立して動作するので、パソコンからMicroUSBケーブルを外しモバイルバッテリーに付け替えても楽しめます 〇最後に 今回はSonyより提供されているデータセットを使用して学習モデルを生成しました しかし、これで満足できない方も多いと思います ハンドサインで演奏したり、人の顔で演奏したり? その思いが、機械学習を本格的に学習するきっかけになれば幸いです spresenseに関してSonyより提供された様々なドキュメント、および有志の方々の記事を「大いに」参考にさせていただきました この場を借りてお礼申し上げます