部署qwen2.5-VL-7B

news2025/4/19 9:34:13

简单串行执行

from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info
import torch, time, threading

def llm(
    model_path,
    prompt=None,
    image=None,
    video=None,
    images=None,
    videos=None,
    max_new_tokens=2048,
    temperature=0.6,
):
    """
    model_path: 模型路径
    prompt: 文本prompt
    image: 单张图片路径
    video: 单个视频路径
    images: 图片路径列表
    videos: 视频路径列表
    max_new_tokens: 最大生成token数
    temperature: 采样温度
    """
    old_time = time.time()
    gpu_memories = []

    # 监控代码占用显存
    def monitor_gpu_memory():
        import torch
        while not getattr(monitor_gpu_memory, 'stop', False):
            mem = torch.cuda.memory_allocated() / 1024 / 1024  # MB
            gpu_memories.append(mem)
            time.sleep(5)

    # 加载模型
    model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
        model_path,
        torch_dtype=torch.bfloat16,
        attn_implementation="flash_attention_2", # "sdpa"
        device_map="cuda"
    )

    # 启动显存监控线程
    monitor_gpu_memory.stop = False
    mem_thread = threading.Thread(target=monitor_gpu_memory)
    mem_thread.start()

    processor = AutoProcessor.from_pretrained(model_path, use_fast=True)

    # 构建messages
    contents = []
    if prompt is not None:
        contents.append({"type": "text", "text": prompt})
    if images is not None:
        for img in images:
            contents.append({"type": "image", "image": img})
    elif image is not None:
        contents.append({"type": "image", "image": image})
    elif videos is not None:
        for vid in videos:
            contents.append({"type": "video", "video": vid})
    elif video is not None:
        contents.append({"type": "video", "video": video})
    
    messages = [{"role": "user", "content": contents}]

    # 准备输入
    text = processor.apply_chat_template(
        messages, tokenize=False, add_generation_prompt=True
    )
    image_inputs, video_inputs = process_vision_info(messages)
    inputs = processor(
        text=[text],
        images=image_inputs,
        videos=video_inputs,
        padding=True,
        return_tensors="pt",
    )
    inputs = inputs.to(model.device)

    # 推理
    generated_ids = model.generate(
        **inputs,
        max_new_tokens=max_new_tokens,
        temperature=temperature
    )
    generated_ids_trimmed = [
        out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
    ]
    output_text = processor.batch_decode(
        generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
    )

    # 停止显存监控线程
    monitor_gpu_memory.stop = True
    mem_thread.join()

    total_time = time.time() - old_time
    total_tokens = sum(len(ids) for ids in generated_ids_trimmed)
    speed = total_tokens / total_time if total_time > 0 else 0
    avg_mem = sum(gpu_memories) / len(gpu_memories) if gpu_memories else 0

    return {
        "output_text": output_text,
        "total_time": total_time,
        "total_tokens": total_tokens,
        "speed": speed,
        "avg_mem": avg_mem,
    }

# 示例调用
if __name__ == "__main__":
    # https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-unsloth-bnb-4bit
    model_path = "/mnt/d/LLaMA-Factory/Qwen/Qwen2.5-VL-7B-Instruct-unsloth-bnb-4bit"

    result = llm(
        model_path=model_path,
        prompt="识别图中文字,如果有表格等特殊格式需要保留原格式。不用解释和总结,直接输出识别结果。",
        image=r"/mnt/c/Users/CJK/Desktop/3.png",
        max_new_tokens=2048,
        temperature=1.0
    )
    print(result["output_text"])
    print(f"总耗时: {result['total_time']:.2f}s, 生成token数: {result['total_tokens']}, 输出速度: {result['speed']:.2f} token/s, 平均占用显存: {result['avg_mem']:.2f} MB")

    result = llm(
        model_path=model_path,
        prompt="识别图中文字,如果有表格等特殊格式需要保留原格式。不用解释和总结,直接输出识别结果。",
        images=[r"/mnt/c/Users/CJK/Desktop/1.png", r"/mnt/c/Users/CJK/Desktop/3.png"],
        max_new_tokens=2048,
        temperature=0.6
    )
    print(result["output_text"])
    
    print(f"总耗时: {result['total_time']:.2f}s, 生成token数: {result['total_tokens']}, 输出速度: {result['speed']:.2f} token/s, 平均占用显存: {result['avg_mem']:.2f} MB")
    result = llm(
        model_path=model_path,
        prompt="识别图中文字,如果有表格等特殊格式需要保留原格式。不用解释和总结,直接输出识别结果。",
        video=r"/mnt/c/Users/CJK/Desktop/2.mp4",
        max_new_tokens=2048,
        temperature=0.6
    )
    print(result["output_text"])
    print(f"总耗时: {result['total_time']:.2f}s, 生成token数: {result['total_tokens']}, 输出速度: {result['speed']:.2f} token/s, 平均占用显存: {result['avg_mem']:.2f} MB")

    print(f"总耗时: {result['total_time']:.2f}s, 生成token数: {result['total_tokens']}, 输出速度: {result['speed']:.2f} token/s, 平均占用显存: {result['avg_mem']:.2f} MB")
    result = llm(
        model_path=model_path,
        prompt="识别图中文字,如果有表格等特殊格式需要保留原格式。不用解释和总结,直接输出识别结果。",
        videos=[r"/mnt/c/Users/CJK/Desktop/1.mp4", r"/mnt/c/Users/CJK/Desktop/2.mp4"],
        max_new_tokens=2048,
        temperature=0.6
    )
    print(result["output_text"])
    print(f"总耗时: {result['total_time']:.2f}s, 生成token数: {result['total_tokens']}, 输出速度: {result['speed']:.2f} token/s, 平均占用显存: {result['avg_mem']:.2f} MB")

