通义千问Qwen-VL-Chat大模型本地训练(二)

news2024/9/25 7:22:28

目录

前言

环境准备

软件安装

数据准备

模型训练

        模型名称修改

        数据集修改

        模型参数修改

        数据读取编码修改

        output_dir修改

模型调用

 验证

小结


前言

        人工智能大模型是一种能够利用大数据和神经网络来模拟人类思维和创造力的人工智能算法。它利用海量的数据和深度学习技术来理解、生成和预测新内容,通常情况下有数十亿乃至数百亿个参数,可以在不同的领域和任务中表现出智能拟人的效果。

        现在大模型火的不行,项目中如果没有大模型好像都缺少点啥?没办法要跟着时代进步,最近研究了一下开源的通义千问大模型,翻阅了大量文档,记录一下使用心得。我使用的是通义千问Qwen-VL-Chat多模态模型。LLM模型可以通过Ollama下载官网最新推出的Qwen2模型,网上教程很多比较简单,但我们怎么可能仅仅只用聊天,必须得上多模态,Ollama的多模态模型很少,并且尝试过效果都不好,最后盯上modelScope上的Qwen-VL-Chat多模态,官网提供了modelScope和transformers两种途径获取模型,训练需要用到transformers,梯子已经架好。

        

环境准备

       硬件:  本人使用的是window10系统,电脑为工作站内存,显存不需要考虑,正常情况下16G内存,6G显存能跑低7亿参数的模型。

        软件: Anconda、Pytorch、Python、cuda(有GPU的考虑)主要用到这3个,其它包稍后说明。版本之间要按照官网上的说明来寻找适合的版本。我使用的版本如下:

        Anconda:23.3.1;

        Pytorch:2.0.1;

        Python:3.10;

        cuda:11.7;

软件安装

        详细环境安装请看通义千问Qwen-VL-Chat大模型本地部署(一);

数据准备

[
  {
    "id": "identity_0",
    "conversations": [
      {
        "from": "user",
        "value": "你好"
      },
      {
        "from": "assistant",
        "value": "我是Qwen-VL,一个支持视觉输入的大模型。"
      }
    ]
  },
  {
    "id": "identity_1",
    "conversations": [
      {
        "from": "user",
        "value": "Picture 1: <img>https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-VL/assets/demo.jpeg</img>\n图中的狗是什么品种?"
      },
      {
        "from": "assistant",
        "value": "图中是一只拉布拉多犬。"
      },
      {
        "from": "user",
        "value": "框出图中的格子衬衫"
      },
      {
        "from": "assistant",
        "value": "<ref>格子衬衫</ref><box>(588,499),(725,789)</box>"
      }
    ]
  },
  { 
    "id": "identity_2",
    "conversations": [
      {
        "from": "user",
        "value": "Picture 1: <img>assets/mm_tutorial/Chongqing.jpeg</img>\nPicture 2: <img>assets/mm_tutorial/Beijing.jpeg</img>\n图中都是哪"
      },
      {
        "from": "assistant",
        "value": "第一张图片是重庆的城市天际线,第二张图片是北京的天际线。"
      }
    ]
  }
]

         数据格式如上,文件喂.json格式。<img>标签为图片地址标签,<box>标签为左上角,右下角坐标,用于标出矩形框,<ref>引用文本标签。

模型训练

        这里面踩了不少坑,网上一大堆linux环境训练的教学,找个windows环境的训练找不到,身边也没有linux系统,头铁只能硬搞finetune.py脚本。finetune.py是windows系统执行训练的脚本,直接运行报错,问题不少下面列举我遇到的问题以及解决方式:

        模型名称修改

        将代码模型名称改成

class ModelArguments:
    model_name_or_path: Optional[str] = field(default="QWen/QWen-VL-Chat")

        数据集修改

@dataclass
class DataArguments:
    data_path: str = field(
        default="自己的训练数据集位置", metadata={"help": "Path to the training data."}
    )
    eval_data_path: str = field(
        default="自己的验证集位置", metadata={"help": "Path to the evaluation data."}
    )
    lazy_preprocess: bool = False

        模型参数修改

@dataclass
class TrainingArguments(transformers.TrainingArguments):
    cache_dir: Optional[str] = field(default=None)
    optim: str = field(default="adamw_torch")
    model_max_length: int = field(
        default=1024, # 这里根据自己硬件内存适当调整我的内存是150G 改成1024跑起来会占掉120G左右
        metadata={
            "help": "Maximum sequence length. Sequences will be right padded (and possibly truncated)."
        },
    )
    use_lora: bool = True # 使用lora参数 将false 改成true
    fix_vit: bool = True

         model_max_length根据自己计算机内存适当调整,我们需要使用lora参数。

        数据读取编码修改

