0


AI嵌入式K210项目(18)-卷积人工神经网络硬件加速器 KPU

文章目录


前言

K210内置了丰富的加速器,包括神经网络处理器 (KPU),AES(高级加密加速器),APU 麦克风阵列语音数据加速计算处理器,现场可编程 IO 阵列 (FPIOA),数字摄像头接口 (DVP),相对于软件可以极大的提高 AES 运算速度,快速傅里叶变换加速器 (FFT),安全散列算法加速器 (SHA256)。
本文介绍内置的卷积人工神经网络硬件加速器 KPU;

一、K210的KPU

KPU 是通用的神经网络处理器,它可以在低功耗的情况下实现卷积神经网络计算,实时获取被检测目
标的大小、坐标和种类,对人脸或者物体进行检测和分类。使用 kpu 时,必须结合 model compiler。

KPU 是通用神经网络处理器,内置卷积、批归一化、激活、池化运算单元,可以对人脸或物体进行实
时检测,具体特性如下:
• 支持主流训练框架按照特定限制规则训练出来的定点化模型
• 对网络层数无直接限制,支持每层卷积神经网络参数单独配置,包括输入输出通道数目、输入输
出行宽列高
• 支持两种卷积内核 1x1 和 3x3
• 支持任意形式的激活函数
• 实时工作时最大支持神经网络参数大小为 5.5MiB 到 5.9MiB
• 非实时工作时最大支持网络参数大小为(Flash 容量-软件体积)
在这里插入图片描述
KPU 的内部结构如下图所示:
在这里插入图片描述
对应的头文件 kpu.h

为用户提供以下接口:

• kpu_task_init (0.6.0 以后不再支持,请使用kpu_single_task_init):初始化kpu 任务句柄,该函数具体实现在model compiler 生成的gencode_output.c 中。

• kpu_run (0.6.0 以后不再支持,请使用kpu_start):启动KPU,进行AI 运算。

• kpu_get_output_buf (0.6.0 以后不再支持):获取KPU 输出结果的缓存。

• kpu_release_output_buf (0.6.0 以后不再支持):释放KPU 输出结果缓存。

• kpu_start:启动KPU,进行AI 运算。

• kpu_single_task_init:初始化kpu 任务句柄。

• kpu_single_task_deinit:注销kpu 任务。

• kpu_model_load_from_buffer:解析kmodel 并初始化kpu 句柄。

• kpu_load_kmodel:加载kmodel,需要与nncase 配合使用。

• kpu_model_free:释放kpu 资源。

• kpu_get_output:获取KPU 最终处理的结果。

• kpu_run_kmodel:运行kmodel。

二、实验过程

本实验代码较多,这里只贴出main.c的内容,其余内容稍后上传到gitCode上https://gitcode.com/bin_zhangg0n/K210/tree/main

#include<stdio.h>#include<string.h>#include<unistd.h>#include<stdlib.h>#include"dvp.h"#include"fpioa.h"#include"lcd.h"#include"ov2640.h"#include"ov9655.h"#include"plic.h"#include"sysctl.h"#include"uarths.h"#include"st7789.h"#include"dvp_cam.h"#include"utils.h"#include"kpu.h"#include"l_conv.h"#include"sleep.h"#include"encoding.h"#include"gpiohs.h"#include"pin_config.h"#include"dvp_cam.h"int key_flag =0;gpio_pin_value_t key_state =1;volatileuint8_t g_ai_done_flag;uint8_t g_ai_buf_out[320*240*3]__attribute__((aligned(128)));/* KPU完成 */staticintkpu_done(void*ctx){
    g_ai_done_flag =1;return0;}//  卷积    池化    批归一化    激活    输出偏置float conv_data[9*3*3]={//origin//R0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//G0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,//B0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,};int demo_index=0;constfloat conv_data_demo[4][9*3*3]={{//origin//R0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//G0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,//B0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,},{//edge//R-1,-1,-1,-1,8,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//G0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,8,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,//B0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,8,-1,-1,-1,-1,},{//sharp//R-1,-1,-1,-1,9,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//G0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,9,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,//B0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,9,-1,-1,-1,-1,},{//relievo//R2,0,0,0,-1,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//G0,0,0,0,0,0,0,0,0,2,0,0,0,-1,0,0,0,-1,0,0,0,0,0,0,0,0,0,//B0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,-1,0,0,0,-1,},};/**
