支持黑神话悟空的超长视频理解,Qwen2-VL多模态大模型分享

news2024/9/16 11:33:53

Qwen2-VL是由阿里巴巴达摩院开发并开源的第二代视觉与语言多模态人工智能模型。

Qwen2-VL结合了视觉理解和自然语言处理的能力,使得它能够处理和理解图像、视频以及文本数据。

Qwen2-VL支持多种语言,包括但不限于英语、中文、大多数欧洲语言、日语、韩语、阿拉伯语及越南语等。

Qwen2-VL模型系列包括不同规模的版本,如 2B、7B 和 72B 参数规模的模型,以适应不同的应用需求和计算资源限制。

Qwen2-VL可以处理不同分辨率和长宽比的图片,无需将图片分割成块,并且在各种视觉理解基准测试中表现出色,例如 MathVista(数学推理)、DocVQA(文档图像理解)、RealWorldQA(现实世界空间理解)以及 MTVQA(多语言理解)等。

Qwen2-VL 还能够理解长达20分钟以上的视频内容,这使得它能够在基于视频的问答、对话生成和内容创作等方面发挥作用。

github项目地址:https://github.com/QwenLM/Qwen2-VL。

一、环境安装

1、python环境

建议安装python版本在3.10以上。

2、pip库安装

pip install torch==2.4.0+cu118 torchvision==0.19.0+cu118 torchaudio==2.4.0 --extra-index-url https://download.pytorch.org/whl/cu118

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install av -i https://pypi.tuna.tsinghua.edu.cn/simple

3、Qwen2-VL-7B-Instruct模型下载

git lfs install

git clone https://www.modelscope.cn/qwen/Qwen2-VL-7B-Instruct.git

4、Qwen2-VL-2B-Instruct模型下载

git lfs install

git clone https://www.modelscope.cn/models/qwen/Qwen2-VL-2B-Instruct.git

、功能测试

1、运行测试

(1)python代码调用测试
 

from PIL import Image
import torch
from transformers import Qwen2VLForConditionalGeneration, AutoTokenizer, AutoProcessor
from qwen_vl_utils import process_vision_info


class VisionLanguageModel:
    def __init__(self, model_dir, min_pixels, max_pixels):
        self.model = Qwen2VLForConditionalGeneration.from_pretrained(model_dir, device_map="auto", torch_dtype=torch.float16)
        self.processor = AutoProcessor.from_pretrained(model_dir, min_pixels=min_pixels, max_pixels=max_pixels)

    def prepare_inputs(self, messages):
        text = self.processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
        image_inputs, video_inputs = process_vision_info(messages)
        inputs = self.processor(text=[text], images=image_inputs, videos=video_inputs, padding=True, return_tensors="pt")
        inputs = inputs.to('cuda')
        return inputs

    def generate_output(self, inputs):
        generated_ids = self.model.generate(**inputs, max_new_tokens=128)
        generated_ids_trimmed = [out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)]
        output_text = self.processor.batch_decode(generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False)
        return output_text

    def describe_image(self, image_url):
        messages = [{"role": "user", "content": [{"type": "image", "image": image_url}, {"type": "text", "text": "Describe this image."}]}]
        inputs = self.prepare_inputs(messages)
        output_text = self.generate_output(inputs)
        return output_text

    def identify_similarities(self, image_paths):
        content = [{"type": "image", "image": path} for path in image_paths]
        content.append({"type": "text", "text": "Identify the similarities between these images."})
        messages = [{"role": "user", "content": content}]
        inputs = self.prepare_inputs(messages)
        output_text = self.generate_output(inputs)
        return output_text

    def describe_video(self, video_path):
        messages = [{"role": "user", "content": [{"type": "video", "video": video_path, 'max_pixels': 360*420, 'fps': 1.0}, {"type": "text", "text": "Describe this video."}]}]
        inputs = self.prepare_inputs(messages)
        output_text = self.generate_output(inputs)
        return output_text


# Usage example
model_dir = "Qwen2-VL-7B-Instruct"
min_pixels = 256*28*28
max_pixels = 1280*28*28

vl_model = VisionLanguageModel(model_dir, min_pixels, max_pixels)

# Describe an image
image_description = vl_model.describe_image("test.jpeg")
print(image_description)

# Identify similarities between images
image_paths = ["image1.jpg", "image2.jpg"]
image_similarities = vl_model.identify_similarities(image_paths)
print(image_similarities)

# Describe a video
video_description = vl_model.describe_video("video1.mp4")
print(video_description)

(2)web端测试
 

import copy
import re
import gc
from argparse import ArgumentParser
from threading import Thread

import gradio as gr
import torch
from qwen_vl_utils import process_vision_info
from transformers import AutoProcessor, Qwen2VLForConditionalGeneration, TextIteratorStreamer

