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

news2024/9/30 23:33:39

文章目录

  • 前言
  • 一、K210的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的内容,其余内容稍后上传到gitee上

#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;
volatile uint8_t g_ai_done_flag;
uint8_t g_ai_buf_out[320 * 240 * 3] __attribute__((aligned(128)));

/* KPU完成 */
static int kpu_done(void *ctx)
{
	g_ai_done_flag = 1;
	return 0;
}

//  卷积	池化	批归一化	激活	输出偏置
float conv_data[9*3*3] ={
//origin
//R
0,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,
//G
0,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,
//B
0,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;
const float conv_data_demo[4][9*3*3] ={
{	//origin
//R
0,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,
//G
0,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,
//B
0,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,
//G
0,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,
//B
0,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,
//G
0,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,
//B
0,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
//R
2,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,
//G
0,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,
//B
0,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   无
*/
void hardware_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 camera
    fpioa_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和DVP
    sysctl_set_spi0_dvp_data(1);
}

/**
* Function       io_set_power
* @brief         设置bank6/bank7电源域1.8V
* @param[in]     void
* @param[out]    void
* @retval        void
* @par History   无
*/
static void io_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格式 */
void rgb888_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);
	}
}

/* 在原来图像的基础上增加数据(字符) */
void lcd_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;
}

/* 左上角显示模式 */
void draw_text(void)
{
	char string_buf[8 * 16 * 2 * 16]; //16个字符
	char title[20];

	switch (demo_index)
	{
	case 0:
		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;
	case 1:
		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;
	case 2:
		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;
	case 3:
		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;
	}

}

/* 按键中断回调 */
int key_irq_cb(void *ctx)
{
	key_flag = 1;
	key_state = gpiohs_get_pin(KEYPAD_MIDDLE_GPIONUM);
	return 0;
}

/* 初始化按键 */
void init_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   无
*/
int main(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();
    }   
    else if(OV_type == OV_2640) 
    {
        ov2640_init();
    }
    else 
    {
       return 0;//打不开摄像头,结束
    }

	/* 按键初始化*/
	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;
			}
		}
	}
	return 0;
}

代码完成后,进行编译

cd build

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

make

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

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

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1407023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

源码篇--Redis 五种数据类型

文章目录 前言一、 字符串类型&#xff1a;1.1 字符串的编码格式&#xff1a;1.1.1 raw 编码格式:1.1.2 empstr编码格式:1.1.3 int 编码格式:1.1.4 字符串存储结构展示: 二、 list类型&#xff1a;2.1 List 底层数据支持&#xff1a;2.2 List 源码实现&#xff1a;2.3 List 结构…

水经微图系列产品新功能盘点!

水经微图&#xff0c;简称“微图”。 我们曾在直播中分享过微图APP苹果版的功能&#xff0c;本周四晚19:30我们将在另一个视频号分享盘点微图APP安卓版的详细功能&#xff0c;以及Web版近期上线的新功能功能。 微图APP安卓版 我们在《水经微图安卓版APP正式上线》一文中&…

ABAP SQL CDSView Entity中使用正则RegEx表达式(Regular Expressions)