* Function       hardware_init
* @brief         硬件初始化,绑定GPIO口
* @param[in]     void
* @param[out]    void
* @retval        void
* @par History   无
*/voidhardware_init(void){/* 按键 */fpioa_set_function(PIN_KEYPAD_MIDDLE, FUNC_KEYPAD_MIDDLE);/* LCD */fpioa_set_function(PIN_LCD_CS,  FUNC_LCD_CS);fpioa_set_function(PIN_LCD_RST, FUNC_LCD_RST);fpioa_set_function(PIN_LCD_RS,  FUNC_LCD_RS);fpioa_set_function(PIN_LCD_WR,  FUNC_LCD_WR);// DVP camerafpioa_set_function(PIN_DVP_RST,   FUNC_CMOS_RST);fpioa_set_function(PIN_DVP_PWDN,  FUNC_CMOS_PWDN);fpioa_set_function(PIN_DVP_XCLK,  FUNC_CMOS_XCLK);fpioa_set_function(PIN_DVP_VSYNC, FUNC_CMOS_VSYNC);fpioa_set_function(PIN_DVP_HSYNC, FUNC_CMOS_HREF);fpioa_set_function(PIN_DVP_PCLK,  FUNC_CMOS_PCLK);fpioa_set_function(PIN_DVP_SCL,   FUNC_SCCB_SCLK);fpioa_set_function(PIN_DVP_SDA,   FUNC_SCCB_SDA);// 使能SPI0和DVPsysctl_set_spi0_dvp_data(1);}/**
* Function       io_set_power
* @brief         设置bank6/bank7电源域1.8V
* @param[in]     void
* @param[out]    void
* @retval        void
* @par History   无
*/staticvoidio_set_power(void){/* Set dvp and spi pin to 1.8V */sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);}/* 转化图像数据格式,因为摄像头输出到AI的是RGB888格式,而显示屏需要RGB565格式 */voidrgb888_to_565(uint8_t*src_r,uint8_t*src_g,uint8_t*src_b,uint16_t*dst,uint32_t len){uint32_t i;for(i =0; i < len; i +=2){
        dst[i]=(((uint16_t)(src_r[i +1]>>3))<<11)+(((uint16_t)src_g[i +1]>>2)<<5)+(((uint16_t)src_b[i +1])>>3);
        dst[i +1]=(((uint16_t)(src_r[i]>>3))<<11)+(((uint16_t)src_g[i]>>2)<<5)+(((uint16_t)src_b[i])>>3);}}/* 在原来图像的基础上增加数据(字符) */voidlcd_ram_cpyimg(char*lcd,int lcdw,char*img,int imgw,int imgh,int x,int y){int i;for(i =0; i < imgh; i++){memcpy(lcd + lcdw *2*(y + i)+ x *2, img + imgw *2* i, imgw *2);}return;}/* 左上角显示模式 */voiddraw_text(void){char string_buf[8*16*2*16];//16个字符char title[20];switch(demo_index){case0:sprintf(title," origin ");lcd_ram_draw_string(title,(uint32_t*)string_buf, BLUE, BLACK);lcd_ram_cpyimg((char*)g_display_buf,320, string_buf,strlen(title)*8,16,0,0);break;case1:sprintf(title,"  edge  ");lcd_ram_draw_string(title,(uint32_t*)string_buf, BLUE, BLACK);lcd_ram_cpyimg((char*)g_display_buf,320, string_buf,strlen(title)*8,16,0,0);break;case2:sprintf(title," sharp  ");lcd_ram_draw_string(title,(uint32_t*)string_buf, BLUE, BLACK);lcd_ram_cpyimg((char*)g_display_buf,320, string_buf,strlen(title)*8,16,0,0);break;case3:sprintf(title,"relievos");lcd_ram_draw_string(title,(uint32_t*)string_buf, BLUE, BLACK);lcd_ram_cpyimg((char*)g_display_buf,320, string_buf,strlen(title)*8,16,0,0);break;default:break;}}/* 按键中断回调 */intkey_irq_cb(void*ctx){
    key_flag =1;
    key_state =gpiohs_get_pin(KEYPAD_MIDDLE_GPIONUM);return0;}/* 初始化按键 */voidinit_key(void){// 设置按键的GPIO模式为上拉输入gpiohs_set_drive_mode(KEYPAD_MIDDLE_GPIONUM, GPIO_DM_INPUT_PULL_UP);// 设置按键的GPIO电平触发模式为上升沿和下降沿gpiohs_set_pin_edge(KEYPAD_MIDDLE_GPIONUM, GPIO_PE_BOTH);// 设置按键GPIO口的中断回调gpiohs_irq_register(KEYPAD_MIDDLE_GPIONUM,1, key_irq_cb,NULL);}/**
* Function       main
* @brief         主函数,程序的入口
* @param[in]     void
* @param[out]    void
* @retval        void
* @par History   无
*/intmain(void){hardware_init();io_set_power();/* 设置系统时钟和DVP时钟 */sysctl_pll_set_freq(SYSCTL_PLL0,800000000UL);sysctl_pll_set_freq(SYSCTL_PLL1,300000000UL);sysctl_pll_set_freq(SYSCTL_PLL2,45158400UL);uarths_init();/* 系统中断初始化 */plic_init();/* 使能系统全局中断 */sysctl_enable_irq();/* 初始化显示屏,并显示一秒图片 */printf("LCD init\r\n");lcd_init();lcd_draw_picture_half(0,0,320,240, gImage_logo);sleep(1);/* ov摄像头初始化 */int OV_type;
    OV_type=OVxxxx_read_id();/* 初始化摄像头 */if(OV_type == OV_9655){ov9655_init();}elseif(OV_type == OV_2640){ov2640_init();}else{return0;//打不开摄像头,结束}/* 按键初始化*/init_key();/* kpu初始化 */kpu_task_t task;conv_init(&task, CONV_3_3, conv_data);printf("KPU TASK INIT, FREE MEM: %ld\r\n",get_free_heap_size());printf("Please press the keypad to switch mode\r\n");while(1){while(g_dvp_finish_flag ==0);/* 开始运算 */conv_run(&task, g_ai_buf_in, g_ai_buf_out, kpu_done);while(!g_ai_done_flag);
        g_ai_done_flag =0;
        g_dvp_finish_flag =0;/* 转化成LCD支持的RGB565格式 */rgb888_to_565(g_ai_buf_out, g_ai_buf_out +320*240, g_ai_buf_out +320*240*2,(uint16_t*)g_display_buf,320*240);/* 左上角写字母提示是哪个模式 */draw_text();/* 显示图像 */lcd_draw_picture(0,0,320,240, g_display_buf);if(key_flag)//使用按键选择的卷积核{if(key_state ==0)//按下{msleep(20);//延迟去抖
                key_flag =0;
                demo_index =(demo_index +1)%4;memcpy((void*)conv_data,(void*)(conv_data_demo[demo_index]),3*3*3*3*sizeof(float));conv_init(&task, CONV_3_3, conv_data);}else//弹起{msleep(20);//延迟去抖
                key_flag =0;}}}return0;}

代码完成后,进行编译

cd build

cmake ..-DPROJ=kpu -G "MinGW Makefiles"

make

编译完成后,在build文件夹下会生成kpu.bin文件。

使用type-C数据线连接电脑与K210开发板,打开kflash,选择对应的设备,再将程序固件烧录到K210开发板上。
在这里插入图片描述
实验结果:烧录固件完成后,系统会自动弹出一个终端窗口,并且打印一些初始化的信息,此时我们看显示器的已经显示了摄像头当前采集的画面,而且左上角还有一个‘origin’的单词,当我们按下keypad中间的键时,模式切换,LCD显示的画面会变化,除了原始画面,还有其他三种模式可以显示,每按一次keypad都可以切换一次模式。
在这里插入图片描述

总结

K210芯片内置了卷积人工神经网络硬件加速器KPU,它可以在低功耗的情况下实现卷积神经网络计算,实时获取被检测目
标的大小、坐标和种类,对人脸或者物体进行检测和分类;


本文转载自: https://blog.csdn.net/bin_zhang1/article/details/135656147
版权归原作者 疯狂飙车的蜗牛 所有, 如有侵权,请联系我们删除。

“AI嵌入式K210项目(18)-卷积人工神经网络硬件加速器 KPU”的评论:

还没有评论