[模型部署] 3. 性能優化

👋 你好!這里有實用干貨與深度分享?? 若有幫助,歡迎:?
👍 點贊 | ? 收藏 | 💬 評論 | ? 關注 ,解鎖更多精彩!?
📁 收藏專欄即可第一時間獲取最新推送🔔。?
📖后續我將持續帶來更多優質內容,期待與你一同探索知識,攜手前行,共同進步🚀。?



?人工智能

性能優化

本文介紹深度學習模型部署中的性能優化方法,包括模型量化、模型剪枝、模型蒸餾、混合精度訓練和TensorRT加速等技術,以及具體的實現方法和最佳實踐,幫助你在部署階段獲得更高的推理效率和更低的資源消耗。


1. 模型量化

量化類型優點缺點適用場景
靜態量化- 精度損失小
- 推理速度快
- 內存占用小
- 需要校準數據
- 實現復雜
- 對精度要求高
- 資源受限設備
動態量化- 實現簡單
- 無需校準數據
- 靈活性高
- 精度損失較大
- 加速效果有限
- 快速部署
- RNN/LSTM模型
量化感知訓練- 精度最高
- 模型適應量化
- 需要重新訓練
- 開發成本高
- 高精度要求
- 大規模部署

1.1 PyTorch靜態量化

靜態量化在模型推理前完成權重量化,適用于對精度要求較高的場景,需提供校準數據。

import torch
from torch.quantization import get_default_qconfig
from torch.quantization.quantize_fx import prepare_fx, convert_fxdef quantize_model(model, calibration_data):# 設置量化配置(fbgemm用于x86架構,qnnpack用于ARM架構)qconfig = get_default_qconfig('fbgemm')  qconfig_dict = {"":qconfig}# 準備量化(插入觀察節點)model_prepared = prepare_fx(model, qconfig_dict)# 校準(收集激活值的分布信息)for data in calibration_data:model_prepared(data)# 轉換為量化模型(替換浮點運算為整數運算)model_quantized = convert_fx(model_prepared)return model_quantized# 使用示例
model = YourModel()
model.eval()  # 量化前必須設置為評估模式
calibration_data = get_calibration_data()  # 獲取校準數據
quantized_model = quantize_model(model, calibration_data)# 保存量化模型
torch.jit.save(torch.jit.script(quantized_model), "quantized_model.pt")

1.2 動態量化

動態量化在推理過程中動態計算激活值的量化參數,操作簡單,特別適用于線性層和RNN。

import torch
import torch.quantizationdef dynamic_quantize(model):# 應用動態量化(僅量化權重,激活值在運行時量化)quantized_model = torch.quantization.quantize_dynamic(model,{torch.nn.Linear, torch.nn.LSTM, torch.nn.GRU},  # 量化的層類型dtype=torch.qint8  # 量化數據類型)return quantized_model# 驗證量化效果
def verify_quantization(original_model, quantized_model, test_input):# 比較輸出結果with torch.no_grad():original_output = original_model(test_input)quantized_output = quantized_model(test_input)# 計算誤差error = torch.abs(original_output - quantized_output).mean()print(f"平均誤差: {error.item()}")# 比較模型大小original_size = get_model_size_mb(original_model)quantized_size = get_model_size_mb(quantized_model)print(f"原始模型大小: {original_size:.2f} MB")print(f"量化模型大小: {quantized_size:.2f} MB")print(f"壓縮比: {original_size/quantized_size:.2f}x")return error.item()# 獲取模型大小(MB)
def get_model_size_mb(model):torch.save(model.state_dict(), "temp.p")size_mb = os.path.getsize("temp.p") / (1024 * 1024)os.remove("temp.p")return size_mb

1.3 量化感知訓練

量化感知訓練在訓練過程中模擬量化效果,使模型適應量化帶來的精度損失。