1. 正则表达式测试程序 DEMO_REGEXDEMO_REGEX_TOY 2. ABAP SQL & CDSView Entity支持正则语法的场景 SQL函数语法作用执行逻辑返回类型CDS View EntitiesABAP SQLLIKE_REGEXPRLIKE_REGEXPR( PCRE pcre, VALUE sql_exp1[, CASE_SENSIT…

Unity Mask合批情况验证

1.首先是两个Mask完全重合的情况下 每张图片使用的image都来自同一个图集 发现彼此之间是没有合批的&#xff0c;但是每个Mask内部是实现了合批的 经过计算此种情况的visiableList&#xff1a;mask1&#xff0c;IM1&#xff0c;IM2&#xff0c;mask2&#xff0c;IM3&#xf…

Centos7 两种方式安装 MySQL5.7 步骤 yum 、本地 tar 文件

一、使用 yum 源方式安装 1、卸载系统自带 mariadb MariaDB Server 是最流行的开源 关系型数据库 之一。它由 MySQL 的原始开发者制作&#xff0c;并保证保持开源。 在 CentOS 7 中默认安装有 MariaDB 可忽略&#xff0c;安装完成之后可以直接覆盖掉 MariaDB。 查看并卸载系统…

如何在阿里云提交使用工单

有时候大家在使用阿里云的服务时候&#xff0c;可能会遇到一些问题&#xff0c;或许是云服务器如何升级了如何改套餐啊之类的&#xff0c;亦或者是域名ICP备案啊看进度啊等等问题&#xff0c;遇到问题怎么办不要慌。我们可以使用阿里云的工单系统&#xff0c;阿里云工单系统可以…

虚拟机网络配置及Moba工具的使用

A、设置IP和网关 1、设置IP [roothadoop00 ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0 &#xff08;修改如下标红内容&#xff0c;没有的就添加&#xff09; DEVICEeth0 HWADDR08:00:27:BD:9D:B5 #不用改 TYPEEthernet UUID53e4e4b6-9724-43ab-9da7-68792e611031…

Confluence6+mysql5.7破j安装避坑详细记录

目录 一、前言 二、下载与安装 1、版本和安装环境 2、安装数据库 3、配置数据库 4、安装confluence 三、Pj confluence 1、选择语言和产品安装 2、Pj 3、上传mysql驱动 4、重启Confluence服务继续安装 四、Confluence重启卸载方法 重启方法 方法一 方法二 卸载…

acwing 动态规划dp 0 1背包问题

前言 hello小伙伴们&#xff0c;最近由于个人放假原因颓废了一段时间很长时间没有更新CSDN的内容了&#xff0c;唉&#xff0c;毕竟懂得都懂寒暑假静下心来学习的难度远比在学校里大的多。 但是&#xff0c;也不是毫无办法克服&#xff0c;今天我来了我们当地的一家自习室来学习…

《WebKit 技术内幕》学习之四(3): 资源加载和网络栈

3. 网络栈 3.1 WebKit的网络设施 WebKit的资源加载其实是交由各个移植来实现的&#xff0c;所以WebCore其实并没有什么特别的基础设施&#xff0c;每个移植的网络实现是非常不一样的。 从WebKit的代码结构中可以看出&#xff0c;网络部分代码的确比较少的&#xff0c;它们都在…

Mybatis 全局配置文件(三)

文章目录 第一章&#xff1a;概述第二章&#xff1a;properties (了解)第三章&#xff1a;settings第四章&#xff1a;typeAliases (别名处理器)第五章&#xff1a;typeHandlers (类型处理器)第六章&#xff1a;plugins(插件)第七章&#xff1a;environments (环境)第八章&…

k8s-基础知识(Service,NodePort,CusterIP,NameSpace,资源限制)

Node Node 是 Pod 真正运行的主机&#xff0c;可以是物理机&#xff0c;也可以是虚拟机。 Annotations 原文链接 Annotations 是 key/value 形式附加于对象的注解。不同于 Labels 用于标志和选择对象&#xff0c;Annotations 则是用来记录一些附加信息&#xff0c;用来辅助应…

深入理解JS语法与变量

深入理解JS语法与变量 前言初识JavaScriptJavaScript的语言风格和特性 JavaScript的书写位置认识输出语句学会处理报错REPL 环境 变量定义变量改变变量变量的合法命名变量的默认值变量的常见错误等号表示赋值同时声明多个变量 变量声明提升注意事项 结语 前言 在现代Web开发中…

Vue构建项目断点调试过程问题总结

Vue构建项目断点调试过程问题总结 问题背景 前端开发过程中&#xff0c;碰到问题时需要debug&#xff0c;快速分析和解决问题。一般除了console.log的方式打印日志外&#xff0c;更方便直观的方式就是打断点debug。本文对vue项目debug过程可能碰到的问题进行总结&#xff0c;…

Kafka(二)原理详解

一 、kafka核心总控制器&#xff08;Controller&#xff09; 在Kafka集群中会有一个或者多个broker&#xff0c;其中有一个broker会被选举为控制器&#xff08;Kafka Controller&#xff09;&#xff0c;它负责管理整个集群中所有分区和副本的状态。 作用&#xff1a;leader副…

FireAlpaca:轻量级、免费的Mac/Win绘图软件,让你的创意如火燃烧!

FireAlpaca是一款轻量级、免费的绘图软件&#xff0c;适用于Mac和Win系统&#xff0c;让你的创作过程更加快捷、简便。无论是绘制漫画、插图、设计作品还是进行简单的图片编辑&#xff0c;FireAlpaca都能满足你的需求。 首先&#xff0c;FireAlpaca具有直观友好的用户界面&…

国辰智企资产管理系统:实现资产精细化管理的首选

在市场竞争日益激烈、金融环境不断变化的背景下&#xff0c;有效的资产管理已成为企业保持竞争优势和实现财务目标的关键。传统资产管理方法已显不足以适应现代经济环境的快速变化。为了迎接这一挑战&#xff0c;越来越多企业纷纷采用先进的资产管理系统&#xff0c;以提高效率…

【面试突击】微信亿级朋友圈的社交系统设计

微信亿级朋友圈的社交系统设计 先来说一下业务需求吧&#xff1a; 每个用户可以发朋友圈&#xff0c;可以点赞&#xff0c;评论可以设置权限&#xff0c;不看某些人朋友圈、不让某些人看你的朋友圈可以刷朋友圈中其他人的动态 对于这样的系统设计&#xff0c;主要从业务来考虑…

Springboot项目启动报错:Command line is too long问题解决

启动项目报错:Error running ‘xxxxxxxx’: Command line is too long. Shorten command line for ‘xxxxxxxx’ or also for Application default configuration 方法一 点击提示中的&#xff1a;default&#xff1a;然后在弹出窗口中选择&#xff1a;JAR xxxx xxx&#xff0…

搭建k8s集群实战(一)系统设置

1、架构及服务 Kubernetes作为容器集群系统&#xff0c;通过健康检查重启策略实现了Pod故障自我修复能力&#xff0c;通过调度算法实现将Pod分布式部署&#xff0c;并保持预期副本数&#xff0c;根据Node失效状态自动在其他Node拉起Pod&#xff0c;实现了应用层的高可用性。 …