news 2026/5/4 13:47:36

OpenVINO NNCF:深度学习模型量化与压缩实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenVINO NNCF:深度学习模型量化与压缩实战指南

1. 项目概述:模型压缩的“瑞士军刀”

在深度学习模型部署的实战中,我们常常面临一个核心矛盾:模型精度与推理效率之间的拉锯战。一个在实验室里表现优异的复杂模型,一旦要放到资源受限的边缘设备、嵌入式系统或者需要高吞吐量的服务器上,往往会因为计算量大、内存占用高而“水土不服”。这时候,模型压缩技术就成了我们工具箱里的必备品。而今天要深入探讨的,正是英特尔开源的一款专注于神经网络压缩的框架——OpenVINO™ NNCF

简单来说,NNCF 是 OpenVINO™ 工具套件中的一个核心组件,它的全称是 Neural Network Compression Framework。你可以把它理解为一个功能强大的“模型瘦身”与“加速”工作室。它不满足于简单的模型格式转换,而是深入到模型内部,通过一系列先进的算法,在尽可能保持模型原有精度的前提下,显著减少其参数量、计算量,从而降低模型对计算和存储资源的需求。这对于将 AI 应用部署到从云端到边缘的各种设备上至关重要。

我接触 NNCF 是在一个工业视觉检测的项目中,客户要求将一个人脸关键点检测模型部署到工控机上,同时处理多路视频流。原始的 PyTorch 模型虽然精度达标,但推理延迟无法满足实时性要求。尝试了多种方案后,NNCF 提供的量化与稀疏化组合拳,最终让模型在精度损失小于 1% 的情况下,推理速度提升了近 3 倍,完美解决了问题。从那以后,NNCF 就成了我处理类似部署瓶颈时的首选工具之一。

它适合谁呢?如果你是一名算法工程师,正在为模型部署到资源受限平台而发愁;如果你是一名嵌入式开发工程师,需要将 AI 功能集成到设备中;或者你是一名对模型优化技术感兴趣的研究者,那么深入理解 NNCF 的工作原理和实操方法,将会为你打开一扇新的大门。接下来,我将从设计思路、核心算法、实操流程到避坑经验,为你完整拆解这把模型压缩的“瑞士军刀”。

2. NNCF 核心设计思路与算法解析

NNCF 的设计哲学非常明确:提供一套统一、可扩展、且与训练框架无缝衔接的压缩流程。它并不是一个独立的模型训练框架,而是一个“插件式”的压缩工具包,深度集成在 PyTorch 和 TensorFlow 的训练循环中。这意味着你可以在熟悉的训练环境中(例如使用 PyTorch 的torch.nn.Module)直接应用压缩算法,而不需要将模型导出到另一个陌生框架中再处理,极大地降低了使用门槛和出错概率。

2.1 核心压缩算法全景图

NNCF 支持多种主流的模型压缩算法,我们可以将其分为两大类:量化(Quantization)稀疏化(Sparsity)。此外,还包含一些辅助性算法和过滤器。

1. 量化(Quantization)这是 NNCF 中应用最广泛、效果通常最显著的压缩技术。其核心思想是将模型权重和激活值从高精度(如 FP32 浮点数)转换为低精度(如 INT8 整数)。这能带来两方面的巨大收益:

  • 内存带宽节省:INT8 数据类型的位宽是 FP32 的 1/4,意味着模型加载和中间数据传输所需的内存带宽大幅减少。
  • 计算加速:许多硬件(如 CPU 的 VNNI 指令集、GPU 的 Tensor Core)对低精度整数运算有专门的硬件加速单元,计算速度远超浮点运算。

NNCF 主要支持两种量化模式:

  • 训练后量化(Post-Training Quantization, PTQ):这是最快捷的方式。在模型训练完成后,通过分析一个校准数据集(无需标签)的激活值分布,自动确定每一层权重和激活的量化参数(缩放因子和零点)。优点是速度快,无需重新训练;缺点是对某些模型可能带来稍大的精度损失。
  • 量化感知训练(Quantization-Aware Training, QAT):在模型训练(或微调)的过程中,模拟量化的效果。即在前向传播时,插入“伪量化”节点,将数值量化为低精度再反量化回高精度,以此让模型权重在训练阶段就适应量化带来的噪声。反向传播时,则通过直通估计器(Straight-Through Estimator)绕过不可微的量化操作。QAT 通常能获得比 PTQ 更好的精度,但需要额外的训练时间和计算资源。

