大模型開發:源碼分析 Qwen 2.5-VL 視頻抽幀模塊(附加FFmpeg 性能對比測試)

目錄

qwen 視頻理解能力

messages 構建 demo

qwen 抽幀代碼分析

驗證兩個實際 case

官網介紹圖

性能對比:ffmpeg 抽幀、decord 庫抽幀

介紹

聯系

對比

測試結果

測試明細

ffmpeg

100 qps 測試(CPU)

decord

100 qps 測試(CPU)

100 qps 測試(GPU)


本文也錄制了詳細的視頻講解:

[IT超016] 大模型:源碼分析Qwen2.5VL視頻抽幀模塊(附加FFmpeg性能對比測試)_嗶哩嗶哩_bilibili

qwen 視頻理解能力

Qwen2.5-VL 是由阿里云 Qwen 團隊開發的多模態大型語言模型系列,倉庫地址:https://github.com/QwenLM/Qwen2.5-VL

messages 構建 demo

# 方式一:輸入視頻文件(這種才會走抽幀邏輯)
messages = [{"role": "user","content": [{"type": "video","video": "file:///path/to/video1.mp4","max_pixels": 360 * 420,"fps": 1.0,},{"type": "text", "text": "Describe this video."},],}
]# 方式二:直接輸入多圖
messages = [{"role": "user","content": [{"type": "video","video": ["file:///path/to/frame1.jpg","file:///path/to/frame2.jpg","file:///path/to/frame3.jpg","file:///path/to/frame4.jpg",],},{"type": "text", "text": "Describe this video."},],}
]

qwen 抽幀代碼分析

視頻 message 處理的核心代碼:https://github.com/QwenLM/Qwen2.5-VL/blob/main/qwen-vl-utils/src/qwen_vl_utils/vision_process.py

視頻解析抽幀能力依賴——decord 庫:https://github.com/dmlc/decord?tab=readme-ov-file#install-from-source

Decord 是一個專門為視頻數據處理和深度學習設計的輕量級、高性能的視頻解碼庫,擅長處理幀的隨機訪問模式,避免了像 FFmpeg 那樣從頭開始逐幀解碼——Qwen 抽幀模塊用的這個庫


?

1、vision_process.py # process_vision_info:處理 messages 中的 圖像 / 視頻 輸入


?

2、vision_process.py # fetch_video:處理 messages 中的 視頻 輸入


?

🚩 核心抽幀邏輯(簡單來說:0.5 秒抽一張)(30 秒視頻,最終抽幀是 60 張)

根據 FPS 常數(默認 2)、視頻總幀數(秒時長 * 原始 fps)計算抽幀數量 nframes,之后等距離/步長抽取 nframes 張幀圖

  • 可解析總幀數 = 秒時長 * 原始 fps ———— 例如 30s 視頻,24 fps,值為 720
  • 抽幀數 = FPS 常數(默認 2)* 秒時長 ————例如 30s 視頻,值為 60張
  • 抽幀步長:默認 0.5 秒————(等距步長平均分割,和 FPS 常數有關)


?



?

驗證兩個實際 case

錄屏設置:24 fps

方案

30秒 的視頻

1分30秒 的視頻

qwen 抽幀

加入日志


?


?

...

加入日志


?

...


?

摘出 qwen 2.5-vl 抽幀模塊代碼(增加自定義日志)

