NNOM-mnist-simple实例

        在之前验证了PC环境的基础上,继续测试原开源项目中的手写数字识别。这是中文简介链接,

docs/example_mnist_simple_cn.md · RT-Thread-Mirror/nnom - 码云 - 开源中国 (gitee.com)

一、编译原模型

        打开项目文件mnist-simple,编译运行mnist_simple.py文件,如果之前跑过Auto-test实例,环境应该没有问题,在目录下会生成几个新文件,主要关注如下几个文件,

        image.h是图像测试文件,weight.h是模型训练完成后的权重参数文件。

二、MCU移植

        原项目作者用的是RT-Thread系统,移植文件也仅限于MCU文件夹下的image.h、weight.h和main.c文件,并且在测试时还使用了RT-Thread下的测试模块?我并没有接触过RT-Thread,NNOM是一个纯C的框架,在其他操作系统和MCU上应该也是可以运行的,在研究了移植文件的代码后,选择用Freertos+STM32H7来测试。    

1、文件移植

nnom
├───docs 
│   ├───figures                     // 文档图片
│   └───*.md                        // 文档
├───examples                        // 例子
├───inc                             // 头文件
├───port                            // 移植文件
├───scripts                         // 脚本工具,模型转换工具
├───src                             // 源代码
│   LICENSE                         // 软件包许可证
│   README.md                       // 软件包简介
└───SConscript                      // 构建脚本

         按照目录结构的解释,NNOM需要移植src、port、inc三个文件夹,image.h、weight.h是图像测试和权重参数,因此也需要移植。

        在keil的项目目录下建立对应目录,添加相应的.c和.h文件。

        keil的目录管理是不能建立多级目录的,因此要把整个NNOM的.c文件都加在一个目录下,如下图所示,

        不要遗漏,全部加过来。另外不要忘了添加对应的.h文件路径,除了NNOM的头文件路径,还要image.h、weight.h路径,

2、部分接口的移植

        在nnom_port.h文件中,找到以下代码,

#define nnom_malloc(n)      pvPortMalloc(n)       
#define nnom_free(p)        vPortFree(p)
...
#define nnom_us_get()       0       // return a microsecond timestamp
#define nnom_ms_get()       0       // return a millisecond timestamp
#define NNOM_LOG(...)       App_Printf(__VA_ARGS__)

        需要在现有环境下提供几个接口,如上图中的内存申请/释放接口,日志打印接口。内存接口我直接用的freertos下的内存接口,测试下来能用;log打印的接口,重映射一个串口到printf或者随便什么名字就行,函数写好后,把它贴过来(STM32重映射串口到printf,网上教程一堆);还有获取时间什么的,还没研究咋给。

        另外,代码中的NNOM_LOG打印都是\n结尾,实际打印是换不了行的,要以‘\r\n’结尾才行,我直接在代码中replace替换的,或者在给log打印接口的函数那里做个逻辑判断,检测到\n结尾就自动打印一个\r也行。

NNOM_LOG("Model version: %d.%d.%d\r\n", major, sub, rev);

3、main.c文件移植

        结合原项目的一些注释,原本的main.c大概就是用一个调试接口FINSH_FUNCTION_EXPORT(mnist, mnist(4) )(可能是串口?)给板子发了一个指令,然后板子收到指令后正常跑模型,完事以后把对应结果再打印出来。所以我们只需要移植main函数部分就行,如果需要接收上位机命令,可以另做逻辑(接个摄像头也可以),更改后的代码如下所示,

#include "ModelRun.h"
#include "printtask.h"
#include "weights.h"
nnom_model_t *model;

// extern static nnom_model_t* nnom_model_create(void);
//串口画图用的字符串
const char codeLib[] = "@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'.   ";

void model_test()
{

	model = nnom_model_create();    //创建模型
    model_run(model);               //运行模型
}