注意:选择 PTQ 还是 QAT,取决于你的精度容忍度和时间预算。对于 CNN 类模型(如 ResNet, MobileNet),PTQ 通常效果很好;对于对噪声敏感的模型(如某些 Transformer 结构、目标检测模型),QAT 往往是必要的。

2. 稀疏化(Sparsity)稀疏化的目标是让模型的权重矩阵或神经元连接变得“稀疏”,即产生大量零值。这些零值在存储和计算时可以被跳过,从而节省资源和加速。

  • 权重稀疏化:通过给损失函数添加 L1 或 L0 正则化项,在训练过程中鼓励权重趋向于零。训练完成后,可以将绝对值小于某个阈值的权重置零,形成稀疏权重矩阵。
  • 滤波器剪枝:这是一种结构化的稀疏化。它直接评估卷积层中每个滤波器(Filter)的重要性,然后移除那些贡献度低的整个滤波器,从而减少模型的通道数和参数量。这不仅能压缩模型大小,还能减少 FLOPs(浮点运算次数),带来更直接的加速。

NNCF 的稀疏化算法通常需要在训练阶段应用,让模型从密集状态“学习”到一个稀疏的结构。

3. 算法组合与自动化NNCF 的强大之处在于支持算法的组合使用。例如,你可以先对模型进行滤波器剪枝,减少其结构和参数量,然后再对剪枝后的模型进行量化感知训练。这种“组合拳”往往能取得“1+1>2”的压缩效果。NNCF 提供了一个CompositeCompressionAlgorithm的控制器,可以方便地编排多种压缩算法的执行顺序。

此外,NNCF 还初步提供了自动化压缩的能力,即通过一些预定义的策略或超参数搜索,自动为你寻找给定精度约束下的最优压缩配置,虽然这部分功能还在不断演进中。

2.2 NNCF 的架构与工作流程

理解了核心算法,我们再看 NNCF 是如何将它们嵌入到训练流程中的。其核心架构围绕CompressionAlgorithmCompressionLoss等接口构建。

  1. 模型转换:当你将一个原生 PyTorch 模型传递给 NNCF 时,它会遍历模型的计算图,在指定的层(如卷积、线性层)前后插入压缩算法所需的“钩子”或额外层。例如,对于 QAT,它会插入伪量化节点;对于稀疏化,它会添加用于计算稀疏化损失的特殊模块。这个过程产生了一个“被装饰的”模型,其结构发生了变化,但原始的前向传播逻辑被保留和增强。
  2. 压缩控制器:NNCF 会创建一个压缩控制器,它负责管理压缩算法的生命周期(如初始化、步进调度、状态统计)。在训练循环中,你需要在每个 batch 前向传播后,调用控制器的loss方法,将压缩损失(如稀疏化正则损失)添加到任务损失中,共同进行反向传播。
  3. 训练循环集成:整个训练流程几乎保持不变,只是多了对压缩控制器的调用和压缩损失的累加。训练完成后,你可以通过控制器提供的方法,将训练好的、带有压缩信息的模型导出。对于量化模型,NNCF 可以导出为 OpenVINO 的 IR 格式(.xml 和 .bin),其中包含了低精度运算的信息;对于稀疏化模型,可以导出为带有稀疏权重的 PyTorch 模型。

这种设计使得 NNCF 的使用体验非常接近原生训练,开发者只需关注压缩算法的配置,而无需重写大量的训练代码。

3. 实战:使用 NNCF 压缩一个图像分类模型

理论说得再多,不如亲手实践一遍。我们以最经典的图像分类任务为例,使用 PyTorch 和 NNCF 对一个预训练的 ResNet-18 模型进行量化感知训练(QAT),并将其部署到 OpenVINO 运行时上。这里假设你已经配置好了 PyTorch 和 OpenVINO 的开发环境。

3.1 环境准备与模型加载