import torch
from torch.quantization import get_default_qat_qconfig
from torch.quantization.quantize_fx import prepare_qat_fx, convert_fxdef quantization_aware_training(model, train_loader, epochs=5):# 設置量化感知訓練配置qconfig = get_default_qat_qconfig('fbgemm')qconfig_dict = {"":qconfig}# 準備量化感知訓練model_prepared = prepare_qat_fx(model, qconfig_dict)# 訓練optimizer = torch.optim.Adam(model_prepared.parameters())criterion = torch.nn.CrossEntropyLoss()for epoch in range(epochs):for inputs, targets in train_loader:optimizer.zero_grad()outputs = model_prepared(inputs)loss = criterion(outputs, targets)loss.backward()optimizer.step()# 轉換為量化模型model_quantized = convert_fx(model_prepared)return model_quantized

2. 模型剪枝

剪枝類型優點缺點適用場景
結構化剪枝- 硬件友好
- 實際加速效果好
- 易于實現
- 精度損失較大
- 壓縮率有限
- 計算密集型模型
- 需要實際加速
非結構化剪枝- 高壓縮率
- 精度損失小
- 靈活性高
- 需要特殊硬件/庫支持
- 實際加速有限
- 存儲受限場景
- 可接受稀疏計算

2.1 結構化剪枝

結構化剪枝移除整個卷積核或通道,可直接減少模型參數量和計算量,提升推理速度。

import torch
import torch.nn.utils.prune as prunedef structured_pruning(model, amount=0.5):# 按通道剪枝for name, module in model.named_modules():if isinstance(module, torch.nn.Conv2d):prune.ln_structured(module,name='weight',amount=amount,  # 剪枝比例n=2,  # L2范數dim=0  # 按輸出通道剪枝)return modeldef fine_tune_pruned_model(model, train_loader, epochs=5):# 剪枝后微調恢復精度optimizer = torch.optim.Adam(model.parameters())criterion = torch.nn.CrossEntropyLoss()for epoch in range(epochs):for inputs, targets in train_loader:optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, targets)loss.backward()optimizer.step()return modeldef remove_pruning(model):# 移除剪枝,使權重永久化for name, module in model.named_modules():if isinstance(module, torch.nn.Conv2d):prune.remove(module, 'weight')return model

2.2 非結構化剪枝

非結構化剪枝(細粒度剪枝)可獲得更高稀疏率,但對硬件加速支持有限。

def fine_grained_pruning(model, threshold=0.1):# 按權重大小剪枝for name, module in model.named_modules():if isinstance(module, torch.nn.Conv2d) or isinstance(module, torch.nn.Linear):# 創建掩碼:保留絕對值大于閾值的權重mask = torch.abs(module.weight.data) > threshold# 應用掩碼module.weight.data *= maskreturn model# 評估剪枝效果
def evaluate_sparsity(model):total_params = 0zero_params = 0for name, param in model.named_parameters():if 'weight' in name:  # 只考慮權重參數total_params += param.numel()zero_params += (param == 0).sum().item()sparsity = zero_params / total_paramsprint(f"模型稀疏度: {sparsity:.2%}")print(f"非零參數數量: {total_params - zero_params:,}")print(f"總參數數量: {total_params:,}")return sparsity

3. 模型蒸餾

蒸餾類型優點缺點適用場景
響應蒸餾- 實現簡單
- 效果穩定
- 信息損失
- 依賴教師質量
- 分類任務
- 小型模型訓練
特征蒸餾- 傳遞更多信息
- 效果更好
- 實現復雜
- 需要匹配特征
- 復雜任務
- 深層網絡
關系蒸餾- 保留樣本關系
- 泛化性好
- 計算開銷大- 度量學習
- 表示學習

3.1 知識蒸餾

通過教師模型指導學生模型訓練,實現模型壓縮和加速。