void mnist_pre()
{
	uint32_t tick, time;
	uint32_t predic_label;	//预测出的标签
	float prob;
	unsigned char index=6;	//实际的标签的数组位号
	int Probability;

	model_stat(model);
	App_Printf("Total Memory cost (Network and NNoM): %d\r\n", nnom_mem_stat());

	memcpy(nnom_input_data, (int8_t*)&img[index][0], 784);
	nnom_predict(model, &predic_label, &prob);

	print_img((int8_t*)&img[index][0]);	
	// printf("Time: %d tick\n", time);
	App_Printf("Truth label: %d\r\n", label[index]);
	App_Printf("Predicted label: %d\r\n", predic_label);
	App_Printf("Probability: %d%%\r\n", (int)(prob*100));

}


void print_img(int8_t * buf)
{
    for(int y = 0; y < 28; y++) 
	{
        for (int x = 0; x < 28; x++) 
		{
            int index =  69 / 127.0 * (127 - buf[y*28+x]); 
			if(index > 69) index =69;
			if(index < 0) index = 0;
            App_Printf("%c",codeLib[index]);
			App_Printf("%c",codeLib[index]);
        }
        App_Printf("\r\n");
    }
}
void StartBSSTask(void *argument)
{
  /* USER CODE BEGIN StartBSSTask */
    unsigned int len = 0;
    char *p = NULL;
  /* Infinite loop */
  for(;;)
  {
    //fft_test();
    //len = xPortGetFreeHeapSize();
    //App_Printf("Free Heap Size is:\t%d\r\n",len);

    model_test();
    osDelay(200);
    mnist_pre();  
    osThreadSuspend(BSSTaskHandle);

  }
  /* USER CODE END StartBSSTask */
}

        代码放在ModelRun.c和ModelRun.h中,在freertos中新建测试任务,调用函数即可。这里测试的预测标签位号是6,在对应的image.h中找到img数组,IMG6是LABLE 4,也就是实际图像数字是4。

...
#define IMG6_LABLE 4 
...
static const int8_t img[10][784] = {IMG0,IMG1,IMG2,IMG3,IMG4,IMG5,IMG6,IMG7,IMG8,IMG9};
...

 4、运行输出

        编译下载,上位机的串口接收结果如下所示,可以正确预测出结果,速度的话,体感很快,具体需要做时间测试的接口才知道。