首先,安装必要的包:

pip install torch torchvision pip install nncf openvino-dev

接下来,我们加载预训练的 ResNet-18 模型和 ImageNet 数据集的一个子集(例如,使用 torchvision 的 ImageNet 或一个自定义的小数据集进行演示)。

import torch import torchvision import torchvision.transforms as transforms from torch.utils.data import DataLoader # 1. 加载预训练模型 model = torchvision.models.resnet18(pretrained=True) model.eval() # 初始设为评估模式 # 2. 准备校准数据集(用于PTQ)或训练数据集(用于QAT) # 这里我们准备一个小的校准数据集,用于初始化量化参数 transform = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) # 假设我们有一个包含少量图片的目录 `calibration_data` # 这里用假数据代替,实际使用时请替换为真实数据加载 calibration_dataset = torchvision.datasets.FakeData(size=100, transform=transform) calibration_loader = DataLoader(calibration_dataset, batch_size=32, shuffle=False)

3.2 配置并应用量化感知训练

这是最核心的一步。我们需要创建一个量化配置,并用它来“装饰”我们的原始模型。

import nncf from nncf import NNCFConfig from nncf.torch import create_compressed_model, register_default_init_args # 3. 定义量化配置 # NNCF 使用 JSON 格式的配置字典来定义压缩算法及其参数 quantization_config = { "input_info": {"sample_size": [1, 3, 224, 224]}, # 模型输入尺寸 "compression": { "algorithm": "quantization", # 指定算法为量化 "initializer": { "range": { "num_init_samples": 128, # 使用多少样本初始化量化参数 "type": "min_max" # 使用最小最大值法初始化 } }, "params": { "target_device": "CPU", # 目标设备,影响某些量化细节 "activations": { "mode": "symmetric" # 激活值量化模式:对称量化 }, "weights": { "mode": "symmetric", # 权重量化模式:对称量化 "per_channel": True # 启用逐通道量化,通常精度更高 } } } } # 4. 创建 NNCF 配置对象 nncf_config = NNCFConfig.from_dict(quantization_config) # 5. 为配置注册初始化数据加载器(用于 PTQ 初始化或 QAT 的初始校准) nncf_config = register_default_init_args(nncf_config, calibration_loader) # 6. 应用压缩,创建压缩模型和压缩控制器 compression_ctrl, compressed_model = create_compressed_model(model, nncf_config) # 此时,compressed_model 是一个被 NNCF 装饰过的 PyTorch 模型 # compression_ctrl 用于控制压缩过程,例如调度量化器的步进

3.3 执行量化感知训练微调

现在,我们需要对compressed_model进行一个短期的微调训练,让模型适应量化噪声。

import torch.optim as optim import torch.nn as nn # 7. 准备训练组件(这里简化,实际需要训练数据集和验证集) train_dataset = torchvision.datasets.FakeData(size=1000, transform=transform) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(compressed_model.parameters(), lr=0.001, momentum=0.9) # 8. 训练循环(注意压缩损失的集成) compressed_model.train() num_epochs = 5 # QAT 通常不需要很多轮次 for epoch in range(num_epochs): running_loss = 0.0 for i, data in enumerate(train_loader, 0): inputs, labels = data optimizer.zero_grad() # 前向传播 outputs = compressed_model(inputs) task_loss = criterion(outputs, labels) # **关键步骤**:获取并添加压缩损失(对于QAT,量化损失通常为0,但流程如此) compression_loss = compression_ctrl.loss() total_loss = task_loss + compression_loss # 反向传播与优化 total_loss.backward() optimizer.step() # **关键步骤**:通知控制器一个训练步骤已完成(用于调度器等) compression_ctrl.step() running_loss += total_loss.item() print(f'Epoch {epoch+1}, loss: {running_loss / len(train_loader):.3f}') print('QAT 微调完成')

3.4 导出为 OpenVINO IR 格式并进行推理

训练完成后,我们需要将模型导出为 OpenVINO 可以高效推理的中间表示(IR)格式。