DEFAULT_CKPT_PATH = 'Qwen2-VL-7B-Instruct'


def _get_args():
    """Parse command line arguments."""
    parser = ArgumentParser(description="Qwen2-VL WebUI Options.")
    
    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=7870, help='Demo server port.')
    parser.add_argument('--server-name', type=str, default='0.0.0.0', help='Demo server name.')

    return parser.parse_args()


def _load_model_processor(args):
    """Load model and processor based on provided arguments."""
    device_map = 'cpu' if args.cpu_only else 'auto'
    model_load_args = {'torch_dtype': 'auto', 'device_map': device_map}

    if args.flash_attn2:
        model_load_args['attn_implementation'] = 'flash_attention_2'

    model = Qwen2VLForConditionalGeneration.from_pretrained(args.checkpoint_path, **model_load_args)
    processor = AutoProcessor.from_pretrained(args.checkpoint_path)

    return model, processor


def _parse_text(text):
    """Parse markdown-styled text to HTML."""
    def html_escape(text):
        """Escape HTML special characters."""
        html_escape_table = {
            "`": r'\`', "<": "&lt;", ">": "&gt;", " ": "&nbsp;", "*": "&ast;", "_": "&lowbar;", 
            "-": "&#45;", ".": "&#46;", "!": "&#33;", "(": "&#40;", ")": "&#41;", "$": "&#36;"
        }
        return "".join(html_escape_table.get(c, c) for c in text)
    
    lines = filter(bool, text.split('\n'))
    inside_code = False
    for i, line in enumerate(lines):
        if '```' in line:
            inside_code = not inside_code
            items = line.split('`')
            lines[i] = f'<pre><code class="language-{items[-1]}">' if inside_code else '<br></code></pre>'
        elif inside_code:
            lines[i] = html_escape(line)
        else:
            lines[i] = '<br>' + line
    
    return ''.join(lines)


def _remove_image_special(text):
    """Remove image-related special tags from the text."""
    text = text.replace('<ref>', '').replace('</ref>', '')
    return re.sub(r'<box>.*?(</box>|$)', '', text)


def _is_video_file(filename):
    """Check if the given filename is a video file."""
    video_extensions = {'.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm', '.mpeg'}
    return any(filename.lower().endswith(ext) for ext in video_extensions)


def _gc():
    """Perform garbage collection and empty CUDA cache if available."""
    gc.collect()
    if torch.cuda.is_available():
        torch.cuda.empty_cache()


def _transform_messages(original_messages):
    """Transform original message structure to suitable format for processing."""
    def get_content_type(content_item):
        """Identify the type of content item."""
        if 'image' in content_item:
            return {'type': 'image', 'image': content_item['image']}
        elif 'text' in content_item:
            return {'type': 'text', 'text': content_item['text']}
        elif 'video' in content_item:
            return {'type': 'video', 'video': content_item['video']}
        return None
    
    return [
        {'role': message['role'], 'content': [get_content_type(item) for item in message['content'] if get_content_type(item)]}
        for message in original_messages
    ]


def _launch_demo(args, model, processor):
    """Launch the Gradio demo interface."""

    def call_local_model(model, processor, messages):
        """Handle the interaction with the local model."""
        messages = _transform_messages(messages)
        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)

        tokenizer = processor.tokenizer
        streamer = TextIteratorStreamer(tokenizer, timeout=20.0, skip_prompt=True, skip_special_tokens=True)
        gen_kwargs = {'max_new_tokens': 512, 'streamer': streamer, **inputs}

        thread = Thread(target=model.generate, kwargs=gen_kwargs)
        thread.start()

        generated_text = ''
        for new_text in streamer:
            generated_text += new_text
            yield generated_text

    def create_predict_fn():
        def predict(_chatbot, task_history):
            """Generate responses based on chat and task history."""
            nonlocal model, processor
            chat_query = _chatbot[-1][0]
            query = task_history[-1][0]
            if len(chat_query) == 0:
                _chatbot.pop()
                task_history.pop()
                return _chatbot

            print('User: ' + _parse_text(query))
            full_response, messages = '', []

            for q, a in copy.deepcopy(task_history):
                content = []
                if isinstance(q, (tuple, list)):
                    file_type = 'video' if _is_video_file(q[0]) else 'image'
                    content.append({file_type: f'file://{q[0]}'})
                else:
                    content.append({'text': q})
                    messages.extend([{'role': 'user', 'content': content}, {'role': 'assistant', 'content': [{'text': a}]}])
            if messages:
                messages.pop()

            for response in call_local_model(model, processor, messages):
                _chatbot[-1] = (_parse_text(chat_query), _remove_image_special(_parse_text(response)))
                yield _chatbot
                full_response = _parse_text(response)
            task_history[-1] = (query, full_response)
            print('Qwen-VL-Chat: ' + full_response)
            yield _chatbot

        return predict

    def create_regenerate_fn():
        def regenerate(_chatbot, task_history):
            """Regenerate the last response."""
            nonlocal model, processor
            if not task_history:
                return _chatbot

            query, last_response = task_history[-1]
            if last_response is None:
                return _chatbot
            
            task_history[-1] = (query, None)
            last_q, _ = _chatbot[-1]
            _chatbot[-1] = (last_q, None)
            
            for _chatbot in predict(_chatbot, task_history):
                yield _chatbot

        return regenerate

    def add_text(history, task_history, text):
        """Add text input to histories and reset the input box."""
        task_text = text
        history = history or []
        task_history = task_history or []
        history.append((_parse_text(text), None))
        task_history.append((task_text, None))
        return history, task_history, ''

    def add_file(history, task_history, file):
        """Add file input to histories."""
        history = history or []
        task_history = task_history or []
        history.append(((file.name,), None))
        task_history.append(((file.name,), None))
        return history, task_history

    def reset_user_input():
        """Reset the user input box."""
        return gr.update(value='')

    def reset_state(_chatbot, task_history):
        """Clear history and perform garbage collection."""
        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>