import torch
import time
import math
from typing import Tuple
from torchvision.utils import save_imageIMAGE_FACTOR = 28
MIN_PIXELS = 4 * 28 * 28
MAX_PIXELS = 16384 * 28 * 28
MAX_RATIO = 200VIDEO_MIN_PIXELS = 128 * 28 * 28
VIDEO_MAX_PIXELS = 768 * 28 * 28
FRAME_FACTOR = 2
FPS = 2.0
FPS_MIN_FRAMES = 4
FPS_MAX_FRAMES = 768def _read_video_decord(ele: dict,
) -> Tuple[torch.Tensor, float]:"""read video using decord.VideoReaderArgs:ele (dict): a dict contains the configuration of video.support keys:- video: the path of video. support "file://", "http://", "https://" and local path.- video_start: the start time of video.- video_end: the end time of video.Returns:torch.Tensor: the video tensor with shape (T, C, H, W)."""import decordvideo_path = ele["video"]st = time.time()vr = decord.VideoReader(video_path)# TODO: support start_pts and end_ptsif 'video_start' in ele or 'video_end' in ele:raise NotImplementedError("not support start_pts and end_pts in decord for now.")total_frames, video_fps = len(vr), vr.get_avg_fps()print(f"==11:  {video_path=}, {total_frames=}, {video_fps=}, time={time.time() - st:.3f}s\n")nframes = smart_nframes(ele, total_frames=total_frames, video_fps=video_fps)idx = torch.linspace(0, total_frames - 1, nframes).round().long().tolist()video = vr.get_batch(idx).asnumpy()print(f"==22:  {nframes=}, {idx=}, {len(idx)=}, video: ")print("Type:", type(video))print("Shape:", video.shape)print("Data Type:", video.dtype)print("Number of dimensions:", video.ndim)print("Number of elements:", video.size)print("Size in bytes:", video.nbytes)print('\n')video = torch.tensor(video).permute(0, 3, 1, 2)  # Convert to TCHW formatsample_fps = nframes / max(total_frames, 1e-6) * video_fpsreturn video, sample_fpsdef smart_nframes(ele: dict,total_frames: int,video_fps: float,
) -> int:"""calculate the number of frames for video used for model inputs.Args:ele (dict): a dict contains the configuration of video.support either `fps` or `nframes`:- nframes: the number of frames to extract for model inputs.- fps: the fps to extract frames for model inputs.- min_frames: the minimum number of frames of the video, only used when fps is provided.- max_frames: the maximum number of frames of the video, only used when fps is provided.total_frames (int): the original total number of frames of the video.video_fps (int | float): the original fps of the video.Raises:ValueError: nframes should in interval [FRAME_FACTOR, total_frames].Returns:int: the number of frames for video used for model inputs."""assert not ("fps" in ele and "nframes" in ele), "Only accept either `fps` or `nframes`"if "nframes" in ele:nframes = round_by_factor(ele["nframes"], FRAME_FACTOR)else:fps = ele.get("fps", FPS)min_frames = ceil_by_factor(ele.get("min_frames", FPS_MIN_FRAMES), FRAME_FACTOR)max_frames = floor_by_factor(ele.get("max_frames", min(FPS_MAX_FRAMES, total_frames)), FRAME_FACTOR)nframes = total_frames / video_fps * fpsif nframes > total_frames:print(f"smart_nframes: nframes[{nframes}] > total_frames[{total_frames}]")nframes = min(min(max(nframes, min_frames), max_frames), total_frames)nframes = floor_by_factor(nframes, FRAME_FACTOR)if not (FRAME_FACTOR <= nframes and nframes <= total_frames):raise ValueError(f"nframes should in interval [{FRAME_FACTOR}, {total_frames}], but got {nframes}.")return nframesdef round_by_factor(number: int, factor: int) -> int:"""Returns the closest integer to 'number' that is divisible by 'factor'."""return round(number / factor) * factordef ceil_by_factor(number: int, factor: int) -> int:"""Returns the smallest integer greater than or equal to 'number' that is divisible by 'factor'."""return math.ceil(number / factor) * factordef floor_by_factor(number: int, factor: int) -> int:"""Returns the largest integer less than or equal to 'number' that is divisible by 'factor'."""return math.floor(number / factor) * factorvideo, sample_fps = _read_video_decord(ele={"video": "150108580006469_30s.mp4"})
print(f"read_video_decord result:  {video=}, {sample_fps=}\n")# 將視頻幀保存為本地圖片
for i, frame in enumerate(video):# 將像素值縮放到 [0, 1] 范圍frame = frame.float() / 255.0save_image(frame, f'./video-frame-30s/frame_{i}.png')# save_image(frame, f'./video-frame-1m30s/frame_{i}.png')print(f"Frame {i} saved as frame_{i}.png")

官網介紹圖


?

性能對比:ffmpeg 抽幀、decord 庫抽幀

介紹

ffmpeg 是一個強大且廣泛使用的開源多媒體框架,它由多個庫和工具組成,例如libavformat(處理音視頻封裝格式)、libavcodec(進行音視頻編解碼)、libavutil(提供通用的工具函數)等。在抽幀時,FFmpeg 會利用這些庫協同工作。


?

Decord 是一個專門為視頻數據處理和深度學習設計的輕量級、高性能的視頻解碼庫,擅長處理幀的隨機訪問模式,避免了像 FFmpeg 那樣從頭開始逐幀解碼


?

聯系

decord 依賴 ffmpeg 的核心庫


?

