[ESP32]:TFLite Micro推理CIFAR10模型

[ESP32]:TFLite Micro推理CIFAR10模型

模型训练

数据集处理

from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential, load_model, Model
from keras.layers import Input, Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D, GlobalAveragePooling2D
import pandas as pd
import matplotlib.pyplot as plt
import time, pickle
from keras.utils import to_categorical
from keras import layers
import tensorflow as tf
from tensorflow.keras.callbacks import EarlyStopping

(x_train, y_train), (x_test, y_test) = cifar10.load_data()

y_train = y_train.reshape(y_train.shape[0])
y_test = y_test.reshape(y_test.shape[0])

print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'training samples')
print(x_test.shape[0], 'validation samples')

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

模型搭建

def build_model():
    model = tf.keras.Sequential()
    model.add(layers.Conv2D(32, kernel_size=(4,4), strides=1,activation='relu', input_shape=(32, 32, 3)))
    model.add(layers.MaxPooling2D((2, 2)))

    model.add(layers.Conv2D(32, kernel_size=(4,4), strides=1,activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))


    model.add(layers.Flatten())
    model.add(layers.Dense(256, activation='relu'))
    model.add(layers.Dense(10, activation='softmax'))

    print(model.summary())
    return model

model=build_model()

tflite模型转换


converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
open("cifar10.tflite", "wb").write(tflite_model)

ESP32推理

本文采用的是2DCNN,添加所需的op算子即可

static tflite::MicroMutableOpResolver<5> resolver;
// 这里需要添加我们模型使用的层
if (resolver.AddReshape() != kTfLiteOk)
{
    ESP_LOGI(TAG, "Add reshape failed");
    return;
}

if (resolver.AddConv2D() != kTfLiteOk)
{
    ESP_LOGI(TAG, "Add reshape failed");
    return;
}

if (resolver.AddMaxPool2D() != kTfLiteOk)
{
    ESP_LOGI(TAG, "Add reshape failed");
    return;
}

if (resolver.AddFullyConnected() != kTfLiteOk)
{
    ESP_LOGI(TAG, "Add reshape failed");
    return;
}

if (resolver.AddSoftmax() != kTfLiteOk)
{
    ESP_LOGI(TAG, "Add reshape failed");
    return;
}

推理方案1:PC端JPG图片转换为数组

每一个像素点都有RGB三个数值,依次排开即可,以下为python的一段实例

from PIL import Image
import numpy as np

def image_to_c_array(image_path):
    # 读取图片
    image = Image.open(image_path)

    print(image.size)
    # 转换为numpy数组
    image_array = np.array(image)


    # 归一化
    # normalized_image_array = image_array / 255.0
    print(image_array.size)
    x_array_flatten = image_array.flatten()
    print(len(x_array_flatten))
    c_array_string = "{" + ", ".join(str(pixel) for pixel in x_array_flatten) + "}"

    with open("image_array.h", "w") as f:
        f.write("#ifndef IMAGE_ARRAY_H\n")
        f.write("#define IMAGE_ARRAY_H\n\n")
        f.write("const float image_array[] = %s;\n" % c_array_string)
        f.write("#endif\n")


# 调用函数生成.h文件
image_to_c_array("0042.jpg")

在这里插入图片描述

这样,我们可以直接将这个数组作为模型的输入去推理,记得归一化,除以255。

推理方案2:esp_jpeg解码jpg

size_t pic_buf_size = 32 * 32 * sizeof(uint32_t);
        uint8_t *pic_buf = (uint8_t *)heap_caps_malloc(pic_buf_size + 1, MALLOC_CAP_SPIRAM); // create out image buffer
        esp_jpeg_image_cfg_t jpeg_cfg = {
            .indata = (uint8_t *)file_buf,
            .indata_size = filesize,
            .outbuf = (uint8_t *)pic_buf,
            .outbuf_size = pic_buf_size,
            .out_format = JPEG_IMAGE_FORMAT_RGB888,
            .out_scale = JPEG_IMAGE_SCALE_0,
        };

        // // decode jpg
        esp_jpeg_image_output_t outimage;
        esp_jpeg_decode(&jpeg_cfg, &outimage);
        ESP_LOGI(TAG, "%s size: %d x %d", filename, outimage.width, outimage.height);

