gasschina commited on
Commit
5c3ae1a
·
verified ·
1 Parent(s): 0009e6d

Upload scripts/deploy_spark_t4.sh with huggingface_hub

Browse files
Files changed (1) hide show
  1. scripts/deploy_spark_t4.sh +248 -0
scripts/deploy_spark_t4.sh ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # deploy_spark_t4.sh — Spark-X2.5-4B 在 NVIDIA T4 (16GB) 上的一键部署脚本
4
+ # 推理引擎: llama.cpp CUDA (XHToken 官方 fork)
5
+ #
6
+ # 【为什么必须编译,不能用现成的 llama.cpp / Ollama 二进制?】
7
+ # 1. spark2_5 架构(1 全注意力 + 3 滑窗 SWA 混合)尚未合并进 mainline
8
+ # llama.cpp,直接用主分支或 Ollama 自带运行时会报
9
+ # "unknown architecture" 无法加载 GGUF —— 官方模型卡指定要用
10
+ # github.com/XHToken/llama.cpp 这个 fork。
11
+ # 2. Linux 默认编译产物不带 CUDA 后端,必须 -DGGML_CUDA=ON 重编。
12
+ # 这两点与 T4 无关,任何显卡都一样。T4 (SM 7.5 Turing) 是 llama.cpp
13
+ # CUDA 后端完整支持的架构,编译一次即可,之后日常使用无需再编译。
14
+ #
15
+ # 【量化档位怎么选(T4 16GB 显存)】
16
+ # Q8_0 (8bit) 4.07GB 质量近无损,T4 跑 32k~64k 上下文很从容 <- 默认
17
+ # Q6_K (6bit) 3.15GB 质量与速度折中
18
+ # Q4_K_M(4bit) 2.42GB 速度最快、可冲 128k+ 长上下文
19
+ # 注意: 官方仓 XHToken/Spark-X2.5-4B-GGUF 里的 7.66GB 文件是 F16
20
+ # 全精度(不是 8bit),T4 上没必要用;8bit 用本脚本的默认 imatrix 仓。
21
+ #
22
+ # 【用法】
23
+ # chmod +x deploy_spark_t4.sh
24
+ # ./deploy_spark_t4.sh deps # 1. 装系统依赖 + 构建工具
25
+ # ./deploy_spark_t4.sh build # 2. 克隆 fork 并编译 CUDA 版(约10~20分钟)
26
+ # ./deploy_spark_t4.sh download # 3. 下载量化模型(默认 Q8_0)
27
+ # ./deploy_spark_t4.sh serve # 4. 启动 OpenAI 兼容 API 服务
28
+ # ./deploy_spark_t4.sh test # 5. 发一条测试请求
29
+ # ./deploy_spark_t4.sh status # 查看运行状态
30
+ # ./deploy_spark_t4.sh stop # 停止服务
31
+ # ./deploy_spark_t4.sh all # 1~3 连跑(不含 serve)
32
+ #
33
+ # 换量化档位: QUANT=Q4_K_M ./deploy_spark_t4.sh download
34
+ # 换上下文长度: CTX=65536 ./deploy_spark_t4.sh serve
35
+ # 无GPU机器只验证编译能否通过: GGML_CUDA=OFF ./deploy_spark_t4.sh build
36
+ # ============================================================================
37
+
38
+ set -euo pipefail
39
+
40
+ # ---------------------------- 可调配置 --------------------------------------
41
+ QUANT="${QUANT:-Q8_0}" # Q8_0 / Q6_K / Q4_K_M / Q5_K_M ...
42
+ GGUF_REPO="${GGUF_REPO:-miifanboy/Spark-X2.5-4B-i1-GGUF}" # 含全档位 imatrix 量化
43
+ LLAMA_REPO="${LLAMA_REPO:-https://github.com/XHToken/llama.cpp.git}"
44
+ BASE_DIR="${BASE_DIR:-$HOME/spark-t4}"
45
+ CTX="${CTX:-32768}" # 上下文长度, T4+Q8_0 建议 32k 起步
46
+ PORT="${PORT:-8080}"
47
+ NGL="${NGL:-999}" # 全部层放 GPU
48
+ GGML_CUDA="${GGML_CUDA:-ON}" # 有 nvcc+GPU 用默认 ON;纯CPU验证编译改 OFF
49
+ BUILD_JOBS="${BUILD_JOBS:-$(nproc)}" # 内存紧张(<8GB)时建议 BUILD_JOBS=1
50
+ EXTRA_LLAMA_ARGS="${EXTRA_LLAMA_ARGS:-}" # 例如 "-ctk q8_0 -ctv q8_0"
51
+ HF_ENDPOINT_OPT="${HF_ENDPOINT_OPT:-}" # 国内镜像: export HF_ENDPOINT_OPT=https://hf-mirror.com
52
+
53
+ BUILD_DIR="$BASE_DIR/llama.cpp-spark"
54
+ MODEL_DIR="${MODEL_DIR:-$BASE_DIR/models}" # 模型目录可独立于 BASE_DIR(如 Colab 上放本地盘省 Drive 配额)
55
+ LOG_FILE="$BASE_DIR/llama-server.log"
56
+ PID_FILE="$BASE_DIR/llama-server.pid"
57
+ MODEL_FILE="$MODEL_DIR/Spark-X2.5-4B-${QUANT}.gguf"
58
+
59
+ GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
60
+ info() { echo -e "${GREEN}[INFO]${NC} $*"; }
61
+ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
62
+ fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; }
63
+
64
+ preflight() {
65
+ if ! command -v nvidia-smi >/dev/null 2>&1; then
66
+ if [[ "${GGML_CUDA^^}" == "ON" ]]; then
67
+ fail "未检测到 nvidia-smi,请先装好 NVIDIA 驱动(GCP 可用 Deep Learning VM 镜像自带驱动)"
68
+ else
69
+ warn "未检测到 nvidia-smi(GGML_CUDA=OFF 纯 CPU 验证模式,继续)"
70
+ fi
71
+ return 0
72
+ fi
73
+ nvidia-smi --query-gpu=name,memory.total --format=csv,noheader | grep -qi "t4" \
74
+ || warn "未检测到 T4(当前 GPU: $(nvidia-smi --query-gpu=name --format=csv,noheader | head -1)),脚本仍可继续"
75
+ }
76
+
77
+ # ---------------------------- 1. 系统依赖 ------------------------------------
78
+ do_deps() {
79
+ preflight
80
+ info "安装系统构建依赖(需要 sudo)..."
81
+ sudo apt-get update -y
82
+ sudo apt-get install -y build-essential cmake git curl python3 python3-pip python3-venv
83
+
84
+ # 编译 CUDA 后端需要 nvcc;GCP DLVM 镜像一般自带
85
+ if ! command -v nvcc >/dev/null 2>&1; then
86
+ warn "未检测到 nvcc (CUDA Toolkit)"
87
+ read -r -p "是否用 apt 安装 nvidia-cuda-toolkit(Ubuntu 源,版本较旧但足够编 T4)?[y/N] " ans
88
+ if [[ "${ans,,}" == "y" ]]; then
89
+ sudo apt-get install -y nvidia-cuda-toolkit
90
+ else
91
+ fail "请自行安装 CUDA Toolkit 12.x(https://developer.nvidia.com/cuda-downloads)后重试"
92
+ fi
93
+ fi
94
+ nvcc --version | tail -1
95
+
96
+ info "安装 Hugging Face 下载工具..."
97
+ python3 -m pip install -q -U "huggingface_hub[cli]" || \
98
+ python3 -m pip install -q --user -U "huggingface_hub[cli]"
99
+ info "依赖安装完成。"
100
+ }
101
+
102
+ # ---------------------------- 2. 编译 fork -----------------------------------
103
+ do_build() {
104
+ preflight
105
+ if [[ "${GGML_CUDA^^}" == "ON" ]]; then
106
+ command -v nvcc >/dev/null 2>&1 || fail "CUDA=ON 需要 nvcc,请先执行 ./deploy_spark_t4.sh deps;纯 CPU 验证用 GGML_CUDA=OFF ./deploy_spark_t4.sh build"
107
+ fi
108
+ mkdir -p "$BASE_DIR"
109
+
110
+ if [[ -d "$BUILD_DIR/.git" ]]; then
111
+ info "已存在 fork 目录,拉取最新代码..."
112
+ git -C "$BUILD_DIR" pull --ff-only || warn "git pull 失败,使用现有代码继续"
113
+ else
114
+ info "克隆官方 llama.cpp fork (XHToken/llama.cpp)..."
115
+ git clone --depth 1 "$LLAMA_REPO" "$BUILD_DIR"
116
+ fi
117
+
118
+ if [[ "${GGML_CUDA^^}" == "ON" ]]; then
119
+ info "配置 CMake (CUDA 后端, 针对 T4/SM75)..."
120
+ cmake -S "$BUILD_DIR" -B "$BUILD_DIR/build" \
121
+ -DGGML_CUDA=ON \
122
+ -DCMAKE_BUILD_TYPE=Release
123
+ else
124
+ info "配置 CMake (纯 CPU 验证模式, 不编译 CUDA 内核)..."
125
+ cmake -S "$BUILD_DIR" -B "$BUILD_DIR/build" \
126
+ -DGGML_CUDA=OFF \
127
+ -DCMAKE_BUILD_TYPE=Release
128
+ fi
129
+
130
+ info "开始编译,线程数: $BUILD_JOBS,约 10~20 分钟..."
131
+ cmake --build "$BUILD_DIR/build" --config Release -j "$BUILD_JOBS"
132
+
133
+ local bin="$BUILD_DIR/build/bin/llama-server"
134
+ [[ -x "$bin" ]] || fail "编译完成但未找到 llama-server,请检查上方日志"
135
+ info "编译成功: $bin"
136
+ }
137
+
138
+ # ---------------------------- 3. 下载模型 ------------------------------------
139
+ do_download() {
140
+ mkdir -p "$MODEL_DIR"
141
+ if [[ -f "$MODEL_FILE" ]]; then
142
+ info "模型已存在: $MODEL_FILE(如需重下请先删除)"
143
+ return 0
144
+ fi
145
+ [[ -n "$HF_ENDPOINT_OPT" ]] && export HF_ENDPOINT="$HF_ENDPOINT_OPT"
146
+
147
+ local dl
148
+ if command -v hf >/dev/null 2>&1; then dl="hf download"
149
+ elif command -v huggingface-cli >/dev/null 2>&1; then dl="huggingface-cli download"
150
+ else fail "缺少 huggingface_hub,请先执行 ./deploy_spark_t4.sh deps"; fi
151
+
152
+ info "下载 $GGUF_REPO / Spark-X2.5-4B-${QUANT}.gguf ..."
153
+ $dl "$GGUF_REPO" "Spark-X2.5-4B-${QUANT}.gguf" --local-dir "$MODEL_DIR"
154
+
155
+ [[ -f "$MODEL_FILE" ]] || fail "下载后未找到 $MODEL_FILE"
156
+ local size
157
+ size=$(du -m "$MODEL_FILE" | cut -f1)
158
+ info "下载完成: ${size} MB"
159
+ # 档位合理性提示(T4 16GB)
160
+ if [[ "$QUANT" == "Q8_0" ]]; then
161
+ info "Q8_0 (8bit) 在 T4 上建议上下文 32k~64k;要冲 128k 请换 QUANT=Q4_K_M 重新 download"
162
+ fi
163
+ }
164
+
165
+ # ---------------------------- 4. 启动服务 ------------------------------------
166
+ do_serve() {
167
+ [[ -x "$BUILD_DIR/build/bin/llama-server" ]] || fail "请先执行 build"
168
+ [[ -f "$MODEL_FILE" ]] || fail "请先执行 download"
169
+ do_stop 2>/dev/null || true
170
+
171
+ info "启动 llama-server: ctx=$CTX port=$PORT quant=$QUANT"
172
+ nohup "$BUILD_DIR/build/bin/llama-server" \
173
+ -m "$MODEL_FILE" \
174
+ -ngl "$NGL" \
175
+ -c "$CTX" \
176
+ --jinja \
177
+ --host 0.0.0.0 \
178
+ --port "$PORT" \
179
+ $EXTRA_LLAMA_ARGS \
180
+ > "$LOG_FILE" 2>&1 &
181
+ echo $! > "$PID_FILE"
182
+
183
+ sleep 5
184
+ if kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
185
+ info "服务已启动 (PID $(cat "$PID_FILE")),日志: $LOG_FILE"
186
+ info "API 地址: http://<本机IP>:$PORT/v1/chat/completions"
187
+ info "思考模式默认开启,响应会包含推理过程;max_tokens 建议给大一些"
188
+ warn "若服务几秒后退出,执行 ./deploy_spark_t4.sh status 看日志"
189
+ warn "常见原因: ①--jinja 参数不被该 fork 支持 → EXTRA_LLAMA_ARGS 去掉重试"
190
+ warn " ②显存不足 → 调小 CTX 或换 QUANT=Q4_K_M"
191
+ else
192
+ fail "启动失败,最近日志:\n$(tail -20 "$LOG_FILE")"
193
+ fi
194
+ }
195
+
196
+ do_stop() {
197
+ if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
198
+ kill "$(cat "$PID_FILE")" && info "已停止 PID $(cat "$PID_FILE")"
199
+ fi
200
+ rm -f "$PID_FILE"
201
+ }
202
+
203
+ do_status() {
204
+ nvidia-smi --query-gpu=name,memory.used,memory.total,utilization.gpu --format=csv,noheader || true
205
+ if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
206
+ info "服务运行中 (PID $(cat "$PID_FILE"))"
207
+ tail -5 "$LOG_FILE" 2>/dev/null || true
208
+ else
209
+ warn "服务未运行"
210
+ fi
211
+ }
212
+
213
+ # ---------------------------- 5. 测试请求 ------------------------------------
214
+ do_test() {
215
+ info "发送测试请求到 http://127.0.0.1:$PORT ..."
216
+ curl -s "http://127.0.0.1:$PORT/v1/chat/completions" \
217
+ -H "Content-Type: application/json" \
218
+ -d '{
219
+ "model": "spark",
220
+ "messages": [{"role": "user", "content": "用一句话介绍你自己"}],
221
+ "max_tokens": 1024,
222
+ "temperature": 1.0,
223
+ "top_p": 0.95
224
+ }' | python3 -c "
225
+ import json, sys
226
+ try:
227
+ d = json.load(sys.stdin)
228
+ print(d['choices'][0]['message'].get('reasoning_content') or '')
229
+ print(d['choices'][0]['message']['content'])
230
+ except Exception as e:
231
+ print('解析失败:', e); sys.exit(1)
232
+ "
233
+ info "官方推荐采样参数: temperature=1.0, top_p=0.95, top_k=-1 (llama.cpp 中 top_k=0 表示禁用)"
234
+ }
235
+
236
+ # ---------------------------- 入口 ------------------------------------------
237
+ case "${1:-help}" in
238
+ deps) do_deps ;;
239
+ build) do_build ;;
240
+ download) do_download ;;
241
+ serve) do_serve ;;
242
+ stop) do_stop ;;
243
+ status) do_status ;;
244
+ test) do_test ;;
245
+ all) do_deps; do_build; do_download
246
+ info "全部就绪!执行 ./deploy_spark_t4.sh serve 启动服务" ;;
247
+ *) sed -n '2,40p' "$0" | sed 's/^# \{0,1\}//' ;;
248
+ esac