如何本地部署大模型(以PaddleOCR-VL-1.5为例)

如何本地部署大模型(以PaddleOCR-VL-1.5为例)

  • 阶段1:Windows环境基础准备
    • [1-1 显卡驱动准备](#1-1 显卡驱动准备)
    • [1-2 开启 WSL2](#1-2 开启 WSL2)
    • [1-3 安装Docker Desktop](#1-3 安装Docker Desktop)
  • 阶段2:建立工作区
    • [2-1 创建存放模型的文件夹](#2-1 创建存放模型的文件夹)
    • [2-2 下载模型](#2-2 下载模型)
  • 阶段3:编写配置文件
    • [3-1 配置文件docker-compose.yml](#3-1 配置文件docker-compose.yml)
    • [3-2 配置文件Dockerfile](#3-2 配置文件Dockerfile)
    • [3-3 版面分析接口文件layout_api.py](#3-3 版面分析接口文件layout_api.py)
  • 阶段4:一键启动与验证
  • 续更~
    • [文件1- Docker](#文件1- Docker)
    • [文件2- docker-compose.yml](#文件2- docker-compose.yml)
    • [文件3- layout_api.py](#文件3- layout_api.py)
    • [文件4- test_ocr.py](#文件4- test_ocr.py)

背景描述
近期工作时发现自己对高精度OCR的需求量很大,需求点是可支持本地离线使用+高精度,尝试了Umi-OCR模型测试第一张照片便败下阵来,联想起前段时间使用Quicker自带的OCR功能(精度很高,但免费使用次数有限,后经查询发现是百度的API),决定在本地部署百度的 PaddleOCR-VL-1.5 模型:参数量不大约为0.9B、模型文件约4GB、运行内存占用约为6GB、显卡要求为RTX3060及其以上。

由于不想面临CUDA版本以及底层C++库的冲突,决定选择在Docker中部署该视觉模型,以下是一份保姆级的配置方案。

阶段1:Windows环境基础准备

1-1 显卡驱动准备

要确保自己的Windows安装了最新的 NVIDIA 显卡驱动。

  • Step1。确定自己电脑的显卡类型。win+r输入指令dxdiag显示中查看自己
    的GPU类型,图1中可看到我的GPU是RTX 3060。

(图1)

(图2)


(图3)





(图4-图6)

  • Step3。测试显卡驱动是否成功安装。win+r -> cmd -> nvidia-smi ,可看到类似图7的驱动版本信息

(图7)

1-2 开启 WSL2

  • Step1。管理员身份打开WindowsPowerShell,输入命令wsl --install并回车(过程中不要开启梯子)


(图8)

  • Step2。重启电脑使WSL2生效(WSL2,即Windows Subsystem for Linux 2,是微软在 Windows 10/11 上运行 Linux 环境的第二代架构)

1-3 安装Docker Desktop

  • Step1。查看自己电脑的架构类型。win+r -> cmd -> msinfo32 ,会出现图9所示的界面,系统类型显示为基于x64的电脑说明我的电脑为AMD64架构(若这里显示基于 ARM64 的电脑基于 ARM的电脑则说明电脑为ARM64架构)

(图9)

(图10)

  • Step3。Docker启动初尝试。点击桌面的Docker Desktop图标,可能会弹出一个服务条款让你点击 Accept(接受)。进去之后稍微等一下,直到你看到软件界面左下角显示绿色的 "Engine running",这就说明底层环境全部搭建完毕了。

(图11)

  • Step4。更改Dockerd数据输出位置。"Settings" -> "Resources" -> "Browse",选择你中意的文件夹路径,然后点击"Apply""即可。(这步一定要做,我去看了一下Docker解压后的基础配置文件,分居于C:\Users\Lxf\AppData\Local\Docker和C:\Program Files\Docker下,直接干了我C盘5.5个G,后面进一步部署大模型会把全部文件放到C盘会导致C盘直接炸掉)

(图12)

阶段2:建立工作区

2-1 创建存放模型的文件夹

这一步的目的是在物理盘中建立一个干净的工作区。打开 PowerShell,按顺序运行以下命令创建文件夹:

bash 复制代码
# 创建主目录
mkdir E:\PaddleDeploy
# 创建存放模型权重的目录
mkdir E:\PaddleDeploy\models
# 创建存放版面分析代码的目录
mkdir E:\PaddleDeploy\layout_service

2-2 下载模型

由于我本地Base环境中已经安装了Python,因此直接使用pip install指令将PaddleOCR-VL-1.5的权重下载到本地即可,但正式下载前需要先做一下网络配置以确保Powershell终端能正常使用上网络代理。

  • Step1。开启网络代理软件、查看HTTP本地代理端口。"Settings" -> "基本配置" ,下拉列表中找到"端口",可知我的端口为7890(我使用的软件是FIClash,其他网络代理的设置步骤也都大同小异)

(图13-图14)

  • Step2。PowerShell中手动指派本地代理。分别输入以下两句指令并回车即可
bash 复制代码
$env:HTTP_PROXY="http://127.0.0.1:7890"
$env:HTTPS_PROXY="http://127.0.0.1:7890"
  • Step3。下载模型到本地
    直接在PowerShell中使用下面的指令并回车。(下载过程将持续一段时间,因为大概有4GB,下载过程中请打开梯子以确保能稳定访问到Huggingface官网)
bash 复制代码
pip install -U "huggingface_hub[cli]"
huggingface-cli download PaddlePaddle/PaddleOCR-VL --local-dir E:\PaddleDeploy\models\PaddleOCR-VL

阶段3:编写配置文件

在这个阶段将创建3个配置文件,可以用任意的文本编辑器(记事本、VScode、Notepad++等)来创建它们,建议使用Visual Studio Code来写,可支持文件类型更多而且还支持无扩展名文件,保存文件时记得编码格式要调整为UTF-8

3-1 配置文件docker-compose.yml

创建文件docker-compose.yml,存放于路径E:\PaddleDeploy下,文件的源码放在下面的代码框中。

bash 复制代码
version: '3.8'

services:
  # 服务 1: 视觉大模型 (vLLM)
  vlm-service:
    image: vllm/vllm-openai:latest
    container_name: ocr_vlm_node
    ipc: host
    ports:
      - "8000:8000"
    volumes:
      # 将 Windows 下的模型目录映射到容器内的 /models
      - ./models:/models
    command: >
      --model /models/PaddleOCR-VL
      --trust-remote-code
      --max-model-len 4096
      --enforce-eager
      --gpu-memory-utilization 0.4
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

  # 服务 2: 版面分析 (PaddlePaddle)
  layout-service:
    build: 
      context: ./layout_service
      dockerfile: Dockerfile
    container_name: ocr_layout_node
    ports:
      - "8001:8001"
    volumes:
      - ./models:/models
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

3-2 配置文件Dockerfile

创建文件Dockerfile(注意没有后缀名,可参考图15),存放于路径E:\PaddleDeploy\layout_service下,文件的源码放在下面的代码框中。

bash 复制代码
FROM paddlepaddle/paddle:latest-gpu-cuda11.8-cudnn8.6-trt8.5
RUN pip install --no-cache-dir paddleocr fastapi uvicorn python-multipart
COPY layout_api.py /app/layout_api.py
WORKDIR /app
CMD ["uvicorn", "layout_api:app", "--host", "0.0.0.0", "--port", "8001"]


(图15)

3-3 版面分析接口文件layout_api.py

创建文件layout_api.py,将其存放于路径E:\PaddleDeploy\layout_service,文件源码存放于下面的代码块中。

python 复制代码
from fastapi import FastAPI, UploadFile, File
from paddleocr import PPStructure
import cv2
import numpy as np

app = FastAPI()
# 初始化版面分析
layout_engine = PPStructure(show_log=True, image_dir=None)

@app.post("/analyze_layout")
async def analyze_layout(file: UploadFile = File(...)):
    contents = await file.read()
    nparr = np.frombuffer(contents, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    
    result = layout_engine(img)
    
    regions = []
    for region in result:
        regions.append({
            "type": region['type'],
            "bbox": region['bbox']
        })
    return {"status": "success", "regions": regions}

阶段4:一键启动与验证

  • Step1。为Docker配置网络代理。由于在前面的环节我已经确定自己本地代理的端口为7890,因此这里直接进入Docker Desktop中进行配置即可。Settings -> Resources -> Proxies -> Manual configuration ,在 Web Server (HTTP) 和 Secure Web Server (HTTPS) 框中输入http://127.0.0.1:7890,在Bypass proxy settings for these hosts & domains 框中输入localhost,127.0.0.1,然后点击Apply & restart


(图16)

  • Step2。在PowrShell中输入指令cd E:\PaddleDeploy,切换到工作目录。
  • Step3。执行一键启动命令。(经过一段漫长的等待,等Docker 从网上下载 vLLM 和 PaddlePaddle 的基础环境镜像,大约60个GB,过程中可能出现CPU占用率100%、风扇狂响,等到出现图17的画面,就说明安装成功了!)
bash 复制代码
docker-compose up -d --build


(图17)

续更~

Step3中的安装过程可能的问题说明

  • 问题1。出现图18所示的unexpected EOF报错问题,原因是网络波动导致下载中途停止,这时候不用慌,调整一下网络然后在PowerShell中输入指令docker-compose up -d --build继续下载就行。

(图18)

  • 问题2。大模型安装包下载完成,却在结尾报错"docker.io/paddlepaddle/paddle... not found"(如图19所示),这说明Docker 在官方仓库里找不到 latest-gpu-cuda11.8-cudnn8.6-trt8.5 这个确切的名字,这个问题出现概率很大,因为官方镜像库里的标签命名规则经常变动导致原来的名字失效。此时,你只需要把报错代码喂给AI(如图20所示),让他去找现在对应最新的镜像库来修改一下配置文件即可。


(图19)


(图20)

对于我前面的配置文件,AI给出的修改有2处,一是文件Dockerfile,二是文件docker-compose.yml,分别对应下面这两个代码块。修改完以后继续在PowerShell中使用指令docker-compose up -d --build,最终得到了图17的成功安装画面!

bash 复制代码
FROM registry.baidubce.com/paddlepaddle/paddle:2.6.1-gpu-cuda11.7-cudnn8.4-trt8.4

# 使用清华源加速安装
RUN pip install --no-cache-dir paddleocr fastapi uvicorn python-multipart -i https://pypi.tuna.tsinghua.edu.cn/simple

COPY layout_api.py /app/layout_api.py
WORKDIR /app

CMD ["uvicorn", "layout_api:app", "--host", "0.0.0.0", "--port", "8001"]
bash 复制代码
# 服务 2: 版面分析服务 (使用 PaddlePaddle GPU)
  layout-service:
    build: 
      context: ./layout_service
      dockerfile: Dockerfile
    container_name: ocr_layout_node
    ports:
      - "8001:8001"
    volumes:
      - ./models:/models
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
  • 问题3-问题n。PaddleOCR-VL-1.5部署完成后,我拿他做了本地测试(写一个test_ocr.py文件来识别本地图片),没想到各种出现了各种设置问题,图21是我让AI帮我总结的部分问题,过程中改了很多次Dockerfile、docker-compose.yml、test_ocr.py,我将最新版的配置文件以及我的测试py文件放到下面,有需自取。

(图21)

文件1- Docker

bash 复制代码
FROM registry.baidubce.com/paddlepaddle/paddle:2.6.1-gpu-cuda11.7-cudnn8.4-trt8.4

# 1. 修复底层环境:安装 OpenCV 强依赖的系统级动态链接库
RUN apt-get update && apt-get install -y libgl1 libglib2.0-0 && rm -rf /var/lib/apt/lists/*

# 2. 安装 Python 库:严格锁死 paddleocr==2.8.1 经典稳定版,避免 3.x 版本 API 报错
RUN pip install --no-cache-dir "paddleocr==2.8.1" fastapi uvicorn python-multipart -i https://pypi.tuna.tsinghua.edu.cn/simple

COPY layout_api.py /app/layout_api.py
WORKDIR /app

# 启动 FastAPI 服务
CMD ["uvicorn", "layout_api:app", "--host", "0.0.0.0", "--port", "8001"]

文件2- docker-compose.yml

bash 复制代码
services:
  # 服务 1: 视觉大模型 (vLLM)
  vlm-service:
    image: vllm/vllm-openai:latest
    container_name: ocr_vlm_node
    ipc: host
    ports:
      - "8000:8000"
    volumes:
      - ./models:/models
    environment:
      # 解决 Windows WSL2 环境下的 PyTorch 多进程崩溃问题
      - VLLM_WORKER_MULTIPROC_METHOD=spawn
      - VLLM_USE_V1=0
    command: >
      --model /models/PaddleOCR-VL
      --trust-remote-code
      --max-model-len 4096
      --enforce-eager
      --gpu-memory-utilization 0.5
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

  # 服务 2: 版面分析服务
  layout-service:
    build: 
      context: ./layout_service
      dockerfile: Dockerfile
    container_name: ocr_layout_node
    ports:
      - "8001:8001"
    volumes:
      - ./models:/models
    environment:
      # 限制 Paddle 显存占用
      - FLAGS_fraction_of_gpu_memory_to_use=0.1
      - FLAGS_allocator_strategy=naive_best_fit
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

文件3- layout_api.py

bash 复制代码
from fastapi import FastAPI, UploadFile, File
from paddleocr import PPStructure
import cv2
import numpy as np

app = FastAPI()
# 初始化版面分析
layout_engine = PPStructure(show_log=True, image_dir=None)

@app.post("/analyze_layout")
async def analyze_layout(file: UploadFile = File(...)):
    contents = await file.read()
    nparr = np.frombuffer(contents, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    
    result = layout_engine(img)
    
    regions = []
    for region in result:
        regions.append({
            "type": region['type'],
            "bbox": region['bbox']
        })
    return {"status": "success", "regions": regions}

文件4- test_ocr.py

bash 复制代码
import requests
import cv2
import base64
import sys

# ====== 配置区 ======
IMAGE_PATH = "test.png"
LAYOUT_URL = "http://localhost:8001/analyze_layout"
VLM_URL = "http://localhost:8000/v1/chat/completions"


# ====================

def main():
    print(f"👀 1. 正在读取图片: {IMAGE_PATH}")
    img = cv2.imread(IMAGE_PATH)
    if img is None:
        print("❌ 找不到图片,请检查图片路径和名称是否正确!")
        sys.exit(1)

    print("🚀 2. 正在请求版面分析服务 (Port 8001)...")
    proxies = {"http": None, "https": None}

    with open(IMAGE_PATH, "rb") as f:
        try:
            res_layout = requests.post(LAYOUT_URL, files={"file": f}, proxies=proxies)
            if res_layout.status_code != 200:
                print(f"❌ 8001 返回错误!状态码: {res_layout.status_code}, 内容: {res_layout.text}")
                sys.exit(1)
            layout_data = res_layout.json()
        except Exception as e:
            print(f"❌ 版面分析失败: {e}")
            sys.exit(1)

    regions = layout_data.get("regions", [])
    print(f"✅ 版面分析完成,发现 {len(regions)} 个目标区域。")

    if not regions:
        regions = [{"bbox": [0, 0, img.shape[1], img.shape[0]], "type": "Text"}]

    print("🧠 3. 开始调用 0.9B 大模型进行高精度识别 (Port 8000)...")
    for idx, region in enumerate(regions):
        x1, y1, x2, y2 = region["bbox"]
        region_type = region["type"]

        crop_img = img[int(y1):int(y2), int(x1):int(x2)]

        # 【核心改进 1】:动态压缩长边,防止视觉 Token 超出 vLLM 的 3600 预算
        max_size = 960  # 锁定长边最大 960 像素
        h, w = crop_img.shape[:2]
        if max(h, w) > max_size:
            scale = max_size / max(h, w)
            crop_img = cv2.resize(crop_img, (int(w * scale), int(h * scale)))

        # 【核心改进 2】:使用 85 质量的 JPEG 编码,把 Base64 体积缩小 70% 以上
        _, buffer = cv2.imencode('.jpg', crop_img, [int(cv2.IMWRITE_JPEG_QUALITY), 85])
        img_base64 = base64.b64encode(buffer).decode('utf-8')

        prompt = "请精准识别这张图中的所有文字。"
        if region_type == "Table":
            prompt = "请识别图中的表格,并以 Markdown 格式严格输出。"

        payload = {
            "model": "/models/PaddleOCR-VL",
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": prompt},
                        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img_base64}"}}
                    ]
                }
            ],
            "temperature": 0.0
        }

        print(f"   -> 正在识别第 {idx + 1} 个区域 [{region_type}],请稍候...", end="", flush=True)
        try:
            # 【核心改进 3】:加入 timeout=120,允许大模型在第一次加载图片时有充足的预热时间
            res_vlm = requests.post(VLM_URL, json=payload, proxies=proxies, timeout=120)

            if res_vlm.status_code != 200:
                print(f" ❌ 8000 返回错误!状态码: {res_vlm.status_code}, 内容: {res_vlm.text}")
                continue

            text = res_vlm.json()["choices"][0]["message"]["content"]
            print(" 完成!")
            print(f"\n【识别结果】:\n{text}\n" + "-" * 40)
        except requests.exceptions.Timeout:
            print(" ❌ 识别超时,初次加载较慢,请再运行一次重试!")
        except Exception as e:
            print(f" ❌ 识别失败: {e}")


if __name__ == "__main__":
    main()

下面,以一张成功OCR的图收尾,纪念我做了一晚上的工作~

后面每次需要使用OCR服务时,直接打开Docker Desktop的启动面板,然后在PowerShell中运行py脚本执行识别任务即可~

flag is all you need !!!

相关推荐
2501_915918412 小时前
苹果应用开发编译流程,用快蝎(kxapp)工具完成 iOS 构建与调试
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
XPoet2 小时前
AI 编程工程化:AI 时代程序员的基本功
aigc·ai编程·claude
该用户已不存在6 小时前
月薪2w养不起龙虾?试试OpenClaw+Ollama
人工智能·aigc·ai编程
爱吃的小肥羊6 小时前
我的Claude账号被封了,复盘了一下,感觉非常冤!
aigc
雾霾下的天空6 小时前
AIGC长时记忆开源项目Zep技术原理
aigc
大厂码农老A9 小时前
3天实现"睡后收入"—— Cursor & Skills打造"全自动出海"Agent
人工智能·aigc·ai编程
树獭叔叔10 小时前
OpenClaw Agents 系统:多代理架构与智能编排的完整技术解析
后端·aigc·openai
树獭叔叔12 小时前
OpenClaw Workspace 文件完整指南:从文件到 AI 行为的完整链路
后端·aigc·openai
Lupino12 小时前
别再只聊 AI 写代码了:技术负责人要把“变更治理”提到第一优先级
python·docker·容器