對比

  • 速度:ffmpeg 更優,比 decord 快 16%
  • 資源消耗:ffmpeg 更優,比 decord 節省資源 25%(只測了下 cpu 抽幀)
  • 官方維護:
    • ffmpeg 一直在更新,社區也更活躍,48.9k star
    • decord 庫已經 3 年未更新,2.1k star


?

測試結果

測試指標:

  • 100 batch 視頻文件測試
  • 開發機:train-A100-6 配置為 94核 - 860GiB - 4卡A100


?

抽幀方案

測試樣本(37秒視頻)

video_150108527915923_37s.mp4

測試樣本(1分21秒視頻)video_150108525914511_1m21s.mp4

現狀

ffmpeg - cpu

總耗時: 4.18 秒

平均耗時: 2829.07 毫秒

成功數: 100

失敗數: 0


?

抽出 37 張 + 寫入磁盤


?

CPU核數換算——需 7 核(94*6%*120%)

總耗時: 12.09 秒

平均耗時: 9383.33 毫秒

成功數: 100

失敗數: 0


?

抽出 81 張 + 寫入磁盤


?

CPU核數換算——需 23 核(94*22%*120%)

新方案

decord - cpu

總耗時: 5.33 秒

平均耗時: 3352.33 毫秒

成功數: 100

失敗數: 0


?

抽出 38 張 + 寫入磁盤



?

CPU核數換算——需 7 核(94*7%*120%)

總耗時: 15.89 秒

平均耗時: 12617.40 毫秒

成功數: 100

失敗數: 0


?

抽出 85 張 + 寫入磁盤


?

CPU核數換算——需 24 核(94*25%*120%)


?

decord - gpu

環境不兼容

環境不兼容



?

測試明細

ffmpeg

# 登陸開發機

ffmpeg -i /root/zhoulongchao/script/resource/video_150108527915923_37s.mp4 -map 0:v -q:v 3 -vsync 0 -f image2 -vf fps=1 -y ./%d.jpg


?

100 qps 測試(CPU)

cd /root/zhoulongchao/script/ffmpeg

vim demo-ffmpeg.py

python demo-ffmpeg.py

import subprocess
import time
from concurrent.futures import ThreadPoolExecutordef run_ffmpeg_command():# FFmpeg 命令command = ['ffmpeg', '-i', '/root/zhoulongchao/script/resource/video_150108525914511_1m21s.mp4','-map', '0:v', '-q:v', '3', '-vsync', '0', '-f', 'image2', '-vf', 'fps=1', '-y', './%d.jpg']start_time = time.time()# 運行 FFmpeg 命令result = subprocess.run(command, capture_output=True, text=True)end_time = time.time()# 計算耗時(毫秒)elapsed_time_ms = (end_time - start_time) * 1000print("FFmpeg 輸出:")print(result.stdout)print("錯誤信息:")print(result.stderr)print(f"耗時: {elapsed_time_ms:.2f} 毫秒")# 根據返回碼判斷是否成功success = result.returncode == 0return elapsed_time_ms, successif __name__ == "__main__":# 目標 QPStarget_qps = 100# 每個請求的間隔時間(秒)interval = 1 / target_qpstotal_elapsed_time = 0all_elapsed_times = []success_count = 0failure_count = 0with ThreadPoolExecutor(max_workers=target_qps) as executor:start_time = time.time()futures = []for _ in range(target_qps):future = executor.submit(run_ffmpeg_command)futures.append(future)time.sleep(interval)for future in futures:elapsed_time, success = future.result()all_elapsed_times.append(elapsed_time)total_elapsed_time += elapsed_timeif success:success_count += 1else:failure_count += 1end_time = time.time()average_elapsed_time = total_elapsed_time / target_qps if target_qps > 0 else 0print(f"總耗時: {end_time - start_time:.2f} 秒")print(f"平均耗時: {average_elapsed_time:.2f} 毫秒")print(f"成功數: {success_count}")print(f"失敗數: {failure_count}")


?

decord

cd /root/zhoulongchao/script/decord

vim main.py

python main.py


?

100 qps 測試(CPU)