def make_supervised_data_module(
    tokenizer: transformers.PreTrainedTokenizer, data_args, max_len,
) -> Dict:
    """Make dataset and collator for supervised fine-tuning."""
    dataset_cls = (
        LazySupervisedDataset if data_args.lazy_preprocess else SupervisedDataset
    )
    rank0_print("Loading data...")
    # 使用UTF-8加载
    train_json = json.load(open(data_args.data_path, "r", encoding='utf-8'))
    train_dataset = dataset_cls(train_json, tokenizer=tokenizer, max_len=max_len)
    # 使用UTF-8加载
    if data_args.eval_data_path:
        eval_json = json.load(open(data_args.eval_data_path, "r", encoding='utf-8'))
        eval_dataset = dataset_cls(eval_json, tokenizer=tokenizer, max_len=max_len)
    else:
        eval_dataset = None

    return dict(train_dataset=train_dataset, eval_dataset=eval_dataset)

        这里要在open()中添加encoding='utf-8',不然文件读取会编码集错误。

        output_dir修改

        在运行finetune.py文件的时候会报output_dir找不到的错误,如果使用pycharm运行需要修改如下设置:

        edit添加运行指令 --output_dir 模型输出路径,点OK;

        命令行方式启动:

python finetune.py --output_dir 输出文件地址

        至此需要修改的内容都结束了,如果运行提示内存不足那么需要修改模型参数model_max_length到合适值。我使用的内存为150G,model_max_length=1024运行会占120G左右。这里用到transformers的版本是项目中自带版本不需要升级到最新版。上一篇中如果要使用transformers需要升级最新版。

模型调用

        训练结束后会在设置的输出目录中看到保存的微调模型。接下来就是调用,我们还继续使用上一篇中的http_api.py调用。代码如下:

        代码中添加了model_name_or_path = "H:/ali-qwen/Qwen-VL/output_dir"为上一步模型训练的输出地址,通过peft的PeftModel在模型加载的时候使用如下方式将我们自己训练的模型参数添加到预训练模型中。并且将modelscope相关加载方式换成了transformers的。

model = PeftModel.from_pretrained(model, model_id=model_name_or_path)
from argparse import ArgumentParser
from contextlib import asynccontextmanager

import torch
import uvicorn
from fastapi import FastAPI, Response
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
# from modelscope import (
#     AutoModelForCausalLM, AutoTokenizer, GenerationConfig
# )
from sse_starlette.sse import EventSourceResponse
from transformers import AutoTokenizer, AutoModelForCausalLM
from transformers.generation import GenerationConfig
from peft import PeftModel

DEFAULT_CKPT_PATH = 'QWen/QWen-VL-Chat'
model_name_or_path = "H:/ali-qwen/Qwen-VL/output_dir"

@asynccontextmanager
async def lifespan(app: FastAPI):  # collects GPU memory
    yield
    if torch.cuda.is_available():
        torch.cuda.empty_cache()
        torch.cuda.ipc_collect()


app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


class RequestParams(BaseModel):
    image: str
    text: str


@app.post("/v1/chat/demo")
async def _launch_demo(params: RequestParams, resp: Response):
    # 设置响应头部信息
    resp.headers["Content-Type"] = "text/event-stream"
    resp.headers["Cache-Control"] = "no-cache"
    global model, tokenizer
    message = params.text
    query = tokenizer.from_list_format([
        {'image': 'C:/Users/LENOVO/Desktop/f0d17c6f301f675ac8cbe600da4a8e1.png'},
        {'text': '这是什么'},
    ])

    return EventSourceResponse(stream_generate_text(query))


async def stream_generate_text(message):
    for response in model.chat_stream(tokenizer, message, history=[]):
        yield _parse_text(response)


# 设置模型参数
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("--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=8000,
                        help="Demo server port.")
    parser.add_argument("--server-name", type=str, default="0.0.0.0",
                        help="Demo server name.")

    args = parser.parse_args()
    return args


def _parse_text(text):
    lines = text.split("\n")
    lines = [line for line in lines if line != ""]
    count = 0
    for i, line in enumerate(lines):
        if "```" in line:
            count += 1
            items = line.split("`")
            if count % 2 == 1:
                lines[i] = f'<pre><code class="language-{items[-1]}">'
            else:
                lines[i] = f"<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>" + line
    text = "".join(lines)
    return text