<center><font size=8>Qwen2-VL</center>
<center><font size=3>This WebUI is based on Qwen2-VL, developed by Alibaba Cloud.</center>
<center><font size=3>本WebUI基于Qwen2-VL。</center>
""")
        chatbot = gr.Chatbot(label='Qwen2-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_btn = gr.Button('🧹 Clear History (清除历史)')

        submit_btn.click(add_text, [chatbot, task_history, query], [chatbot, task_history]).then(
            create_predict_fn(), [chatbot, task_history], [chatbot], show_progress=True
        )
        submit_btn.click(reset_user_input, [], [query])
        empty_btn.click(reset_state, [chatbot, task_history], [chatbot], show_progress=True)
        regen_btn.click(create_regenerate_fn(), [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-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-VL的许可协议限制。我们强烈建议,用户不应传播及不应允许他人传播以下内容,\
包括但不限于仇恨言论、暴力、色情、欺诈相关的有害信息。)
""")

    demo.queue().launch(
        share=args.share,
        inbrowser=args.inbrowser,
        server_port=args.server_port,
        server_name=args.server_name,
    )


def main():
    """Main function to parse arguments, load the model and processor, and launch the demo."""
    args = _get_args()
    model, processor = _load_model_processor(args)
    _launch_demo(args, model, processor)


if __name__ == '__main__':
    main()

未完......

更多详细的欢迎关注:杰哥新技术

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

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

相关文章

【分支-快速排序】

【分支-快速排序】 1. 颜色分类1.1 题目来源1.2 题目描述1.3 题目解析 2. 排序数组2.1 题目来源2.2 题目描述2.3 题目解析 3. 数组中的第K个最大元素3.1 题目来源3.2 题目描述3.3 题目解析 4. 库存管理 III4.1 题目来源4.2 题目描述4 .3 题目解析 1. 颜色分类 1.1 题目来源 7…

JS基础学习笔记

1.引入方式 内部脚本 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> <…

为什么要使用大模型RAG一体机

使用大模型RAG&#xff08;Retrieval-Augmented Generation&#xff09;一体机&#xff0c;如AntSKPro AI 离线知识库一体机&#xff0c;有以下几个原因和优势&#xff1a; 提高效率&#xff1a;RAG模型结合了检索&#xff08;Retrieval&#xff09;和生成&#xff08;Generati…

鸿蒙(API 12 Beta6版)GPU加速引擎服务【自适应VRS】

XEngine Kit提供自适应VRS功能&#xff0c;其通过合理分配画面的计算资源&#xff0c;视觉无损降低渲染频次&#xff0c;使不同的渲染图像使用不同的渲染速率&#xff0c;能够有效提高渲染性能。 接口说明 以下接口为自适应VRS设置接口&#xff0c;如要使用更丰富的设置和查询…

windows10-VMware17-Ubuntu-22.04-海康2K摄像头兼容问题,求解(已解决)

文章目录 1.webrtc camera测试2.ffmpeg 测试3.Ubuntu 自带相机4.解决办法 环境&#xff1a;windows10系统下&#xff0c;VMware的Ubuntu-22.04系统 问题&#xff1a;摄像头出现兼容问题&#xff0c;本来是想开发测试的&#xff0c;Ubuntu方便些。买了海康2K的USB摄像头&#xf…

人机交互与现代战争

人机交互技术在现代战争中的应用越来越广泛&#xff0c;它可以帮助士兵更好地完成任务&#xff0c;提高作战效能&#xff0c;减少人员伤亡。人机交互与认知在军事应用方面的进展有很多&#xff0c;比如&#xff1a; &#xff08;1&#xff09;虚拟现实和增强现实技术&#xff1…

