在经历完各种准备工作后,现在终于来到了正主。直接部署Tensorflow Lite Micro那一套玩意确实没啥问题,但是太麻烦,要添加一大堆文件,还得用它家训练生成模型,然后转换,麻烦的很,在ST平台,怎么能不提到用ST自家工具去部署模型,方便快捷,简单实用。; Q8 i: p; ` ]" B5 X x& w( t
拿出之前准备的工程,选取ai开发需要支持的软件包cue-ai,在software packs点select components; w# p2 u J* b1 @1 c/ }
7 f+ H( T2 q& }/ L# D
- \+ K E. O+ Z* k: ~6 V) d1 K7 O# N- P5 {. B# |9 K
1 g0 Y( {$ `- H4 f3 ]在X-CUBE-AI行下core勾选,点OK完成
7 k& R2 U% Z( s) h* L/ p# P9 e) ?
- `; v( n" w2 c& J" {
! l% r, l! \; Q- u$ N* A* C
: u W- j" v) P! q# ?3 [回到引脚配置页面,最下方就是上面导入的CUBE-AI工具包
1 R# i" j( d" e4 k
7 ~% r! }) a' m
2 t) a& S' B' ]3 R( R4 F! M2 X% ^7 e- `" v6 b
* j3 l. R2 `7 \
点击+添加,这里要根据自己使用的模型,以及模型特点选择,如下图选择的是原始模型) R$ h ^ H) {! h, P
. F5 O B1 o3 o% r& G) U
7 ~5 p& \; t' E! c这里选择的是量化后的模型(量化可以减少模型的要求,但是精度会下降),点击分析! [8 v8 t) h8 o; @
$ V0 }& K6 h9 N& `
( k, @+ c, i" k分析中) B4 F9 {" `0 v& j& \
6 K4 W: Y; s- Q B1 G/ D- l; @; }" c" Z* a, Z; ?5 e' q
分析完成会显示是否可以部署到设备上,以及资源使用情况。9 L$ O4 Y& [ Q) q
7 G; {; s3 c" u: u0 [3 z6 h
1 z$ S/ ~8 J' a' w0 j回到工程,有个小bug(使用的STM32CubeMX版本为6.6.1,X-CUBE-AI版本为7.2.0),下图的几个文件路径老是生成错0 f' p' D" C) Z+ h8 i
6 M" Y) D) b3 f* ?6 W
; U* a: r9 d. j5 |& _4 f. r
: c/ J& y+ m% J+ r8 L% Y5 } ]& b# V8 m, K
右键文件打开设置,修改一下路径就行
7 }) h, b2 q* @8 p$ C( N# N" p: i! a* J( T
+ |3 z' B+ O0 G7 N' S( x, @8 h- E( N
3 X3 C- x1 }4 F6 c4 o
! _+ a2 o* U& b& p8 g头文件路径也有一样的问题/ O2 M5 n$ @ y
t3 p3 a) b; {" {6 c2 O
7 @3 P' r* }1 P8 g, ~
初始化模型- ai_handle ai_init(void)
# M) S/ F* c) x) O - {& n) @; _1 K2 a% k- ^& s
- network_handle = AI_HANDLE_NULL;5 O8 _3 w. W& x9 |0 a% }
# z, f) E. ]8 L0 u7 d; S/ N- /* Creating the network */
$ n1 e! Y2 v' P" f" D& @ - ai_network_create(&network_handle, AI_NETWORK_DATA_CONFIG);5 a! G# b! b% t: \' Z+ l$ \$ {2 {
- / R, G3 t9 q% u# l
- /* Initialize param structure for the activation and weight buffers */9 K' X' Y) ^* L( h5 ~$ ]1 D
- const ai_network_params params = AI_NETWORK_PARAMS_INIT(" L& Y, r2 Q6 p1 Z+ U2 v
- AI_NETWORK_DATA_WEIGHTS(ai_network_data_weights_get()),
# e# u7 a* c6 J2 x1 i& `# ]1 \1 G - AI_NETWORK_DATA_ACTIVATIONS(activations)
* r# d2 m. V8 { o6 o2 R% s0 b - );/ V0 @1 I& c# v0 P! z6 M2 a( J7 [
- 8 B! y4 @! {0 x+ q2 ]8 U
- /* Initializing the network */
r6 g& L1 ]6 m# J" {2 j7 O - ai_network_init(network_handle, ¶ms);
# z, n4 o0 b" z- I: S0 S9 L -
1 Y c `" \ R) r% i - /*Retrieve network descriptor*/1 J q. I0 t" B6 D$ |# u
- ai_network_get_info(network_handle, &desc_report);
$ R( ]/ v# ~' Z- l( ~& i - V( k/ |* D( C" y7 p
- /*Copy descriptor info*/
3 L4 c& `8 d2 v3 @ - ai_input[0]= desc_report.inputs[0];- a) W: m. P1 m6 l
- ai_output[0]= desc_report.outputs[0];+ n5 e& \: N( u* d4 x5 l! M
-
3 p6 j$ m: b( U- t7 P/ |/ k - return desc_report.inputs->data; R1 e8 {' M2 a3 J: l: s
- }
复制代码 5 }% s7 l! ] C, n+ ^2 {
运行模型. ~! G* O- R$ U/ ~- ?; l' w
- void ai_run(void* input, void* output)
- w9 s$ c8 u9 H& W, A. _+ p - { U) c/ l7 p2 R. A
- ai_i32 nbatch;% `5 N2 I9 l/ ]5 ~6 o ^: c
- 9 }0 m5 v5 w* |
- ai_input[0].data = AI_HANDLE_PTR(input);
" E' m( H+ S6 ~8 y - ai_output[0].data = AI_HANDLE_PTR(output);# F# [8 ~/ a! Y/ N/ x* r* k# G
- 0 T0 W: t9 [7 c7 q
- nbatch = ai_network_run(network_handle, &ai_input[0], &ai_output[0]);
9 n/ X5 y- z* E3 m$ Y - ! g4 `" Q& v0 ]& ?2 n
- if (nbatch != 1) {
7 c, Z+ {$ t8 W( @& [% m - while(1);
& K9 {3 ?& Z! N7 c! _ - }0 N( I4 p7 {5 u, D. J
- }
复制代码 ( t$ q' }$ I. O0 K* L
图像接收处理,这个模型要求输入224*224的RGB888的图像,把数据转换一下。2 g# y3 k- ~ F# d' Q( S
- void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
1 \* J2 j6 Q1 i. w0 F; y7 b i - {2 J; J3 b* J. N5 `- M; L6 @
- uint8_t person_flag;
+ j; p5 T3 H" h1 \& k: f( B - int i,j;
: B2 C7 f, V, C; s1 V* u- u: N8 _7 g - for(i=0; i<224; i++)
E4 X6 U/ m- P9 Q - {
& L9 _- i" i1 e- v5 o6 F; Q* A: U7 e - for(j=0; j<224; j++)
0 w0 L+ G( b7 v! S% s - {
8 \6 ?9 _% n( x, V9 N# s; g1 \ - uint16_t bg_color = ((uint16_t *)_OV2640->frame->buffer)[i*320 + j];
4 }( \3 G: V- a' p; I% ? - network_input[3*i*224 + 3*j + 0] = ((bg_color>>11)&0xff)<<3;
6 t% M; l6 t/ a! W7 y4 | y - network_input[3*i*224 + 3*j + 1] = ((bg_color>>5)&0x3f)<<2;7 A' R$ `8 L; ~& ?
- network_input[3*i*224 + 3*j + 2] = (bg_color&0x1f)<<2;6 b n2 z# T4 g% H
- }; P/ @) r' v6 U; ~0 u. e
- }
b; l4 P) n" `- M9 F: N. y - ai_run(network_input, network_output);2 A3 v# J# E6 @% \
- 5 L5 v& v) _# c; t
- LCD_Draw_Image(0, 0, 320, 240, (uint16_t *)_OV2640->frame->buffer);
1 _" g+ Z3 Y4 G, b3 B& j% L - LCD_Draw_String(0, 0, 320, 240, 32, output_labels[network_max()]);
4 U; ~& n; [/ u! z -
; a4 T4 J" T- ?& Y) A - OV2640_DMA_Config(_OV2640->frame->buffer, (_OV2640->frame->length)/4);
7 l' L" ]$ c1 n5 Q: T; [ -
2 w) m7 w& b* w6 S2 K( M: Z+ Q - }
复制代码 ) T9 j, p! d- x9 i
2 \. q% k9 O; F$ \; |8 P
运行效果(一共能识别18种食物,这里选了几个看看), ]/ B) @$ s5 ~1 ~
& l: f5 Y9 p3 }% G( E4 f0 w9 m/ }空
& ~0 v3 b1 {* [" E* _
* W4 F' _) t- X2 r! o0 W可乐
5 v7 R; R+ c5 o6 ?( z
z5 |$ R4 ] ~, R* p: v: P9 `# a( T% |
甜甜圈
; s0 i/ J N e$ ~5 M
2 a( t+ {; ]: [; O8 Z
3 h8 N* ]2 z+ N汉堡包: C1 n3 c( [* ?: }: S [
( T1 Z7 ]' S/ ^* [' U/ w
. k2 i; {9 G. z/ L E3 n薯条6 ^/ E! S$ W2 ?9 D: V( d- e1 u
% O" i0 t* u& X
* X( R% u. O2 w( }
( P6 G4 c# z6 m, I小结:STM32Cube.AI工具真的太香了,这里仅仅演示了模型的部署,其实可以快速验证AI模型在目标板上的运行情况,只用串口连接,直接把输入发送到单片机,然后运行完后把结果返回来,全部都集成到了一起,快速验证模型运行情况。很是方便(本文未涉及,有需要的可以在X-CUBE-AI行下勾选时,application里面选择validation,回到配置界面后设置通信接口即可)" u, X4 ~6 o4 d/ P
Wio Lite AI视觉开发套件确实是开发AI的很好的选择之一,板子虽小五脏俱全,拿来做单片机视觉绰绰有余,但是不得不吐槽的一点是资料支持太差了,原理图,代码全都藏起来,前期调驱动花了很长的时间,后来管管给了一个例程后好转了一些(但是已经晚了。。。),Ai在单片机上应用已经有很多厂商都推出类似的解决方案了,ST这一个环境很优秀,就是如果相关的培训跟资料再多一点就好了。
8 I6 L; Z# q2 W; a3 U- R/ F |