异步/并行执行

from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info
import torch, time, threading
import concurrent.futures
from typing import List, Dict, Union, Optional, Any

# 全局变量用于存储加载的模型和处理器
_MODEL = None
_PROCESSOR = None
_MODEL_LOCK = threading.Lock()

def load_model_and_processor(model_path):
    """加载模型和处理器,如果已经加载则返回缓存的实例"""
    global _MODEL, _PROCESSOR
    
    with _MODEL_LOCK:
        if _MODEL is None or _PROCESSOR is None:
            # 加载模型
            _MODEL = Qwen2_5_VLForConditionalGeneration.from_pretrained(
                model_path,
                torch_dtype=torch.bfloat16,
                attn_implementation="flash_attention_2",  # "sdpa"
                device_map="cuda"
            )
            
            # 加载处理器
            _PROCESSOR = AutoProcessor.from_pretrained(model_path, use_fast=True)
    
    return _MODEL, _PROCESSOR

def llm(
    model_path,
    prompt=None,
    image=None,
    video=None,
    images=None,
    videos=None,
    max_new_tokens=2048,
    temperature=0.6,
    parallel=False,
    max_workers=4,
):
    """
    model_path: 模型路径
    prompt: 文本prompt
    image: 单张图片路径
    video: 单个视频路径
    images: 图片路径列表
    videos: 视频路径列表
    max_new_tokens: 最大生成token数
    temperature: 采样温度
    parallel: 是否并行处理多个图片/视频
    max_workers: 并行处理的最大工作线程数
    """
    # 如果启用并行处理且有多个图片或视频
    if parallel and ((images and len(images) > 1) or (videos and len(videos) > 1)):
        return parallel_process(
            model_path=model_path,
            prompt=prompt,
            images=images,
            videos=videos,
            max_new_tokens=max_new_tokens,
            temperature=temperature,
            max_workers=max_workers
        )
    
    old_time = time.time()
    gpu_memories = []

    # 监控代码占用显存
    def monitor_gpu_memory():
        import torch
        while not getattr(monitor_gpu_memory, 'stop', False):
            mem = torch.cuda.memory_allocated() / 1024 / 1024  # MB
            gpu_memories.append(mem)
            time.sleep(5)

    # 加载模型和处理器
    model, processor = load_model_and_processor(model_path)

    # 启动显存监控线程
    monitor_gpu_memory.stop = False
    mem_thread = threading.Thread(target=monitor_gpu_memory)
    mem_thread.start()

    # 构建messages
    contents = []
    if prompt is not None:
        contents.append({"type": "text", "text": prompt})
    if images is not None:
        for img in images:
            contents.append({"type": "image", "image": img})
    elif image is not None:
        contents.append({"type": "image", "image": image})
    elif videos is not None:
        for vid in videos:
            contents.append({"type": "video", "video": vid})
    elif video is not None:
        contents.append({"type": "video", "video": video})
    
    messages = [{"role": "user", "content": contents}]

    # 准备输入
    text = processor.apply_chat_template(
        messages, tokenize=False, add_generation_prompt=True
    )
    image_inputs, video_inputs = process_vision_info(messages)
    inputs = processor(
        text=[text],
        images=image_inputs,
        videos=video_inputs,
        padding=True,
        return_tensors="pt",
    )
    inputs = inputs.to(model.device)

    # 推理
    generated_ids = model.generate(
        **inputs,
        max_new_tokens=max_new_tokens,
        temperature=temperature
    )
    generated_ids_trimmed = [
        out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
    ]
    output_text = processor.batch_decode(
        generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
    )

    # 停止显存监控线程
    monitor_gpu_memory.stop = True
    mem_thread.join()

    total_time = time.time() - old_time
    total_tokens = sum(len(ids) for ids in generated_ids_trimmed)
    speed = total_tokens / total_time if total_time > 0 else 0
    avg_mem = sum(gpu_memories) / len(gpu_memories) if gpu_memories else 0

    return {
        "output_text": output_text,
        "total_time": total_time,
        "total_tokens": total_tokens,
        "speed": speed,
        "avg_mem": avg_mem,
    }