和上面python版本的一样,解码出来的pic_buf存放的也是每一个的像素,类似于这样

pic_buf[]= {像素0的R,像素0的G,像素0的B,像素1的R....}

所以在输入网络的时候,pic_buf的长度一定是图像宽图像高3,其中3为RGB,包括解码的时候选择RGB888

推理端的代码,记得归一化。

void cifar10_model_predict(const uint8_t *pic, int size)
{
    for (int i = 0; i < size; i++)
    {
        input->data.f[i] = pic[i] / 255.0f;
    }

    TfLiteStatus invoke_status = interpreter->Invoke();
    if (invoke_status != kTfLiteOk)
    {
        MicroPrintf("Invoke failed on");
        return;
    }

    for (int i = 0; i < 10; i++)
    {
        printf("%.2f ", output->data.f[i]);
    }
    printf("\n");
}
LiteOk)
    {
        MicroPrintf("Invoke failed on");
        return;
    }

    for (int i = 0; i < 10; i++)
    {
        printf("%.2f ", output->data.f[i]);
    }
    printf("\n");
}

可以看到推理结果还是挺不错的。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SSH新功能揭秘:远程工作提升指南【AI写作】

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

【快速入门 LVGL】-- 5、Gui Guider界面移植到STM32工程

上篇&#xff0c;我们已学习&#xff1a;【快速入门 LVGL】-- 4、显示中文 工程中添加了两个按钮作示范。运行效果如图&#xff1a; 本篇&#xff1a;把Gui Guider设计好的界面&#xff0c;移植到STM32工程。 特别地&#xff1a; 在使用Gui Guider进行界面设计时&#xff0c;应…

浅谈叉车车载电脑的市场现状

叉车的起源 叉车源于美国&#xff0c;兴于日本&#xff0c;虽然中国起步较晚&#xff0c;但是近些年来发展迅速。叉车又称叉式装载车&#xff0c;是对于成件托盘类货物进行装卸、堆垛和短距离运输&#xff0c;实现重物搬运作业的轮式工业车辆。 叉车的分类 叉车分为以上六大类…

Apache RocketMQ ACL 2.0 全新升级

作者&#xff1a;徒钟 引言 RocketMQ 作为一款流行的分布式消息中间件&#xff0c;被广泛应用于各种大型分布式系统和微服务中&#xff0c;承担着异步通信、系统解耦、削峰填谷和消息通知等重要的角色。随着技术的演进和业务规模的扩大&#xff0c;安全相关的挑战日益突出&am…

报错:测试报错postman(测试接口)

报错如下 c.e.exception.GlobalExceptionHandler : 异常信息&#xff1a; Content type multipart/form-data;boundary--------------------------952399813172082093419475;charsetUTF-8 not supported 解决&#xff1a; 异常信息 Content type multipart/form-data;boundary…

git常见命令(成长版)

ps&#xff1a;所谓成长版就是后续可能还会添加命令&#xff1a; 1.删除本地分支&#xff1a; git branch -d 分支名 2.拉取代码后默认master分支&#xff0c;切换到线上其他分支&#xff1a; &#xff08;1&#xff09;查看线上所有分支&#xff1a; git branch -a &#…

【网络安全】HTTP协议 — 特点

专栏文章索引&#xff1a;网络安全 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 学习目标​ 一、请求与响应 1.服务器和客户端 二、不保存状态 1.不保存状态的协议 三、资源定位 1.URI&#xff08;统一资源标识符&#xff09; 四、请求方法 1.请求方法 五…

代码随想录算法训练营Day10 | 232.用栈实现队列、225. 用队列实现栈

232.用栈实现队列 题目&#xff1a;请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除…

Git的操作和使用

一、基本操作 1、创建git本地仓库 &#xff08;1&#xff09;创建目录&#xff1a;mkdir gitcode &#xff08;2&#xff09;进入目录&#xff1a;cd gitcode/ &#xff08;3&#xff09;查询目录内容&#xff1a;ls &#xff08;4&#xff09;在当前目录下创建git本地仓库…

数据结构(七)---二叉树

目录 一.树的基本概念 二.树的性质 三.二叉树 1.二叉树的基本概念 2.特殊的二叉树 &#xff08;1&#xff09;满二叉树 &#xff08;2&#xff09;完全二叉树 &#xff08;3&#xff09;二叉排序树 &#xff08;4&#xff09;平衡二叉树 3.二叉树的性质 4.完全二叉树…

CC软件防火墙和WEB应用防火墙哪个好

本文将从CC软件防火墙的定义、原理、功能以及应用方面进行全面探讨&#xff0c;旨在加深对CC软件防火墙的理解&#xff0c;并推动网络安全意识的普及。以及WEB应用防火墙二者之间的对比。让用户更了解两个形态产品并作出选择。 第一部分&#xff1a;CC软件防火墙的定义和原理 …

北京小米智能工厂

小米工厂智能化 小米集团昌平区的小米智能工厂二期&#xff0c;成为引领智能化制造的重要一环。这座工厂计划打造成为京津冀地区智能制造示范工厂和全球级的“灯塔工厂”。 工厂位于小米未来产业园区&#xff0c;占地81000平方米&#xff0c;年产能可达千万台智能手机&#xff…

创新指南 | 2024年企业如何十步打造最佳的数字化营销策略组合

营销是一个动态且不断变化的领域。顶级的数字营销策略随着消费者和技术趋势的变化而变化。这就是为什么每个公司都需要一个经过良好规划并具有明确里程碑和目标的营销策略。一旦你有了正确的计划&#xff0c;你实现为业务设定的目标的可能性就会大大增加。这意味着&#xff0c;…

提交链码-编辑前后端,调用链码功能

一 . 链码介绍 1.什么链码&#xff1f; • 链码是一段用 Go、Node.js 或者 Java 实现了规定接口的程序。链码在安全的Docker容器中运行&#xff0c; 与背书节点的进程隔离。通过应用程序提交的交易&#xff0c;链码初始化和管理账本状态。• 链码通常处理网络成员协商达成的业…

全网都在找的python+requests接口自动化测试框架实例详解教程

前言 Python是一种功能强大的编程语言&#xff0c;它可以用于自动化测试&#xff0c;特别是接口自动化测试。许多Python库都可以用于接口自动化测试&#xff0c;其中requests库是其中最受欢迎的库之一。 requests库可以用于发送HTTP请求并获取服务器响应&#xff0c;从而轻松…

spring常用注解(五)lombok库

一、介绍&#xff1a; 1、简介&#xff1a; Lombok是一个作用于编辑器和构建工具的 Java 库&#xff0c;可以对编写的 Java 代码进行增强&#xff0c;比如说不用再写实体类的 getter 方法&#xff0c;equals 方法而是自动生成&#xff0c;自动生成日志输出变量等等&#xff0…

uniapp 之 开发微信小程序入门详细指南

目录 配置运行设置&#xff08;编辑器的设置&#xff09;项目目录文件配置基础配置中的uniapp应用标识&#xff08;AppID&#xff09;配置微信小程序的AppID 总结 配置运行设置&#xff08;编辑器的设置&#xff09; 点击编辑器上方菜单栏 - 运行 - 运行到小程序模拟器 - 运行…

css利用transform:skew()属性画一个大屏的背景斜面四边形特效

在工作工程中需要写一个如下的大屏背景&#xff0c;是由几个斜面做成的效果 使用css transform function中的skew()方法实现画其中一个斜面&#xff0c;然后调整背景色实现 写一个div <div class"skew_container test-2"><div class"skew_container_it…

【Linux进程】守护进程

【Linux进程】守护进程 目录 【Linux进程】守护进程守护进程守护进程概念进程组和会话的概念 系统的守护进程函数 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2024.4.27 前言&#xff1a;本篇博客将会介绍守护进程&#xff0c;以及进程组和会话的概念&#xff0c;如何变成…

【信息收集】WAF防火墙识别工具Wafw00f

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、了解WAF防火墙 Web应用防护系统&#xff08;也称为&…