import cv2
import time
from decord import VideoReader
from decord import cpu
from concurrent.futures import ProcessPoolExecutor
import multiprocessingdef process_video(video_path):start_time = time.time()try:vr = VideoReader(video_path, ctx=cpu(0))fps = vr.get_avg_fps()interval = int(fps)for i in range(0, len(vr), interval):frame = vr[i].asnumpy()frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)cv2.imwrite(f'frame_{i}.jpg', frame_bgr)end_time = time.time()elapsed_time = (end_time - start_time) * 1000return elapsed_time, Trueexcept Exception:end_time = time.time()elapsed_time = (end_time - start_time) * 1000return elapsed_time, Falseif __name__ == "__main__":video_path = '/root/zhoulongchao/script/resource/video_150108527915923_37s.mp4'target_qps = 100interval = 1 / target_qpstotal_elapsed_time = 0success_count = 0failure_count = 0# 獲取系統的 CPU 核心數量cpu_count = multiprocessing.cpu_count()with ProcessPoolExecutor(max_workers=cpu_count) as executor:start_time = time.time()futures = []for _ in range(target_qps):future = executor.submit(process_video, video_path)futures.append(future)time.sleep(interval)for future in futures:elapsed_time, success = future.result()total_elapsed_time += elapsed_timeif success:success_count += 1else:failure_count += 1end_time = time.time()average_elapsed_time = total_elapsed_time / target_qps if target_qps > 0 else 0print(f"總耗時: {end_time - start_time:.2f} 秒")print(f"平均耗時: {average_elapsed_time:.2f} 毫秒")print(f"成功數: {success_count}")print(f"失敗數: {failure_count}")



?

100 qps 測試(GPU)

?》這種方式環境配置失敗了,暫時只寫了一半

1、安裝用于構建共享庫的系統包 Ubuntu 運行:

# official PPA comes with ffmpeg 2.8, which lacks tons of features, we use ffmpeg 4.0 here
add-apt-repository ppa:jonathonf/ffmpeg-4 # for ubuntu20.04 official PPA is already version 4.2, you may skip this step
apt-get update
apt-get install -y build-essential python3-dev python3-setuptools make cmake
apt-get install -y ffmpeg libavcodec-dev libavfilter-dev libavformat-dev libavutil-dev
# note: make sure you have cmake 3.8 or later, you can install from cmake official website if it's too old


?

2、遞歸克隆 repo(重要)

git clone --recursivehttps://github.com/dmlc/decord


?

3、在源根目錄中構建共享庫(指定-DUSE_CUDA=ON或-DUSE_CUDA=/path/to/cuda或-DUSE_CUDA=ON-DCMAKE_CUDA_COMPILER=/path/to/cuda/nvcc啟用 NVDEC 硬件加速解碼)(要指定自定義的 FFMPEG 庫路徑,請使用“-DFFMPEG_DIR=/path/to/ffmpeg”):

cd /root/zhoulongchao/script/decord

cd decord
mkdir build && cd build
cmake .. -DUSE_CUDA=ON -DCMAKE_BUILD_TYPE=Release
make

請注意,如果您遇到了問題libnvcuvid.so,可能是由于缺少鏈接 libnvcuvid.so,可以手動找到它(ldconfig -p | grep libnvcuvid)并將庫鏈接到,CUDA_TOOLKIT_ROOT_DIR\lib64以便decord順利檢測并鏈接正確的庫。或者——

Video Codec SDK - Get Started | NVIDIA Developer

mv libnvcuvid.so /usr/local/cuda/lib64/


?

4、安裝python綁定:

cd ../python
# option 1: add python path to $PYTHONPATH, you will need to install numpy separately
pwd=$PWD
echo "PYTHONPATH=$PYTHONPATH:$pwd" >> ~/.bashrc
source ~/.bashrc
# option 2: install with setuptools
python3 setup.py install --user


?

make




?

import cv2
import time
from decord import VideoReader
from decord import gpu
from concurrent.futures import ProcessPoolExecutor
import multiprocessingdef process_video(video_path):start_time = time.time()try:# 修改為使用 GPU 進行解碼vr = VideoReader(video_path, ctx=gpu(0))fps = vr.get_avg_fps()interval = int(fps)for i in range(0, len(vr), interval):frame = vr[i].asnumpy()frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)cv2.imwrite(f'frame_{i}.jpg', frame_bgr)end_time = time.time()elapsed_time = (end_time - start_time) * 1000return elapsed_time, Trueexcept Exception:end_time = time.time()elapsed_time = (end_time - start_time) * 1000return elapsed_time, Falseif __name__ == "__main__":video_path = '/root/zhoulongchao/script/resource/video_150108527915923_37s.mp4'target_qps = 100interval = 1 / target_qpstotal_elapsed_time = 0success_count = 0failure_count = 0# 獲取系統的 CPU 核心數量cpu_count = multiprocessing.cpu_count()with ProcessPoolExecutor(max_workers=cpu_count) as executor:start_time = time.time()futures = []for _ in range(target_qps):future = executor.submit(process_video, video_path)futures.append(future)time.sleep(interval)for future in futures:elapsed_time, success = future.result()total_elapsed_time += elapsed_timeif success:success_count += 1else:failure_count += 1end_time = time.time()average_elapsed_time = total_elapsed_time / target_qps if target_qps > 0 else 0print(f"總耗時: {end_time - start_time:.2f} 秒")print(f"平均耗時: {average_elapsed_time:.2f} 毫秒")print(f"成功數: {success_count}")print(f"失敗數: {failure_count}")



?

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

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

相關文章

git的上傳流程

好久沒使用git 命令上傳遠程倉庫了。。。。。溫習了一遍&#xff1b; 幾個注意點--單個文件大小不能超過100M~~~ 一步步運行下面的命令&#xff1a; 進入要上傳的文件夾內&#xff0c;點擊git bash 最終 hbu的小伙伴~有需要nndl實驗的可以自形下載哦

驅動學習專欄--字符設備驅動篇--2_字符設備注冊與注銷

對于字符設備驅動而言&#xff0c;當驅動模塊加載成功以后需要注冊字符設備&#xff0c;同樣&#xff0c;卸載驅動模 塊的時候也需要注銷掉字符設備。字符設備的注冊和注銷函數原型如下所示 : static inline int register_chrdev(unsigned int major, const char *name, const…

redis 放置序列化的對象,如果修改對象,需要修改版本號嗎?

在 Redis 中存儲序列化對象時,如果修改了對象的類結構(例如增刪字段、修改字段類型或順序),是否需要修改版本號取決于序列化協議的兼容性策略和業務場景的容錯需求。以下是詳細分析: 1. 為什么需要考慮版本號? 序列化兼容性問題: 當對象的類結構發生變化時,舊版本的序列…

WPF ObjectDataProvider

在 WPF(Windows Presentation Foundation)中,ObjectDataProvider 是一個非常有用的類,用于將非 UI 數據對象(如業務邏輯類或服務類)與 XAML 綁定集成。它允許在 XAML 中直接調用方法、訪問屬性或實例化對象,而無需編寫額外的代碼。以下是關于 ObjectDataProvider 的詳細…

深度學習-損失函數 python opencv源碼(史上最全)

目錄 定義 種類 如何選擇損失函數&#xff1f; 平方&#xff08;均方&#xff09;損失函數&#xff08;Mean Squared Error, MSE&#xff09; 均方根誤差 交叉熵 對數損失 筆記回饋 邏輯回歸中一些注意事項&#xff1a; 定義 損失函數又叫誤差函數、成本函數、代價函數…

poll為什么使用poll_list鏈表結構而不是數組 - 深入內核源碼分析

一&#xff1a;引言 在Linux內核中,poll機制是一個非常重要的I/O多路復用機制。它允許進程監視多個文件描述符,等待其中任何一個進入就緒狀態。poll的內部實現使用了poll_list鏈表結構而不是數組,這個設計選擇背后有其深層的技術考量。本文將從內核源碼層面深入分析這個設計決…

使用 Azure AKS 保護 Kubernetes 部署的綜合指南

企業不斷尋求增強其軟件開發和部署流程的方法。DevOps 一直是這一轉型的基石,彌合了開發與運營之間的差距。然而,隨著安全威脅日益復雜,將安全性集成到 DevOps 流水線(通常稱為 DevSecOps)已變得勢在必行。本指南深入探討了如何使用 Azure Kubernetes 服務 (AKS) 來利用 D…