Model version: 0.4.3
NNoM version 0.4.3
To disable logs, please void the marco 'NNOM_LOG(...)' in 'nnom_port.h'.
Data format: Channel last (HWC)
Start compiling model...
Layer(#)         Activation    output shape    ops(MAC)   mem(in, out, buf)      mem blk lifetime
-------------------------------------------------------------------------------------------------
#1   Input      -          - (  28,  28,   1,)          (   784,   784,     0)    1 - - -  - - - - 
#2   Conv2D     - ReLU     - (  28,  28,  12,)      84k (   784,  9408,     0)    1 1 - -  - - - - 
#3   MaxPool    -          - (  14,  14,  12,)          (  9408,  2352,     0)    1 1 1 -  - - - - 
#4   Conv2D     - ReLU     - (  14,  14,  24,)     508k (  2352,  4704,     0)    1 - 1 -  - - - - 
#5   MaxPool    -          - (   7,   7,  24,)          (  4704,  1176,     0)    1 1 1 -  - - - - 
#6   Conv2D     - ReLU     - (   7,   7,  48,)     508k (  1176,  2352,     0)    1 - 1 -  - - - - 
#7   MaxPool    -          - (   4,   4,  48,)          (  2352,   768,     0)    1 1 1 -  - - - - 
#8   Flatten    -          - ( 768,          )          (   768,   768,     0)    - - 1 -  - - - - 
#9   Dense      - ReLU     - (  96,          )      73k (   768,    96,  1536)    1 1 1 -  - - - - 
#10  Dense      -          - (  10,          )      960 (    96,    10,   192)    1 1 1 -  - - - - 
#11  Softmax    -          - (  10,          )          (    10,    10,     0)    1 - 1 -  - - - - 
#12  Output     -          - (  10,          )          (    10,    10,     0)    1 - - -  - - - - 
-------------------------------------------------------------------------------------------------
Memory cost by each block:
 blk_0:4704  blk_1:9408  blk_2:2352  blk_3:0  blk_4:0  blk_5:0  blk_6:0  blk_7:0  
 Memory cost by network buffers: 16464 bytes
 Total memory occupied: 18632 bytes

Print running stat..
Layer(#)        -   Time(us)     ops(MACs)   ops/us 
--------------------------------------------------------
#1  Input      -         0                  
#2  Conv2D     -         0          84k     
#3  MaxPool    -         0                  
#4  Conv2D     -         0         508k     
#5  MaxPool    -         0                  
#6  Conv2D     -         0         508k     
#7  MaxPool    -         0                  
#8  Flatten    -         0                  
#9  Dense      -         0          73k     
#10 Dense      -         0          960     
#11 Softmax    -         0                  
#12 Output     -         0                  

Summary:
Total ops (MAC): 1175424(1.17M)
Prediction time :0us
Total memory:18632
Total Memory cost (Network and NNoM): 18632
                                                        
                                                        
                                                        
                                                        
                                                        
                                          rr@@II        
                      ''{{[[            ]]@@ww          
                      {{@@LL          !!WW##``          
                    ``**OO            CChh``            
                    ,,@@++          ""##&&^^            
                    ~~@@''          !!@@XX              
                  ``oodd..        ^^pp%%                
                  __%%~~          }}@@&&                
                  ZZMM          ..pp88__                
                {{@@}}          ??@@qq                  
                11@@ll      ..{{##oo::                  
                11@@cc[[>>}}pp@@@@00                    
                !!&&@@@@BBWWOOqq@@]]                    
                  <<XXXX11::..ZZCC                      
                            zz@@ff                      
                          ,,oo##""                      
                          ww@@xx                        
                        [[@@00..                        
                      ``&&WWll                          
                      {{WW>>                            
                                                        
                                                        
                                                        
Truth label: 4
Predicted label: 4
Probability: 100%

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于这是一个较为复杂的问题,我们逐步来回答。 1. 在Simulink中建立调速系统的动态结构图 根据传递函数1/s3+18s2+72s,我们可以使用Simulink中的Transfer Fcn模块来建立传递函数模型。建立模型的步骤如下: 1. 打开Simulink并创建一个新模型。 2. 在模型中添加Transfer Fcn模块,并将传递函数输入到模块中。 3. 添加一个Sum模块,并将输入连接到该模块中。 4. 在Sum模块中添加反馈,即连接输出到Transfer Fcn模块中。 5. 添加一个Step模块,该模块代表输入信号。 6. 连接Step模块到Sum模块中。 7. 运行模型并观察输出结果。 2. 计算额定磁通下电机电动势转速比 电机电动势常数K_E等于额定磁通下电机电动势与转速之比。因此,我们可以使用以下公式来计算电动势转速比: K_E = V_RMS / (2 * pi * f * n) 其中,V_RMS是电源电压,f是电网频率,n是电机转速。 3. 求闭环系统的闭环放大倍数 系统调速范围为D=20,静差率为s=5%。因此,我们可以使用以下公式来计算闭环放大倍数: K_P = (D / 100) * (1 / s) 4. 求拖动系统测速反馈系数 给定信号un*=12V时,n=nnom=1000r/m。因此,我们可以使用以下公式来计算测速反馈系数: K_S = un* / (K_E * nnom) 5. 求满足调速范围和静差率的比例调节器放大系数KP 我们已经求得了闭环放大倍数K_P和测速反馈系数K_S。因此,我们可以使用以下公式来计算比例调节器放大系数K_P: K_P = K_P / K_S 6. 系统稳定性分析 要确定系统是否稳定,我们需要计算系统的临界开环放大倍数,并将其与闭环放大倍数进行比较。系统的临界开环放大倍数等于系统传递函数的分母中最大的实部。如果闭环放大倍数大于临界开环放大倍数,则系统不稳定。 7. 设计控制器参数以满足相角裕度要求 为了满足相角裕度要求,我们可以使用控制器设计工具箱中的根轨迹法来设计控制器。具体步骤如下: 1. 打开MATLAB并创建一个新的脚本文件。 2. 在脚本文件中使用Control System Designer打开调节器设计工具箱。 3. 在工具箱中输入系统传递函数,并设置相角裕度要求。 4. 使用根轨迹法来设计控制器参数。 5. 在脚本文件中编写代码来实现控制器。 以上是对问题的回答,根据具体情况可能还需要进一步的调整和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值