PAT甲级-1085 Perfect Sequence

题目 题目大意 在一组数中找到一个完美数列&#xff0c;满足M < mp&#xff0c;M是该数列的最大值&#xff0c;m是最小值&#xff0c;p是题目给定的一个常数。 思路 模拟或者二分法。二分法可用upper_bound()函数实现。 知识点 upper_bound() 和 lower_bound() 函数在&…

C高级编程 第十六天(树 二叉树)

1.树 1.1结构特点 非线性结构&#xff0c;有一个直接前驱&#xff0c;但可能有多个直接后继有递归性&#xff0c;树中还有树可以为空&#xff0c;即节点个数为零 1.2相关术语 根&#xff1a;即根结点&#xff0c;没有前驱叶子&#xff1a;即终端结点&#xff0c;没有后继森…

02-java实习工作一个多月-经历分享

一、描述一下最近不写博客的原因 离我发java实习的工作的第一天的博客已经过去了一个多月了&#xff0c;本来还没入职的情况是打算每天工作都要写一份博客来记录一下的&#xff08;最坏的情况也是每周至少总结一下的&#xff09;&#xff0c;其实这个第一天的博客都是在公司快…

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext)&#xff0c;和uboot一样&#xff0c;都是从汇编阶段开始的&#xff0c;因为对于kernel而言&#xff0c;还没进行栈的维护&#xff0c;所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。 内核起始部分代码被解压代码调用&#xff0c…

深入手撕链表

链表 分类概念单链表增尾插头插插入 删尾删头删删除 查完整实现带头不带头 双向链表初始化增尾插头插插入 删查完整代码 数组 分类 #mermaid-svg-qKD178fTiiaYeKjl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-qK…

Java 入门指南:JVM(Java虚拟机)—— Java 内存运行时的数据区域

前言 对于 Java 程序员来说&#xff0c;在虚拟机自动内存管理机制下&#xff0c;不再需要像 C/C程序开发程序员这样为每一个 new 操作去写对应的 delete/free 操作&#xff0c;不容易出现内存泄漏和内存溢出问题。 由于程序员把内存控制权利交给 Java 虚拟机&#xff0c;一旦…

【CSS in Depth 2 精译_025】4.3 弹性布局的方向

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

NISP 一级 | 2.3 身份认证

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 0x01&#xff1a;身份认证基本方法 身份认证是用户登录系统或网站面对的第一道安全防线&#xff0c;如输入账号口令来登录。身份认证是在网络中确认操作者身份的过程。身份认证一般依据以下三种情…

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html Thread Index和Thread ID之间有什么关系呢&#xff1f;&#xff08;线程架构参考这里&#xff1a;CUDA C Programming Guide (nvidia.com)open in new window&#xff09; 1维的Thread Index&am…

ORCAD出BOM--位号在同一个Excel格子里

所有相同属性的器件都在同一个格子里 Tools\ Bill of Materials, 注意勾选Open in excel. 勾选Open in excel, 所有相同属性的器件都在同一个格子里 不勾选Open in excel, 5个相同属性的器件都在同一个格子里

代码随想录Day 39|打家劫舍问题,leetcode题目:198.打家劫舍、213.打家劫舍Ⅱ、337.打家劫舍Ⅲ

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 题目题目一&#xff1a;198.打家劫舍解题思路&#xff1a; 题目二&#xff1a;213.打家劫舍II解题思路&#xff1a; 题目三&#xff1a; 337.打家劫舍 III解题思路暴力递归记忆化递推动态规划 总结…

Linux基础2-权限2(操作权限,粘滞位,umask,目录文件的rwx权限)

上篇内容&#xff1a;Linux基础2-权限1(用户&#xff0c;权限是什么&#xff1f;)-CSDN博客 目录 一. 权限的操作&#xff08;命令&#xff09; 1.1 chmod 1.2 chown 1.3 chgrp 二. 粘滞位 三. umask&#xff08;遮掩码&#xff09; 四. 目录文件的 r w x 权限 一. 权限…

数据库的操作:SQL语言的介绍

一.前言 SQL是一种结构化查询语言。关系型数据库中进行操作的标准语言。 二.特点 ①对大小写不敏感 例如&#xff1a;select与Select是一样的 ②结尾要使用分号 没有分号认为还没结束; 三.分类 ①DDL&#xff1a;数据定义语言&#xff08;数据库对象的操作&#xff08;结…

服务器重装系统,数据备份 容器备份

文章目录 1.前言2.docker备份2.1 容器备份2.2 镜像备份2.3 数据卷备份 3.docker安装4.jdk安装5.导入镜像6.导入容器 本文档只是为了留档方便以后工作运维&#xff0c;或者给同事分享文档内容比较简陋命令也不是特别全&#xff0c;不适合小白观看&#xff0c;如有不懂可以私信&a…