:從原理到部署,打造高效輕量級AI模型)
在深度學習模型部署的實踐中我們常常面臨一個核心矛盾大模型如GPT、LLaMA等強大的性能與高昂的推理成本、緩慢的響應速度之間的矛盾。無論是云端按Token計費帶來的成本壓力還是端側設備如手機、嵌入式NPU上對模型大小和速度的嚴苛限制都迫使開發(fā)者尋找更高效的解決方案。這時“知識蒸餾”這項技術便頻繁進入我們的視野。它并非新概念但伴隨著大模型時代的到來其價值被重新審視和放大。很多人可能認為蒸餾技術復雜且難以落地但事實上一套完整的“蒸餾-推理”技術鏈路其核心思想和基礎工具早已成熟且可行。從YOLOv8/YOLOv11的目標檢測蒸餾到LangChain框架中對大模型推理痕跡的優(yōu)化再到為華為Atlas NPU、麒麟系統定制的輕量化模型其底層邏輯一脈相承。本文旨在為算法工程師、后端開發(fā)者和對模型優(yōu)化感興趣的開發(fā)者系統梳理知識蒸餾的核心原理、實戰(zhàn)流程以及如何將其與推理引擎高效結合。我們將從零開始構建一個完整的蒸餾案例并深入探討如何保存、優(yōu)化推理結果最終實現一個可在生產環(huán)境或資源受限設備上高效運行的輕量級模型。讀完本文你將能獨立完成一個模型蒸餾項目并理解如何根據云端或端側的不同需求如SSD存儲優(yōu)化、NPU適配進行針對性優(yōu)化。1. 背景與核心概念為什么需要“蒸餾”在深入代碼之前我們必須厘清幾個關鍵概念什么是知識蒸餾它要解決什么問題以及“推理痕跡”又指的是什么1.1 知識蒸餾的定義與目標知識蒸餾是一種模型壓縮技術其核心思想是訓練一個小的“學生模型”去模仿一個大的“教師模型”的行為。這里“知識”并非指訓練數據而是指教師模型在訓練數據上學到的“暗知識”即輸入到輸出之間的復雜映射關系特別是教師模型輸出的概率分布軟標簽。它主要解決兩大問題部署效率問題大模型參數多、計算量大導致推理延遲高、內存占用大難以在資源有限的端側設備或高并發(fā)云端服務中部署。成本問題云端大模型API按Token計價長期調用成本高昂。通過蒸餾得到一個性能相近的小模型進行私有化部署可以顯著降低成本。類比就像一位經驗豐富的老師大模型將自己的解題思路和技巧知識傳授給學生小模型使學生能在不直接接觸所有原始難題數據的情況下快速掌握核心方法。1.2 “推理痕跡”是什么在本文語境及相關的網絡熱詞如langchain推理框架占用硬盤大小、yolov11保存推理結果中“推理痕跡”可以理解為模型在推理過程中產生并可能被持久化的中間或最終結果。這包括軟標簽教師模型對分類任務輸出的概率分布如[0.05, 0.85, 0.1]比硬標簽如[0, 1, 0]包含更多信息。中間層特征教師模型某些中間層的激活值蘊含了豐富的特征信息。推理結果緩存例如LangChain應用中將大模型的回答緩存到磁盤以避免重復計算但這會占用硬盤空間。計算圖與優(yōu)化記錄推理引擎如ONNX Runtime, TensorRT對模型進行優(yōu)化算子融合、量化時產生的中間表示或日志。蒸餾推理痕跡即利用這些“痕跡”作為監(jiān)督信號來訓練學生模型。例如用教師模型輸出的軟標簽而不僅僅是真實標簽來訓練學生模型。1.3 蒸餾與推理引擎的關系蒸餾后的模型最終需要被推理引擎加載和執(zhí)行。這里涉及兩個層面模型格式蒸餾訓練通常在PyTorch/TensorFlow等框架中進行部署時需要轉換為推理引擎支持的格式如ONNX、TensorRT Plan、NCNN或特定硬件如華為NPU的專屬格式。引擎優(yōu)化推理引擎如大模型推理引擎、端側推理框架會對模型進行圖優(yōu)化、量化、內核調優(yōu)等操作以進一步提升在目標硬件CPU/GPU/NPU上的性能。例如SSD正在成為AI推理核心強調了存儲介質對模型加載速度的影響而麒麟v10安裝atlas推理卡則涉及了華為昇騰硬件的特定部署流程。結論蒸餾是為推理做準備的關鍵步驟而一個高效的推理引擎是蒸餾價值得以體現的最終舞臺。2. 環(huán)境準備與版本說明我們將使用PyTorch框架完成一個圖像分類任務的蒸餾實驗并簡要介紹模型轉換到ONNX格式的流程。以下環(huán)境是推薦配置你可以根據實際情況調整。# 1. 基礎環(huán)境 操作系統: Ubuntu 20.04 LTS 或 Windows 10/11 (WSL2推薦) Python: 3.8 或 3.9 CUDA: 11.3 (如果使用GPU) cuDNN: 對應CUDA版本 # 2. 核心Python包 (建議使用虛擬環(huán)境) pip install torch1.12.1cu113 torchvision0.13.1cu113 --extra-index-url https://download.pytorch.org/whl/cu113 pip install torchinfo # 用于模型結構查看 pip install onnx onnxruntime # 用于模型轉換與推理 pip install matplotlib tqdm # 3. 可選用于更復雜蒸餾策略 # pip install pytorch-lightning版本說明PyTorch 1.12 和 Torchvision 0.13 提供了穩(wěn)定的API。ONNX 和 ONNX Runtime 是當前業(yè)界標準的模型交換與推理框架支持多硬件后端。本文示例將基于CIFAR-10數據集因為它體積小、訓練快適合演示。項目結構預覽knowledge_distillation_demo/ ├── models/ # 模型定義 │ ├── teacher.py │ └── student.py ├── utils/ # 工具函數 │ └── data_loader.py ├── train_teacher.py # 單獨訓練教師模型 ├── train_distill.py # 蒸餾訓練學生模型 ├── convert_to_onnx.py # 模型轉換腳本 ├── inference_demo.py # 推理示例腳本 └── README.md3. 核心原理與損失函數拆解知識蒸餾的核心在于損失函數的設計。它通常不是簡單地使用真實標簽而是結合了教師模型的“知識”。3.1 軟標簽與溫度系數教師模型通常使用一個較高的“溫度”來產生軟標簽。softmax函數被修改為 [ q_i \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)} ] 其中( z_i ) 是模型最后一層的logits未歸一化的分數( T ) 是溫度系數。T1就是標準的softmax。T1概率分布變得更“軟”不同類別之間的差異被平滑蘊含了更多關于類別間相似性的信息例如貓和狗可能比貓和飛機有更高的相似概率。蒸餾時我們用高的 ( T ) 從教師模型產生軟標簽也用相同的 ( T ) 讓學生模型產生預測計算兩者之間的差異如KL散度。在最終推理時學生模型使用 ( T1 )。3.2 蒸餾損失函數最經典的蒸餾損失由兩部分組成蒸餾損失衡量學生模型軟預測與教師模型軟預測的差異常用KL散度。 [ L_{distill} T^2 \cdot KL(\text{Student_soft_labels} || \text{Teacher_soft_labels}) ] 乘以 ( T^2 ) 是為了平衡不同溫度下梯度的大小。學生損失衡量學生模型硬預測T1與真實標簽的差異常用交叉熵損失。 [ L_{student} CE(\text{Student_hard_labels}, \text{True_Labels}) ]總損失兩者加權和。 [ L_{total} \alpha \cdot L_{student} (1 - \alpha) \cdot L_{distill} ] 其中( \alpha ) 是一個超參數用于平衡兩種損失。3.3 特征蒸餾除了最終輸出的軟標簽教師模型中間層的特征圖Feature Maps也包含豐富的知識。我們可以讓學生模型中間層的特征圖去匹配教師模型的特征圖這通常通過一個“適配層”和均方誤差損失來實現。 [ L_{feat} MSE(\phi(\text{Student_Feat}), \text{Teacher_Feat}) ] 其中( \phi ) 是一個可選的適配層如1x1卷積用于將學生特征圖的通道數對齊到教師特征圖。4. 完整實戰(zhàn)案例CIFAR-10圖像分類蒸餾讓我們動手實現一個完整的流程訓練一個教師模型然后蒸餾出一個學生模型。4.1 定義教師模型與學生模型我們使用ResNet-18作為教師模型一個更小的自定義CNN作為學生模型。# models/teacher.py import torch import torch.nn as nn import torchvision.models as models class TeacherModel(nn.Module): def __init__(self, num_classes10): super(TeacherModel, self).__init__() # 使用預訓練的ResNet-18并替換最后的全連接層 self.backbone models.resnet18(pretrainedTrue) in_features self.backbone.fc.in_features self.backbone.fc nn.Linear(in_features, num_classes) def forward(self, x): return self.backbone(x) # models/student.py import torch.nn as nn class StudentModel(nn.Module): def __init__(self, num_classes10): super(StudentModel, self).__init__() # 一個簡單的CNN參數遠少于ResNet-18 self.features nn.Sequential( nn.Conv2d(3, 32, kernel_size3, padding1), nn.BatchNorm2d(32), nn.ReLU(inplaceTrue), nn.MaxPool2d(2, 2), nn.Conv2d(32, 64, kernel_size3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(2, 2), nn.Conv2d(64, 128, kernel_size3, padding1), nn.BatchNorm2d(128), nn.ReLU(inplaceTrue), nn.MaxPool2d(2, 2), ) self.avgpool nn.AdaptiveAvgPool2d((1, 1)) self.classifier nn.Linear(128, num_classes) def forward(self, x): x self.features(x) x self.avgpool(x) x torch.flatten(x, 1) x self.classifier(x) return x4.2 訓練教師模型首先我們需要一個強大的教師模型。這里我們快速訓練一個ResNet-18在CIFAR-10上。# train_teacher.py import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader from models.teacher import TeacherModel import os def train_teacher(): device torch.device(cuda if torch.cuda.is_available() else cpu) print(fUsing device: {device}) # 數據預處理與加載 transform_train transforms.Compose([ transforms.RandomCrop(32, padding4), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) transform_test transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) trainset datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform_train) trainloader DataLoader(trainset, batch_size128, shuffleTrue, num_workers2) testset datasets.CIFAR10(root./data, trainFalse, downloadTrue, transformtransform_test) testloader DataLoader(testset, batch_size100, shuffleFalse, num_workers2) # 初始化模型、損失函數、優(yōu)化器 model TeacherModel(num_classes10).to(device) criterion nn.CrossEntropyLoss() optimizer optim.SGD(model.parameters(), lr0.1, momentum0.9, weight_decay5e-4) scheduler optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max200) # 訓練循環(huán) epochs 50 for epoch in range(epochs): model.train() running_loss 0.0 for i, (inputs, labels) in enumerate(trainloader): inputs, labels inputs.to(device), labels.to(device) optimizer.zero_grad() outputs model(inputs) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() scheduler.step() # 簡單驗證 model.eval() correct 0 total 0 with torch.no_grad(): for inputs, labels in testloader: inputs, labels inputs.to(device), labels.to(device) outputs model(inputs) _, predicted outputs.max(1) total labels.size(0) correct predicted.eq(labels).sum().item() acc 100. * correct / total print(fEpoch [{epoch1}/{epochs}], Loss: {running_loss/len(trainloader):.4f}, Test Acc: {acc:.2f}%) # 保存教師模型 os.makedirs(checkpoints, exist_okTrue) torch.save(model.state_dict(), checkpoints/teacher_resnet18_cifar10.pth) print(Teacher model saved to checkpoints/teacher_resnet18_cifar10.pth) if __name__ __main__: train_teacher()運行此腳本你將得到一個在CIFAR-10上準確率約90%的教師模型。4.3 實現知識蒸餾訓練這是最核心的部分。我們將實現包含溫度系數和損失權重的蒸餾訓練。# train_distill.py import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader from models.teacher import TeacherModel from models.student import StudentModel import os def distillation_loss(student_logits, teacher_logits, labels, temperature, alpha): 計算蒸餾總損失。 Args: student_logits: 學生模型的原始輸出。 teacher_logits: 教師模型的原始輸出。 labels: 真實標簽。 temperature: 溫度系數。 alpha: 學生損失權重。 # 計算軟標簽損失 (KL散度) soft_loss F.kl_div( F.log_softmax(student_logits / temperature, dim1), F.softmax(teacher_logits / temperature, dim1), reductionbatchmean ) * (temperature ** 2) # 乘以T^2平衡梯度 # 計算硬標簽損失 (交叉熵) hard_loss F.cross_entropy(student_logits, labels) # 總損失 total_loss alpha * hard_loss (1 - alpha) * soft_loss return total_loss, hard_loss, soft_loss def train_distillation(): device torch.device(cuda if torch.cuda.is_available() else cpu) print(fUsing device: {device}) # 加載數據 transform_train transforms.Compose([ transforms.RandomCrop(32, padding4), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) trainset datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform_train) trainloader DataLoader(trainset, batch_size128, shuffleTrue, num_workers2) # 加載預訓練好的教師模型 teacher_model TeacherModel(num_classes10).to(device) teacher_checkpoint torch.load(checkpoints/teacher_resnet18_cifar10.pth, map_locationdevice) teacher_model.load_state_dict(teacher_checkpoint) teacher_model.eval() # 教師模型固定不更新參數 print(Teacher model loaded.) # 初始化學生模型 student_model StudentModel(num_classes10).to(device) print(Student model created.) # 定義優(yōu)化器 optimizer optim.SGD(student_model.parameters(), lr0.01, momentum0.9, weight_decay5e-4) scheduler optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max100) # 蒸餾超參數 temperature 4.0 alpha 0.3 # 硬標簽損失權重 # 訓練循環(huán) epochs 100 for epoch in range(epochs): student_model.train() running_total_loss 0.0 running_hard_loss 0.0 running_soft_loss 0.0 for i, (inputs, labels) in enumerate(trainloader): inputs, labels inputs.to(device), labels.to(device) # 前向傳播 with torch.no_grad(): # 教師模型不計算梯度 teacher_logits teacher_model(inputs) student_logits student_model(inputs) # 計算蒸餾損失 total_loss, hard_loss, soft_loss distillation_loss( student_logits, teacher_logits, labels, temperature, alpha ) # 反向傳播與優(yōu)化 optimizer.zero_grad() total_loss.backward() optimizer.step() # 統計 running_total_loss total_loss.item() running_hard_loss hard_loss.item() running_soft_loss soft_loss.item() scheduler.step() avg_total_loss running_total_loss / len(trainloader) avg_hard_loss running_hard_loss / len(trainloader) avg_soft_loss running_soft_loss / len(trainloader) print(fEpoch [{epoch1}/{epochs}], Total Loss: {avg_total_loss:.4f}, fHard Loss: {avg_hard_loss:.4f}, Soft Loss: {avg_soft_loss:.4f}) # 保存學生模型 os.makedirs(checkpoints, exist_okTrue) torch.save(student_model.state_dict(), checkpoints/student_distilled_cifar10.pth) print(Distilled student model saved.) if __name__ __main__: train_distillation()4.4 模型評估與對比訓練完成后我們需要評估學生模型的性能并與從頭訓練的學生模型進行對比。# evaluate.py import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader from models.student import StudentModel from models.teacher import TeacherModel def evaluate_model(model, model_path, device): 評估模型在CIFAR-10測試集上的準確率 model.load_state_dict(torch.load(model_path, map_locationdevice)) model.to(device) model.eval() transform_test transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) testset datasets.CIFAR10(root./data, trainFalse, downloadTrue, transformtransform_test) testloader DataLoader(testset, batch_size100, shuffleFalse, num_workers2) correct 0 total 0 with torch.no_grad(): for inputs, labels in testloader: inputs, labels inputs.to(device), labels.to(device) outputs model(inputs) _, predicted outputs.max(1) total labels.size(0) correct predicted.eq(labels).sum().item() acc 100. * correct / total return acc if __name__ __main__: device torch.device(cuda if torch.cuda.is_available() else cpu) print(fUsing device: {device}) # 評估教師模型 teacher_model TeacherModel(num_classes10) teacher_acc evaluate_model(teacher_model, checkpoints/teacher_resnet18_cifar10.pth, device) print(fTeacher Model Accuracy: {teacher_acc:.2f}%) # 評估蒸餾后的學生模型 student_distilled StudentModel(num_classes10) student_distilled_acc evaluate_model(student_distilled, checkpoints/student_distilled_cifar10.pth, device) print(fDistilled Student Model Accuracy: {student_distilled_acc:.2f}%) # 可選評估從頭訓練的學生模型作為基線對比 # 你需要先運行一個 train_student_from_scratch.py 腳本 # student_scratch StudentModel(num_classes10) # student_scratch_acc evaluate_model(student_scratch, checkpoints/student_scratch_cifar10.pth, device) # print(fStudent Model (Trained from Scratch) Accuracy: {student_scratch_acc:.2f}%)預期結果在CIFAR-10上教師模型ResNet-18準確率可能在90%左右。一個精心設計的小學生模型通過蒸餾其準確率通常會顯著高于從頭訓練的同一結構學生模型例如高出3-8個百分點同時模型大小和計算量大幅減少。4.5 模型轉換與推理部署訓練好的PyTorch模型需要轉換為推理格式。這里以轉換為ONNX為例。# convert_to_onnx.py import torch from models.student import StudentModel def convert_to_onnx(): device torch.device(cpu) # ONNX轉換通常在CPU上進行 model StudentModel(num_classes10) model.load_state_dict(torch.load(checkpoints/student_distilled_cifar10.pth, map_locationdevice)) model.eval() # 創(chuàng)建一個示例輸入張量 (batch_size, channels, height, width) dummy_input torch.randn(1, 3, 32, 32, devicedevice) # 指定輸入和輸出的名稱 input_names [input] output_names [output] # 導出模型 onnx_path checkpoints/student_distilled.onnx torch.onnx.export( model, dummy_input, onnx_path, input_namesinput_names, output_namesoutput_names, opset_version11, # ONNX算子集版本 dynamic_axes{input: {0: batch_size}, output: {0: batch_size}} # 支持動態(tài)batch ) print(fModel has been converted to ONNX and saved to {onnx_path}) # 可選使用ONNX Runtime驗證模型 import onnxruntime as ort import numpy as np ort_session ort.InferenceSession(onnx_path) outputs ort_session.run(None, {input: dummy_input.numpy()}) print(fONNX Runtime inference output shape: {outputs[0].shape}) if __name__ __main__: convert_to_onnx()轉換成功后你可以使用ONNX Runtime在任何支持的后端CPU, GPU, NPU等上進行高效推理實現與訓練框架的解耦。5. 常見問題與排查思路在實際操作中你可能會遇到以下問題問題現象常見原因解決思路蒸餾后學生模型性能反而下降1. 溫度系數T設置不當。2. 損失權重alpha不平衡。3. 學生模型容量太小無法學習教師知識。4. 教師模型本身性能不佳。1. 調整T(常見范圍2-10)。2. 調整alpha(如從0.1到0.9)。3. 適當增加學生模型的寬度或深度。4. 確保教師模型在任務上達到足夠高的精度。訓練過程不穩(wěn)定損失震蕩大1. 學習率過高。2. 批次大小太小。3. 教師模型的軟標簽噪聲大。1. 降低學習率使用學習率預熱。2. 增大批次大小。3. 嘗試對教師模型的logits進行平滑或截斷。轉換ONNX時出錯1. PyTorch模型包含ONNX不支持的算子。2. 輸入/輸出動態(tài)軸設置錯誤。3. 使用了不穩(wěn)定的PyTorch版本。1. 簡化模型結構或使用自定義算子。2. 檢查dynamic_axes參數。3. 使用PyTorch穩(wěn)定版本并指定合適的opset_version。端側推理速度不達標1. ONNX模型未經過圖優(yōu)化。2. 未使用針對硬件的推理引擎如TensorRT for NVIDIA, NCNN for Mobile。3. 未進行量化INT8。1. 使用ONNX Runtime的圖優(yōu)化工具或onnxoptimizer。2. 轉換到硬件專用格式如.plan,.ncnn。3. 進行訓練后量化或量化感知訓練。LangChain等框架中模型占用硬盤大1. 緩存了完整的模型參數和中間結果。2. 序列化方式低效。1. 使用模型量化減小文件體積。2. 考慮使用模型切片或分塊加載。3. 定期清理不必要的緩存文件。6. 最佳實踐與工程建議要將蒸餾技術成功應用于生產項目需注意以下工程細節(jié)6.1 教師模型的選擇與訓練質量優(yōu)先教師模型的性能是天花板。確保教師模型在目標任務上經過充分訓練和調優(yōu)。多樣性集成多個教師模型進行蒸餾可以向學生模型傳遞更豐富、更穩(wěn)健的知識。數據增強一致性在蒸餾訓練時對學生和教師模型使用相同的數據增強流水線確保知識傳遞在一致的“視角”下進行。6.2 學生模型的設計結構搜索不要盲目設計??梢越柚窠浖軜嬎阉骰騾⒖家阎母咝ЬW絡如MobileNetV3、EfficientNet-Lite作為學生模型的起點。容量匹配學生模型需要有足夠的容量來承載教師模型的知識。如果學生模型太小知識蒸餾可能無效。特征圖對齊對于特征蒸餾仔細設計適配層1x1卷積、全連接層來匹配教師和學生特征圖的通道數與空間尺寸。6.3 蒸餾策略進階漸進式蒸餾先使用一個中等大小的模型作為“助教”蒸餾出第一個學生再用這個學生作為教師去蒸餾更小的模型。自蒸餾模型自身作為教師通過不同的數據增強或子網絡產生軟標簽進行自我訓練和正則化。注意力蒸餾不僅蒸餾輸出還蒸餾中間層的注意力圖讓學生模型學習教師關注的重點區(qū)域。6.4 推理部署優(yōu)化格式選擇根據部署環(huán)境選擇最優(yōu)格式。云端服務可能用ONNX/TensorRT安卓端用TFLite/NCNN華為昇騰用OM模型。量化這是端側推理的核心優(yōu)化手段。使用訓練后量化或量化感知訓練將FP32模型轉換為INT8可大幅減少模型體積、提升推理速度、降低功耗對SSD存儲和內存帶寬都更友好。引擎調優(yōu)充分利用推理引擎的優(yōu)化選項。例如在ONNX Runtime中啟用所有圖優(yōu)化在TensorRT中選擇最優(yōu)的精度和內核。監(jiān)控與迭代部署后持續(xù)監(jiān)控模型的推理延遲、吞吐量和準確率。收集真實場景的數據可用于后續(xù)的模型微調或再蒸餾。6.5 項目管理與協作版本控制對教師模型、學生模型、訓練腳本、超參數配置、轉換腳本進行嚴格的版本控制。實驗記錄使用MLflow、Weights Biases等工具記錄每一次蒸餾實驗的超參數、損失曲線和最終精度便于分析和復現。自動化流水線將數據準備、教師訓練、蒸餾訓練、模型轉換、精度驗證等步驟構建成CI/CD流水線提高迭代效率。從原理到實踐知識蒸餾的技術鏈條已經非常清晰。它早已不是實驗室里的玩具而是工業(yè)界應對大模型推理成本與效率挑戰(zhàn)的成熟武器。無論是想優(yōu)化YOLOv11的檢測速度還是減少LangChain應用對硬盤的占用抑或是為華為NPU或麒麟系統定制高效的端側模型掌握蒸餾與推理的完整工作流都是不可或缺的技能。希望本文提供的從零開始的實戰(zhàn)指南能幫助你順利跨過從理論到落地的門檻構建出屬于自己的高效輕量級模型。