2025年常見滲透測試面試題-webshell免殺思路(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 webshell免殺思路 PHP免殺原理 webshell免殺測試&#xff1a; webshell免殺繞過方法&#xff1a; 編…

訪問不到服務器上啟動的llamafactory-cli webui

采用SSH端口轉發有效&#xff0c;在Windows上面進行訪問 在服務器上啟動 llamafactory-cli webui 后&#xff0c;訪問方式需根據服務器類型和網絡環境選擇以下方案&#xff1a; 一、本地服務器&#xff08;物理機/虛擬機&#xff09; 1. 直接訪問 若服務器與操作設備處于同一…

基于 LSTM 的多特征序列預測-SHAP可視化!

往期精彩內容&#xff1a; 單步預測-風速預測模型代碼全家桶-CSDN博客 半天入門&#xff01;鋰電池剩余壽命預測&#xff08;Python&#xff09;-CSDN博客 超強預測模型&#xff1a;二次分解-組合預測-CSDN博客 VMD CEEMDAN 二次分解&#xff0c;BiLSTM-Attention預測模型…

C++ 編程指南35 - 為保持ABI穩定,應避免模板接口

一&#xff1a;概述 模板在 C 中是編譯期展開的&#xff0c;不同模板參數會生成不同的代碼&#xff0c;這使得模板類/函數天然不具備 ABI 穩定性。為了保持ABI穩定&#xff0c;接口不要直接用模板&#xff0c;先用普通類打個底&#xff0c;模板只是“外殼”&#xff0c;這樣 AB…

【iOS】OC高級編程 iOS多線程與內存管理閱讀筆記——自動引用計數(二)

自動引用計數 前言ARC規則所有權修飾符**__strong修飾符**__weak修飾符__unsafe_unretained修飾符__autoreleasing修飾符 規則屬性數組 前言 上一篇我們主要學習了一些引用計數方法的內部實現&#xff0c;現在我們學習ARC規則。 ARC規則 所有權修飾符 OC中&#xff0c;為了處…

可信空間數據要素解決方案

可信空間數據要素解決方案 一、引言 隨著數字經濟的蓬勃發展&#xff0c;數據已成為重要的生產要素。可信空間數據要素解決方案旨在構建一個安全、可靠、高效的數據流通與應用環境&#xff0c;促進數據要素的合理配置和價值釋放&#xff0c;推動各行業的數字化轉型和創新發展…

mysql刪除表后重建表報錯Tablespace exists

版本 mysql:8.0.23 復現步驟 1、刪除表 DROP TABLE IF EXISTS xxx_demo; 2、新建表 CREATE TABLE xxx_demo (id bigint NOT NULL AUTO_INCREMENT COMMENT 主鍵id,creator varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT COMMENT 創建者,c…

【Leetcode-Hot100】缺失的第一個正數

題目 解答 有一處需要注意&#xff0c;我使用注釋部分進行交換值&#xff0c;報錯&#xff1a;超出時間限制。有人知道是為什么嗎&#xff1f;難道是先給nums[i]賦值后&#xff0c;從而改變了后一項的索引&#xff1f; class Solution(object):def firstMissingPositive(sel…

從單模態到多模態:五大模型架構演進與技術介紹

前言 1. ResNet — 殘差神經網絡背景核心問題與解決方案原理模型架構ResNet 系列變體技術創新與影響 2. ViT — Vision Transformer背景核心思想發展歷程Transformer的起源&#xff1a;ViT的出現&#xff1a;ViT的進一步發展&#xff1a; 模型架構技術創新與影響 3. Swin Trans…

JavaScript事件循環

目錄 JavaScript 執行機制與事件循環 一、同步與異步代碼 1. 同步代碼&#xff08;Synchronous Code&#xff09; 2. 異步代碼&#xff08;Asynchronous Code&#xff09; 二、事件循環&#xff08;Event Loop&#xff09; 1. 核心組成 2. 事件循環基本流程 3. 運行機制…

Java Collection(7)——Iterable接口

1.Iterator接口 1.1 Iterator接口和其他集合類的關系 Java集合類中&#xff0c;Iterable接口屬于頂層接口&#xff0c;除Map接口外&#xff0c;其他都實現了Iterable接口&#xff0c;這意味著它們都可以重寫和使用Iterable接口中的方法 1.2 Iterable接口簡介 在JDK1.7以前&a…

若依微服務版啟動小程序后端

目錄標題 本地啟動&#xff0c;dev對應 nacos里的 xxx-xxx-dev配置文件 本地啟動&#xff0c;dev對應 nacos里的 xxx-xxx-dev配置文件

STM32基礎教程——DMA+ADC多通道

目錄 前言 ?編輯 技術實現 連線圖 代碼實現 技術要點 實驗結果 問題記錄 前言 DMA(Direct Memory Access)直接存儲器存取&#xff0c;用來提供在外設和存儲器 之間或者存儲器和存儲器之間的高速數據傳輸。無需CPU干預&#xff0c;數據可以通過DMA快速地移動&#xff0…