import torch
import torch.nn as nn
import torch.nn.functional as Fclass DistillationLoss(nn.Module):def __init__(self, temperature=4.0, alpha=0.5):super().__init__()self.temperature = temperature  # 溫度參數控制軟標簽的平滑程度self.alpha = alpha  # 平衡硬標簽和軟標簽的權重self.ce_loss = nn.CrossEntropyLoss()self.kl_loss = nn.KLDivLoss(reduction='batchmean')def forward(self, student_logits, teacher_logits, labels):# 硬標簽損失(學生模型與真實標簽)ce_loss = self.ce_loss(student_logits, labels)# 軟標簽損失(學生模型與教師模型輸出)soft_teacher = F.softmax(teacher_logits / self.temperature, dim=1)soft_student = F.log_softmax(student_logits / self.temperature, dim=1)kd_loss = self.kl_loss(soft_student, soft_teacher)# 總損失 = (1-α)·硬標簽損失 + α·軟標簽損失total_loss = (1 - self.alpha) * ce_loss + \self.alpha * (self.temperature ** 2) * kd_lossreturn total_lossdef train_with_distillation(teacher_model, student_model, train_loader, epochs=10):teacher_model.eval()  # 教師模型設為評估模式student_model.train()  # 學生模型設為訓練模式criterion = DistillationLoss(temperature=4.0, alpha=0.5)optimizer = torch.optim.Adam(student_model.parameters(), lr=1e-3)for epoch in range(epochs):total_loss = 0for data, labels in train_loader:optimizer.zero_grad()# 教師模型推理(不計算梯度)with torch.no_grad():teacher_logits = teacher_model(data)# 學生模型前向傳播student_logits = student_model(data)# 計算蒸餾損失loss = criterion(student_logits, teacher_logits, labels)loss.backward()optimizer.step()total_loss += loss.item()print(f"Epoch {epoch+1}/{epochs}, Loss: {total_loss/len(train_loader):.4f}")return student_model

3.2 特征蒸餾

特征蒸餾通過匹配中間層特征,傳遞更豐富的知識。

class FeatureDistillationLoss(nn.Module):def __init__(self, alpha=0.5):super().__init__()self.alpha = alphaself.ce_loss = nn.CrossEntropyLoss()self.mse_loss = nn.MSELoss()def forward(self, student_logits, teacher_logits, student_features, teacher_features, labels):# 分類損失ce_loss = self.ce_loss(student_logits, labels)# 特征匹配損失feature_loss = 0for sf, tf in zip(student_features, teacher_features):# 可能需要調整特征維度if sf.shape != tf.shape:sf = F.adaptive_avg_pool2d(sf, tf.shape[2:])feature_loss += self.mse_loss(sf, tf)# 總損失total_loss = (1 - self.alpha) * ce_loss + self.alpha * feature_lossreturn total_loss

4. 混合精度訓練與推理

混合精度使用FP16和FP32混合計算,在保持精度的同時提升性能。

# 混合精度訓練
import torch
from torch.cuda.amp import autocast, GradScalerdef train_with_mixed_precision(model, train_loader, epochs=10):optimizer = torch.optim.Adam(model.parameters())criterion = torch.nn.CrossEntropyLoss()scaler = GradScaler()  # 梯度縮放器,防止FP16下溢for epoch in range(epochs):for inputs, targets in train_loader:inputs, targets = inputs.cuda(), targets.cuda()optimizer.zero_grad()# 使用自動混合精度with autocast():outputs = model(inputs)loss = criterion(outputs, targets)# 縮放梯度以防止下溢scaler.scale(loss).backward()scaler.step(optimizer)scaler.update()return model# 混合精度推理
def inference_with_mixed_precision(model, test_loader):model.eval()results = []with torch.no_grad():with autocast():for inputs in test_loader:inputs = inputs.cuda()outputs = model(inputs)results.append(outputs)return results

5. TensorRT優化

TensorRT可極大提升NVIDIA GPU上的推理速度。

