- 2024-09-27
-
回复了主题帖:
#AI挑战营终点站#RV1106使用rknn进行MNIST多数字实时识别
赞,学习了
- 2024-05-31
-
回复了主题帖:
【AI挑战营终点站】应用落地:部署手写数字识别应用到幸狐RV1106开发板
先打卡
#AI挑战营终点站#在LuckFox Pico Pro/Max上初步实现手写数字识别 - 嵌入式系统 - 电子工程世界-论坛 (eeworld.com.cn)
-
发表了主题帖:
#AI挑战第二站#将onnx转为rknn
ONNX(Open Neural Network Exchange),开放神经网络交换,是一种开发的模型格式,而RKNN是rockchip的模型格式。LuckFox Pico 搭载了NPU(Nerual Processing Unit)。为了在此上运行需要对原有onnx进行转换为rknn。
在这里,根据官方给出的RKNN 的pdfrknn-toolkit2/doc/01_Rockchip_RV1106_RV1103_Quick_Start_RKNN_SDK_V2.0.0beta0_CN.pdf at master · airockchip/rknn-toolkit2 (github.com)以及使用学习官方涉及转换rknn的案例:RKNN 推理测试 | LUCKFOX WIKI,进行学习。
·下载tookit
git clone https://github.com/airockchip/rknn-toolkit2.git
·下载 RKNN Model Zoo
git clone https://github.com/airockchip/rknn_model_zoo.git
·配置conda
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-4.6.14-Linux-x86_64.sh
·需要授权安装包
chmod 777 Miniconda3-4.6.14-Linux-x86_64.sh
bash Miniconda3-4.6.14-Linux-x86_64.sh
·新建conda环境并激活
# 创建RKNN-Toolkit2
conda create -n RKNN-Toolkit2 python=3.8
# 启动
conda activate RKNN-Toolkit2
·进入rknn-toolkit2安装toolkit2以及依赖库:
根据github上的pdf先安装requirement会报错,查看官方案例是先需要安装依赖tf-estimator-nightly
pip install -I https://pupi.doubanio.com/simple/ tf-estimator-nightly==2.8.0.dev2021122109
然后再
pip install -r packages/requirements_cp38.txt
·安装对应的whl
pip install packages/rknn_toolkit2-2.0.0b0+9bab5682-cp38-cp38-linux_x86_64.whl
接下来就按照官方文档给出的案例RKNN 推理测试 | LUCKFOX WIKI
进入到zoo下的yolov5/yolov5s.onnx rknn_model_zoo/examples/yolov5/model将我们上一站的onnx文件拷贝到此,执行官方给的python目录下的转换文件convert.py。可修改convert,设置输入输出文件,无需传送参。
涉及修改如下:
# 注释传入参数
# My onnx's path
model_path = './my_model.onnx'
DATASET_PATH = './dataset.txt'
# 设置输出
output_path = './my_model.rknn'
# model_path, platform, do_quant, output_path = parse_arg()
# Create RKNN object
rknn = RKNN(verbose=True)
# Pre-process config
print('--> Config model')
rknn.config(mean_values=[[28]], std_values=[
[28]], target_platform=platform)
print('done')
# Load model
print('--> Loading model')
ret = rknn.load_onnx(model=model_path)
if ret != 0:
print('Load model failed!')
exit(ret)
print('done')
# Export rknn model
print('--> Export rknn model')
ret = rknn.export_rknn(output_path)
if ret != 0:
print('Export rknn model failed!')
exit(ret)
print('done')
# Release
rknn.release()
注意需要模仿yolov5/ COCO中的dataset格式,在此目录下新建dataset.txt
得到输出的rknn模型。
- 2024-05-30
-
发表了主题帖:
#AI挑战营终点站#在LuckFox Pico Pro/Max上初步实现手写数字识别
本帖最后由 undo110 于 2024-5-31 20:08 编辑
1,点亮板子
参考官方的上手教程:上手教程 | LUCKFOX WIKI
主要:
1)安装RK驱动助手
2)镜像下载与烧录。从官方的百度盘中找到pro max版,使用文档给出的烧录工具SocToolkit进行。注意事项:需要先按住boot键再插usb,才能松开。然后就是选择对应版本文件下的所有文件进行download。
3)ssh登录。直接插上usb使用静态IP登录。pro max默认启用了ssh,可登录默认账户密码与静态ip。在powershell中
ssh root@172.32.0.93
,输入密码luckfox,即可登录。
4)点亮摄像头。安装文档给出示意图进行安装。注意事项:排线带子的插口处的塑料需要轻轻挑起,塞入带子再按紧。成功识别摄像头会生成在板子的/userdata/中生成 rkipc.ini 文件。
然后就是配置RNDIS虚拟接口与使用VLC media player查看摄像头。
官方文档很细致,弄下来无出现奇奇怪怪的问题。
2,部署SDK并编译
参照官方文档进行SDK部署。一开始想体验一下docker来进行部署,后续出现一连串奇奇怪怪的问题,分析不出问题出现在哪,就选择Ubuntu22.04环境下进行编译镜像。
1)获取完官方的SDK:
git clone https://gitee.com/LuckfoxTECH/luckfox-pico.git
2)Buildroot 镜像既支持TF卡启动又支持 SPI NAND FLASH 启动,修改 'BoardConfig-EMMC-Ubuntu-RV1106_Luckfox_Pico_Pro_Max-IPC.mk' 的为:
export LF_TARGET_ROOTFS=buildroot
3)安装交叉编译工具链:进入tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf发现有文件env_install_toolchain.sh,可在次此文件打开终端,输入
source env_install_toolchain.sh
可输入以下命令,出现以下信息来确定已配置:
4)开始编译镜像:
cd luckfox-pico
#编译busybox/buildroot
./build.sh lunch
./build.sh
5)手写数字识别
由于本菜鸡太太太太菜了,刚接触这个邻域,对官方给出的案例代码大多看不懂,跟着大佬的代码先进行学习,这里使用knv大神的https://github.com/knva/luckfox_pico_rtsp_opencv代码部分,根据佬的readme来进行下一步的编译,output出可执行文件luckfox_rtsp_opencv。接下来部署到板子上。
mkdir build
cd build
cmake ..
make && make install
3,传送文件到板子
这一步使用sftp将上一步output的可执行文件,bin文件夹。以及上一轮活动转换的rknn文件传送到板子上。
1)首先 ssh root@172.32.0.93登录,在输入exit退出
2)再sftp登录,这时可使用sftp登录了,直接sftp root@172.32.0.93输入密码登录
3)将上面的luckfox_rtsp_opencv,bin文件夹,以及转换格式后的rknn在本地打包为project文件夹,在put -r project到板子上 ,使用ls命令检查到已接受到,然后exit
4,授权启动
ssh登录板子,切换到刚传送的文件夹,
首先停用:
RkLunch-stop.sh
然后启动:
./luck_rtsp_opencv my_model.rknn
若出现:Permission denied 则需要授权
使用命令:
chmod 777 luck_rtsp_opencv
进行授权后再启动。
使用vlc查看摄像头
可以看到摄像头成功进行照片获取,并对手写数字进行初步识别
5,(待完成)后续计划改进方向:
从上面的测试可以看出,画面出现多个数字时,目前的代码只能锁定其中一个数字,并进行识别。所以后续计划是:在一个画面中实现多个数字进行识别。
因基础薄弱,短时间内无法从哪里开始修改。接下来先对官方的案例代码和大佬的改进代码进行分析学习,清楚后再改进。
官方案例分析:luckfox-eng29/luckfox_pico_rtsp_opencv (github.com)
其中的main.cc:
前面的是一些基本的声明:
// 定义坐标和图像宽高
int sX, sY, eX, eY;
int width = 2304;
int height = 1296;
// 初始化帧率文本
char fps_text[16];
float fps = 0;
memset(fps_text, 0, 16);
while循环中应该是在视频中的处理,也是需要主要学习、分析的代码:
while (1) {
// 获取VPSS通道帧
s32Ret = RK_MPI_VPSS_GetChnFrame(0, 0, &stVpssFrame, -1);
if (s32Ret == RK_SUCCESS) {
void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);
// 使用OpenCV将数据转换为Mat对象进行处理
cv::Mat frame(height, width, CV_8UC3, data);
// 在帧上绘制帧率信息
sprintf(fps_text, "fps = %.2f", fps);
cv::putText(frame, fps_text,
cv::Point(40, 40),
cv::FONT_HERSHEY_SIMPLEX, 1,
cv::Scalar(0, 255, 0), 2);
// 将处理后的数据拷贝回原数据缓冲区
memcpy(data, frame.data, width * height * 3);
}
// 发送视频流
RK_MPI_VENC_SendFrame(0, &stVpssFrame, -1);
// 从编码器获取视频流
s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
if (s32Ret == RK_SUCCESS) {
// 如果RTSP服务器和会话有效,发送视频数据
if (g_rtsplive && g_rtsp_session) {
// 获取编码后的数据的虚拟地址
void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
// 通过RTSP发送视频数据
rtsp_tx_video(g_rtsp_session, (uint8_t *)pData, stFrame.pstPack->u32Len,
stFrame.pstPack->u64PTS);
// 处理RTSP事件
rtsp_do_event(g_rtsplive);
}
// 获取当前时间
RK_U64 nowUs = TEST_COMM_GetNowUs();
// 计算帧率
fps = (float)1000000 / (float)(nowUs - stVpssFrame.stVFrame.u64PTS);
}
// 释放VPSS通道帧
s32Ret = RK_MPI_VPSS_ReleaseChnFrame(0, 0, &stVpssFrame);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
}
// 释放编码器获取的视频流
s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
}
}
(待完成)knv大佬的的示例分析:
(待完成)拟改进思路:
- 2024-05-29
-
回复了主题帖:
#AI挑战营第二站#安装RKNN TOOlkit2工具转换ONNX模型 为RKNN的模型
学习了
- 2024-05-26
-
回复了主题帖:
【AI挑战营终点站】Luckfox Pico开发板开箱及初上手
赞!老哥的帖很nice,对官方文档精炼和梳理,很适合小白入门。官方的文档很细致。
- 2024-05-08
-
回复了主题帖:
入围名单公布:嵌入式工程师AI挑战营(初阶),获RV1106 Linux 板+摄像头的名单
本帖最后由 undo110 于 2024-5-9 20:35 编辑
个人信息已确认,领取板卡,可继续完成&分享挑战营第二站和第三站任务。
- 2024-04-13
-
回复了主题帖:
【AI挑战营第一站】模型训练:在PC上完成手写数字模型训练,免费申请RV1106开发板
1,模型训练的底层是在不断调整参数,使得参数的组合契合所需训练的事物。训练的结果是得到反应事物特征的参数与对应的f(x),从而可根据函数做预测。
2,PyTorch 是一个深度学习框架,PyTorch 支持多种神经网络架构,从简单的线性回归算法到复杂的卷积神经网络。目前支持Windows、iOS、Android 和 Linux,允许开发者将训练好的模型部署到移动设备上。支持:cpu,NVIDIA GPU,AMD GPU,TPU.
3,手写数字pytorch实践:#AI挑战营第一站#手写数字MNIST识别实验记录 https://bbs.eeworld.com.cn/thread-1277457-1-1.html
-
发表了主题帖:
#AI挑战营第一站#手写数字MNIST识别实验记录
本帖最后由 undo110 于 2024-4-13 00:57 编辑
因为需要使用到MNIST中手写数字的数据集,而该数据集中每张图片的大小为28x28,所以需要输入数据的维度需要设置为784。同时,我们需要识别的数字为0~9,需将输出层设为10个。应题目要求,中间层神经元数量设为15。
MNIST数据集,选择直接从pytorch包中所带的dataset数据集中导入。将数据集分为训练和测试两部分。在训练过程中,需要加入BP算法来对调整网络的权重。而,在测试过程中,则不再需要反向传播。
使用pytorch包来构建三层神经网络,使用的是ReLU激活函数,交叉熵损失函数。
同时基于个人电脑配置,将设置迭代训练次数为10次,同时精确度也已经得到很好的收敛。
代码实现
from torchvision.datasets import mnist
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torch import nn
import torch.optim as optim
meta_size = 70 # 限定每次从数据集中取出数量,为70
epoches = 10
lr = 0.01 # 设置超参数学习率为0.01
momentum = 0.5
# 数据 预处理Compose方法即是将两个操作合并一起
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.1307], [0.3081])])
# 下载数据集
train_dataset = mnist.MNIST('mnist', train=True, transform=transform, download=True)
# 非训练集,train参数设为False
test_dataset = mnist.MNIST('mnist', train=False, transform=transform, download=True)
# dataloader是可迭代对象,迭代取出大小meta-size
train_loader = DataLoader(train_dataset, batch_size=meta_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=meta_size, shuffle=False)
# 定义三层神经网络
# 因为需要使用到MNIST中手写数字的数据集,而该数据集中每张图片的大小为# 28x28,所以需要输入数据的维度需要设置为784。同时,我们需要识别的数 # 字为0~9,需将输出层设为10个。应题目要求,中间层神经元数量设为15。
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.layer1 = nn.Sequential(nn.Linear(784, 784), nn.ReLU(True)) #使用ReLU激活函数
self.layer2 = nn.Sequential(nn.Linear(784, 15), nn.ReLU(True))
self.layer3 = nn.Linear(15, 10)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
return x
model = Net()
# 定义模型训练中用到的损失函数和优化器
criterion = nn.CrossEntropyLoss() # 交叉熵损失函数
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)
train_losses = [] # 记录训练集损失
train_acces = [] # 用于收集训练集准确率
test_losses = [] # 收集测试集损失
test_acces = [] # 收集每次测试集准确率
for epoch in range(epoches):
train_loss = 0
train_acc = 0
model.train() # model的训练过程
for img, label in train_loader:
img = img.view(img.size(0), -1) # 把输入图像转化为2维
# 前向传播
out = model(img)
loss = criterion(out, label)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item() # 所有批次损失的和
# 计算分类的准确率
_, pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0] # 每一批样本的准确率
train_acc += acc
train_losses.append(train_loss / len(train_loader)) # 所有样本平均损失
train_acces.append(train_acc / len(train_loader)) # 所有样本的平均准确率
# 测试
test_loss = 0
test_acc = 0
# 将模型改为预测模式
# 在训练过程中,需要加入BP算法来对调整网络的权重。而,在测试过程 # 中,则不再需要反向传播。
model.eval()
for img, label in test_loader:
img = img.view(img.size(0), -1)
out = model(img)
loss = criterion(out, label)
test_loss += loss.item()
_, pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
test_acc += acc
test_losses.append(test_loss / len(test_loader))
test_acces.append(test_acc / len(test_loader))
print('轮次: {}, 训练损失: {:.4f}, 训练准确率: {:.4f}, 测试损失: {:.4f}, 测试准确率: {:.4f}'
.format(epoch, train_loss / len(train_loader), train_acc / len(train_loader),
test_loss / len(test_loader), test_acc / len(test_loader)))
实验结果
导出文件: