当前位置: 首页 > article >正文

qwen2.5-vl多机多卡分布式部署

记录一下工作中进行多机多卡部署qwen2.5-vl多模态大模型踩过的坑
第一个天坑就是官方提供的镜像qwenllm/qwenvl:2.5-cu121有问题,在titan显卡会抛出cuda error:no kernel image is availabe for execution on the device. 这是cuda内核与GPU不兼容的问题,可是手动制作的其他cuda12镜像就能跑。在官网镜像基础上重装cuda11.8,倒是可以用了,但在gradio页面调用时会出现卡死情况,最终还是自己从头配置环境。关于如何配置docker镜像,没啥技术点,这里不说了。

一 容器配置

使用ray+vllm方式进行分布式部署,采用host模式。当一台机器不是所有机器都可用时,需要通过CUDA_VISIBLE_DEVICES变量指定ray分布式使用的显卡编号,通常在起容器时指定,当使用显卡编号有变化时,停掉分布式,在容器内手动指定显卡后再重新搭建分布式集群。

另外,机器之间的通信要指定网卡,host模式容器直接使用宿主机网卡,通过ifconfig查看当前机器可用网卡,每台机器网卡可能不同,所以在启动容器时将当前机器的网卡以环境变量的形式传入。下面就是集群中两台机器使用不同网卡的案例。
在这里插入图片描述

下面是一个启动容器的docker-compose命令,容器不分head与work节点,在容器内搭建集群时指定。

version: "3"services:# 服务名,可以不与container_name同名, 在Nginx中使用服务名做调度,yblir_qwen2.5-vl:image: qwen2.5-vl:cu12-torch25-vllm073-distcontainer_name: dist_head_qwen2.5-vl# 获取宿主机root权限,要映射端口也需要trueprivileged: true# 设置共享内存大小为16g,防止分布式训练dataloader时出错shm_size: "32gb"# 路径映射, 主机目录:容器内目录volumes:- /home/data/liyabin_project:/home#ports:#    - "10086:22"        # 容器内22端口映射到外部10086,22端口通常用于在外部调用容器内Python环境#    - "10087:10087"     # 用途待定,比如可以tensorboard --logdir=路径 --port 10087  # 从外部传入变量environment:- NVIDIA_VISIBLE_DEVICES=0,3,4- GLOO_SOCKET_IFNAME=enp134s0f0- NCCL_SOCKET_IFNAME=enp134s0f0# 容器重新启动,比如当容器被其他人kill了,会自动重启restart: alwaysentrypoint: /bin/bash# command: ["-c", "ray start --head --dashboard-host=0.0.0 --port 6379"]tty: truenetwork_mode:"bridge"    # 默认桥接模式,容器之间不须要互相通讯."host"    # 当前模式下ports端口映射失效, 容器环境不隔离,将使用主机的端口和ip.

注意,所有容器的环境,容器内模型文件路径必须一致。

vllm官方给了一个部署脚本,不好用,这里使用更灵活的手动搭建集群的方法。前面说在搭建集群时确定head与work节点,
在想做head节点的容器内执行如下命令:

ray start --head --dashboard-host=0.0.0.0 --port=6379

在work容器节点执行如下命令:

ray start --address='xx.xx.xx.xx:6379'

只能有一个head节点,work可以有多个。

在任意容器节点执行ray status,可以看到集群上所有节点设备情况
在这里插入图片描述ray另一个常用命令是ray stop, 停止集群。在head节点上执行会杀掉整个集群,在work节点上执行则仅会卸载当前节点。
关于ray, 会使用这两个命令就能应对绝大部分集群问题。

在head节点执行启动集群时,会暴露一个URL,在浏览器页面监控设备使用情况:
在这里插入图片描述
如果一切顺利,到此完成集群搭建工作了,不过过程中难免会出现各种各样的坑,比如我曾在2x8 2080ti设备上搭建集群,work节点介入集群后很快就掉线,推测大概率时机器间通信不稳定造成的,所以,搭建集群的机器尽量处在同一网段。

二 环境测试

搭建好集群后,还需要对环境做测试,保证代码能跑通。
部署qwen2.5-vl最低环境要求为vllm>=0.7.2, transformers>=4.49

使用vllm命令行启动3b量化版来做测试:

vllm serve /home/Qwen2.5-VL-3B-Instruct-AWQ --tensor-parallel-size 2 --pipeline-parallel-size 2 --dtype float16 \
--port 8811 --gpu-memory-untilization 0.5 --max-num-seqs 2 --max-model-len 4096 --enforce-eager
  • 问题1 cuda error: cuda error:no kernel image is availabe for execution on the device
    问题看起来是cuda内核与GPU不兼容,开始以为是各种依赖包和cuda装的版本太高,不兼容titan显卡了,多次排查无果,只得重装cuda11.8,问题解决。之后又从零构建了cuda12.1的镜像,可以正常使用,只能把锅甩给qwen官方提供的镜像有问题。
    在这里插入图片描述
  • 问题2 attendtion计算后端不兼容问题
    xformers wasn’t build with CUDA suport
    requires device with capability > (8, 0) but your GPU has capability (7, 5)
    原因:计算后端要在当前设备上现场编译,比如下面这个,xformers是在其他显卡预编译好的,使用时就会报错。
    在这里插入图片描述
    下载xformers源码编译安装,之后查看xformers详细信息。
python -m xformers.info

在这里插入图片描述

  • 问题3 量化问题
    The input size is not aligned with the quantized weight shape. This can be casused by too large tensor parallel size
    官方早起Qwen2.5-VL-72B-Instruct-AWQ没做好,记得是FFN层参数不能整除的原因,不支持–tensor-parallel-size 2,4,8等设置,不过现在新版模型官方已经做好,不纠结这个问题了。
    在这里插入图片描述- 问题4 max_model_len设置问题
    valueerror: The model’s max seq len (10240) is larger than the maximum number of tokens that can be stored in KV cache (3408). Try increasing ‘gpu_memory_utilization’ or decreasing max_model_len when initializing the engine.
    原因: 这是设定最大上下文长度超过可存储的最大的kv-cache数量, 是显存不足的表现之一,增加gpu_memory_utilization或减少max_model_len可解决
    在这里插入图片描述
    max_model_len由入参指定, kv-cache在初始化时配置, 二者是一对相互矛盾的值, 当把max_model_len从10240减小到5120时, cuda blocks可用之从213增加到2090.
    在这里插入图片描述
  • 问题5 显存不足的另一中表现
    torch.outofmemoryerror:cuda out of memory. tried to allocate 640.00MiB GPU 0 has a total capacity …
    解决方案同问题4, 当修改gpu_memory_utilization后,报错信息无变化(连报错数值都没变化), 基本可确定是max_model_len引起的. 这是因为vllm初始化时会提前开辟一块显存空间存储max_model_len个全0 kv-cache备用, 开启这块空间时显存不够引起了报错. 关于max_model_len与kv-cache的关系在问题4中有说明.
    在这里插入图片描述
  • 问题6 head整除问题
    total number of attention heads(16) must be divisible by tensor parallel size(6)
    这是–tensor-parallel-size值没设定好,这个值必须被attention heads 整数. 模型head数量在模型文件config.json中可查看.
    vllm 中tensor-parallel-size=N是指张量并行,标准说法是将 QKV 投影的参数矩阵会被切分成 N 份,每个 GPU 只存储并计算其中的一部分. 说人话就是一个attention由多个head attention组成, 将所有heads均分到N个gpu上做计算(有行并行和列并行的两种方式), 然后合并结果.
    在这里插入图片描述
  • 问题7 分布式启动问题
    runtimeError: cannot re-initialize cuda in forked subprocess. To use CUDA with multiprocessing. you must use the ‘spawn’ start method
    原因: vllm与torch两个组件分布式模块冲突, 在环境变量或启动脚本中指定分布式方式就好.
import os
os.environ['VLLM_WORKER_MULTIPROC_METHOD']='spawn'

在这里插入图片描述

三 服务代码改写及部署

使用vllm serve启动服务,然后通过request请求调用, 这是常用的方式,在上一份工作qwen2.5-vl使用vllm部署gradio页面调用已经详细描述过

工作中本地部署还尝试了另一方案,即改造qwen2.5-vl官方给的本地gradio页面调用的方式. vllm+gradio属于异步调用, 要使用vllm的AsyncLLMEngine来构建推理模型.

# -*- coding: utf-8 -*-
# @Time    : 2025/3/10 下午19:31
# @Author  : yblir
# @File    : dist_demo_mm.py
# explain  :
# =======================================================import copy
import re
from argparse import ArgumentParser# from threading import Thread
import threading
from vllm import SamplingParams, AsyncLLMEngine
from vllm.engine.arg_utils import AsyncEngineArgsimport gradio as gr
import torch
from qwen_vl_utils import process_vision_info
from transformers import AutoProcessor, Qwen2_5_VLForConditionalGeneration, TextIteratorStreamer# DEFAULT_CKPT_PATH = '/home/Qwen2.5-VL-7B-Instruct'
# DEFAULT_CKPT_PATH = r'E:\PyCharm\PreTrainModel\Qwen2.5-VL-7B-Instruct'
DEFAULT_CKPT_PATH = '/home/Qwen25-VL-3B-Instruct-AWQ'def _get_args():parser = ArgumentParser()parser.add_argument('-c','--checkpoint-path',type=str,default=DEFAULT_CKPT_PATH,help='Checkpoint name or path, default to %(default)r')parser.add_argument('--cpu-only', action='store_true', help='Run demo with CPU only')parser.add_argument('--flash-attn2',action='store_true',default=False,help='Enable flash_attention_2 when loading the model.')parser.add_argument('--share',action='store_true',default=False,help='Create a publicly shareable link for the interface.')parser.add_argument('--inbrowser',action='store_true',default=False,help='Automatically launch the interface in a new tab on the default browser.')# ===================================================================================================================parser.add_argument('--server-port', type=int, default=7860, help='Demo server port.')parser.add_argument('--server-name', type=str, default='0.0.0.0', help='Demo server name.')parser.add_argument('--max-image-nums',type=int,default=10,help='多轮对话时可接受的最大图片数量')parser.add_argument('--dtype',type=str,default='float16',help='模型处理的数据类型,这里默认使用flaot16,减少显存')parser.add_argument('--gpu-memory-utilization',type=float,default=0.15,help='vllm要占用的gpu显存比例,若有其他程序也在使用显卡, 需要把该值设小')parser.add_argument('--enforce-eager',action='store_true',default=True,help='false时使用cuda graph, 会增加显存占用')parser.add_argument('--max-model-len',type=int,default=4096,help='可处理的最大输入token数量, 如果进行多轮对话,需要设置大值,不然token数量会超标,''也可以缺省,不设上限, 不过这样有报显存风险')parser.add_argument('--tensor-parallel-size',type=int,default=2,help='一台机器上使用的gpu数量, 该值的设定需要被attention的head数量整除')parser.add_argument('--pipeline-parallel-size',type=int,default=2,help='分布式系统使用的机器数量')args = parser.parse_args()return argsdef _parse_text(text):lines = text.split('\n')lines = [line for line in lines if line != '']count = 0for i, line in enumerate(lines):if '```' in line:count += 1items = line.split('`')if count % 2 == 1:lines[i] = f'<pre><code class="language-{items[-1]}">'else:lines[i] = '<br></code></pre>'else:if i > 0:if count % 2 == 1:line = line.replace('`', r'\`')line = line.replace('<', '&lt;')line = line.replace('>', '&gt;')line = line.replace(' ', '&nbsp;')line = line.replace('*', '&ast;')line = line.replace('_', '&lowbar;')line = line.replace('-', '&#45;')line = line.replace('.', '&#46;')line = line.replace('!', '&#33;')line = line.replace('(', '&#40;')line = line.replace(')', '&#41;')line = line.replace('$', '&#36;')lines[i] = '<br>' + linetext = ''.join(lines)return textdef _remove_image_special(text):text = text.replace('<ref>', '').replace('</ref>', '')return re.sub(r'<box>.*?(</box>|$)', '', text)def _is_video_file(filename):video_extensions = ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm', '.mpeg']return any(filename.lower().endswith(ext) for ext in video_extensions)def _gc():import gcgc.collect()if torch.cuda.is_available():torch.cuda.empty_cache()def _transform_messages(original_messages):transformed_messages = []for message in original_messages:new_content = []for item in message['content']:if 'image' in item:new_item = {'type': 'image', 'image': item['image']}elif 'text' in item:new_item = {'type': 'text', 'text': item['text']}elif 'video' in item:new_item = {'type': 'video', 'video': item['video']}else:continuenew_content.append(new_item)new_message = {'role': message['role'], 'content': new_content}transformed_messages.append(new_message)return transformed_messagesasync def async_generate(request_id, engine, inputs):sampling_params = SamplingParams(temperature=0.1,top_p=0.001,repetition_penalty=1.05,max_tokens=512,stop_token_ids=[])response_gen = engine.generate(request_id=request_id,prompt=inputs,sampling_params=sampling_params)async for result in response_gen:for output in result.outputs:yield output.textdef _launch_demo(args, model, processor):async def call_local_model(model, processor, messages):request_id = f"req-{threading.get_ident()}"messages = _transform_messages(messages)text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)# image_inputs, video_inputs = process_vision_info(messages)image_inputs, video_inputs, video_kwargs = process_vision_info(messages, return_video_kwargs=True)mm_data = {}if image_inputs is not None:mm_data['image'] = image_inputsif video_inputs is not None:mm_data["video"] = video_inputsll_inputs = {'prompt'             : text,'multi_modal_data'   : mm_data,# FPS will be returned in video_kwargs"mm_processor_kwargs": video_kwargs}async for new_next in async_generate(request_id, model, ll_inputs):yield new_nextdef create_predict_fn():async def predict(_chatbot, task_history):nonlocal model, processorchat_query = _chatbot[-1][0]query = task_history[-1][0]if len(chat_query) == 0:_chatbot.pop()task_history.pop()yield _chatbotprint('User: ' + _parse_text(query))history_cp = copy.deepcopy(task_history)full_response = ''messages = []content = []for q, a in history_cp:if isinstance(q, (tuple, list)):if _is_video_file(q[0]):content.append({'video': f'file://{q[0]}'})else:content.append({'image': f'file://{q[0]}'})else:content.append({'text': q})messages.append({'role': 'user', 'content': content})messages.append({'role': 'assistant', 'content': [{'text': a}]})content = []messages.pop()async for response in call_local_model(model, processor, messages):# print("response=",response)_chatbot[-1] = (_parse_text(chat_query), _remove_image_special(_parse_text(response)))yield _chatbotfull_response = _parse_text(response)task_history[-1] = (query, full_response)print('Qwen-VL-Chat: ' + _parse_text(full_response))yield _chatbotreturn predictdef create_regenerate_fn():async def regenerate(_chatbot, task_history):nonlocal model, processorif not task_history:yield _chatbotitem = task_history[-1]if item[1] is None:yield _chatbottask_history[-1] = (item[0], None)chatbot_item = _chatbot.pop(-1)if chatbot_item[0] is None:_chatbot[-1] = (_chatbot[-1][0], None)else:_chatbot.append((chatbot_item[0], None))_chatbot_gen = predict(_chatbot, task_history)async for _chatbot in _chatbot_gen:yield _chatbotreturn regeneratepredict = create_predict_fn()regenerate = create_regenerate_fn()def add_text(history, task_history, text):task_text = texthistory = history if history is not None else []task_history = task_history if task_history is not None else []history = history + [(_parse_text(text), None)]task_history = task_history + [(task_text, None)]return history, task_history, ''def add_file(history, task_history, file):history = history if history is not None else []task_history = task_history if task_history is not None else []history = history + [((file.name,), None)]task_history = task_history + [((file.name,), None)]return history, task_historydef reset_user_input():return gr.update(value='')def reset_state(_chatbot, task_history):task_history.clear()_chatbot.clear()_gc()return []with gr.Blocks() as demo:gr.Markdown("""\
<p align="center"><img src="https://modelscope.oss-cn-beijing.aliyuncs.com/resource/qwen.png" style="height: 80px"/><p>""")gr.Markdown("""<center><font size=8>Qwen2.5-VL</center>""")gr.Markdown("""\
<center><font size=3>This WebUI is based on Qwen2.5-VL, developed by Alibaba Cloud.</center>""")gr.Markdown("""<center><font size=3>本WebUI基于Qwen2.5-VL�?/center>""")chatbot = gr.Chatbot(label='Qwen2.5-VL', elem_classes='control-height', height=500)query = gr.Textbox(lines=2, label='Input')task_history = gr.State([])with gr.Row():addfile_btn = gr.UploadButton('📁 Upload (上传文件)', file_types=['image', 'video'])submit_btn = gr.Button('🚀 Submit (发送)')regen_btn = gr.Button('🤔️ Regenerate (重试)')empty_bin = gr.Button('🧹 Clear History (清除历史)')submit_btn.click(add_text, [chatbot, task_history, query],[chatbot, task_history]).then(predict, [chatbot, task_history], [chatbot], show_progress=True)submit_btn.click(reset_user_input, [], [query])empty_bin.click(reset_state, [chatbot, task_history], [chatbot], show_progress=True)regen_btn.click(regenerate, [chatbot, task_history], [chatbot], show_progress=True)addfile_btn.upload(add_file, [chatbot, task_history, addfile_btn], [chatbot, task_history], show_progress=True)gr.Markdown("""\
<font size=2>Note: This demo is governed by the original license of Qwen2.5-VL. \
We strongly advise users not to knowingly generate or allow others to knowingly generate harmful content, \
including hate speech, violence, pornography, deception, etc. \
(注:本演示受Qwen2.5-VL的许可协议限制。我们强烈建议,用户不应传播及不应允许他人传播以下内容,\
包括但不限于仇恨言论、暴力、色情、欺诈相关的有害信息�?""")demo.queue().launch(share=args.share,inbrowser=args.inbrowser,server_port=args.server_port,server_name=args.server_name,)def main():args = _get_args()engine_args = AsyncEngineArgs(model=args.checkpoint_path,limit_mm_per_prompt={"image": args.max_image_nums, "video": 10},dtype=args.dtype,gpu_memory_utilization=args.gpu_memory_utilization,enforce_eager=args.enforce_eager,max_model_len=args.max_model_len,tensor_parallel_size=args.tensor_parallel_size,pipeline_parallel_size=args.pipeline_parallel_size)model = AsyncLLMEngine.from_engine_args(engine_args)processor = AutoProcessor.from_pretrained(args.checkpoint_path)_launch_demo(args, model, processor)# 简单描述下这张图片
if __name__ == '__main__':main()

在2台 2080ti机器,共16张显卡上部署Qwen2.5-VL-72B-Instruct模型, 显存共占用约149GB
在这里插入图片描述

关于bfloat16与float16的区别
bfloat16只支持Ampere架构,公司大多数旧卡2080ti, rtx titan都用不了. 于是特地在RTX 4060上测试这两个数据类型对显存的占用情况.

下图是在单机4张4060显卡上,分别使用两种类型部署Qwen2.5-VL-7B-Instruct的显存占用情况:
(27966-17938)/1024=9.8GB

bfloat16要比float16要整体增加约9.8G显存. 当显存资源紧张时, 建议使用float16类型.
在这里插入图片描述

相关文章:

qwen2.5-vl多机多卡分布式部署

记录一下工作中进行多机多卡部署qwen2.5-vl多模态大模型踩过的坑 第一个天坑就是官方提供的镜像qwenllm/qwenvl:2.5-cu121有问题&#xff0c;在titan显卡会抛出cuda error:no kernel image is availabe for execution on the device. 这是cuda内核与GPU不兼容的问题&#xff0c…...

tsfresh:时间序列特征自动提取与应用

tsfresh&#xff1a;时间序列特征自动提取与应用 本文系统介绍了 tsfresh 技术在 A 股市场数据分析与量化投资中的应用。从基础特征提取到高级策略开发&#xff0c;结合实战案例&#xff0c;详细讲解了如何利用 tsfresh 构建量化投资策略&#xff0c;并优化风险控制&#xff0c…...

C++Primer学习(7.1 定义抽象数据类型)

类的基本思想是数据抽象(data abstraction)和封装(encapsulation)。数据抽象是种依赖于接口(interface)和实现(implementation)分离的编程(以及设计)技术。类的接口包括用户所能执行的操作:类的实现则包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。 封…...

【PHP】新版本特性记录(持续更新)

文章目录 前言PHP 7.01&#xff09;NULL合并运算符&#xff1a;??2&#xff09;参数、返回值支持类型声明3&#xff09;太空船操作符&#xff1a;<>4&#xff09;通过 define 定义常量数组5&#xff09;匿名类实例化6&#xff09;字符串里使用\u转义unicode codepoint …...

《蓝耘容器全栈技术指南:企业级云原生与异构计算实战大全》

在数字化转型的浪潮中&#xff0c;容器技术已成为企业构建云原生架构的核心引擎&#xff0c;而蓝耘容器凭借其轻量化内核、异构计算支持及混合云调度能力&#xff0c;正成为企业级应用的首选方案。本文基于《蓝耘容器全栈技术指南》&#xff0c;结合实战案例与技术原理&#xf…...

【红黑树】—— 我与C++的不解之缘(二十五)

前言 学习了avl树&#xff0c;现在来学习红黑树。 一、什么是红黑树 红黑树是一颗平衡二叉搜索树&#xff0c;它每一个节点增加了一个存储位表示节点的颜色&#xff0c;可以是红色或者黑色。 相比较于AVL树&#xff0c;红黑树也是一个自平衡二叉搜索树&#xff0c;但是它与AVL树…...

驾驭 DeepSeek 科技之翼,翱翔现代学习新天际

在当今这个信息爆炸的时代&#xff0c;学习的方式和途径正在经历着前所未有的变革。人工智能技术的飞速发展&#xff0c;为我们的学习带来了全新的机遇和挑战。DeepSeek 作为一款强大的大语言模型&#xff0c;凭借其卓越的性能和丰富的功能&#xff0c;为现代学习注入了新的活力…...

DeepSeek本地部署 (Windows+Ollama+Docker Desktop+ RAGFlow)

适用场景&#xff1a; 1、商城的小机器人自动根据实际情况回复 2、需要7*24小时运行在线回复&#xff0c;如&#xff1a;在线购物、在线咨询、在线招生等 3、无人值守环境 2025年1月&#xff0c;DeepSeek 正式发布 DeepSeek-R1 推理大模型&#xff0c;DeepSeek-R1 成本价格低…...

SPI驱动(八) -- SPI_DAC设备驱动程序

文章目录 参考资料&#xff1a;一、编写设备树二、 编写驱动程序三、编写测试APP四、Makefile五、上机实验 参考资料&#xff1a; 参考资料&#xff1a; 内核头文件&#xff1a;include\linux\spi\spi.h内核文档&#xff1a;Documentation\spi\spidevDAC芯片手册&#xff1a;…...

MySQL 衍生表(Derived Tables)

在SQL的查询语句select …. from …中&#xff0c;跟在from子句后面的通常是一张拥有定义的实体表&#xff0c;而有的时候我们会用子查询来扮演实体表的角色&#xff0c;这个在from子句中的子查询会返回一个结果集&#xff0c;这个结果集可以像普通的实体表一样查询、连接&…...

Day16:最小的k个数

仓库管理员以数组 stock 形式记录商品库存表&#xff0c;其中 stock[i] 表示对应商品库存余量。请返回库存余量最少的 cnt 个商品余量&#xff0c;返回 顺序不限。 示例 1&#xff1a; 输入&#xff1a;stock [2,5,7,4], cnt 1 输出&#xff1a;[2]示例 2&#xff1a; 输入…...

MinIo前后端实现

这几天想玩玩Minio&#xff0c;整体来说简单使用起来不复杂&#xff08;当然也有可能是我配置的太少了&#xff09; Minio下载 我是通过Dokcer在虚拟机上下载的&#xff08;Docker真好用啊&#xff09; 拉取Minio镜像 docker pull minio/minio启动Minio容器 docker run -d …...

HarmonyOS NEXT开发进阶(十二):build-profile.json5 文件解析

文章目录 一、前言二、Hvigor脚本文件三、任务与任务依赖图四、多模块管理4.1 静态配置模块 五、分模块编译六、配置多目标产物七、配置APP多目标构建产物八、定义 product 中包含的 target九、拓展阅读 一、前言 编译构建工具DevEco Hvigor&#xff08;以下简称Hvigor&#x…...

利用 OpenCV 库进行实时目标物体检测

一、代码概述 此代码利用 OpenCV 库实现了基于特征匹配的实时物体检测系统。通过摄像头捕获实时视频帧&#xff0c;将其与预先加载的参考图像进行特征匹配&#xff0c;从而识别出视频帧中是否存在与参考图像匹配的物体。 二、环境依赖 OpenCV&#xff1a;用于图像处理、特征提…...

深度学习笔记(37周)

目录 摘要 Abstracts 1. 介绍 2. 相关工作 3. 模型 3.1 时序段网络TSN 3.2 学习时序段网络 4. 训练结果 5. 结论 摘要 本周阅读的论文是《Temporal Segment Networks: Towards Good Practices for Deep Action Recognition》。作者主要想通过较少的训练样本&#xff…...

Vue2+Vant2 项目初学

Vant 2 - Mobile UI Components built on Vue Vue.js 安装 | 菜鸟教程 // 通过脚手架安装 // 在新项目中使用 Vant 时&#xff0c;推荐使用 Vue 官方提供的脚手架 Vue Cli 创建项目并安装 Vant。 // # 安装 Vue Cli // npm install -g vue/cli // # 创建一个项目 // vue …...

ELK+Filebeat+Kafka+Zookeeper安装部署

1.安装zookeeper zookpeer下载地址:apache-zookeeper-3.7.1-bin.tar.gzhttps://link.csdn.net/?targethttps%3A%2F%2Fwww.apache.org%2Fdyn%2Fcloser.lua%2Fzookeeper%2Fzookeeper-3.7.1%2Fapache-zookeeper-3.7.1-bin.tar.gz%3Flogin%3Dfrom_csdn 1.1解压安装zookeeper软件…...

【接口封装】——21、解析Json对象数组的文本块

解释&#xff1a; 1、封装内容&#xff1a;Json数组的数据处理 Json 数组&#xff1a;[[ {"txt" : "你好"}, { "img", "1"} , {"txt" : "世界"} ], [ {"txt" : "你好"} ]] 数组内的文本块&am…...

【软考-架构】3.3、模式分解-事务并发-封锁协议

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 模式分解&#xff08;难点&#xff09;无损分解&#x1f4af;考试真题并发控制封锁协议&#x1f4af;考试真题第一题第二题 模式分解&#xff08;难点&#xff09; 保持函…...

审批工作流系统xFlow

WorkFlow-审批流程系统 该项目为完全开源免费项目 可用于学习或搭建初始化审批流程系统 希望有用的小伙伴记得点个免费的star gitee仓库地址 仿钉钉飞书工作审批流系统 介绍 前端技术栈: vue3 ts vite arcodesign eslint 后端技术栈:springbootspring mvc mybatis mavenmysq…...

【数据结构初阶第十九节】八大排序系列(下篇)—[详细动态图解+代码解析]

hello&#xff0c;好久不见&#xff01; 云边有个稻草人-CSDN博客 上篇内容&#xff0c;回顾一下吧【数据结构初阶第十八节】八大排序系列(上篇)—[详细动态图解代码解析]-CSDN博客 今天我们来学习下篇 目录 &#xff08;2&#xff09;快速排序 【挖坑法】 —思路 —思路…...

定制开发开源 AI 智能名片 S2B2C 商城小程序源码在小程序直播营销中的应用与价值

摘要&#xff1a; 本文主要探讨了定制开发开源 AI 智能名片 S2B2C 商城小程序源码在小程序直播营销中的应用与价值。首先详细阐述了小程序直播的基本概念、特点、发展历程及营销意义&#xff0c;包括其便捷性、广泛的受众连接能力以及对企业推广的重要作用。接着深入剖析了定制…...

蓝桥杯Python赛道备赛——Day3:排序算法(二)(归并排序、堆排序、桶排序)

本博客是蓝桥杯备赛系列中排序算法的第二期&#xff0c;包括&#xff1a;归并排序、堆排序和桶排序。每一个算法都在给出概念解释的同时&#xff0c;给出了示例代码&#xff0c;以供低年级师弟师妹们学习和练习。 由于本期的三个算法的复杂度相对来说要高于上一期的三个算法&am…...

Type-C:智能家居的电力革命与空间美学重构

在万物互联的时代浪潮中&#xff0c;家居空间正经历着从功能容器到智慧终端的蜕变。当意大利设计师安东尼奥奇特里奥提出"消失的设计"理念二十年后&#xff0c;Type-C充电技术正以润物无声的方式重塑着现代家居的形态与内核&#xff0c;开启了一场静默的居住革命。 【…...

第十五届蓝桥杯C/C++组:宝石组合题目(从小学奥数到编程题详解)

这道题目真的一看就不好做&#xff0c;如果直接暴力去做百分之90必挂掉&#xff0c;那么这道题目到底应该怎么去做呢&#xff1f;这我们就得从小学奥数开始聊了。&#xff08;闲话&#xff1a;自从开始蓝桥杯备赛后&#xff0c;每天都在被小学奥数震惊&#xff0c;为什么我小的…...

@RequestParam、@RequestBody、@PathVariable

1. RequestParam RequestParam&#xff1a;重要的是它的属性&#xff0c;如果它的属性用不到&#xff0c;这个注解可以不用 要点&#xff1a; 可用于任何类型的请求&#xff08;get请求数据在请求行中&#xff0c; post请求数据在请求体中&#xff09;无论时在请求行还是请求体…...

ECharts中Map(地图)样式配置、渐变色生成

前言 ECharts是我们常用的图表控件&#xff0c;功能特别强大&#xff0c;每次使用都要查API比较繁琐&#xff0c;这里就记录开发中常用的配置。 官网&#xff1a;https://echarts.apache.org/handbook/zh/get-started 配置项&#xff1a;https://echarts.apache.org/zh/opti…...

什么是 slot-scope?怎么理解。

1. 什么是 slot-scope&#xff1f; slot-scope 是 Vue 2 中用于作用域插槽的语法。它的作用是让子组件可以把一些数据传递给父组件&#xff0c;父组件可以根据这些数据自定义渲染内容。 简单来说&#xff1a; 子组件&#xff1a;负责提供数据。 父组件&#xff1a;负责根据数…...

MySQL | MySQL表的增删改查(CRUD)

目录 前言&#xff1a;什么是 CRUD ?一、Creat 新增1.1 语法1.2 示例1.2.1 单行数据全列插入1.2.2 单行数据指定列插入1.2.3 多行数据指定列插入 二、Retrieve 检索2.1 语法2.2 示例2.2.1 全列查询2.2.2 指定列查询2.2.3 查询字段为表达式2.2.4 结果去重查询2.2.5 where条件查…...

电子电气架构 --- 分布到集中的动カ系统及基于域控制器的架构

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…...