import tensorrt as trt
import numpy as np
import pycuda.driver as cuda
import pycuda.autoinitdef build_engine(onnx_path, engine_path, precision='fp16'):logger = trt.Logger(trt.Logger.WARNING)builder = trt.Builder(logger)network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))parser = trt.OnnxParser(network, logger)# 解析ONNX模型with open(onnx_path, 'rb') as model:if not parser.parse(model.read()):for error in range(parser.num_errors):print(parser.get_error(error))return None# 配置構建器config = builder.create_builder_config()config.max_workspace_size = 1 << 30  # 1GB# 設置精度模式if precision == 'fp16' and builder.platform_has_fast_fp16:config.set_flag(trt.BuilderFlag.FP16)elif precision == 'int8' and builder.platform_has_fast_int8:config.set_flag(trt.BuilderFlag.INT8)# 需要提供校準器進行INT8量化# config.int8_calibrator = ...# 構建引擎engine = builder.build_engine(network, config)# 保存引擎with open(engine_path, 'wb') as f:f.write(engine.serialize())print(f"TensorRT引擎已保存到: {engine_path}")return enginedef inference_with_tensorrt(engine_path, input_data):logger = trt.Logger(trt.Logger.WARNING)# 加載引擎with open(engine_path, 'rb') as f:runtime = trt.Runtime(logger)engine = runtime.deserialize_cuda_engine(f.read())# 創建執行上下文context = engine.create_execution_context()# 獲取輸入輸出綁定信息input_binding_idx = engine.get_binding_index("input")output_binding_idx = engine.get_binding_index("output")# 分配GPU內存input_shape = engine.get_binding_shape(input_binding_idx)output_shape = engine.get_binding_shape(output_binding_idx)input_size = trt.volume(input_shape) * engine.get_binding_dtype(input_binding_idx).itemsizeoutput_size = trt.volume(output_shape) * engine.get_binding_dtype(output_binding_idx).itemsize# 分配設備內存d_input = cuda.mem_alloc(input_size)d_output = cuda.mem_alloc(output_size)# 創建輸出數組h_output = cuda.pagelocked_empty(trt.volume(output_shape), dtype=np.float32)# 將輸入數據復制到GPUh_input = np.ascontiguousarray(input_data.astype(np.float32).ravel())cuda.memcpy_htod(d_input, h_input)# 執行推理bindings = [int(d_input), int(d_output)]context.execute_v2(bindings)# 將結果復制回CPUcuda.memcpy_dtoh(h_output, d_output)# 重塑輸出為正確的形狀output = h_output.reshape(output_shape)return output

6. 最佳實踐

6.1 量化策略選擇

  • 靜態量化:精度高,需校準數據,適合CNN模型
  • 動態量化:實現簡單,適合RNN/LSTM/Transformer模型
  • 量化感知訓練:精度最高,但需要重新訓練
  • 選擇建議:先嘗試動態量化,如精度不滿足再使用靜態量化或量化感知訓練

6.2 剪枝方法選擇

  • 結構化剪枝:規則性好,加速效果明顯,適合計算受限場景
  • 非結構化剪枝:壓縮率高,但需要特殊硬件支持,適合存儲受限場景
  • 選擇建議:優先考慮結構化剪枝,除非對模型大小有極高要求

6.3 蒸餾技巧

  • 選擇合適的教師模型:教師模型應比學生模型性能顯著更好
  • 調整溫度參數:較高溫度(4~10)使知識更軟化,有助于傳遞類間關系
  • 平衡硬標簽和軟標簽損失:通常軟標簽權重0.5~0.9效果較好
  • 特征匹配:對于深層網絡,匹配中間層特征效果更佳

6.4 混合精度優化

  • 訓練時使用AMP:自動混合精度可顯著加速訓練
  • 推理時選擇合適精度:根據硬件和精度要求選擇FP32/FP16/INT8
  • 注意數值穩定性:某些操作(如歸一化層)保持FP32精度

6.5 部署優化

  • 使用TensorRT等推理引擎加速:可獲得2~5倍性能提升
  • 優化內存訪問和批處理大小:根據硬件特性調整
  • 模型融合:合并連續操作減少內存訪問
  • 量化與剪枝結合:先剪枝再量化通常效果更好

6.6 評估和監控

  • 全面評估指標:不僅關注精度,還要測量延遲、吞吐量和內存占用
  • 測量真實設備性能:在目標部署環境測試,而非僅在開發環境
  • 監控資源使用:CPU/GPU利用率、內存占用、功耗等
  • 建立性能基準:記錄優化前后的各項指標,量化優化效果

6.7 優化流程建議

  1. 建立基準:記錄原始模型性能指標
  2. 分析瓶頸:識別計算密集或內存密集操作
  3. 選擇策略:根據瓶頸和部署環境選擇優化方法
  4. 漸進優化:從簡單到復雜,逐步應用優化技術
  5. 持續評估:每步優化后評估性能和精度變化
  6. 權衡取舍:根據應用需求平衡精度和性能

?
?



📌 感謝閱讀!若文章對你有用,別吝嗇互動~?
👍 點個贊 | ? 收藏備用 | 💬 留下你的想法 ,關注我,更多干貨持續更新!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/81283.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81283.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/81283.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