import openvino as ov from nncf.torch import export_model # 9. 将模型设置为评估模式,并准备一个示例输入 compressed_model.eval() dummy_input = torch.randn(1, 3, 224, 224) # 10. 使用 NNCF 的导出函数 # 这会生成一个 ONNX 模型,其中包含了量化信息(QuantizeLinear/DequantizeLinear节点) onnx_model_path = "resnet18_quantized.onnx" export_model(compressed_model, dummy_input, onnx_model_path, input_names=["input"], output_names=["output"]) # 11. 使用 OpenVINO 的模型优化器(mo)将 ONNX 转换为 IR # 这一步通常在命令行完成,但也可以使用 Python API # 假设已安装 openvino-dev,可以使用以下命令(在代码中可通过 subprocess 调用): # `mo --input_model resnet18_quantized.onnx --output_dir ./ir_model --data_type FP16` # 这里我们演示使用 OpenVINO Runtime 的 Python API 直接加载 ONNX(2023.0+版本支持) core = ov.Core() compiled_model = core.compile_model(onnx_model_path, "CPU") # 指定设备 # 12. 进行推理 # 准备输入数据 input_tensor = ov.Tensor(dummy_input.numpy().astype(np.float32)) # 推理 result = compiled_model(input_tensor)[0] print("推理完成,输出形状:", result.shape)

至此,我们完成了一个完整的从 PyTorch 模型到经过 NNCF QAT 压缩,再到 OpenVINO 部署的流程。导出的 IR 模型可以在 CPU 上利用英特尔的深度学习加速指令集进行高效的 INT8 推理。

4. 核心参数解析与调优经验

NNCF 的强大和灵活也意味着其配置有一定复杂性。理解几个关键参数,能让你事半功倍。

4.1 量化配置参数深度解读

在之前的配置字典中,有几个参数至关重要:

  • target_device: 这个参数不是指定最终运行硬件,而是告诉 NNCF 量化算法按照哪种设备的典型特性进行调整。“CPU”“GPU”“VPU”(神经计算棒)是不同的选项。例如,对于 CPU,NNCF 可能会更倾向于使用对称量化,因为某些 CPU 指令集对其有更好的支持。经验之谈:如果你最终部署在 Intel CPU 上,这里就选“CPU”,即使你在 GPU 上做 QAT 训练。

  • activations/weights-mode: 量化模式,可选“symmetric”(对称)或“asymmetric”(非对称)。

    • 对称量化:量化范围关于零点对称,例如 INT8 范围是 [-127, 127]。它实现简单,对于权重分布关于零对称(如经过批归一化的权重)的情况效果很好。
    • 非对称量化:量化范围可以不包含零点,例如 INT8 范围是 [-128, 127]。它能更好地拟合激活值的分布(如 ReLU 后的激活全为非负)。通常,对于激活值,尝试“asymmetric”可能获得更好精度;对于权重,“symmetric”足矣且更高效。
  • weights-per_channel: 布尔值,是否启用逐通道量化。这是 INT8 量化中的一个高级技巧。默认的逐层量化(per-tensor)对整个卷积核或权重矩阵使用一套缩放因子。而逐通道量化则对每个输出通道(对于卷积权重)或每个列(对于全连接层权重)使用独立的缩放因子。这极大地增加了灵活性,能更精细地匹配权重的分布,几乎总是能带来精度提升,强烈建议设置为True。现代 CPU(如支持 VNNI 的 Cascade Lake)和 GPU 都已支持逐通道量化计算。

  • initializer-range-num_init_samples: 在 PTQ 或 QAT 初始校准阶段,用于统计激活值范围(min, max)的样本数。不宜过少,否则统计不准;也不宜过多,否则初始化慢。一般 128-512 个样本是一个合理的范围。对于小数据集,可以适当减少;对于稳定的大模型,可以增多。

4.2 稀疏化与剪枝参数要点

如果你要使用滤波器剪枝,配置可能如下:

{ "compression": { "algorithm": "filter_pruning", "params": { "pruning_init": 0.0, // 初始稀疏率 "pruning_target": 0.5, // 目标稀疏率(50%的滤波器被移除) "pruning_steps": 100, // 从初始到目标,经过多少训练步骤达到 "pruning_structure_type": "filters", // 结构化剪枝:滤波器 "schedule": "exponential" // 稀疏率增长计划 } } }
  • pruning_target: 这是最重要的参数,决定了模型的压缩率。需要谨慎设置。一个实用的方法是渐进式剪枝:从一个较小的目标(如 0.2)开始,训练评估后,如果精度可接受,再加载这个稀疏模型,设置一个更高的目标(如 0.4)继续训练。直接设置一个很高的目标(如 0.8)很可能导致模型崩溃,无法恢复精度。
  • pruning_steps: 控制稀疏率增加的速度。步数太少,稀疏率增长过快,模型来不及适应;步数太多,训练时间过长。通常设置为一个 epoch 内 batch 数量的若干倍。

4.3 算法组合的配置策略

当同时使用多种算法时,顺序很重要。一个常见的组合是:先稀疏化/剪枝,再量化。因为剪枝改变了模型的结构和权重分布,先量化再剪枝可能会让量化参数失效。配置示例:

{ "compression": [ { "algorithm": "filter_pruning", "params": { ... } }, { "algorithm": "quantization", "params": { ... } } ] }

NNCF 会按照数组顺序依次应用这些算法。在训练循环中,compression_ctrl.loss()会返回所有激活算法损失的总和。

5. 常见问题、故障排查与实战心得

在实际使用 NNCF 的过程中,你肯定会遇到各种问题。下面是我总结的一些典型场景和解决方案。

5.1 精度损失过大

这是最常见的问题。如果你的量化或剪枝模型精度下降远超预期(例如 >3%),请按以下步骤排查:

  1. 检查校准/训练数据:确保用于 PTQ 校准或 QAT 微调的数据具有代表性,且预处理方式与原始模型训练时完全一致。数据分布不匹配是精度损失的元凶之一。
  2. 调整量化配置
    • 尝试将激活量化模式从symmetric改为asymmetric
    • 确保per_channel权重量化已启用。
    • 对于 QAT,增加微调 epoch 数,或使用更小的学习率进行更温和的微调。
    • 对于 PTQ,尝试不同的initializer类型,如将“min_max”改为“mean_min_max”“percentile”(如 99.9%),后者可以排除一些极端激活值的影响,使量化范围更鲁棒。
  3. 模型结构排查:某些模型层对量化特别敏感,例如:
    • 注意力机制中的 Softmax:输入范围可能很大,量化误差会被指数运算放大。NNCF 提供了“ignored_scopes”参数,可以指定某些层或操作不被量化。你可以尝试将注意力模块中的softmaxmatmul加入忽略列表。
    • 残差连接(Add操作):要求输入和输出的量化参数匹配良好,否则误差会累积。NNCF 通常能较好地处理,但如果出现问题,可以检查这些加法节点的量化情况。
  4. 使用精度分析工具:NNCF 提供了nncf.deprecated.tensor_statistics等工具,可以输出各层量化前后的数值分布对比,帮助你定位哪一层的量化引入了最大误差。

5.2 导出或推理失败

  1. ONNX 导出错误:NNCF 的export_model依赖于 PyTorch 的 ONNX 导出器。如果遇到不支持的算子,可能需要简化模型结构或检查 PyTorch/ONNX opset 版本。确保你使用的是 NNCF 官方文档推荐或测试过的环境版本组合。
  2. OpenVINO 模型优化器(mo)转换错误:转换 ONNX 到 IR 时失败。首先检查 ONNX 模型本身是否能被 ONNX Runtime 正确加载和推理。其次,查看 mo 工具的详细错误日志,常见问题包括算子不支持、输入输出形状推断失败等。可以尝试更新到最新版本的 OpenVINO 工具套件。
  3. 推理结果不正确:IR 模型推理结果与 PyTorch 模型差异巨大。请进行精度验证
    • 在 PyTorch 端,使用compression_ctrl.prepare_for_export()然后运行模型,此时是“真量化”模拟。
    • 在 OpenVINO 端,使用相同的输入数据运行推理。
    • 逐层对比中间输出(虽然麻烦,但这是定位问题的终极方法)。确保在模型导出和转换过程中,没有丢失或错误处理量化节点(QuantizeLinear/DequantizeLinear)。

5.3 性能提升未达预期

模型压缩了,但推理速度没快多少。这可能是因为:

  1. 瓶颈不在计算:如果推理的瓶颈是数据预处理、IO 或后处理,那么模型加速的效果就会被掩盖。需要用性能分析工具(如 OpenVINO 的 Benchmark App,torch.profiler)确认热点。
  2. 硬件不支持:确保你的 CPU 支持 INT8 指令集(如 Intel DL Boost 的 VNNI)。在不支持的硬件上运行 INT8 模型,可能会回退到低效的模拟路径,速度反而可能变慢。使用lscpu命令查看 CPU 特性。
  3. 层融合不充分:量化后,理想的优化是“量化-卷积-反量化”这一系列操作被融合为一个低精度卷积算子。检查 OpenVINO 的性能基准测试输出,确认算子融合是否成功。有时模型结构过于复杂(如大量分支、动态形状)会阻碍融合优化。

5.4 我的实战心得与技巧

  • 从小模型开始:如果你是第一次使用 NNCF,不要直接对庞大的 Swin Transformer 或 3D 卷积网络动手。先用 ResNet-18、MobileNetV2 这样的小模型走通整个流程,理解每个步骤的输出和中间状态,建立信心。
  • 善用官方示例:OpenVINO 的 GitHub 仓库和 NNCF 的独立仓库提供了大量针对不同任务(分类、检测、分割)和不同框架(PyTorch, TensorFlow)的示例代码。这些是最佳的学习起点和调试参考。
  • 版本对齐至关重要:PyTorch、NNCF、OpenVINO 这三个组件的版本兼容性必须严格匹配。强烈建议使用 OpenVINO 官方发布的openvino-dev包,它会自动安装兼容版本的nncf。自行搭配版本很容易掉入依赖地狱。
  • 量化感知训练需要“热身”:在开始正式的 QAT 微调前,建议先以极低的学习率(如初始学习率的 1/10)训练几个 epoch,让模型中的 BatchNorm 统计量适应量化噪声,这有助于稳定训练过程。
  • 稀疏化不是银弹:滤波器剪枝能减少参数和 FLOPs,但实际的推理加速比高度依赖于推理引擎和硬件对稀疏计算的支持程度。许多推理框架对结构化稀疏的支持优于非结构化稀疏。在投入大量时间进行稀疏化训练前,最好先调研目标部署平台对稀疏模型的加速能力。

模型压缩是一门实践性极强的工程艺术,没有放之四海而皆准的最优参数。NNCF 提供了强大的工具和灵活的接口,但最终的效果取决于你对模型、任务和数据的深入理解,以及反复实验和调优的耐心。每一次成功的压缩部署,都是对模型效率和精度之间微妙平衡的一次深刻把握。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 13:46:31

DownKyi专业指南:高效获取B站视频的完整工作流解决方案

DownKyi专业指南:高效获取B站视频的完整工作流解决方案 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等&…

作者头像 李华
网站建设 2026/5/4 13:45:40

终极解密:wxapkg-convertor 实战指南,高效反编译微信小程序源码

终极解密:wxapkg-convertor 实战指南,高效反编译微信小程序源码 【免费下载链接】wxapkg-convertor 一个反编译微信小程序的工具,仓库也收集各种微信小程序/小游戏.wxapkg文件 项目地址: https://gitcode.com/gh_mirrors/wx/wxapkg-convert…

作者头像 李华
网站建设 2026/5/4 13:40:00

ComfyUI-FramePackWrapper终极指南:8GB显存也能玩转高质量视频生成

ComfyUI-FramePackWrapper终极指南:8GB显存也能玩转高质量视频生成 【免费下载链接】ComfyUI-FramePackWrapper 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-FramePackWrapper 想要在有限硬件条件下实现专业级AI视频生成吗?ComfyUI-Fr…

作者头像 李华
网站建设 2026/5/4 13:37:36

如何在10分钟内为Xiaomusic创建你的第一个自定义语音命令插件

如何在10分钟内为Xiaomusic创建你的第一个自定义语音命令插件 【免费下载链接】xiaomusic 使用小爱音箱播放音乐,音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic Xiaomusic是一个开源音乐播放器项目,它让你…

作者头像 李华