一、事有蹊跷
; U( K( j- m5 Q 接篇一,前面提到在使用cube.AI生成的c语言神经网络模型API调用时,输入数据数量是24,输出数据数量是4,但上文设想采集了三轴加速度传感器的x/y/z三个各数据,按Jogging(慢跑),Walking(走了)两种态势采集了两组数据.csv,那么在实际中应该是输入数据数量是3(x/y/x-value),输出数据数量是2(Jogging,Walking两种类别)。
' Q$ Y5 R* ~( ^. ?
6 V7 L+ I& o& C" A. Z 由于模型API是cube.AI基于训练输出的神经网络模型而生成的,想必应该是训练神经网络模型时参数设置问题,因此我们重新回顾HAR训练项目.- E) W+ L" V& B1 W( a: ~9 Q2 C
1 s3 u$ Q8 A- k. f
进入“STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR”目录,运行 python .\RunMe.py -h命令,查看参数设置指令帮助,可以看到--seqLength和--stepSize参数设置都和input有关,默认数值是24,就可以笃定在API中调用时,输入数据数量是24就来自于此。8 m0 ^6 w9 ?5 U# x
- PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR> python3 .\RunMe.py -h
8 E) r. x3 K0 [ - Using TensorFlow backend.
% H) d# x% [3 u3 y; N) F - usage: RunMe.py [-h] [--model MODEL] [--dataset DATASET] [--dataDir DATADIR]
; M# Q) A" c$ ?. q$ P! Z( A1 I* M2 V - [--seqLength SEQLENGTH] [--stepSize STEPSIZE] [-m MERGE]% r% I# j% F3 k; j
- [--preprocessing PREPROCESSING] [--trainSplit TRAINSPLIT]
) h; I; P: }# \+ ~ - [--validSplit VALIDSPLIT] [--epochs N] [--lr LR]
4 p! G- f5 ~* ^1 M% {) _ - [--decay DECAY] [--batchSize N] [--verbose N]
6 B" E9 _, s4 g: b2 P" h - [--nrSamplesPostValid NRSAMPLESPOSTVALID]
( Y* {: }: w! q3 C8 D/ O- l3 e l* l -
6 ^* ]; k: j. d1 a - Human Activity Recognition (HAR) in Keras with Tensorflow as backend on WISDM
. k1 J1 }2 V2 x8 {# r - and WISDM + self logged datasets
2 T0 X/ A- {- q4 m8 R. G - 8 B4 t7 _+ c6 Z# z# Y4 S4 F
- optional arguments:
5 _: S2 X7 l" }& R9 H: k F - -h, --help show this help message and exit( i+ E% K. C8 U* J0 r
- --model MODEL choose one of the two availavle choices, IGN or GMP, (4 x4 t+ F7 L7 B
- default = IGN )- w" X3 G& W, M
- --dataset DATASET choose a dataset to use out of two choices, WISDM or
8 q/ S# h4 u }( y! N9 g - AST, ( default = WISDM )
: Z: d! o9 y r - --dataDir DATADIR path to new data collected using STM32 IoT board
* ?6 x* F1 [- X) n/ Q/ n" M - recorded at 26Hz as sampling rate, (default = )
" r; A4 P" Y7 y0 l - --seqLength SEQLENGTH9 P$ }- k( L5 ]; x2 |# U' @9 n0 _
- input sequence lenght (default:24)8 |0 ^3 P$ V* L2 X, a+ `9 z
- --stepSize STEPSIZE step size while creating segments (default:24, equal2 B% D) n. c6 j; r" W5 |" G a
- to seqLen)
" B: r8 l( H4 [' M' I - -m MERGE, --merge MERGE/ l: @( |7 _: M0 N" B$ G
- if to merge activities (default: True)
/ h, v! C0 z: ]8 H - --preprocessing PREPROCESSING
( h1 [. f3 J; ^ - gravity rotation filter application (default = True)! Q; m( l7 j* f
- --trainSplit TRAINSPLIT( E6 A' f# S. W% B2 x
- train and test split (default = 0.6 (60 precent for( {2 ?6 x0 |4 S& [
- train and 40 precent for test))& U6 p6 V6 Q3 w Z- V4 l0 E
- --validSplit VALIDSPLIT# L$ n/ i/ |& m0 s7 @$ c. Q) ]
- train and validation data split (default = 0.7 (70
) f3 A \. y, C - percent for train and 30 precent for validation))! V2 \: h+ e7 U
- --epochs N number of total epochs to run (default: 20)6 q7 J6 ~5 v* x# b' s3 o; p( R* }
- --lr LR initial learning rate
! z3 ^# ^0 [/ K7 I - --decay DECAY decay in learning rate, (default = 1e-6)2 _7 W0 A1 o) Y$ B2 c" s# W8 U
- --batchSize N mini-batch size (default: 64)
8 l; |! d& U" F! H+ L' [# ` - --verbose N verbosity of training and test functions in keras, 0,
+ P. Y2 v$ |) K - 1, or 2. Verbosity mode. 0 = silent, 1 = progress bar,
9 T+ v5 S9 H3 n `0 [* I& e- O, Z - 2 = one line per epoch (default: 1)
0 ]9 e: `* ]. d/ }6 f, i - --nrSamplesPostValid NRSAMPLESPOSTVALID, a* ]9 O' w# ^- K7 h; i8 ]
- Number of samples to save from every class for post
9 @& L% P2 X+ U - training and CubeAI conversion validation. (default =
+ N% _1 G! S! s; W( @ - 2) i- s# m6 v9 W2 J: F: O
- PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR>
复制代码
/ z# s; e* h" H 而输出数据数量是4的原因追踪源码可以看到,来自于PrepareDataset.py(数据集预处理源文件),由于在参数--dataset默认设置是WISDM,因此分类输出即为'Jogging', 'Stationary', 'Stairs', 'Walking',即输出数据数量为4:
7 u: I, H) a i; h" [: @2 w
$ Y' `5 J9 s( S( j9 |+ e
8 E3 j+ c( t6 Q( C) r4 d. v
8 ?9 P! c" C# |) p9 W1 J/ H* ^7 z 下面来深入了解HAR(Human Activity Recognition,人类行为识别)案例为何会有这样的设置。
3 K4 F. y+ t' B- M3 J9 w) r
8 ]$ q" A# O( r7 c7 L: F* U( ~1 M二、HAR训练项目分析
1 O; A* B/ \& `2 r( o* ^- T 由于前文仅仅采集Jogging(慢跑),Walking(走了)两种态势数据,但通常Stationary(站立不动)态势更常见和默认姿态,因此本文按篇一方法再采集一组Stationary姿态日志数据。
# q6 a1 w5 r1 n8 \2 Y
! I( x2 p+ I6 Z, U
8 J' w$ [% j) e
: h, n5 F1 I3 D0 P% K& d9 W% ]
并同样拷贝到HAR/Log_data目录下,数据如下:7 e0 F; N$ H( y7 h" V" ]
( c" C' _9 q; v& ?+ \
+ I+ `6 {* i( m! F i$ f' m9 D
1 W) S+ a2 Y/ k, G* x
在PrepareDataset.py文件中,read_dataset( self )和preprocess_data( self, data )是用来处理WISDM数据集的,而get_data_from_file( self, fileName, preparedDataFileName )和prepare_self_logged_data( self )函数是用来处理自行采集数据集的。
# H! R4 H" J3 j0 O8 {5 g0 R) H
7 S/ t* T2 y1 v: e
* @: H6 D/ _6 A/ C7 {$ ^
/ G9 p- S: T$ `' K; G% { read_dataset会读取WISDM数据集的datasets/WISDM_ar_v1.1_raw.txt文件$ w2 m) f7 Z: \' Z2 \
5 V! _2 U, J' H( i4 o# j v1 S P
3 R7 E) W1 V1 w
" t8 \" E( o9 l/ t9 [ 这些数据是已经做了转换预处理的数据集,见下图红线标注部分。
5 w" s- Q( O: [7 R7 M5 l5 {7 B+ t6 O7 L5 P4 A- x4 g) {
! m% I* Z! x4 N5 `! z# V& @ p" r6 |0 l4 H' ^/ r
而get_data_from_file( self, fileName, preparedDataFileName )函数读取自行采集数据集(.csv)文件时,做了转换预处理,确保和WISDM数据集一致。
0 p7 g" N2 D9 n( ]! r4 y3 C# d
# ^, @5 ?# ^+ w& \# W" l4 N% {3 K
/ H& ]/ N3 u- N, ?' r( b6 H ^
. i3 ^3 O0 ]+ z4 n2 }1 K
同时项目还把预处理过的自行采集数据集与训练好的模型一并以csv格式输出到目录中,以源数据目录命名,例如Log_data.csv。) j) E) _! {: y6 i$ |; q5 r# t$ K
2 Z4 F. \) w& U. @
6 O; Q3 R6 a5 [; g8 k* ]* h8 {/ Y5 M# f o
下来就是输入数据数量问题,由于在FP-AI-SENSING1案例项目,数据采集是按一定时间间隔连续实时采集的,采集间隔也很短(毫秒级别)1 f& g) i7 o- [2 L% L; B
& j% w& m8 V6 ~* {; t8 u0 o
) n( `# Z7 F; ^) X' y4 E
. b+ u" x, F$ h9 Q$ h
因此get_segment_indices和get_data_segments函数就是将采集到的连续数据处理成一个长度为seqLength的窗口的输入数据集,即每次输入数据是一段24组(一组3个数据值,x/y/z)数据,也就对应了我们前文定义输入数据缓存是static ai_float in_data[AI_HAR_IGN_IN_1_SIZE=24*3*1];,共72个float 数据。显然HAR项目做法是通过一组连续数据集作为输入比单个态势数据更能反应人类行为姿态的持续性,更贴近实际。
Y/ N! _, ?! T; E" X' ]
5 v; _, ~$ t0 M3 e' {* X' E" m
" m; @/ {8 K/ P( o
Q9 b! u4 j- l 在read_dataset函数加入打印读取的WISDM数据集语句。
! n7 | P( U' l6 y2 {" @0 j
! c4 z% ]+ ]! Z& g6 A3 Q
5 e! Z; J* c# z0 ?( f Y( W3 R# m
$ P$ [0 O- m0 ^! J# I/ T
在prepare_self_logged_data函数加入打印读取自行采集数据集语句
, |. J) M; O$ Y* Y! w3 p8 g
( s( S; Y2 @: \8 ~
! S7 ~1 O) q% V6 @# D0 g
' t8 F- U* ]8 ?5 ^7 ` 因为打印输出依据后,后续会打印数据按输入数据长度来分段的信息,暂时保持seqLength和stepSize为默认的24数值,运行python3 .\RunMe.py --dataDir=Log_data命令:. D# x! _/ R9 s1 ~( h
- PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR> python3 .\RunMe.py --dataDir=Log_data$ Z2 p$ r: f* U g. h/ ^/ A
- Using TensorFlow backend.
4 ^. |, T; J+ v9 |8 Q8 _ F: W - Running HAR on WISDM dataset, with following variables* x- `* S( E, f' \
- merge = True
- U2 P6 q1 I) L1 Z% |: }" B4 A - modelName = IGN,' y" P) o! |1 @0 f7 E
- segmentLength = 24
: v3 y) F# n9 J1 ]0 ~1 ~ - stepSize = 24" I3 ^$ e# @) q9 T2 W
- preprocessing = True
8 O7 I) K9 d1 h! i n/ f - trainTestSplit = 0.6
; n# H! S7 ^2 z4 M" z3 X4 ^7 a8 B - trainValidationSplit = 0.7( ^8 h; T) @! I
- nEpochs = 207 U6 P, y2 k2 T% m% v7 C+ L3 ]
- learningRate = 0.0005
4 s3 Q. _ K( q" }4 m - decay =1e-06
- L& [8 Z( `( M, i+ `* S - batchSize = 64
" `7 x7 R: H5 q( K/ O2 D& |: y5 g% F - verbosity = 1 T7 s: V) A* j6 n+ q
- dataDir = Log_data% \& |2 L9 L d! y
- nrSamplesPostValid = 2
7 n1 P) V; u9 b7 u, \1 j - User Activity_Label Arrival_Time x y z: ?* E) }1 R: u9 N
- 0 33 Jogging 49105962326000 -0.694638 12.680544 0.50395286;
; X. |- C- {+ E% g - 1 33 Jogging 49106062271000 5.012288 11.264028 0.95342433;
1 m, {! s1 }5 E# U* U. v1 o4 ?* H$ n1 y - 2 33 Jogging 49106112167000 4.903325 10.882658 -0.08172209;# J; m2 i7 i X+ r2 q
- 3 33 Jogging 49106222305000 -0.612916 18.496431 3.0237172;
) _% h2 @& j6 [2 Q, ~; K7 T - 4 33 Jogging 49106332290000 -1.184970 12.108489 7.205164;2 U2 w8 h+ J3 O
- ... ... ... ... ... ... ...
1 X' K9 D7 F+ q - 1098199 19 Sitting 131623331483000 9.000000 -1.570000 1.69;
3 u9 k2 q( Y; e! G! d5 g& b/ E - 1098200 19 Sitting 131623371431000 9.040000 -1.460000 1.73;
/ j, P. g5 K& L8 Z' c - 1098201 19 Sitting 131623411592000 9.080000 -1.380000 1.69;2 c4 K( S1 R! G. |7 b8 R
- 1098202 19 Sitting 131623491487000 9.000000 -1.460000 1.73;! h; z+ f8 s; A: f/ Z" D
- 1098203 19 Sitting 131623531465000 8.880000 -1.330000 1.61;( n+ [7 M3 p( E0 }
-
$ I [4 |( j, k7 ?" h1 Z' u8 b) h' g- g - [1098204 rows x 6 columns]
: I+ I) l& f& v' K9 F# _ - Segmenting Train data- @! t" _6 O8 R4 \9 E( n& f
- Segments built : 100%|███████████████████████████████████████████████████| 27456/27456 [00:28<00:00, 954.67 segments/s] Z5 Z7 L$ X7 y |) L% d
- Segmenting Test data5 o8 ^3 s! M# H. x0 i {& r
- Segments built : 100%|██████████████████████████████████████████████████| 18304/18304 [00:14<00:00, 1298.22 segments/s]
/ z: t1 |: k) v; w- t - Segmentation finished!/ X$ F7 q; d# h! J' G
- preparing data file from all the files in directory Log_data$ Z4 o1 b( Q- \
- parsing data from IoT01-MemsAnn_11_Jan_23_16h_57m_17s.csv
; N; C: G! G0 @ - parsing data from IoT01-MemsAnn_11_Jan_23_16h_57m_53s.csv) R& e. S6 O/ G8 @' C ]
- parsing data from IoT01-MemsAnn_26_Jan_23_15h_51m_01s.csv
) m5 g: g9 m" a4 }" [ - x y z Activity_Label
* f, _$ w4 [/ [0 O. ~ |) L - 0 -1.965414 -0.143890 9.367359 Walking, m" s, g5 l1 e- E0 k
- 1 -1.629783 0.664754 9.618931 Walking3 c0 U q# B2 @* a/ t! w* B! d2 A
- 2 -1.720833 0.384629 9.492079 Walking
' {% J$ a: c0 M5 {8 p& m - 3 -1.681419 0.534637 9.648173 Walking2 F1 n- X2 T& s
- 4 -1.729849 0.421650 9.557259 Walking
5 T+ k! E6 K) U2 ^4 f' I) |2 z - ... ... ... ... ...
8 n; Z3 J' q7 w5 U+ L3 ~ - 2639 -1.171046 0.033572 9.746819 Stationary% @2 \2 k* A* A K' @# \
- 2640 -1.212873 0.007256 9.759376 Stationary+ g2 N; W/ \( B. p) n% b
- 2641 -1.212011 0.019485 9.753982 Stationary
7 X" V" N# b' { - 2642 -1.172311 -0.004511 9.734770 Stationary6 A. s* S' w+ @( Y
- 2643 -1.175431 0.035787 9.753447 Stationary* K2 {) Y+ j4 X' X/ l* i/ [
- # H: n+ [3 n- h$ E: p3 ]; R
- [2644 rows x 4 columns]- p# }' p# Y. l7 y$ V# V
- Segmenting the AI logged Train data) I. O3 ~# k( R3 j
- Segments built : 100%|████████████████████████████████████████████████████████| 67/67 [00:00<00:00, 2795.31 segments/s]
3 J( D% X. _6 O9 ~ - Segmenting the AI logged Test data
* u, k; H1 Q: Y' ^# [ - Segments built : 100%|████████████████████████████████████████████████████████| 45/45 [00:00<00:00, 2370.94 segments/s]
2 [. z! _0 ^3 G2 H0 v, t - Segmentation finished!
/ m( j* u/ ]+ x. m- e8 Q - _________________________________________________________________
6 s, z) B5 M- k# j* G" q/ Z/ Y - Layer (type) Output Shape Param #
* D* {$ ~- x7 H5 _/ W" n# r, v9 d - =================================================================
9 z6 t4 E3 X, v& z4 ^ - conv2d_1 (Conv2D) (None, 9, 3, 24) 408
' b# a" Z' A) \: M' p& K) F7 [ - _________________________________________________________________5 V3 c7 e" B( z8 a2 C
- max_pooling2d_1 (MaxPooling2 (None, 3, 3, 24) 0
7 R$ m: E. r# U6 [% Z! l - _________________________________________________________________
- @+ X$ F& p) E5 s& k9 b - flatten_1 (Flatten) (None, 216) 0
: U# `4 D+ M C - _________________________________________________________________+ c( \! m$ m0 X ~ o: V
- dense_1 (Dense) (None, 12) 2604
2 c& k; ?" O0 s3 W! A - _________________________________________________________________
- K4 y1 A+ t; w - dropout_1 (Dropout) (None, 12) 0" ?( c d( j" Q* F, \1 r; t5 F
- _________________________________________________________________
" v/ z8 d: V- z7 y8 T6 I9 w - dense_2 (Dense) (None, 4) 52
) D( X) b0 |5 k! q$ m, E - =================================================================5 f5 R, E4 Y* o7 B
- Total params: 3,0640 M- b: N7 I; v* r4 P$ v$ g
- Trainable params: 3,064
. K, R' w0 L. e2 U - Non-trainable params: 0
E2 @7 N: b% |+ e - _________________________________________________________________8 j( N5 ]& Y, W! e
- Train on 19288 samples, validate on 8233 samples# r9 n1 u4 f" H$ D
- Epoch 1/20
* ^- k5 w0 r; \; m+ N - 2023-01-26 17:12:56.882726: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
. T# X* |4 ^# U( e - 19288/19288 [==============================] - 1s 54us/step - loss: 1.2022 - acc: 0.5290 - val_loss: 0.7089 - val_acc: 0.7409
5 ^* B) F# F9 u( |* [4 M% s4 @# ~ - Epoch 2/20
! o& e" S4 u0 d* i- ~4 q# A$ | - 19288/19288 [==============================] - 1s 41us/step - loss: 0.7520 - acc: 0.7017 - val_loss: 0.5342 - val_acc: 0.7985
9 D1 q+ h: O& v - Epoch 3/20
, y) k" [& A' ~& Q% S. f+ K - 19288/19288 [==============================] - 1s 41us/step - loss: 0.6079 - acc: 0.7571 - val_loss: 0.4573 - val_acc: 0.8153
$ ]4 h7 P' A. G - Epoch 4/20! i& @" _3 i9 B
- ... ...! U/ _5 |6 ?7 P0 M9 ^1 @
- 19288/19288 [==============================] - 1s 39us/step - loss: 0.3306 - acc: 0.8899 - val_loss: 0.2669 - val_acc: 0.91131 X% g& J; m% e/ f
- Epoch 20/205 i; c" E6 L1 V* S @) u
- 19288/19288 [==============================] - 1s 40us/step - loss: 0.3194 - acc: 0.8913 - val_loss: 0.2646 - val_acc: 0.9168
0 U6 f2 N) C% B; u( I - 12831/12831 [==============================] - 0s 22us/step
& p1 u$ n' a5 E8 T- T _* r - Accuracy for each class is given below.
Z0 g# G5 `( v, \( \5 T' B - Jogging : 97.51 %
9 D# x, h: M7 }4 M - Stationary : 98.63 %
% x; e W8 S% u# ^! ^. X - Stairs : 70.94 %+ W5 |6 x* ]0 C e
- Walking : 81.55 %
" t" z9 v+ @" @: X: N. l - PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR>
复制代码 " w& u, h0 d K; {
读取到的WISDM数据集大小是1098204≈24*(27456+18304),而27456+18304是按--trainSplit参数默认值0.6:0.4比例切分的。读取到的自行采集数据大小是2644≈24*(67+45)。& n5 b0 y6 _# j" ?6 i
8 _1 m2 m- E; I: `
8 O! J! F4 _' r5 q" w! }
' e0 g; G) b9 a% Z 三、工程调整" }& c- o& F8 J! B. O
从前面分析来看,输入数据数量还是采用默认数值24问题不大(各位粉丝可以自行调整其大小来测试及观察效果),输出数据数量由于有WISDM数据集参与,保持'Jogging', 'Stationary', 'Stairs', 'Walking'是中分类也OK。现注意到,其实输入数据是经过了预处理转换实际加速度值,而非是传感器原始输出数值。
6 \' k7 W: R) R) k4 U% A, U' a, A; d& i4 v8 y8 ]6 i, s
由于自行采集数据增加了Stationary数据文件,因此在cubeMX上采用新的训练模型文件重新生成c语言的神经网络模型。4 }% O% g+ h4 w6 ~0 j) I8 b# ~) {6 P
7 Y* j5 W+ Q$ S' J
+ C- e4 I1 ]' {- a: q* ]
. O; H1 K. [4 S% Q6 V% ? 然后调整输入数据及预处理函数acquire_and_process_data,采用真实数据来测试1 B7 F1 J7 W5 u
% @5 Z |2 D! X' b L6 t. Q; k6 Y
! h" _2 V/ W3 e; A# h L/ g; \% g% S, j. H! K4 ~8 O& e* N
该函数有原来的随机赋值,. C' \) ?& u+ w; I( z/ e
- int acquire_and_process_data(void *in_data,int factor)5 {4 z; f H2 y
- {$ f; ?/ f% _/ X6 `7 }' |+ s( x
- printf("in_data:");
; e0 g, H ~0 U - for (int i=0; i<AI_HAR_IGN_IN_1_SIZE; i++)1 L/ L0 C, v9 @) A5 M$ Q& F: t& X# F
- {
1 ]3 G9 i9 {2 P" v! N - switch(i%3){; y0 }3 b8 x5 x2 J: H" j
- case 0:6 l9 P% ?$ F4 ?
- ((ai_float*)in_data)[i] = -175+(ai_float)(i*factor*1.2)/10.0;
& k2 g- j, a; o3 t: u9 J- p - break;, ^3 s+ D) F" E: @$ @* D5 l$ v
- case 1:
3 U4 t# l V: `+ c" s# k3 D+ @' X - ((ai_float*)in_data)[i] = 50+(ai_float)(i*factor*0.6)/100.0;7 q$ @# \; y# e$ {5 Q6 c) q, s
- break;/ H8 E# b$ m# g& g) A* x
- case 2:, l9 ^* o) q/ c; G% ~/ _7 Z" |$ z
- ((ai_float*)in_data)[i] = 975-(ai_float)(i*factor*1.8)/100.0; N* O; j6 @5 \' u! D+ D% U
- break;
b& V' J9 D" }1 e V - default:
Q9 |1 s7 K( t( V7 P - break;. f9 S5 \! r- z; M/ C
- }
- w: v, `/ d; M) t; v- _ - printf("%.4f ",((ai_float*)in_data)[i]);7 j1 g6 P T4 N" @& D; L6 k& X
- }
& A* w7 t4 g' {% Z - printf("\n");
8 N5 i, H( l2 c, G2 u, T V -
/ E, J2 f2 L, B5 O$ R - return 0;
. v' G; y$ x+ |6 e - }
复制代码
6 ^; p: P* A, T5 S" ?0 E/ R 调整为; m4 B' d' D" Q- Z
- ai_float in_buf[] =# {7 a) H7 h: s ~% ]2 Z
- {$ t2 m/ ^( k7 ?5 t0 k
- -1.9654135467252831,-0.14388957575400915,9.36735860765576,( u8 R) f0 q3 |) P# _" {( h
- -1.6297827960727935,0.6647544204312931,9.618930851170278,. b3 m2 Z- B4 ?* k5 y
- -1.7208332169161387,0.38462856310059845,9.492079217583663,7 q! I1 f% Q, L( {8 `2 G
- -1.6814190066807724,0.5346365723749872,9.648173176699613,
, A% X- j: C5 |! ?8 R9 g/ x - -1.7298486510592452,0.42164964981080416,9.557259289818587,
' n( c: `9 s. R% o7 k2 m - -1.7618787694384546,0.45864558999786653,9.653153776935605, u6 C4 R( R9 `( N
- -1.7410197123193858,0.4236369742675384,9.55486293595946,
0 D% n# R* G: \$ Q - -1.7600076822930908,0.46214612481362705,9.594426626710453,1 i {* {7 x+ X7 C1 k
- -1.5761631958773263,0.3715109598910308,9.436853714636964,
$ C1 |" F5 l4 [8 F. b, ? - -1.5920827364351244,0.37070313540523914,9.66189484448469,
% f! @" U: f3 C - -1.6178308849438598,0.37500917334673567,9.695719226290015,$ x. {/ \ U$ ~# W4 e5 X* k4 r
- -1.4388296833472143,0.6108605310285585,9.464814699883437,8 A _: c9 B8 G! o
- -1.5651621282887258,0.5691273914891515,9.513897717476588,9 K) }# I4 ]; u: U
- -1.4637992479412343,0.5105873209777632,9.501636895304161,) l1 P5 P. }, E9 W! b
- -0.6794677157685166,0.5024637601753793,8.96404801376064,
! L& `: {4 i3 A& {$ o" ? {& W - 0.2600149177042748,0.6699546179356337,8.903349009412763,
( v( T1 q1 n/ t g) [* \ - 1.0712686735261918,1.4889662656074603,9.520348132500752,1 g+ z/ [3 i& ^. r9 n$ P$ |4 K
- 0.3914123345764725,1.4210706041563634,10.557387805652848,
; @) `, v- K( L/ W8 u - 1.0779003359396493,1.0582703827741018,10.454469820960814,, }5 S5 x1 { x Z
- 0.12433283758079197,-0.27273511643713033,10.328552286632643," t& n0 M" V s5 A
- -0.010219096051988997,0.2961821896002729,9.483084545625971,9 V) ^* m1 r, p% s7 C! r
- -1.6910112286007235,-0.2898761724876157,9.704755735796937,
0 Y& _8 G6 ]) t - -2.693651827312974,-0.41126025575408387,9.825328217800239,
3 X7 q8 ^" |: U - -2.8416981790648177,-0.14586229740441406,9.880552703938179
7 C* B' K. c& M( G! g: f% c% J - };! T* c& E0 r6 H- {
-
8 b: g6 \0 a$ Q+ c2 T, H: Z3 j( F3 f - int acquire_and_process_data(void *in_data,int factor)
d' r- x/ v: H2 R - {* _' t# Y Z6 X, o% e" U: _# Q
- printf("in_data:");( _. |0 L0 Z- I
- for (int i=0; i<AI_HAR_IGN_IN_1_SIZE; i++)$ R C4 [, Y5 o' W, |1 W
- {
' f5 g3 q& a. A! `# ^8 x' D$ w8 ^ - ((ai_float*)in_data)[i] =in_buf[i];
& P. O. H0 B T' X& u - printf("%.4f ",((ai_float*)in_data)[i]);
~4 s! I- e! J( B - }) n4 [1 A' T/ K2 w( i
- printf("\n");
5 s6 N5 G) j/ @( I, e - 4 `/ q* ?% E% V5 Q1 e+ O# U
- return 0;
8 I% z' p) N$ @. q2 J* g! t: c - }
复制代码
/ b$ a- _* `. } 重新编辑及加载到开发板,打开串口助手,输入test*,查看测试效果如下,显然和期待有很大出入:
" D' N7 H: R0 x/ n, A6 q/ E9 @5 ~5 U
% Z+ `$ [4 H8 D
% p6 C! c& P) W5 Q G
四、测试有误问题
& m2 y3 u8 n' F6 w: F8 E2 H+ _. N 上述结果和HAR项目中的PrepareDataset.py分类似乎并没匹配上,那么就要分析PrepareDataset.py分类和生成后的c语言模型时如何对应的,以及用来测试的数据是否符合模型要求。0 {' h; W( a# I# M1 M3 o
$ N1 o2 P. b) E. [/ y( F
, M( z: a2 R4 V* ^; p. o% A
- Y, ~9 B' G2 m# c* @9 D: ?/ W) D
为此,再次回到HAR训练模型项目,在RunMe.py文件中追加以下语句:
* Z- T2 N6 ~, R, h9 v7 d- print("TestX:"): F3 M1 b/ I4 J5 l
- print(TestX[0:1])1 n8 a* J& B9 ~. y* w) S$ |; R4 A1 p
- print("TestY:")
% x1 {+ j7 \% T6 X' m9 i# T9 v - print(TestY[0:1])
复制代码 - N. s0 f2 Y* V9 S
以获取用来测试的真实模拟数据,再次运行python3 .\RunMe.py --dataDir=Log_data命令,最后部分输出如下:* s& r9 y2 `6 V. c/ [
- TestX:4 M. E" E5 p4 }
- [[[[-3.64077855e-16]
) c: \$ X* J( q4 N& p! |6 { - [-4.69612372e-16]
& o. N/ }: F. A4 |* t2 P - [ 3.68092310e-10]]. x8 m, T, T" s* s3 c
- 9 ]+ f/ h1 P! ~/ A& `" |' E* M
- [[ 1.02756571e+01]
! f3 [ X" V- [5 W- ~) U - [-1.14305305e+01]& S; W, ]* F8 G) K7 X5 [& M
- [ 2.61872125e+01]]: l, ^. A- O3 q* w' B" v
- ( w5 w+ @4 K& O5 |# w, Z; k
- [[-2.84181689e+00]
+ k, v0 ^* s. P& z; y `6 r( H - [-3.54747048e+00]
: M8 V6 t Q+ h n0 q - [-5.51206446e+00]]( z$ W& z! _2 H, o8 l p2 [. T
-
. ~" W+ b* y3 b$ T5 t+ S6 M) Z - [[-3.82102513e+00]% s# w8 q2 f- E9 H0 D
- [-1.41233186e+01]# W* z% P1 k: c0 w0 ]! g
- [-4.59900586e+00]]! d2 S" A) i2 q# O% T# x* [
- ! U, h8 Q3 m" Z7 Q5 F1 N: t" t1 E0 t
- [[ 6.68010824e+00]
3 i; R6 \4 w, x+ ] - [ 9.39457601e+00]
) v- s5 N0 U9 d5 r' j - [-2.96397789e+00]]& y& k: G R. Z) y; \
-
6 F6 H; M( Y, k: K* ? - [[-1.71771782e+01]% a, \ W+ X& x0 v p/ j
- [ 1.19374149e+01]
# H/ {+ y+ O- ^9 j6 @ - [ 3.05770680e+00]]4 b1 F7 J |: N# i; ]. e6 j
-
" B5 {0 X8 p0 \" D2 V8 r6 Z/ W - [[-6.65782005e+00]
& Z3 P1 i' e% l: N+ m - [ 2.39062819e+00]6 } e. u: b; \/ n$ X2 C$ b, `0 f
- [ 3.22844912e+00]]. a" g3 t& X3 U8 ~' G2 p- s- y
-
$ G& p' A) `! }* ]# d; E* }4 ] - [[ 4.59021292e+00]
: } r; ^4 l% O. j* j3 K+ A* s' Y - [-6.27548028e+00]: w0 a2 [5 E4 W; \2 j3 Y
- [-4.92783556e+00]]
* x4 U4 B) @4 F5 T- \: S- W0 X! f - 2 |+ q9 _5 h5 K3 e# B* q* [
- [[ 8.03018658e+00]( z; J) W1 v3 g) a- `
- [-2.72208600e+00]6 X3 ?- a8 c, s% E, r
- [-6.35796053e+00]]
2 `0 w1 a3 \9 D6 j) z \ - 8 m7 D0 }- w& u! Y z. ^
- [[ 7.73164454e+00]
# o+ a; _0 O9 u; i) ]) j$ n$ o - [-6.31879160e+00]$ x2 H2 K! m, j3 o, q1 [4 ]3 |+ [" b
- [-5.90723810e+00]] d; T2 w/ i4 ]! D; p' E5 }0 m
- 7 F9 P2 I# C3 O) i9 ?9 j
- [[ 8.53803514e-01]2 t. [# b$ U- Q. C) o
- [-9.75763211e+00]
0 r! S' I5 V$ K' N# V' t - [ 1.02466115e+01]]7 J0 c$ y1 d9 x, D( q; w8 z& ^1 U
-
0 I0 ~: T+ t1 R - [[ 1.11299171e+01]8 a+ n+ h( d' s9 ~3 W( M, f
- [-1.70658346e+01]+ E6 e5 {& \& |% T: C
- [ 2.18511283e+01]]
2 m+ s; W9 M# L3 R+ O9 P - ' W% z- t3 ^0 D. W9 @% y0 y
- [[ 3.92044994e-01]
" h& @1 s+ p" h* E - [ 5.94768181e+00]
9 F% N- D+ S7 `6 E - [ 4.30131750e+00]]- {2 O* `' u- }: o1 U3 M! O
- 3 U3 W( | ?* ?1 L6 ~; t4 H
- [[-5.61807988e+00]. B5 N7 d, a1 i3 {9 W
- [ 1.97310400e+01]
# p2 }9 Q: a; ]/ `0 @+ P - [-2.22512540e+00]]
* b* x" m+ b, x: K" c4 J" J -
1 Y1 H) L$ i& n* M, X0 ^ - [[ 3.86836548e+00]
# W+ H4 I+ C4 G" ~# r& H1 @ - [ 1.71617325e+00]
7 f; H. U# a9 y: P2 x - [-5.86292387e+00]]
4 O* P( _* }3 q9 E6 U; U, ~ -
v- t3 U) Y& O' A9 _2 Z* e - [[ 7.65913325e+00]
$ C' L* v% R" T, O# Y* A - [-7.19628424e+00]
# O K; ]1 u" q0 o - [ 2.01628025e+00]]
4 l4 y0 y: E- ^/ s; i1 }; Q5 ^! s' p( G7 q -
8 X4 Q$ f5 i$ `, K+ U" B4 k9 W2 h$ y - [[-7.52357836e+00]& s& Z, v$ K+ I# k2 `+ R8 v
- [ 3.68102584e+00], b$ E. k6 m% [2 b' I* S# }$ E4 l
- [-1.22753233e+01]]
. E# w y6 z1 i* }( ^' j) Y - * n) c1 E8 x, [
- [[-5.12351958e+00]1 P4 ~, b7 b, d
- [ 1.23941669e+01]
% K4 U/ s2 Z2 R( }- T% `! F% o$ f - [-1.77385540e+00]]
0 C0 L( t3 s2 ?' E8 k+ g# M -
$ P6 `7 ]6 x) K, |1 q1 y- W2 S* b - [[-4.86155823e-01]7 `5 _+ C/ |5 Y$ ~& R
- [ 1.26333902e+01]
. Q6 u3 _, H9 S2 w - [ 5.93595914e+00]]
3 |, ]: e Y5 d& |3 {( O - 9 M: O" ?- x' g7 k0 g6 h% U- ] x
- [[-1.96569165e+01]
# B, ~* c; \- O2 ^: |% T - [ 1.00467317e+01]
' U2 l7 { g& y - [ 9.47374003e+00]]
& K/ u4 L0 b; y/ [* | -
5 `$ e8 l* k; u& z4 O# U4 Q+ I, @ - [[-4.34050581e+00]; h, @) a$ L2 }9 k
- [ 5.16311148e-01]
# M$ a% B1 }/ {+ s9 E. h - [-5.63004156e-01]]
+ b. W' A# V/ [8 D3 L ` - , x) G0 q6 T* g* N/ R2 Y L/ u/ V, L
- [[-3.57974669e+00]
. j5 e2 K- H% T6 T - [ 4.87240857e-01]0 i8 I4 ?$ f, z( D/ v d+ R+ S: @
- [-9.38271247e-01]]" A9 g9 J" l& o: ?7 e3 F
- $ [" a1 Z* R8 X8 w* o% K
- [[ 6.11930536e+00]
' c( F8 D7 G" m) F - [ 5.99067573e+00]. i7 ]# R# ?0 ^% C6 s
- [-7.68834262e+00]]
# p. M+ b- ~# p, V5 s6 z - 8 I) G' Y5 g+ d+ i2 S+ x; m
- [[ 1.12153409e+01]9 {' }: \9 D F' s
- [ 2.37168199e+00]
; L- j$ U0 ]+ h2 J4 \& o( } - [-7.40963357e+00]]]]" l) P. ^& u+ ]3 i$ ^& Q
- TestY:" J. W8 m) q" g4 y
- [[1. 0. 0. 0.]]# X u* r, S- m$ T$ D, V" V
- PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR>
复制代码 0 f+ X |% u$ A! G" a
显然输入24*3的一组数据,输出结果是[1. 0. 0. 0.],再将该数据用于测试 c语言模型神经网络模型API调用。. D# C3 f6 _9 U) J$ g* T% |
- ai_float in_buf[] =
* _. X# I @, U; j% _ - {( {: J1 k* w m" J$ }$ ^
- -3.64077855e-16,-4.69612372e-16,3.68092310e-10,2 Y: _ i. n3 W8 }) e
- 1.02756571e+01,-1.14305305e+01,2.61872125e+01,
2 |. @% n- @( s. E3 Y. \6 a+ i; V - -2.84181689e+00,-3.54747048e+00,-5.51206446e+00,
7 b; Q% d) c- _5 ` _. l% ?% D5 N - -3.82102513e+00,-1.41233186e+01,-4.59900586e+00,
9 Q' K# i6 N! @ - 6.68010824e+00, 9.39457601e+00,-2.96397789e+00,
! l: c& \; ]% Y3 | - -1.71771782e+01,1.19374149e+01,3.05770680e+00,
4 s: L' W0 c6 p$ Z - -6.65782005e+00,2.39062819e+00,3.22844912e+00,$ Q6 |# D ^; _# Q3 \: g( F
- 4.59021292e+00,-6.27548028e+00,-4.92783556e+00,
J6 o) [4 |3 I# k) s0 i) v3 E - 8.03018658e+00,-2.72208600e+00,-6.35796053e+00,: _' o3 O; j5 u5 D7 }- }& N
- 7.73164454e+00,-6.31879160e+00,-5.90723810e+00,: M/ a, P/ T; Q6 R3 k7 Z, n' f
- 8.53803514e-01,-9.75763211e+00, 1.02466115e+01,3 h# g/ ~/ b3 m, [- J8 C* N
- 1.11299171e+01,-1.70658346e+01, 2.18511283e+01,
6 X% ]* Z/ h! [% Q - 3.92044994e-01, 5.94768181e+00, 4.30131750e+00,
$ X+ f2 o! M1 C) K3 D' S. N; o) ^ - -5.61807988e+00, 1.97310400e+01,-2.22512540e+00,& t% P8 t' u- D4 x6 J$ P
- 3.86836548e+00, 1.71617325e+00,-5.86292387e+00,5 C. k5 B+ H# `
- 7.65913325e+00,-7.19628424e+00, 2.01628025e+00,6 R0 k, C' e& L9 U
- -7.52357836e+00, 3.68102584e+00,-1.22753233e+01,% e; o9 ~1 l- g* H+ c# ~) u3 `" m
- -5.12351958e+00, 1.23941669e+01,-1.77385540e+00,
6 C* r+ z$ J' X! w$ d: {" k - -4.86155823e-01, 1.26333902e+01, 5.93595914e+00,
4 l; p$ C" Q% Y/ p% N6 z9 K - -1.96569165e+01, 1.00467317e+01, 9.47374003e+00,2 m$ O3 r; O! S2 N" c* b H' [
- -4.34050581e+00, 5.16311148e-01,-5.63004156e-01,
& u# O4 F# q& c$ l9 \% m - -3.57974669e+00, 4.87240857e-01,-9.38271247e-01,
# @) @, C( u- w% r4 E* W9 v - 6.11930536e+00, 5.99067573e+00,-7.68834262e+00,7 p6 T! L, \$ d* m
- 1.12153409e+01, 2.37168199e+00,-7.40963357e+00
$ ]7 O8 [; ~2 {) T - };
; x0 q% X: P6 o9 }" C, G -
8 n H0 l3 `4 X( ?8 ^* Z2 B - int acquire_and_process_data(void *in_data,int factor)( J6 e7 x6 g7 k3 P" A0 y
- {: H" O8 j+ b; R, `" w: C
- printf("in_data:");
$ g$ n Z$ ^! h9 ^ - for (int i=0; i<AI_HAR_IGN_IN_1_SIZE; i++)
4 l* g% u: R8 L7 u/ ?9 n# s - {
4 C6 [- B! h& u! }2 o3 K2 v - ((ai_float*)in_data)[i] =in_buf[i];
4 G$ O! V) G; t, T$ q1 ^" O- e; }8 B - printf("%.4f ",((ai_float*)in_data)[i]);& w7 r* c# p8 D3 }
- }
2 f/ Z, x9 M7 I" b! z - printf("\n");
8 H, @1 q" z$ v - ' P/ }1 H; i! o
- return 0;1 r8 H) K6 x V0 U
- }
复制代码
+ M% P f5 P8 V 再次编译下载程序,采用串口助手测试如下,输出数据为,【0.943687 0.000000 0.000294 0.056019】,而实际数据是[1. 0. 0. 0.],显然能对应上,只是精度问题:
% S' l/ {4 r0 {- \8 ~% d0 M9 ^: f
- J* n' Y, ~6 K, `2 a; o6 n
" o' H+ d$ U# l5 ?' s
) l: y4 p- H3 C: z- U' w1 @7 W
5 m1 Z! O5 E* @# q; `, \/ i6 a" q五、精度问题$ A- o4 H3 W9 O; O7 L
再次回到HAR训练项目上,如前文所述,训练结果按时间生成一个目录进行输出:
7 n5 n, x! D: a2 H1 c& F) w# P, f" u8 O& U& E) i6 P; R$ I
6 J. V3 h( z9 Z) Z' m
! N1 I' F2 j+ P/ b, d 输出了训练的acc 、loss变化曲线图和混淆矩阵图,观察可以看到,用于训练数据其主要还是来自于WISDM的数据集占据大头,从混淆矩阵也可以看出,为何前面测试时输出结果0.943687 0.000000 0.000294 0.056019】,显然训练过程中,'Jogging'姿态会有一部分判断 'Stairs', 'Walking'姿态。1 m1 S( r3 w U6 e( Z1 V
1 t" O7 {* q) d2 P, ~* R" i
! A2 A- |1 G8 h* [7 T
1 c7 v( [# g% X2 T 在训练过程日志显示:
& \+ u8 W- z' L( N9 `
$ ~# F0 O0 z- m% P% |3 v
! X9 [& P( q% l6 K
Y5 j7 l4 x6 o& e4 O) ?- w
再次改写RunMe.py,加入下面打印语句,查看用于训练、验证及测试的数据集量级:
' p$ Q+ O2 P' V1 ?- print("TrainX:"+str(len(TrainX)))
- N0 L# A; C+ O3 j - print("TrainY:"+str(len(TrainY))); q8 v! i# v. k* j$ `9 i; M
- print("ValidationX:"+str(len(ValidationX)))+ M* w$ e2 P9 K7 t' S& y. V
- print("ValidationY:"+str(len(ValidationY)))- r8 t. T8 H2 N, j4 i: A$ D1 r3 b. d
- print("TestX:"+str(len(TestX)))
( ? B' N+ v7 F6 K$ X6 m) t4 z - print("TestY:"+str(len(TestY)))
复制代码 3 b( F8 p: I2 i2 F
再次运行python3 .\RunMe.py --dataDir=Log_data命令:
4 O+ \1 H! e, [0 K0 X4 o) n9 F- D; _5 `/ B' Z+ A y0 i o
* L+ |( @- C8 t) p5 `: `' Y8 B; ?& a4 |# n; F# X) l
通常在实际项目中,不断优化算法模型是主要原因,但相信ST公司及其合作团队应该就算法模型做了足够好,而本文测试验证为何还出现精度相差这么大,应该是以下几点:
# c$ E1 f6 I1 j5 H* v: g 1)本文用于训练模型的数据集不是同一设备,同一批次,统一采集方法获得足够量数据集。
# T' A5 |: ?1 G l/ U( e
6 [, u4 E8 L! ]) q: e! V8 Z 2)本文自行采集的数量偏小,可能预WISDM采集数据方法存在差异而出现精确性问题,并加入其中,还是会影响模型训练精度的(若仅采用WISDM采集数据集)。
: m* ]; b4 X: [$ Z) U
: f9 m* w2 X g4 o3 D4 n% s 3)本文仅采用了HAR训练项目建议的默认参数,实际项目中,可能需要我们根据数据集及部署环境,不断尝试不同参数设置来训练和使用神经网络模型。
/ k$ [( ^) C" m$ F/ ` V0 {' L
+ b+ b" m. ]1 ]- v7 L# e3 y 4)cube.AI将keras训练的神经网络模型转换为c语言的神经网络模型虽然损耗极小,但还是存在一定精度损失的。4 C& c/ l; _& x0 o: x9 x- V
$ K+ f, S$ @6 i. m" }
+ s$ d; v7 K1 M9 m
) W+ i* M* j3 d0 u' t+ z
篇一、二,是基于FP-AI-SENSING1案例和配套的B-L475E-IOT01A开发板来使用cube.AI软件包的,那么在实际使用cube.AI时,需要与我们项目实际硬件平台,并基于该硬件平台采集的数据进行数据预处理和神经网络模型构建、训练、验证及测试,然后再通过cubeMX和cube.AI将训练好的神经网络模型转换为c语言支持的AI模型,通过嵌入式程序加载(AI模型+cube.AI)从而实现神经网络计算的前端或边缘端部署,请阅读偏三。
7 _5 ]5 B/ B5 |: r: L————————————————& D: G, V1 S! [$ T4 |
版权声明:py_free-物联智能8 N& h0 i$ r9 G7 X7 Y) Y
如有侵权请联系删除6 x- T9 z# S! a6 a" ~& }
|