def process_single_item(
    model_path: str,
    prompt: Optional[str],
    item_path: str,
    is_video: bool = False,
    max_new_tokens: int = 2048,
    temperature: float = 0.6,
) -> Dict[str, Any]:
    """处理单个图片或视频"""
    # 确保模型已加载
    model, processor = load_model_and_processor(model_path)
    
    old_time = time.time()
    gpu_memories = []

    # 监控代码占用显存
    def monitor_gpu_memory():
        import torch
        while not getattr(monitor_gpu_memory, 'stop', False):
            mem = torch.cuda.memory_allocated() / 1024 / 1024  # MB
            gpu_memories.append(mem)
            time.sleep(5)

    # 启动显存监控线程
    monitor_gpu_memory.stop = False
    mem_thread = threading.Thread(target=monitor_gpu_memory)
    mem_thread.start()

    # 构建messages
    contents = []
    if prompt is not None:
        contents.append({"type": "text", "text": prompt})
    
    if is_video:
        contents.append({"type": "video", "video": item_path})
    else:
        contents.append({"type": "image", "image": item_path})
    
    messages = [{"role": "user", "content": contents}]

    # 准备输入
    text = processor.apply_chat_template(
        messages, tokenize=False, add_generation_prompt=True
    )
    image_inputs, video_inputs = process_vision_info(messages)
    
    # 使用处理器处理输入
    inputs = processor(
        text=[text],
        images=image_inputs,
        videos=video_inputs,
        padding=True,
        return_tensors="pt",
    )
    inputs = inputs.to(model.device)

    # 推理
    with _MODEL_LOCK:  # 在生成时加锁,确保一次只有一个线程使用模型
        generated_ids = model.generate(
            **inputs,
            max_new_tokens=max_new_tokens,
            temperature=temperature
        )
    
    generated_ids_trimmed = [
        out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
    ]
    output_text = processor.batch_decode(
        generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
    )

    # 停止显存监控线程
    monitor_gpu_memory.stop = True
    mem_thread.join()

    total_time = time.time() - old_time
    total_tokens = sum(len(ids) for ids in generated_ids_trimmed)
    speed = total_tokens / total_time if total_time > 0 else 0
    avg_mem = sum(gpu_memories) / len(gpu_memories) if gpu_memories else 0

    return {
        "output_text": output_text,
        "total_time": total_time,
        "total_tokens": total_tokens,
        "speed": speed,
        "avg_mem": avg_mem,
    }

def parallel_process(
    model_path: str,
    prompt: Optional[str] = None,
    images: Optional[List[str]] = None,
    videos: Optional[List[str]] = None,
    max_new_tokens: int = 2048,
    temperature: float = 0.6,
    max_workers: int = 4,
) -> Dict[str, Any]:
    """并行处理多个图片或视频"""
    start_time = time.time()
    results = []
    
    # 预先加载模型,确保所有线程共享同一个模型实例
    load_model_and_processor(model_path)
    
    # 确定要处理的项目列表
    items = []
    is_video_flags = []
    
    if images:
        items.extend(images)
        is_video_flags.extend([False] * len(images))
    if videos:
        items.extend(videos)
        is_video_flags.extend([True] * len(videos))
    
    # 使用线程池并行处理
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_to_item = {
            executor.submit(
                process_single_item, 
                model_path, 
                prompt, 
                item, 
                is_video, 
                max_new_tokens, 
                temperature
            ): (item, is_video) 
            for item, is_video in zip(items, is_video_flags)
        }
        
        for future in concurrent.futures.as_completed(future_to_item):
            item, is_video = future_to_item[future]
            try:
                result = future.result()
                results.append(result)
            except Exception as e:
                print(f"处理 {'视频' if is_video else '图片'} {item} 时出错: {e}")
    
    # 合并结果
    all_output_texts = [result["output_text"] for result in results]
    total_time = time.time() - start_time
    total_tokens = sum(result["total_tokens"] for result in results)
    avg_speed = total_tokens / total_time if total_time > 0 else 0
    avg_mem = sum(result.get("avg_mem", 0) for result in results) / len(results) if results else 0
    
    return {
        "output_text": all_output_texts,
        "total_time": total_time,
        "total_tokens": total_tokens,
        "speed": avg_speed,
        "avg_mem": avg_mem,
        "individual_results": results
    }

