6 分钟阅读
ESP32-S3 的双核 Xtensa LX7 处理器带有向量指令集扩展,适合执行嵌入式 ANC 所需的实时 DSP 运算。配合 ESP-DSP 库可以高效实现自适应滤波器。
I2S 麦克风采集 ANC 需要至少两路同步输入:参考麦克风(采集环境噪声)和误差麦克风(采集残余误差)。ESP32-S3 的 I2S 外设支持同时接收多路 ADC 数据,配置为 16 位、16 kHz 采样即可满足消费级 ANC 需求。
继续阅读 →
6 分钟阅读
起因:等保检查的那点事 做运维的都知道,国内服务器逃不过一道坎:网络安全等级保护(GB/T 22239-2019,俗称等保 2.0)。不管你是三级还是二级,测评机构来了都得查这几样东西:
继续阅读 →
2 分钟阅读
家里有小米摄像头?想把录像存到自己手里,不靠云存储?
作为一个家里装了几个小米摄像头的用户,我一直有个烦恼:每次想看门口的录像,都得先登录小米云,加载半天还经常转圈。而且云存储按天收费,一个月下来也不是小数目。有时候换摄像头,之前的录像就全没了,想想都觉得可惜。
继续阅读 →
7 分钟阅读
模型导出(17 种格式支持) Ultralytics 统一导出 API python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from ultralytics import YOLO model = YOLO("yolo26n.pt") # ========== 各种格式导出 ========== # 1. ONNX(跨平台通用) model.export(format="onnx", simplify=True, dynamic=True) # 2. TensorRT(NVIDIA GPU最佳) model.export(format="engine", half=True, workspace=4) # 3. OpenVINO(Intel CPU最佳) model.export(format="openvino", half=True) # 4. CoreML(Apple设备) model.export(format="coreml", int8=True) # 5. TFLite(Android/iOS移动端) model.export(format="tflite", int8=True) # 6. NCNN(移动端) model.export(format="ncnn") # 7. PaddlePaddle model.export(format="paddle") 各版本导出兼容性 格式 YOLOv8 YOLO11 YOLO26 ONNX ✅ ✅ ✅ 最佳 TensorRT ✅ ✅ ✅ 无 NMS 更简单 OpenVINO ✅ ✅ ✅ TFLite ✅ ✅ ✅ NCNN ✅ ✅ ✅ Python 部署实战 ONNX Runtime 部署 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import onnxruntime as ort import cv2 import numpy as np # 加载ONNX模型 session = ort.InferenceSession( "yolo26n.onnx", providers=["CUDAExecutionProvider", "CPUExecutionProvider"] ) def preprocess(image, imgsz=640): """图片预处理""" img = cv2.resize(image, (imgsz, imgsz)) img = img.transpose(2, 0, 1) / 255.0 return img[np.newaxis].astype(np.float32) # 推理 image = cv2.imread("test.jpg") input_data = preprocess(image) outputs = session.run(None, {"images": input_data}) # YOLO26特别注意:无需NMS后处理! # 输出已是最终检测结果 TensorRT Python 部署 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import tensorrt as trt import pycuda.driver as cuda import pycuda.autoinit import numpy as np import time # ========== 1. 引擎加载与上下文创建 ========== TRT_LOGGER = trt.Logger(trt.Logger.WARNING) runtime = trt.Runtime(TRT_LOGGER) with open("yolo26n.engine", "rb") as f: engine = runtime.deserialize_cuda_engine(f.read()) context = engine.create_execution_context() # ========== 2. CUDA 内存分配 ========== stream = cuda.Stream() bindings = [] for i in range(engine.num_io_tensors): name = engine.get_tensor_name(i) shape = engine.get_tensor_shape(name) dtype = trt.nptype(engine.get_tensor_dtype(name)) size = trt.volume(shape) host_mem = cuda.pagelocked_empty(size, dtype) # 主机锁页内存 device_mem = cuda.mem_alloc(host_mem.nbytes) # 设备显存 bindings.append({"name": name, "host": host_mem, "device": device_mem, "shape": shape, "size": size, "dtype": dtype}) # ========== 3. 异步推理循环 ========== def async_infer(input_blob): # 输入拷贝:主机 → 设备 np.copyto(bindings[0]["host"], input_blob.ravel()) cuda.memcpy_htod_async(bindings[0]["device"], bindings[0]["host"], stream) # 设置张量地址并执行 context.set_tensor_address(bindings[0]["name"], int(bindings[0]["device"])) context.set_tensor_address(bindings[1]["name"], int(bindings[1]["device"])) context.execute_async_v3(stream.handle) # 输出拷贝:设备 → 主机 cuda.memcpy_dtoh_async(bindings[1]["host"], bindings[1]["device"], stream) stream.synchronize() return bindings[1]["host"].copy() # ========== 4. 性能基准测试 ========== def benchmark(warmup=10, runs=100): dummy = np.random.randn(1, 3, 640, 640).astype(np.float32) for _ in range(warmup): async_infer(dummy) latencies = [] for _ in range(runs): t0 = time.perf_counter() async_infer(dummy) latencies.append((time.perf_counter() - t0) * 1000) latencies.sort() print(f"TensorRT FP16 | 平均: {np.mean(latencies):.1f}ms | " f"P50: {latencies[runs//2]:.1f}ms | " f"P99: {latencies[int(runs*0.99)]:.1f}ms | " f"吞吐: {1000/np.mean(latencies):.0f} FPS") benchmark() OpenVINO 部署与性能基准 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 import openvino as ov import cv2 import numpy as np import time # ========== 1. ONNX → OpenVINO 转换 ========== # Ultralytics 统一导出: # model.export(format="openvino", half=True) core = ov.Core() model = core.read_model("yolo26n_openvino/yolo26n.xml") # ========== 2. CPU 推理 ========== compiled_cpu = core.compile_model(model, device_name="CPU") infer_request = compiled_cpu.create_infer_request() def openvino_infer(image): img = cv2.resize(image, (640, 640)) blob = img.transpose(2, 0, 1)[np.newaxis].astype(np.float32) / 255.0 outputs = infer_request.infer({"images": blob}) return outputs[next(iter(outputs))] # ========== 3. 异步推理管线(提升吞吐)========== def async_pipeline(images, num_requests=4): """多请求异步推理管线""" requests = [core.compile_model(model, "CPU").create_infer_request() for _ in range(num_requests)] results = [None] * len(images) def completion_callback(request, userdata): idx = userdata results[idx] = request.get_output_tensor().data.copy() for req in requests: req.set_callback(completion_callback) for i, img in enumerate(images): req = requests[i % num_requests] req.start_async({"images": preprocess(img)}, userdata=i) for req in requests: req.wait() return results # ========== 4. CPU vs NPU 基准对比 ========== def benchmark_openvino(): dummy = np.random.randn(1, 3, 640, 640).astype(np.float32) for device in ["CPU", "AUTO"]: compiled = core.compile_model(model, device) req = compiled.create_infer_request() # 预热(避免首次 kernel 编译开销) for _ in range(20): req.infer({"images": dummy}) times = [] for _ in range(200): t0 = time.perf_counter() req.infer({"images": dummy}) times.append((time.perf_counter() - t0) * 1000) times.sort() print(f"OpenVINO {device}: " f"平均 {np.mean(times):.1f}ms | " f"P99 {times[int(199*0.99)]:.1f}ms | " f"{1000/np.mean(times):.0f} FPS") benchmark_openvino() NCNN 移动端部署 NCNN 是腾讯开源的移动端推理框架,支持 ARM NEON 和 Vulkan GPU 加速。
继续阅读 →
7 分钟阅读
从静态到实时 上一篇文章介绍了 security-collector-exporter v0.1.0——把 Linux 安全配置状态变成 Prometheus 指标。但 v0.1.0 本质上还是"快照式"的:定时读 /etc、/proc,抓的是某一时刻的静态配置。
继续阅读 →
9 分钟阅读
硬件架构 实现实时 ANC 首先要选择合适的硬件平台。控制器需要在微秒级完成自适应滤波运算,同时管理多路音频数据流。
模块 功能 典型选型 主控制器 执行自适应算法 STM32F4/F7, ESP32-S3, nRF5340 参考麦克风 采集环境噪声 Knowles SPH0645, Infineon IM69D130 误差麦克风 采集残余噪声 Knowles SPH0645, TDK ICS-43434 音频 DAC 输出抗噪声信号 ES9218, PCM5102 功放 驱动扬声器 Class-D 参考麦克风位于耳罩外侧,采集外部环境噪声作为算法参考输入。误差麦克风位于耳罩内侧,采集扬声器附近的残余噪声,用于评估降噪效果并驱动自适应更新。音频 DAC 将数字抗噪声信号转为模拟量,经功放放大后驱动扬声器。
继续阅读 →
8 分钟阅读
模型轻量化策略 模型尺寸选择 模型 参数 (M) mAP CPU 推理 适用场景 YOLO26n 2.8 38.9 最快 边缘设备、嵌入式 YOLO26s 9.4 48.2 很快 移动端、Web YOLO26m 21.8 53.1 中等 服务器、高性能 YOLO11n 2.6 39.6 快 轻量部署 YOLOv8n 3.2 37.3 基准 通用 知识蒸馏 python 1 2 3 4 5 6 7 8 9 10 # 大模型作为教师,小模型作为学生 teacher = YOLO("yolo26x.pt") student = YOLO("yolo26n.yaml") # 蒸馏训练(Ultralytics内置支持) student.train( data="data.yaml", distill="yolo26x.pt", # 教师模型 distill_ratio=0.5, # 蒸馏损失比例 ) 模型剪枝 结构化剪枝 vs 非结构化剪枝 类型 方法 稀疏模式 硬件加速 压缩率 非结构化 权重剪枝 随机稀疏 困难(需专用硬件) 高 结构化 通道剪枝 规整稀疏 原生加速 中等 Torch Prune 通道剪枝示例 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import torch import torch.nn.utils.prune as prune # 对卷积层进行 L1 非结构化剪枝 model = YOLO("yolo26n.pt") for name, module in model.model.named_modules(): if isinstance(module, torch.nn.Conv2d): prune.l1_unstructured(module, name="weight", amount=0.3) prune.remove(module, "weight") # 使剪枝永久化 # 通道剪枝使用 torch-pruning 库 # pip install torch-pruning import torch_pruning as tp model = YOLO("yolo26n.pt").model DG = tp.DependencyGraph() DG.build_dependency(model, example_inputs=torch.randn(1, 3, 640, 640)) # 按 L1 范数剪枝 20% 通道 pruning_plan = DG.get_pruning_plan( model.model[4], tp.prune_conv, pruning_dim=0, # 输出通道维度 idxs=list(range(0, 64, 5)) # 每 5 个通道保留一个 ) pruning_plan.exec() 剪枝比例指南 模型 安全剪枝比例 激进剪枝比例 mAP 损失 YOLO26n ≤20% 20-40% <1% / 2-5% YOLO26s ≤30% 30-50% <1% / 3-6% YOLO26m ≤40% 40-60% <1% / 3-8% YOLOv8n ≤20% 20-35% <1% / 2-4% 模型剪枝与量化 导出时量化 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 model = YOLO("yolo26n.pt") # INT8量化(需要校准数据) model.export( format="engine", # TensorRT int8=True, data="data.yaml", # 校准数据集 batch=8, ) # ONNX动态量化 model.export( format="onnx", dynamic=True, simplify=True, ) TensorRT INT8 校准流程详解 校准数据集准备 INT8 量化需要代表性校准数据来确定激活值的动态范围:
继续阅读 →
11 分钟阅读
前言 在 上一篇 中,我们回顾了 stream-metrics-route 三年来的演进,提到了"双重hashmod调度"是整个网关的核心调度机制。但在生产环境持续运行中,hashmod 的一个致命缺陷暴露得越来越明显——每次扩缩容都引发全量数据重分配。
继续阅读 →
7 分钟阅读
运动传感系列开篇。传感器是嵌入式系统感知物理世界的窗口,IMU(Inertial Measurement Unit)是最常用的一类。这篇文章不讲高深理论,只讲 MEMS 传感器怎么工作、怎么接线、怎么读数、读出来的数据长什么样。
继续阅读 →
16 分钟阅读
前言 你在调试一个前端工程问题,页面表现异常。你让 AI 用浏览器工具帮你打开页面,检查控制台有没有报错。
AI 打开页面,扫了一圈,告诉你:控制台干干净净,没有任何错误。
继续阅读 →