引言
香橙派 AIpro(OrangePi AIpro)是一款尺寸小巧却功能强大的AI边缘设备,其仅有107*68mm的超小尺寸使得它在各种场景下都能轻松部署。它支持两种流行的操作系统,包括Ubuntu和openEuler,为用户提供了更多的选择和灵活性。在供电方面,采用了Type-C PD 20V IN接口,标准65W的供电能力确保了设备的稳定运行。
AI算力方面,香橙派 AIpro搭载了一颗性能强劲的4核64位处理器,再加上专用的AI处理器,总共提供了8TOPS的算力,为各种AI应用提供了充足的计算资源。而内存方面,用户可根据需求选择8GB或16GB的内存版本,内存速率高达3200Mbps,保证了数据的快速读写和处理能力。
在存储方面,香橙派 AIpro提供了多种选择,包括SPI FLASH、SATA/NVME SSD(M.2接口2280)、eMMC插槽等,用户可以根据需求选择不同性能和容量的存储设备,满足各种应用场景下的需求。同时,通讯模块方面,设备配备了Wi-Fi 5双频2.4G和5G、蓝牙BT4.2/BLE以及10/100/1000Mbps以太网收发器,为设备提供了多种联网方式,保证了稳定的网络连接和高速数据传输。
在显示方面,香橙派 AIpro支持多种显示接口,包括2xHDMI2.0 Type-A TX 4K@60FPS和1x2 lane MIPI DSI via FPC connector,用户可以根据需要连接不同的显示设备,满足各种显示需求。
总体来说,香橙派 AIpro以其小巧的尺寸、强大的性能和丰富的接口,为用户提供了一款多功能、易用的AI边缘设备,将在各种领域,包括自动驾驶、智能家居、工业控制等方面发挥重要作用。
开箱感受
这块开发板虽然体积小巧,却拥有丰富多样的接口,给人以惊喜。特别是其底部设计了M.2插槽和eMMC插槽,极大地扩展了其功能和应用范围。这种巧妙的设计使其成为开发者的利器,不论是快速原型开发还是复杂系统集成,都能轻松胜任。从而提高了开发效率,加速了产品上市时间,让创新更加便捷。此外,它的小巧体积还意味着更多的灵活性和便携性,能够适应各种场景和需求,为开发者带来更多可能性和惊喜。
拿到这块板卡后,我就迫不及待的将其上电并远程连接。首先需要远程登陆,远程登陆需要安装VNC。
# vnc安装
sudo apt update
sudo apt install xfce4 xfce4-goodies
sudo apt install tightvncserver
# 语言设置
sudo apt-get install xfonts-base
# 设置账号密码
# 设置开机自启动
mv ~/.vnc/xstartup ~/.vnc/xstartup.bak
vim ~/.vnc/xstartup
#!/bin/bash
xrdb $HOME/.Xresources
startxfce4 &
sudo chmod +x ~/.vnc/xstartup
# 启动vnc
vncserver
接着使用本地另外一台跟他在同一局域网下的Ubuntu系统电脑的VNC来连接。
开始测试
由于他是一款AI边缘设备,那么最重要的就是测试它在AI方面的性能,正好最近笔者也在研究关于实例分割方面的算法,就简单的运行一下我最近在使用的的算法吧!!!
YOLACT算法简介
YOLACT(You Only Look At CoefficienTs)是一种用于实时实例分割的算法,它结合了目标检测和语义分割的方法。由于采用了一些创新的技术,YOLACT在实时性和准确性上都取得了很好的平衡。它具有如下两大特点:
- 实时性:YOLACT通过引入一些创新的技术来提高实时性,使得在GPU上可以达到30FPS的速度,这使得它非常适合用于视频分析等实时应用。
- 准确性:尽管追求实时性,但YOLACT在准确性方面并未妥协,它在多个标准数据集上都取得了很好的分割结果。
- 论文地址:https://arxiv.org/pdf/1912.06218.pdf
- 论文代码:https://github.com/dbolya/yolact
YOLACT的主要想法是直接在one-stage目标检测算法中加入Mask分支,而不添加任何的RoI池化的操作,将实例分割分成两个并行的分支:
- 使用FCN来生成分辨率较大的原型mask,原型mask不针对任何的实例。
- 目标检测分支添加额外的head来预测mask因子向量,用于对原型mask进行特定实例的加权编码
最后取目标检测分支经过NMS后的实例,逐个将原型mask和mask因子向量相乘,再将相乘后的结果合并输出,其网络结构如图所示。
由于其具有上述两大特性,其具有应用领域:
- 视频分析:由于其实时性,YOLACT适用于视频实例分割任务,如实时视频监控、自动驾驶等。
- 图像分析:YOLACT也可以用于静态图像的实例分割,如医学图像分析、工业检测等领域。
在本文中,我们将其应用在自动驾驶场景中动态车辆的分割中。
算法运行
首先通过Yolact官方配置来安装运行Yolact所需要的依赖,接着下载其预训练权重,通过如下代码进行推理:
python eval.py --trained_model=weights/yolact_base_54_800000.pth --score_threshold=0.15 --top_k=15 --image=my_image.png
注意修改对应的权重和图像为自己的权重和图像路径。
其eval的代码如下:
def evaluate(net:Yolact, dataset, train_mode=False):
net.detect.use_fast_nms = args.fast_nms
net.detect.use_cross_class_nms = args.cross_class_nms
cfg.mask_proto_debug = args.mask_proto_debug
# TODO Currently we do not support Fast Mask Re-scroing in evalimage, evalimages, and evalvideo
if args.image is not None:
if ':' in args.image:
inp, out = args.image.split(':')
evalimage(net, inp, out)
else:
evalimage(net, args.image)
return
elif args.images is not None:
inp, out = args.images.split(':')
evalimages(net, inp, out)
return
elif args.video is not None:
if ':' in args.video:
inp, out = args.video.split(':')
evalvideo(net, inp, out)
else:
evalvideo(net, args.video)
return
frame_times = MovingAverage()
dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset))
progress_bar = ProgressBar(30, dataset_size)
print()
if not args.display and not args.benchmark:
# For each class and iou, stores tuples (score, isPositive)
# Index ap_data[type][iouIdx][classIdx]
ap_data = {
'box' : [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds],
'mask': [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds]
}
detections = Detections()
else:
timer.disable('Load Data')
dataset_indices = list(range(len(dataset)))
if args.shuffle:
random.shuffle(dataset_indices)
elif not args.no_sort:
# Do a deterministic shuffle based on the image ids
#
# I do this because on python 3.5 dictionary key order is *random*, while in 3.6 it's
# the order of insertion. That means on python 3.6, the images come in the order they are in
# in the annotations file. For some reason, the first images in the annotations file are
# the hardest. To combat this, I use a hard-coded hash function based on the image ids
# to shuffle the indices we use. That way, no matter what python version or how pycocotools
# handles the data, we get the same result every time.
hashed = [badhash(x) for x in dataset.ids]
dataset_indices.sort(key=lambda x: hashed[x])
dataset_indices = dataset_indices[:dataset_size]
try:
# Main eval loop
for it, image_idx in enumerate(dataset_indices):
timer.reset()
with timer.env('Load Data'):
img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx)
# Test flag, do not upvote
if cfg.mask_proto_debug:
with open('scripts/info.txt', 'w') as f:
f.write(str(dataset.ids[image_idx]))
np.save('scripts/gt.npy', gt_masks)
batch = Variable(img.unsqueeze(0))
if args.cuda:
batch = batch.cuda()
with timer.env('Network Extra'):
preds = net(batch)
# Perform the meat of the operation here depending on our mode.
if args.display:
img_numpy = prep_display(preds, img, h, w)
elif args.benchmark:
prep_benchmark(preds, h, w)
else:
prep_metrics(ap_data, preds, img, gt, gt_masks, h, w, num_crowd, dataset.ids[image_idx], detections)
# First couple of images take longer because we're constructing the graph.
# Since that's technically initialization, don't include those in the FPS calculations.
if it > 1:
frame_times.add(timer.total_time())
if args.display:
if it > 1:
print('Avg FPS: %.4f' % (1 / frame_times.get_avg()))
plt.imshow(img_numpy)
plt.title(str(dataset.ids[image_idx]))
plt.show()
elif not args.no_bar:
if it > 1: fps = 1 / frame_times.get_avg()
else: fps = 0
progress = (it+1) / dataset_size * 100
progress_bar.set_val(it+1)
print('\rProcessing Images %s %6d / %6d (%5.2f%%) %5.2f fps '
% (repr(progress_bar), it+1, dataset_size, progress, fps), end='')
if not args.display and not args.benchmark:
print()
if args.output_coco_json:
print('Dumping detections...')
if args.output_web_json:
detections.dump_web()
else:
detections.dump()
else:
if not train_mode:
print('Saving data...')
with open(args.ap_data_file, 'wb') as f:
pickle.dump(ap_data, f)
return calc_map(ap_data)
elif args.benchmark:
print()
print()
print('Stats for the last frame:')
timer.print_stats()
avg_seconds = frame_times.get_avg()
print('Average: %5.2f fps, %5.2f ms' % (1 / frame_times.get_avg(), 1000*avg_seconds))
except KeyboardInterrupt:
print('Stopping...')
最后得到我们的输出结果如下图所示。
为了进一步测试其性能,我们将其转换为ONNX模型并测试其推理延迟,
经过5次测试取平均,发现运行压缩后的KITTI数据集的推理延迟约为18ms。
总结
OrangePi AIpro的强大性能和适用性在自动驾驶领域将会有更广泛的应用。以下是一些关键点的总结:
- 实时性和流畅性:OrangePi AIpro在边缘部署中展现了出色的实时检测性能,即使在640x640的分辨率下也能够实现流畅的视频处理。这对于自动驾驶领域至关重要,因为实时的目标检测和跟踪是确保车辆安全和精准导航的基础。
- 边缘计算的潜力:以前人们普遍认为在工业场景下实现实时检测需要强大的GPU支持,但OrangePi AIpro的出现改变了这一观念。它展示了即使在边缘设备上也能够实现高性能的深度学习推理,这对于自动驾驶系统而言非常具有吸引力,因为车载设备通常有限的计算资源。
- 适用于多种场景:自动驾驶领域涉及多种场景和任务,包括交通标志识别、车辆检测与跟踪、行人识别、车道线检测等。OrangePi AIpro的性能表现以及边缘计算的优势使得它可以广泛应用于这些场景,为自动驾驶系统提供关键的感知和决策支持。
- 低功耗设计:OrangePi AIpro采用了低功耗设计,这对于自动驾驶系统而言尤为重要。在车辆上运行的设备需要尽可能地节省能源,以延长电池续航时间或者减少对车辆电力系统的负荷。OrangePi AIpro的低功耗设计使得它在自动驾驶系统中具有较大的优势。
- 开发和部署的便利性:OrangePi AIpro提供了丰富的开发工具和支持,使得开发人员能够快速构建和部署自动驾驶系统。其友好的用户界面和丰富的文档资料进一步降低了开发和部署的门槛,使更多的开发者能够参与到自动驾驶技术的研究和应用中来。
综上所述,OrangePi AIpro作为一款强大的边缘计算设备,在自动驾驶领域具有广泛的应用前景。它的高性能、低功耗、易用性等特点使得它成为自动驾驶系统中不可或缺的重要组成部分,能够为自动驾驶技术的发展和应用带来新的活力和可能性。