# 示例调用
if __name__ == "__main__":
    # https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-unsloth-bnb-4bit
    model_path = "/mnt/d/LLaMA-Factory/Qwen/Qwen2.5-VL-7B-Instruct-unsloth-bnb-4bit"

    # 多图片并行处理示例
    result = llm(
        model_path=model_path,
        prompt="识别图中文字,如果有表格等特殊格式需要保留原格式。不用解释和总结,直接输出识别结果。",
        images=[r"/mnt/c/Users/CJK/Desktop/1.png", r"/mnt/c/Users/CJK/Desktop/2.png", r"/mnt/c/Users/CJK/Desktop/3.png", r"/mnt/c/Users/CJK/Desktop/4.png", r"/mnt/c/Users/CJK/Desktop/5.png", r"/mnt/c/Users/CJK/Desktop/6.png", r"/mnt/c/Users/CJK/Desktop/7.png", r"/mnt/c/Users/CJK/Desktop/8.png"],
        max_new_tokens=2048,
        temperature=0.6,
        parallel=True,
        max_workers=8
    )
    print("并行处理结果:")
    for i, text in enumerate(result["output_text"]):
        print(f"图片 {i+1} 结果: {text}")
    print(f"总耗时: {result['total_time']:.2f}s, 生成token数: {result['total_tokens']}, 平均输出速度: {result['speed']:.2f} token/s, 平均占用显存: {result['avg_mem']:.2f} MB")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

杰弗里·辛顿:深度学习教父

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 杰弗里辛顿:当坚持遇见突破,AI迎来新纪元 一、人物简介 杰弗…

STM32蓝牙连接Android实现云端数据通信(电机控制-开源)

引言 基于 STM32F103C8T6 最小系统板完成电机控制。这个小项目采用 HAL 库方法实现,通过 CubeMAX 配置相关引脚,步进电机使用 28BYJ-48 (四相五线式步进电机),程序通过蓝牙连接手机 APP 端进行数据收发, OL…

第一个Qt开发的OpenCV程序

OpenCV计算机视觉开发实践:基于Qt C - 商品搜索 - 京东 下载安装Qt:https://download.qt.io/archive/qt/5.14/5.14.2/qt-opensource-windows-x86-5.14.2.exe 下载安装OpenCV:https://opencv.org/releases/ 下载安装CMake:Downl…

TCP 如何在网络 “江湖” 立威建交?

一、特点: (一)面向连接 在进行数据传输之前,TCP 需要在发送方和接收方之间建立一条逻辑连接。这一过程类似于打电话,双方在通话前需要先拨号建立连接。建立连接的过程通过三次握手来完成,确保通信双方都…

【小白训练日记——2025/4/15】

变化检测常用的性能指标 变化检测(Change Detection)的性能评估依赖于多种指标,每种指标从不同角度衡量模型的准确性。以下是常用的性能指标及其含义: 1. 混淆矩阵(Confusion Matrix) 定义:统…

数据结构——二叉树(中)

接上一篇,上一篇主要讲解了关于二叉树的基本知识,也是为了接下来讲解关于堆结构和链式二叉树结构打基础,其实无论是堆结构还是链式二叉树结构,都是二叉树的存储结构,那么今天这一篇主要讲解关于堆结构的实现与应用 堆…

02-MySQL 面试题-mk

文章目录 1.mysql 有哪些存储引擎、区别是什么?1.如何定位慢查询?2.SQL语句执行很慢,如何分析?3.索引概念以及索引底层的数据结构4.什么是聚簇索引什么是非聚簇索引?5.知道什么叫覆盖索引嘛 ?6.索引创建原则有哪些?7.什么情况下索引会失效 ?8.谈一谈你对sql的优化的经验…

#include<bits/stdc++.h>

#include<bits/stdc.h> 是 C 中一个特殊的头文件&#xff0c;其作用如下&#xff1a; 核心作用 ​​包含所有标准库头文件​​ 该头文件会自动引入 C 标准库中的几乎全部头文件&#xff08;如 <iostream>、<vector>、<algorithm> 等&#xff09;&…

在企业级部署中如何优化NVIDIA GPU和容器环境配置:最佳实践与常见误区20250414

