【Silicon Labs 开发套件评测】使用tensorflow原型开发手势识别项目
[复制链接]
本帖最后由 北方 于 2021-9-10 16:41 编辑
1、首先需要引用一下资料来源
https://github.com/arduino/ArduinoTensorFlowLiteTutorials/
这个是arduino运用tensorflow的导则,后来看tensorflow也放弃了在lite上的工作,单独分出来tensorflow lite的子项目
https://github.com/tensorflow/tflite-micro
根据这两个资料可以进行掌握如何用这个工具开发
2、首先创建新的工程,感受gesture的智能工具。用原来的tensorflow范例为基准会更省事。
在新的包里安装六轴传感器,
这个是启动SPI接口读取数据的,后面的代码要根据这个API进行初始化,读取和解析。
可以登录网站获取,
https://docs.silabs.com/gecko-platform/3.2/hardware-driver/api/group-icm20648
3、tensorflow的原始数据
3.1 测试原始数据,根据arduino的数据读取如下图。那么这次读取的数据也要归一化到这样类似的数值范围,这样可以直接使用arduino范例库中的model。独自训练还是比较消耗时间的

3.2 然后从arduino的下载包中,找到model.h。经过baking的model数据格式都是一样的,但是如果不用tensorflow的工具,是不能直接编辑和解析这个文件的。
具体的数据格式如下
需要改成model.h,或者直接复制过来。
3.3 对于数据处理是用下面类直接实现
加载model是用下面的语句,在setup()初始化中完成
- model = tflite::GetModel(g_model);
HandleOutput()是自定义的事件处理句柄,可以直接在文件中查询。
3.4 按照上面的逻辑可以很快接用tensorflow的标准训练过程完成一个动态识别的移植,具体识别的手势可以参见上面的引用网址。不再解析。
4. 自定义和训练的方法流程
4.1 更多的情况下,大家还是希望自己训练程序和模型,那么还是建议基于上面的代码框架。
具体需要做的,首先是定义模型的输入数据数量和格式,然后是深度学习网络的结构,最后才是准备数据,开始训练。
4.2 准备数据
如上述采集六轴传感器的每次6组数据,读取数据如下

这组数据是把板子固定在手腕上,向左向右滑动,双击,旋转等任意自己希望定义的手势,至少重复10次,每次的数据都读出并保存在csv文件中,如- flex.csv.同时需要给每种手势一个数字编码。如1-10直接的自然数。
- 4.2 进入训练阶段,这个需要熟悉tensorflow的流程,这个过程在需要科学学习的免费colab上的notebook文件https://colab.research.google.com/github/arduino/ArduinoTensorFlowLiteTutorials/blob/master/GestureToEmoji/arduino_tinyml_workshop.ipynb
为了便于学习全程粘贴如下,很长,但是值得读一下
不过其中最重要的模型一共15行代码,做成隐藏模式,只能直接使用。不能 编辑。这个就需要粉一下百度了,百度的paddlepaddle也做了一个类似的免费网络人工智能训练平台,很烧钱的,大家今早去免费薅羊毛。现在谷歌已经不能免费提供大家这样的服务了,百度估计也坚持不了多久,大家尽早去。
- <a href="https://www.arduino.cc/"><img src="https://raw.githubusercontent.com/sandeepmistry/aimldevfest-workshop-2019/master/images/Arduino_logo_R_highquality.png" width=200/></a>
- # Tiny ML on Arduino
- ## Gesture recognition tutorial
- * Sandeep Mistry - Arduino
- * Don Coleman - Chariot Solutions
-
-
- https://github.com/arduino/ArduinoTensorFlowLiteTutorials/
-
-
-
- The next cell sets up the dependencies in required for the notebook, run it.
-
-
- !apt-get -qq install xxd
- !pip install pandas numpy matplotlib
- !pip install tensorflow==2.0.0-rc1
-
-
-
- 1. Open the panel on the left side of Colab by clicking on the __>__
- 1. Select the files tab
- 1. Drag `punch.csv` and `flex.csv` files from your computer to the tab to upload them into colab.
-
-
-
- We'll graph the input files on two separate graphs, acceleration and gyroscope, as each data set has different units and scale.
-
- import matplotlib.pyplot as plt
- import numpy as np
- import pandas as pd
-
- filename = "punch.csv"
-
- df = pd.read_csv("/content/" + filename)
-
- index = range(1, len(df['aX']) + 1)
-
- plt.rcParams["figure.figsize"] = (20,10)
-
- plt.plot(index, df['aX'], 'g.', label='x', linestyle='solid', marker=',')
- plt.plot(index, df['aY'], 'b.', label='y', linestyle='solid', marker=',')
- plt.plot(index, df['aZ'], 'r.', label='z', linestyle='solid', marker=',')
- plt.title("Acceleration")
- plt.xlabel("Sample #")
- plt.ylabel("Acceleration (G)")
- plt.legend()
- plt.show()
-
- plt.plot(index, df['gX'], 'g.', label='x', linestyle='solid', marker=',')
- plt.plot(index, df['gY'], 'b.', label='y', linestyle='solid', marker=',')
- plt.plot(index, df['gZ'], 'r.', label='z', linestyle='solid', marker=',')
- plt.title("Gyroscope")
- plt.xlabel("Sample #")
- plt.ylabel("Gyroscope (deg/sec)")
- plt.legend()
- plt.show()
-
-
- # Train Neural Network
-
-
-
-
-
- ## Parse and prepare the data
-
- The next cell parses the csv files and transforms them to a format that will be used to train the fully connected neural network.
-
- Update the `GESTURES` list with the gesture data you've collected in `.csv` format.
-
-
- import matplotlib.pyplot as plt
- import numpy as np
- import pandas as pd
- import tensorflow as tf
-
- print(f"TensorFlow version = {tf.__version__}\n")
-
-
-
- SEED = 1337
- np.random.seed(SEED)
- tf.random.set_seed(SEED)
-
-
- GESTURES = [
- "punch",
- "flex",
- ]
-
- SAMPLES_PER_GESTURE = 119
-
- NUM_GESTURES = len(GESTURES)
-
-
- ONE_HOT_ENCODED_GESTURES = np.eye(NUM_GESTURES)
-
- inputs = []
- outputs = []
-
-
- for gesture_index in range(NUM_GESTURES):
- gesture = GESTURES[gesture_index]
- print(f"Processing index {gesture_index} for gesture '{gesture}'.")
-
- output = ONE_HOT_ENCODED_GESTURES[gesture_index]
-
- df = pd.read_csv("/content/" + gesture + ".csv")
-
-
- num_recordings = int(df.shape[0] / SAMPLES_PER_GESTURE)
-
- print(f"\tThere are {num_recordings} recordings of the {gesture} gesture.")
-
- for i in range(num_recordings):
- tensor = []
- for j in range(SAMPLES_PER_GESTURE):
- index = i * SAMPLES_PER_GESTURE + j
-
-
-
- tensor += [
- (df['aX'][index] + 4) / 8,
- (df['aY'][index] + 4) / 8,
- (df['aZ'][index] + 4) / 8,
- (df['gX'][index] + 2000) / 4000,
- (df['gY'][index] + 2000) / 4000,
- (df['gZ'][index] + 2000) / 4000
- ]
-
- inputs.append(tensor)
- outputs.append(output)
-
-
- inputs = np.array(inputs)
- outputs = np.array(outputs)
-
- print("Data set parsing and preparation complete.")
-
-
-
- Randomly split input and output pairs into sets of data: 60% for training, 20% for validation, and 20% for testing.
-
- - the training set is used to train the model
- - the validation set is used to measure how well the model is performing during training
- - the testing set is used to test the model after training
-
-
-
- num_inputs = len(inputs)
- randomize = np.arange(num_inputs)
- np.random.shuffle(randomize)
-
-
- inputs = inputs[randomize]
- outputs = outputs[randomize]
-
-
- TRAIN_SPLIT = int(0.6 * num_inputs)
- TEST_SPLIT = int(0.2 * num_inputs + TRAIN_SPLIT)
-
- inputs_train, inputs_test, inputs_validate = np.split(inputs, [TRAIN_SPLIT, TEST_SPLIT])
- outputs_train, outputs_test, outputs_validate = np.split(outputs, [TRAIN_SPLIT, TEST_SPLIT])
-
- print("Data set randomization and splitting complete.")
-
-
-
- Build and train a [TensorFlow](https://www.tensorflow.org) model using the high-level [Keras](https://www.tensorflow.org/guide/keras) API.
-
-
- model = tf.keras.Sequential()
- model.add(tf.keras.layers.Dense(50, activation='relu'))
- model.add(tf.keras.layers.Dense(15, activation='relu'))
- model.add(tf.keras.layers.Dense(NUM_GESTURES, activation='softmax'))
- model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
- history = model.fit(inputs_train, outputs_train, epochs=600, batch_size=1, validation_data=(inputs_validate, outputs_validate))
-
-
-
-
-
- Graph the models performance vs validation.
-
-
-
-
- Graph the loss to see when the model stops improving.
-
-
- plt.rcParams["figure.figsize"] = (20,10)
-
-
- loss = history.history['loss']
- val_loss = history.history['val_loss']
- epochs = range(1, len(loss) + 1)
- plt.plot(epochs, loss, 'g.', label='Training loss')
- plt.plot(epochs, val_loss, 'b', label='Validation loss')
- plt.title('Training and validation loss')
- plt.xlabel('Epochs')
- plt.ylabel('Loss')
- plt.legend()
- plt.show()
-
- print(plt.rcParams["figure.figsize"])
-
-
-
- We'll graph the same data as the previous code cell, but start at index 100 so we can further zoom in once the model starts to converge.
-
- # graph the loss again skipping a bit of the start
- SKIP = 100
- plt.plot(epochs[SKIP:], loss[SKIP:], 'g.', label='Training loss')
- plt.plot(epochs[SKIP:], val_loss[SKIP:], 'b.', label='Validation loss')
- plt.title('Training and validation loss')
- plt.xlabel('Epochs')
- plt.ylabel('Loss')
- plt.legend()
- plt.show()
-
- ### Graph the mean absolute error
-
- [Mean absolute error](https://en.wikipedia.org/wiki/Mean_absolute_error) is another metric to judge the performance of the model.
-
-
-
- # graph of mean absolute error
- mae = history.history['mae']
- val_mae = history.history['val_mae']
- plt.plot(epochs[SKIP:], mae[SKIP:], 'g.', label='Training MAE')
- plt.plot(epochs[SKIP:], val_mae[SKIP:], 'b.', label='Validation MAE')
- plt.title('Training and validation mean absolute error')
- plt.xlabel('Epochs')
- plt.ylabel('MAE')
- plt.legend()
- plt.show()
-
-
- ### Run with Test Data
- Put our test data into the model and plot the predictions
-
-
- # use the model to predict the test inputs
- predictions = model.predict(inputs_test)
-
- # print the predictions and the expected ouputs
- print("predictions =\n", np.round(predictions, decimals=3))
- print("actual =\n", outputs_test)
-
- # Plot the predictions along with to the test data
- plt.clf()
- plt.title('Training data predicted vs actual values')
- plt.plot(inputs_test, outputs_test, 'b.', label='Actual')
- plt.plot(inputs_test, predictions, 'r.', label='Predicted')
- plt.show()
-
- # Convert the Trained Model to Tensor Flow Lite
-
- The next cell converts the model to TFlite format. The size in bytes of the model is also printed out.
-
- # Convert the model to the TensorFlow Lite format without quantization
- converter = tf.lite.TFLiteConverter.from_keras_model(model)
- tflite_model = converter.convert()
-
- # Save the model to disk
- open("gesture_model.tflite", "wb").write(tflite_model)
-
- import os
- basic_model_size = os.path.getsize("gesture_model.tflite")
- print("Model is %d bytes" % basic_model_size)
-
-
-
- ## Encode the Model in an Arduino Header File
-
- The next cell creates a constant byte array that contains the TFlite model. Import it as a tab with the sketch below.
-
- !echo "const unsigned char model[] = {" > /content/model.h
- !cat gesture_model.tflite | xxd -i >> /content/model.h
- !echo "};" >> /content/model.h
-
- import os
- model_h_size = os.path.getsize("model.h")
- print(f"Header file, model.h, is {model_h_size:,} bytes.")
- print("\nOpen the side panel (refresh if needed). Double click model.h to download the file.")
-
- # Classifying IMU Data
-
- Now it's time to switch back to the tutorial instructions and run our new model on the Arduino Nano 33 BLE Sense to classify the accelerometer and gyroscope data.
-
- 4.3 训练后的就生产了model.h文件,这样就可以如上一节一样来用自定义的模型实现自定义的手势。上面的代码就是一个用手势替代emojo键盘的方式。
- 需要注意的是,这个识别的准确率并不高,有识别错误的概率。一个是训练的数据不够多,另一个是经过压缩的模型有损失了很多的精度。不过用于非严格的方案,还是一个神奇的方法。
- 在arduino的范例里,还有一个简单的语音识别模型。这个模型,识别的是up,down等英语上下单词,可以用来控制小车。不过,普遍反映,这个模型的识别效果不那么好。
|