# 加载模型
def _load_model_tokenizer(args):
    #, revision='master',
    tokenizer = AutoTokenizer.from_pretrained(
        args.checkpoint_path, trust_remote_code=True, resume_download=True
    )

    if args.cpu_only:
        device_map = "cpu"
    else:
        device_map = "cuda"
        # revision='master',
    model = AutoModelForCausalLM.from_pretrained(
        args.checkpoint_path,
        device_map=device_map,
        trust_remote_code=True,
        resume_download=True,

    ).eval()
    # , revision='master',
    model.generation_config = GenerationConfig.from_pretrained(
        args.checkpoint_path, trust_remote_code=True, resume_download=True
    )
    # 添加自定义训练模型节点
    model = PeftModel.from_pretrained(model, model_id=model_name_or_path)
    return model, tokenizer


if __name__ == "__main__":
    args = _get_args()

    # 加载qwen-vl-chat合并后的新模型

    model, tokenizer = _load_model_tokenizer(args)

    uvicorn.run(app, host=args.server_name, port=args.server_port, workers=1)

 验证

        我将自定义的图片添加到数据集中;

        验证图片如下:

         在没有训练情况下模型回答如下:

        经过训练后情况如下:

        从结果来看只是去掉了关于键盘的描述部分,多次询问结果都一样,官网解释为当模型不清楚问题具体想要时会以介绍图片的形式回答问题,我们只是侧重于这张图片的关于烟的描述,训练后模型不再介绍关于这张图片其它之外的内容。说明对于这张图片以及我们喂给模型的数据它已经学习过了。 

小结

        本文介绍了开源Qwen-VL-Chat多模态本地训练功能,供小白参考,欢迎大佬指点问题。

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

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

相关文章

高等数学第一讲:函数极限与连续

函数极限与连续 文章目录 函数极限与连续1.函数概念与特性1.1 函数定义 1.2 几种重要的基本函数类型1.2.1 反函数1.2.2 复合函数1.2.3 隐函数 1.3 函数的基本特性1.3.1 有界性1.3.2 单调性1.3.3 奇偶性1.3.4 周期性 2. 函数的极限2.1函数的极限的定义2.2 函数的极限的性质2.3 无…

react-router实现路由拦截,useLocation,useNavigate钩子

路由拦截 react-router中没有直接给出拦截路由的方法&#xff0c;需要手动的去监听路由的变化来拦截路由 路由拦截的要点&#xff1a; 能够识别出目标路由和原始路由&#xff08;区分跳转前和跳转后&#xff09;能够在跳转时&#xff08;跳转前或者跳转后&#xff09;执行一些…

MySql性能调优04-[MySql事务与锁机制原理]

MySql事务与锁机制原理 从undo与redo日志&#xff0c;理解事务底层ACID底层原理事务四大隔离级别底层实现原理 从undo与redo日志&#xff0c;理解事务底层ACID底层原理 事务特性原子性&#xff1a;当前事务操作要么同时成功&#xff0c;要么同时失败。原子性由undo log日志来保…

银河麒麟高级服务器操作系统 V10 SP3 2403

系统简介 银河麒麟高级服务器操作系统V10是一款为企业级关键业务设计的新一代自主服务器操作系统&#xff0c;它满足虚拟化、云计算、大数据等时代需求&#xff0c;具备高可靠性、安全性、性能和扩展性。该系统基于CMMI5级标准开发&#xff0c;支持多种国产处理器平台&#xf…

【邀请函】庭田科技邀您第五届中国国际复合材料科技大会

第五届中国国际复合材料科技大会暨第七届国际复合材料产业创新成果技术展示&#xff08;ICIE7-新疆&#xff09;将于7月25-27日在新疆乌鲁木齐-国际会展中心举行。上海庭田信息科技有限公司将携多款仿真模拟软件亮相本次大会&#xff0c;诚挚欢迎各位到场咨询了解&#xff01; …

实战演练-2021年电赛国一之三端口DC-DC变换器

