302 lines
10 KiB
Bash
Executable File
302 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
||
set -euo pipefail
|
||
# =============================================================================
|
||
# VLM (Qwen2.5-VL-3B) 依赖安装脚本 — 国内镜像优化版
|
||
# =============================================================================
|
||
# 运行环境:ECS GPU 容器(/workspace 挂载在 EFS 上持久化)
|
||
# 前置条件:NVIDIA GPU 可用,CUDA 驱动已安装
|
||
#
|
||
# 国内镜像策略:
|
||
# - pip 包:阿里云镜像
|
||
# - HuggingFace 模型:hf-mirror.com(默认)或魔搭 ModelScope
|
||
# - PyTorch:优先阿里云,若缺失则回退官方源
|
||
#
|
||
# 如需使用官方源(境外环境):
|
||
# USE_CHINA_MIRROR=false bash scripts/install_vlm.sh
|
||
# =============================================================================
|
||
|
||
ROOT="/workspace"
|
||
SITE_PACKAGES="${ROOT}/.site-packages"
|
||
VLM_MODEL_CACHE="${ROOT}/.cache/huggingface"
|
||
|
||
# 国内镜像开关(默认启用)
|
||
USE_CHINA_MIRROR="${USE_CHINA_MIRROR:-true}"
|
||
|
||
# pip 镜像
|
||
PIP_MIRROR_ALIYUN="https://mirrors.aliyun.com/pypi/simple/"
|
||
PIP_MIRROR_TSINGHUA="https://pypi.tuna.tsinghua.edu.cn/simple"
|
||
PIP_MIRROR_OFFICIAL="https://pypi.org/simple"
|
||
|
||
# HuggingFace 镜像
|
||
HF_MIRROR="https://hf-mirror.com"
|
||
|
||
# 魔搭 ModelScope(阿里云出品,国内速度极快)
|
||
MODELSCOPE_CACHE="${ROOT}/.cache/modelscope"
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||
log_step() { echo -e "${BLUE}[STEP]${NC} $*"; }
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 配置镜像
|
||
# -----------------------------------------------------------------------------
|
||
if [[ "$USE_CHINA_MIRROR" == "true" ]]; then
|
||
log_info "国内镜像模式已启用(USE_CHINA_MIRROR=true)"
|
||
PIP_INDEX="--index-url $PIP_MIRROR_ALIYUN"
|
||
HF_ENDPOINT="$HF_MIRROR"
|
||
export HF_ENDPOINT
|
||
export PIP_INDEX_URL="$PIP_MIRROR_ALIYUN"
|
||
# 让 huggingface_hub 使用国内 endpoint
|
||
export HF_HUB_ENABLE_HF_TRANSFER=0
|
||
else
|
||
log_info "官方源模式(USE_CHINA_MIRROR=false)"
|
||
PIP_INDEX=""
|
||
HF_ENDPOINT="https://huggingface.co"
|
||
fi
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 0. 环境检查
|
||
# -----------------------------------------------------------------------------
|
||
log_step "0. 检查 GPU / CUDA 环境..."
|
||
|
||
if ! command -v nvidia-smi &>/dev/null; then
|
||
log_error "nvidia-smi 未找到。请确认当前为 GPU 实例且 NVIDIA 驱动已安装。"
|
||
exit 1
|
||
fi
|
||
|
||
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader || true
|
||
|
||
if ! python3 -c "import torch; assert torch.cuda.is_available()" 2>/dev/null; then
|
||
log_warn "PyTorch CUDA 未安装或不可用,将重新安装 PyTorch CUDA 版..."
|
||
NEED_PYTORCH_CUDA=1
|
||
else
|
||
python3 -c "import torch; print(f'PyTorch {torch.__version__}, CUDA {torch.version.cuda}, Device: {torch.cuda.get_device_name(0)}')"
|
||
NEED_PYTORCH_CUDA=0
|
||
fi
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 1. 安装 PyTorch CUDA (如需要)
|
||
# -----------------------------------------------------------------------------
|
||
if [[ "$NEED_PYTORCH_CUDA" == "1" ]]; then
|
||
log_step "1. 安装 PyTorch 2.1.2 + CUDA 12.1 ..."
|
||
|
||
if [[ "$USE_CHINA_MIRROR" == "true" ]]; then
|
||
# 国内环境:先尝试阿里云 pip 镜像安装 PyTorch
|
||
# 注意:阿里云上 PyTorch CUDA wheel 可能滞后,若失败则回退官方源
|
||
log_info "尝试从阿里云镜像安装 PyTorch..."
|
||
pip install --target="$SITE_PACKAGES" --upgrade \
|
||
torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 \
|
||
--index-url "$PIP_MIRROR_ALIYUN" \
|
||
--no-cache-dir || {
|
||
log_warn "阿里云镜像安装 PyTorch 失败,回退到官方源..."
|
||
pip install --target="$SITE_PACKAGES" --upgrade \
|
||
torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 \
|
||
--index-url https://download.pytorch.org/whl/cu121 \
|
||
--no-cache-dir
|
||
}
|
||
else
|
||
pip install --target="$SITE_PACKAGES" --upgrade \
|
||
torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 \
|
||
--index-url https://download.pytorch.org/whl/cu121 \
|
||
--no-cache-dir
|
||
fi
|
||
fi
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 2. 安装 transformers / accelerate / qwen_vl_utils 等
|
||
# -----------------------------------------------------------------------------
|
||
log_step "2. 安装 Python 依赖包..."
|
||
|
||
# 先升级 pip 本身(国内镜像)
|
||
pip install $PIP_INDEX --upgrade pip setuptools wheel --no-cache-dir || true
|
||
|
||
pip install --target="$SITE_PACKAGES" $PIP_INDEX --upgrade \
|
||
"transformers>=4.40.0" \
|
||
"accelerate>=0.30.0" \
|
||
"qwen-vl-utils>=0.0.8" \
|
||
"pillow>=10.0.0" \
|
||
"safetensors>=0.4.0" \
|
||
"huggingface-hub>=0.23.0" \
|
||
--no-cache-dir
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 3. 可选:安装 Flash Attention 2 (Ampere+ GPU)
|
||
# -----------------------------------------------------------------------------
|
||
log_step "3. 检查 GPU 架构..."
|
||
|
||
GPU_ARCH=$(python3 -c "
|
||
import sys, os
|
||
sys.path.insert(0, '$SITE_PACKAGES')
|
||
import torch
|
||
major, minor = torch.cuda.get_device_capability()
|
||
print(f'{major}{minor}')
|
||
" 2>/dev/null || echo "0")
|
||
|
||
if [[ "$GPU_ARCH" == "8"* ]] || [[ "$GPU_ARCH" == "9"* ]]; then
|
||
log_info "检测到 Ampere/Hopper 架构 (sm_$GPU_ARCH),尝试安装 Flash Attention 2..."
|
||
pip install --target="$SITE_PACKAGES" $PIP_INDEX --no-build-isolation \
|
||
"flash-attn>=2.5.0" --no-cache-dir || log_warn "Flash Attention 安装失败,将使用 eager attention"
|
||
else
|
||
log_warn "GPU 架构 sm_$GPU_ARCH 不支持 Flash Attention 2,跳过安装"
|
||
fi
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 4. 验证 Python 包
|
||
# -----------------------------------------------------------------------------
|
||
log_step "4. 验证 Python 包..."
|
||
|
||
python3 -c "
|
||
import sys
|
||
sys.path.insert(0, '$SITE_PACKAGES')
|
||
import torch
|
||
print(f'PyTorch: {torch.__version__}')
|
||
print(f'CUDA available: {torch.cuda.is_available()}')
|
||
if torch.cuda.is_available():
|
||
print(f'Device: {torch.cuda.get_device_name(0)}')
|
||
print(f'Memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.2f} GB')
|
||
"
|
||
|
||
python3 -c "
|
||
import sys
|
||
sys.path.insert(0, '$SITE_PACKAGES')
|
||
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
|
||
print('transformers + Qwen2.5-VL classes OK')
|
||
"
|
||
|
||
python3 -c "
|
||
import sys
|
||
sys.path.insert(0, '$SITE_PACKAGES')
|
||
from qwen_vl_utils import process_vision_info
|
||
print('qwen_vl_utils OK')
|
||
"
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 5. 预下载模型(国内镜像优先)
|
||
# -----------------------------------------------------------------------------
|
||
VLM_MODEL="${VLM_MODEL:-Qwen/Qwen2.5-VL-3B-Instruct}"
|
||
|
||
log_step "5. 预下载 VLM 模型: $VLM_MODEL ..."
|
||
|
||
mkdir -p "$VLM_MODEL_CACHE"
|
||
|
||
if [[ "$USE_CHINA_MIRROR" == "true" ]]; then
|
||
log_info "尝试通过魔搭 ModelScope 下载模型(国内 fastest)..."
|
||
|
||
# 先安装 modelscope
|
||
pip install --target="$SITE_PACKAGES" $PIP_INDEX --upgrade \
|
||
"modelscope>=1.15.0" --no-cache-dir
|
||
|
||
python3 -c "
|
||
import sys
|
||
sys.path.insert(0, '$SITE_PACKAGES')
|
||
|
||
from modelscope import snapshot_download
|
||
|
||
# Qwen 模型在魔搭的命名空间:qwen/Qwen2.5-VL-3B-Instruct
|
||
model_id = '$VLM_MODEL'
|
||
# 如果是 HuggingFace 格式的 model_id,转换为魔搭格式
|
||
if model_id.startswith('Qwen/'):
|
||
modelscope_id = model_id.replace('Qwen/', 'qwen/')
|
||
else:
|
||
modelscope_id = model_id
|
||
|
||
print(f'使用魔搭下载: {modelscope_id}')
|
||
model_dir = snapshot_download(
|
||
modelscope_id,
|
||
cache_dir='$MODELSCOPE_CACHE',
|
||
)
|
||
print(f'模型已下载到: {model_dir}')
|
||
|
||
# 记录本地模型路径,供 run_all.sh / detector.py 直接使用
|
||
path_file = '/workspace/.vlm_model_path'
|
||
with open(path_file, 'w') as f:
|
||
f.write(f'export VLM_MODEL={model_dir}\\n')
|
||
print(f'本地模型路径已记录到: {path_file}')
|
||
|
||
# 验证可以加载
|
||
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
|
||
print('验证模型加载...')
|
||
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
|
||
model_dir,
|
||
torch_dtype='auto',
|
||
device_map='auto',
|
||
trust_remote_code=True,
|
||
)
|
||
processor = AutoProcessor.from_pretrained(
|
||
model_dir,
|
||
trust_remote_code=True,
|
||
)
|
||
print('模型加载验证成功!')
|
||
"
|
||
else
|
||
log_info "使用 HuggingFace 官方源下载模型..."
|
||
export HF_HOME="$VLM_MODEL_CACHE"
|
||
|
||
python3 -c "
|
||
import sys
|
||
import os
|
||
sys.path.insert(0, '$SITE_PACKAGES')
|
||
os.environ['HF_HOME'] = '$VLM_MODEL_CACHE'
|
||
|
||
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
|
||
from huggingface_hub import snapshot_download
|
||
|
||
print(f'正在下载模型: $VLM_MODEL ...')
|
||
# 先下载到本地缓存
|
||
model_dir = snapshot_download(
|
||
repo_id='$VLM_MODEL',
|
||
cache_dir='$VLM_MODEL_CACHE/hub',
|
||
)
|
||
print(f'模型已下载到: {model_dir}')
|
||
|
||
# 记录本地模型路径
|
||
path_file = '/workspace/.vlm_model_path'
|
||
with open(path_file, 'w') as f:
|
||
f.write(f'export VLM_MODEL={model_dir}\\n')
|
||
print(f'本地模型路径已记录到: {path_file}')
|
||
|
||
# 验证加载
|
||
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
|
||
model_dir,
|
||
torch_dtype='auto',
|
||
device_map='auto',
|
||
trust_remote_code=True,
|
||
)
|
||
processor = AutoProcessor.from_pretrained(
|
||
model_dir,
|
||
trust_remote_code=True,
|
||
)
|
||
print('模型加载验证成功!')
|
||
"
|
||
fi
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 6. 完成
|
||
# -----------------------------------------------------------------------------
|
||
log_step "6. 安装完成!"
|
||
log_info ""
|
||
log_info "============================================"
|
||
log_info " VLM 安装摘要"
|
||
log_info "============================================"
|
||
log_info "模型: $VLM_MODEL"
|
||
log_info "HF 缓存: $VLM_MODEL_CACHE"
|
||
log_info "魔搭缓存: $MODELSCOPE_CACHE"
|
||
log_info "Python 包路径: $SITE_PACKAGES"
|
||
log_info "国内镜像: $USE_CHINA_MIRROR"
|
||
log_info ""
|
||
log_info "使用方法:"
|
||
log_info " export VISION_BACKEND=vlm"
|
||
log_info " export VLM_INTERVAL=5.0"
|
||
log_info " ros2 run vision_yolo detector"
|
||
log_info ""
|
||
log_info "AWQ 量化版(显存 3-4GB):"
|
||
log_info " export VLM_MODEL=Qwen/Qwen2.5-VL-3B-Instruct-AWQ"
|
||
log_info "============================================"
|