在企业级部署中如何优化NVIDIA GPU和容器环境配置&#xff1a;最佳实践与常见误区 引言 随着AI和深度学习技术的迅速发展&#xff0c;企业对GPU加速计算的需求愈加迫切。在此过程中&#xff0c;如何高效地配置宿主机与容器化环境&#xff0c;特别是利用NVIDIA GPU和相关工具&…

Spring Boot 项目三种打印日志的方法详解。Logger,log,logger 解读。

目录 一. 打印日志的常见三种方法&#xff1f; 1.1 手动创建 Logger 对象&#xff08;基于SLF4J API&#xff09; 1.2 使用 Lombok 插件的 Slf4j 注解 1.3 使用 Spring 的 Log 接口&#xff08;使用频率较低&#xff09; 二. 常见的 Logger&#xff0c;logger&#xff0c;…

[react]Next.js之自适应布局和高清屏幕适配解决方案

序言 阅读前首先了解即将要用到的两个包的作用 1.postcss-pxtorem 自动将 CSS 中的 px 单位转换为 rem 单位按照设计稿尺寸直接写 px 值&#xff0c;由插件自动计算 rem 值 2.amfe-flexible 动态设置根元素的 font-size&#xff08;即 1rem 的值&#xff09;根据设备屏幕宽度和…

STM32H503CB升级BootLoader

首先&#xff0c;使用SWD接口&#xff0c;ST-LINK连接电脑和板子。 安装SetupSTM32CubeProgrammer_win64 版本2.19。 以下是接线和软件操作截图。

在Apple Silicon上部署Spark-TTS:四大核心库的技术魔法解析!!!

在Apple Silicon上部署Spark-TTS&#xff1a;四大核心库的技术魔法解析 &#x1f680; &#xff08;M2芯片实测&#xff5c;Python 3.12.9PyTorch 2.6.0全流程解析&#xff09; 一、核心库功能全景图 &#x1f50d; 在Spark-TTS的部署过程中&#xff0c;pip install numpy li…

VMWare 16 PRO 安装 Rocky8 并部署 MySQL8

VMWare 16 PRO 安装 Rocky8 并部署 MySQL8 一.Rocky OS 下载1.官网二.配置 Rocky1.创建新的虚拟机2.稍后安装系统3.选择系统模板4.设置名字和位置5.设置大小6.自定义硬件设置核心、运存和系统镜像7.完成三.启动安装1.上下键直接选择安装2.回车安装3.设置分区(默认即可)和 roo…

cursor如何回退一键回退多个文件的修改

当我们使用 Cursor 写代码时&#xff0c;起初可能操作得很顺利&#xff0c;但某次更改或许会让代码变得面目全非。这时候如果没有使用 Git 该怎么办呢&#xff1f;别担心&#xff0c;Cursor 已经为我们考虑到了。 具体的操作如下&#xff1a; 当我们要取消某次操作时&#xf…

基于RV1126开发板的口罩识别算法开发

1. 口罩识别简介 口罩识别是一种基于深度学习的判断人员有没有戴口罩的分类算法&#xff0c;能广泛的用于安防、生产安全等多种场景。本算法先基于人脸检测和人脸标准化获取的标准人脸&#xff0c;然后输入到口罩识别分类算法进行识别。 本人脸检测算法在数据集表现如下所示&am…

PyCharm显示主菜单和工具栏

显示主菜单 新版 PyCharm 是不显示主菜单的&#xff0c;要想显示主菜单和工具栏&#xff0c;则通过 “视图” → “外观” &#xff0c;勾选 “在单独的工具栏中显示主菜单” 和 “工具栏” 即可。 设置工具栏 此时工具栏里并没有什么工具&#xff0c;因此我们需要自定义工具…

Java工程行业管理软件源码 - 全面的项目管理工具 - 工程项目模块与功能一览

工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 项目背景 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管理的提升提…

Redis 高可用集群搭建与优化实践

在分布式系统中,缓存技术用于提升性能和响应速度。 Redis 作为一款高性能的键值存储系统,广泛应用于缓存、消息队列和会话管理等场景。随着业务规模的扩大,单机 Redis 的性能和可用性逐渐无法满足需求。 因此,搭建高可用的 Redis 集群可以解决这一问题。我将详细介绍 Red…

【AI大模型】基于阿里百炼大模型进行调用

目录 一、认识阿里云百炼 模型广场 创建自己的模型 二、AI扩图示例 1、开头服务、设置秘钥 2、选择HTTP方式调用流程 3、创建任务请求示例 4、发送http请求提交任务 5、查看任务进度的流程设计 6、后端查看任务进度代码 三、总结 大家好&#xff0c;我是jstart千语…