文章目录 前言一、题目二、题目分析1、题目要求解析2、题目方案选定方案一(使用buck-boost电路&#xff0b;双向DC-DC电路&#xff08;前端&#xff09;)方案二(使用同步整流Boost升压电路&#xff0b;双向DC-DC电路&#xff08;前端&#xff09;)方案三(使用同步整流Boost升压…

基于随机森林与XGBoost模型的机器故障关键因素分析

1.项目背景 在现代工业环境中,机器故障预测已成为提升生产效率和减少停机时间的关键因素,准确预测机器故障能够帮助企业制定预防性维护计划,降低维护成本,提高设备的使用寿命和生产线的连续性。通过深入分析影响机器故障的主要因素,可以帮助企业更好地理解机器运行状态,…

MySQL的插入(DML)

1.给指定字段添加数据 这个就是&#xff0c;想插入所对应的字段&#xff0c;就插入所对应的数值。先把字段列出来&#xff0c;不一定是全部的字段&#xff0c; 然后插入想要的值&#xff0c;注意&#xff0c;只能插入一行。 INSERT INTO 表名 (字段1,字段2,.....) VALUES(值…

车流量统计YOLOV8+DEEPSORT

车流量统计&#xff0c;YOLOV8NANODEEPSORT资源-CSDN文库 车流量统计YOLOV8DEEPSORT&#xff0c;目前支持PYTHON,C开发 PYTHON版本&#xff0c;需要YOLOV8&#xff0c;依赖PYTORCH C版本&#xff0c;只需要OPENCV

无人机光电吊舱技术详解

无人机光电吊舱是一种集成了多种光电探测设备的载荷系统&#xff0c;安装在无人机下方或侧面&#xff0c;用于实现无人机的目标搜索、识别、跟踪和定位等功能。光电吊舱系统通常由稳定平台、光学成像设备、红外成像设备、激光测距设备、惯性导航设备等组成&#xff0c;能够在各…

【C++深度探索】全面解析多态性机制(二)

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 前言 我…

web零碎知识

在后端想要发送一个JSON对象可以使用Gson // 使用 Gson 将对象转换为 JSON 字符串Gson gson new Gson();String json gson.toJson(user); 就会把一个对象转化为一个JSON字符串&#xff0c; // 设置响应内容类型为 JSONresponse.setContentType("application/json&quo…

卷积神经网络-猫狗识别实战

课程来自bilibiliMomodel平台 全长只有两个小时&#xff0c;理论部分讲得很粗糙 1 人的视觉和计算机视觉 人的大脑&#xff1a;神经元细胞&#xff0c;轴突发送信号&#xff0c;树突接收信号&#xff0c;互相连接&#xff0c;连接的强度和状态会随着新的经历刺激而变化。 用…

尚硅谷Vue3入门到实战,最新版vue3+TypeScript前端开发教程

Vue3 编码规范 创建vue3工程 基于vite创建 快速上手 | Vue.js (vuejs.org) npm create vuelatest 在nodejs环境下运行进行创建 按提示进行创建 用vscode打开项目 安装依赖 源文件有src 内有main.ts App.vue 简单分析 编写src vue2语法在三中适用 vue2中的date metho…

C++基础知识:冒泡排序(利用C++实现冒泡排序)

1.冒泡排序的作用: 最常用也是简单的排序算法&#xff0c;对数组内元素进行排序 2.冒泡排序的具体步骤&#xff1a; 1.比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 2.对每一对相邻元素做同样的工作&#xff0c;执行完毕后&#xff0c;找到第一个最大值…

关于思维和智能体模型的思考(2)

在关于思维和智能体模型的思考&#xff08;1&#xff09;一文中&#xff0c;我们提出了思维和Agent 模型&#xff0c;提出了使用确定连接的智能体构建的思维模型。本文我们继续讨论思维与智能体&#xff0c;重点探讨另一种智能体-自主智能体&#xff0c;并且提出了自主智能体的…

《黑马点评》Redis高并发项目实战笔记【完结】P1~P72

花费4周敲完《黑马点评》的课程&#xff0c;做了详细的笔记&#xff0c;感觉受益匪浅&#xff0c;一直一直都在不停成长着。 突然想起《苍穹外卖》系列至今已收获200个赞&#xff0c;500个收藏&#xff0c;好评颇多&#xff0c;私信我的人不计其数&#xff0c;在此谢谢大家。 …

从零开始学习PX4源码3(如何上传官网源码到自己的仓库中)

目录 文章目录 目录摘要1.将PX4源码上传至腾讯工蜂2.从腾讯工蜂克隆源码到本地ubuntu3.如何查看自己源码的版本信息 摘要 本节主要记录从零开始学习PX4源码3(如何上传官网源码到自己的仓库中)及如何查看PX4的固件版本信息&#xff0c;欢迎批评指正&#xff01; PX4源码版本V1.…

东软“引战”国家队 通用技术“补链”大国重器

向来低调温和的东软创始人刘积仁&#xff0c;这一次抛出了“王炸”级的资产交易。 7月3日&#xff0c;《多肽链》获得一则足以引爆国内医疗设备行业的投资信息&#xff1a;被东软集团视为核心资产、掌上明珠的东软医疗&#xff0c;成功引入通用技术集团资本有限公司与中国国有…

240713_昇思学习打卡-Day25-LSTM+CRF序列标注(4)

240713_昇思学习打卡-Day25-LSTMCRF序列标注&#xff08;4&#xff09; 最后一天咯&#xff0c;做第四部分。 BiLSTMCRF模型 在实现CRF后&#xff0c;我们设计一个双向LSTMCRF的模型来进行命名实体识别任务的训练。模型结构如下&#xff1a; nn.Embedding -> nn.LSTM -&…