InternVL3: 利用AI處理文本、圖像、視頻、OCR和數據分析

InternVL3推動了視覺-語言理解、推理和感知的邊界。 在其前身InternVL 2.5的基礎上,這個新版本引入了工具使用、GUI代理操作、3D視覺和工業圖像分析方面的突破性能力。 讓我們來分析一下是什么讓InternVL3成為游戲規則的改變者 — 以及今天你如何開始嘗試使用它。 InternVL…

鴻蒙 ArkUI - ArkTS 組件 官方 UI組件 合集

ArkUI 組件速查表 鴻蒙應用開發頁面上需要實現的 UI 功能組件如果在這 100 多個組件里都找不到&#xff0c;那就需要組合造輪子了 使用技巧&#xff1a;先判斷需要實現的組件大方向&#xff0c;比如“選擇”、“文本”、“信息”等&#xff0c;或者是某種形狀比如“塊”、“圖…

HTTP GET報文解讀

考慮當瀏覽器發送一個HTTP GET報文時&#xff0c;通過Wireshark 俘獲到下列ASCII字符串&#xff1a; GET /cs453/index.html HTTP/1.1 Host: gaia.cs.umass.edu User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) Acc…

【Linux網絡】數據鏈路層

數據鏈路層 用于兩個設備&#xff08;同一種數據鏈路節點&#xff09;之間進行傳遞。 認識以太網 “以太網” 不是一種具體的網絡&#xff0c;而是一種技術標準&#xff1b;既包含了數據鏈路層的內容&#xff0c;也包含了一些物理層的內容。例如&#xff1a;規定了網絡拓撲結…

【打破信息差】萌新認識與入門算法競賽

閱前須知 XCPC萌新互助進步群2??&#xff1a;174495261 博客主頁&#xff1a;resot (關注resot謝謝喵) 針對具體問題&#xff0c;應當進行具體分析&#xff1b;并無放之四海而皆準的方法可適用于所有人。本人尊重并支持每位學習者對最佳學習路徑的自主選擇。本篇所列訓練方…

logrotate按文件大小進行日志切割

? 編寫logrotate文件&#xff0c;進行自定義切割方式 adminip-127-0-0-1:/data/test$ cat /etc/logrotate.d/test /data/test/test.log {size 1024M #文件達到1G就切割rotate 100 #保留100個文件compressdelaycompressmissingoknotifemptycopytruncate #這個情況服務不用…

2025認證杯二階段C題完整論文講解+多模型對比

基于延遲估計與多模型預測的化工生產過程不合格事件預警方法研究 摘要 化工生產過程中&#xff0c;污染物濃度如SO?和H?S對生產過程的控制至關重要。本文旨在通過數據分析與模型預測&#xff0c;提出一種基于延遲估計與特征提取的多模型預測方法&#xff0c;優化閾值設置&a…

前端精度問題全解析:用“挖掘機”快速“填平精度坑”的完美解決方案

寫在前面 “為什么我的計算在 React Native 中總是出現奇怪的精度問題?” —— 這可能是許多開發者在作前端程序猿的朋友們都會遇到的第一個頭疼問題。本文將深入探討前端精度問題的根源,我將以RN為例,并提供一系列實用解決方案,讓你的應用告別計算誤差。 一、精度問題的…

2024 睿抗機器人開發者大賽CAIP-編程技能賽-本科組(國賽) 解題報告 | 珂學家

前言 題解 2024 睿抗機器人開發者大賽CAIP-編程技能賽-本科組(國賽)。 國賽比省賽難一些&#xff0c;做得汗流浹背&#xff0c;T_T. RC-u1 大家一起查作弊 分值: 15分 這題真的太有意思&#xff0c;看看描述 在今年的睿抗比賽上&#xff0c;有同學的提交代碼如下&#xff1…

hghac和hgproxy版本升級相關操作和注意事項

文章目錄 環境文檔用途詳細信息 環境 系統平臺&#xff1a;N/A 版本&#xff1a;4.5.6,4.5.7,4.5.8 文檔用途 本文檔用于高可用集群環境中hghac組件和hgproxy組件替換和升級操作 詳細信息 1.關閉服務 所有數據節點都執行 1、關閉hgproxy服務 [roothgdb01 tools]# system…

userfaultfd內核線程D狀態問題排查

問題現象 運維反應機器上出現了很多D狀態進程&#xff0c;也kill不掉,然后將現場保留下來進行排查。 排查過程 都是內核線程&#xff0c;先看下內核棧D在哪了&#xff0c;發現D在了userfaultfd的pagefault流程。 uffd知識補充 uffd探究 uffd在firecracker與e2b的架構下使…

深入解析:構建高性能異步HTTP客戶端的工程實踐

一、架構設計原理與核心優勢 HTTP/2多路復用技術的本質是通過單一的TCP連接并行處理多個請求/響應流&#xff0c;突破了HTTP/1.1的隊頭阻塞限制。在異步編程模型下&#xff0c;這種特性與事件循環機制完美結合&#xff0c;形成了高性能網絡通信的黃金組合。相較于傳統同步客戶…

根據臺賬批量制作個人表

1. 前期材料準備 1&#xff09;要有 人員總的信息臺賬 2&#xff09;要有 個人明白卡模板 2. 開始操作 1&#xff09;打開 人員總的信息臺賬&#xff0c;選擇所需要的數據模塊&#xff1b; 2&#xff09;點擊插入&#xff0c;選擇數據透視表&#xff0c;按流程操作&…

《AI大模型應知應會100篇》第65篇:基于大模型的文檔問答系統實現

第65篇&#xff1a;基于大模型的文檔問答系統實現 &#x1f4da; 摘要&#xff1a;本文詳解如何構建一個基于大語言模型&#xff08;LLM&#xff09;的文檔問答系統&#xff0c;支持用戶上傳 PDF 或 Word 文檔&#xff0c;并根據其內容進行智能問答。從文檔解析、向量化、存儲到…

RTK哪個品牌好?2025年RTK主流品牌深度解析

在測繪領域&#xff0c;RTK 技術的發展日新月異&#xff0c;選擇一款性能卓越、穩定可靠的 RTK 設備至關重要。2025 年&#xff0c;市場上涌現出眾多優秀品牌&#xff0c;本文將深入解析幾大主流品牌的核心競爭力。 華測導航&#xff08;CHCNAV&#xff09;&#xff1a;技術創…

SpringCloud微服務開發與實戰

本節內容帶你認識什么是微服務的特點&#xff0c;微服務的拆分&#xff0c;會使用Nacos實現服務治理&#xff0c;會使用OpenFeign實現遠程調用&#xff08;通過黑馬商城來帶你了解實際開發中微服務項目&#xff09; 前言&#xff1a;從谷歌搜索指數來看&#xff0c;國內從自201…

pgsql14自動創建表分區

最近有pgsql的分區表功能需求&#xff0c;沒想到都2025年了&#xff0c;pgsql和mysql還是沒有自身支持自動創建分區表的功能 現在pgsql數據庫層面還是只能用老三樣的辦法來處理這個問題&#xff0c;每個方法各有優劣 1. 觸發器 這是最傳統的方法&#xff0c;通過創建一個觸發…

math toolkit for real-time development讀書筆記一三角函數快速計算(1)

一、基礎知識 根據高中知識我們知道&#xff0c;很多函數都可以用泰勒級數展開。正余弦泰勒級數展開如下&#xff1a; 將其進一步抽象為公式可知&#xff1a; 正弦和余弦的泰勒級數具有高度結構化的模式&#xff0c;可拆解為以下核心特征&#xff1a; 1. 符號交替特性 正弦級…

uni-app 中適配 App 平臺

文章目錄 前言? 1. App 使用的 Runtime 架構&#xff1a;**WebView 原生容器&#xff08;plus runtime&#xff09;**&#x1f4cc; 技術棧核心&#xff1a; ? 2. WebView Native 的通信機制詳解&#xff08;JSBridge&#xff09;&#x1f4e4; Web → Native 調用&#xf…

SpringBoot基礎(靜態資源導入)

靜態資源導入 在WebMvcAutoConfiguration自動配置類中 有一個添加資源的方法&#xff1a; public void addResourceHandlers(ResourceHandlerRegistry registry) { //如果靜態資源已經被自定義了&#xff0c;則直接生效if (!this.resourceProperties.isAddMappings()) {logg…