GLM-4-9B-Chat-1M详细步骤:GPU显存监控+推理吞吐量压测方法论
GLM-4-9B-Chat-1M详细步骤:GPU显存监控+推理吞吐量压测方法论
1. 引言:为什么需要性能压测?
当你把GLM-4-9B-Chat-1M这样的大模型部署到本地服务器后,一个很实际的问题就摆在了面前:它到底能跑多快?能同时服务多少人?会不会把显卡搞崩溃?
很多朋友部署完模型,打开网页界面,输入几个问题,看到有回复就觉得“搞定了”。但这其实只是第一步。真正要把模型用起来,特别是在企业环境里,你需要知道它的性能边界在哪里。比如:
- 显卡的显存用了多少?会不会在处理长文本时爆掉?
- 模型每秒能处理多少个字(tokens)?这个速度能支持多少用户同时访问?
- 如果同时有多个请求进来,模型会不会排队等待?响应时间会变慢多少?
这些问题,都需要通过系统性的性能测试来回答。今天,我就带你走一遍完整的GPU显存监控和推理吞吐量压测流程,让你对自己部署的模型了如指掌。
2. 测试环境与工具准备
在开始压测之前,我们需要准备好“武器”。下面这些工具,大部分你可能已经装好了。
2.1 硬件与基础环境
我的测试环境是这样的,你可以参考:
- GPU:NVIDIA RTX 4090 (24GB显存)
- CPU:Intel i9-13900K
- 内存:64GB DDR5
- 系统:Ubuntu 22.04 LTS
- Python:3.10
如果你用的是其他显卡,比如RTX 3090、A100等,方法完全一样,只是具体数值会不同。
2.2 必备的Python库
除了运行GLM-4-9B-Chat-1M需要的库之外,我们还需要几个专门用于监控和测试的工具:
# 安装性能测试和监控相关的库
pip install nvidia-ml-py psutil requests tqdm
简单解释一下这几个库是干什么的:
nvidia-ml-py:NVIDIA官方的Python库,用来读取GPU的各种信息(显存、温度、利用率等)psutil:获取系统资源信息(CPU、内存、磁盘等)requests:用来模拟用户请求,发送HTTP请求到我们的模型服务tqdm:显示进度条,让长时间测试有个直观的进度提示
3. GPU显存实时监控实战
显存是运行大模型时最宝贵的资源,也是最先容易出问题的地方。我们先来看看怎么实时监控它。
3.1 编写一个简单的显存监控脚本
我写了一个Python脚本,可以每隔1秒检查一次GPU的状态,并把数据保存下来。你可以直接复制使用:
# gpu_monitor.py
import time
import csv
from datetime import datetime
import pynvml # 这是nvidia-ml-py的核心模块
def monitor_gpu(interval=1, duration=60, output_file="gpu_usage.csv"):
"""
监控GPU使用情况
参数:
interval: 每次检查的间隔时间(秒)
duration: 总监控时长(秒)
output_file: 保存数据的CSV文件名
"""
# 初始化NVML
pynvml.nvmlInit()
# 获取第一个GPU(如果你有多个GPU,可以修改这里)
handle = pynvml.nvmlDeviceGetHandleByIndex(0)
# 准备CSV文件
with open(output_file, 'w', newline='') as f:
writer = csv.writer(f)
# 写入表头
writer.writerow(['timestamp', 'gpu_utilization', 'memory_used_mb',
'memory_total_mb', 'memory_utilization', 'temperature'])
print(f"开始监控GPU,将持续{duration}秒...")
print("按Ctrl+C可以提前结束")
start_time = time.time()
try:
while time.time() - start_time < duration:
# 获取当前时间
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 获取GPU利用率
util = pynvml.nvmlDeviceGetUtilizationRates(handle)
gpu_util = util.gpu
# 获取显存信息
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
memory_used = mem_info.used // (1024 * 1024) # 转换为MB
memory_total = mem_info.total // (1024 * 1024) # 转换为MB
memory_util = (mem_info.used / mem_info.total) * 100
# 获取温度
temp = pynvml.nvmlDeviceGetTemperature(handle, pynvml.NVML_TEMPERATURE_GPU)
# 写入数据
writer.writerow([current_time, gpu_util, memory_used,
memory_total, memory_util, temp])
# 打印当前状态(可选)
print(f"[{current_time}] GPU使用率: {gpu_util}%, 显存: {memory_used}/{memory_total}MB ({memory_util:.1f}%), 温度: {temp}°C")
# 等待指定间隔
time.sleep(interval)
except KeyboardInterrupt:
print("\n监控被用户中断")
finally:
# 清理
pynvml.nvmlShutdown()
print(f"监控结束,数据已保存到 {output_file}")
if __name__ == "__main__":
# 监控60秒,每秒记录一次
monitor_gpu(interval=1, duration=60)
3.2 如何运行监控脚本
使用这个脚本非常简单:
- 首先,确保你的GLM-4-9B-Chat-1M服务正在运行(通过Streamlit启动的那个)
- 打开一个新的终端窗口,运行监控脚本:
python gpu_monitor.py
-
在模型服务那边,开始进行一些操作,比如:
- 上传一个长文档让模型总结
- 连续问几个复杂问题
- 尝试让模型分析代码仓库
-
观察监控终端的输出,你会看到实时的GPU状态变化。
3.3 监控数据分析:看懂这些数字
运行完监控后,你会得到一个CSV文件。用Excel或者Python的pandas打开,可以看到类似这样的数据:
| timestamp | gpu_utilization | memory_used_mb | memory_total_mb | memory_utilization | temperature |
|---|---|---|---|---|---|
| 2024-01-15 10:30:01 | 0% | 2456 | 24564 | 10.0% | 45 |
| 2024-01-15 10:30:02 | 78% | 15678 | 24564 | 63.8% | 58 |
| 2024-01-15 10:30:03 | 95% | 18942 | 24564 | 77.1% | 62 |
这些数字代表什么?
- gpu_utilization:GPU计算核心的利用率。0%表示空闲,100%表示满负荷运行。处理请求时应该接近100%,空闲时接近0%。
- memory_used_mb:当前已经使用的显存大小(MB)。这是最重要的指标!
- memory_total_mb:显卡的总显存大小。
- memory_utilization:显存使用百分比。建议长期运行不要超过90%,要留一些缓冲空间。
- temperature:GPU温度。70°C以下比较安全,超过80°C就要注意散热了。
关键观察点:
- 模型加载后的基础显存占用:启动服务后,即使不处理请求,模型本身就会占用一部分显存。对于GLM-4-9B-Chat-1M的4-bit量化版,这个值应该在8-10GB左右。
- 处理请求时的峰值显存:当模型处理长文本时,显存会临时增加。这个峰值决定了你能处理多长的文本。
- 多轮对话的显存累积:如果服务支持多轮对话,每轮对话的历史都会占用显存,要注意会不会随着对话轮数增加而显存泄漏。
4. 推理吞吐量压测完整方案
知道了显存情况,接下来我们测试模型的“处理速度”,也就是吞吐量。吞吐量通常用“每秒处理的tokens数”来衡量。
4.1 设计压测场景
一个完整的压测应该包含多种场景:
- 短文本单请求:模拟用户问一个简单问题
- 长文本单请求:模拟用户上传长文档分析
- 多用户并发请求:模拟多个用户同时使用
- 持续压力测试:模拟长时间高负载运行
4.2 编写压测脚本
下面是一个完整的压测脚本,它包含了上面提到的多种测试场景:
# stress_test.py
import requests
import time
import threading
import json
from concurrent.futures import ThreadPoolExecutor
from tqdm import tqdm
import statistics
class GLMStressTester:
def __init__(self, base_url="http://localhost:8080"):
"""
初始化压测器
参数:
base_url: GLM模型服务的地址
"""
self.base_url = base_url
self.api_url = f"{base_url}/v1/chat/completions" # 假设使用OpenAI兼容的API
def send_request(self, prompt, max_tokens=100):
"""
发送单个请求到模型
返回:
response_time: 响应时间(秒)
tokens_generated: 生成的tokens数量
"""
headers = {
"Content-Type": "application/json"
}
payload = {
"model": "glm-4-9b-chat-1m",
"messages": [
{"role": "user", "content": prompt}
],
"max_tokens": max_tokens,
"temperature": 0.7
}
start_time = time.time()
try:
response = requests.post(
self.api_url,
headers=headers,
json=payload,
timeout=120 # 120秒超时
)
end_time = time.time()
if response.status_code == 200:
result = response.json()
# 计算生成的tokens数量(这里简化处理,实际应该从响应中获取)
response_text = result['choices'][0]['message']['content']
# 简单估算:英文大约1个token=0.75个单词,中文1个汉字≈1.2个tokens
tokens_estimated = len(response_text) * 1.2
return end_time - start_time, tokens_estimated
else:
print(f"请求失败: {response.status_code}")
return None, 0
except Exception as e:
print(f"请求异常: {e}")
return None, 0
def test_single_short_request(self, num_requests=10):
"""
测试短文本单请求性能
"""
print("=== 短文本单请求测试 ===")
print(f"发送 {num_requests} 个请求...")
prompts = [
"你好,请介绍一下你自己。",
"Python和JavaScript哪个更容易学习?",
"如何快速学习机器学习?",
"写一个简单的Python函数计算斐波那契数列。",
"解释一下什么是深度学习。",
"如何提高编程效率?",
"推荐几个学习AI的网站。",
"什么是Transformer模型?",
"如何部署一个机器学习模型?",
"解释一下注意力机制的原理。"
]
response_times = []
total_tokens = 0
for i in tqdm(range(num_requests)):
prompt = prompts[i % len(prompts)] # 循环使用提示词
resp_time, tokens = self.send_request(prompt)
if resp_time:
response_times.append(resp_time)
total_tokens += tokens
if response_times:
avg_time = statistics.mean(response_times)
tokens_per_second = total_tokens / sum(response_times)
print(f"\n测试结果:")
print(f"- 总请求数: {len(response_times)}")
print(f"- 平均响应时间: {avg_time:.2f}秒")
print(f"- 最短响应时间: {min(response_times):.2f}秒")
print(f"- 最长响应时间: {max(response_times):.2f}秒")
print(f"- 吞吐量: {tokens_per_second:.1f} tokens/秒")
return tokens_per_second
return 0
def test_concurrent_requests(self, num_concurrent=3, requests_per_user=5):
"""
测试并发请求性能
"""
print(f"\n=== 并发请求测试 ===")
print(f"模拟 {num_concurrent} 个用户,每个用户发送 {requests_per_user} 个请求")
results = []
lock = threading.Lock()
def user_simulation(user_id):
user_results = []
for i in range(requests_per_user):
prompt = f"用户{user_id}的第{i+1}个问题:请用100字介绍人工智能。"
resp_time, tokens = self.send_request(prompt, max_tokens=50)
if resp_time:
user_results.append((resp_time, tokens))
with lock:
results.extend(user_results)
# 使用线程池模拟并发用户
with ThreadPoolExecutor(max_workers=num_concurrent) as executor:
futures = [executor.submit(user_simulation, i) for i in range(num_concurrent)]
# 等待所有任务完成
for future in tqdm(futures, total=num_concurrent, desc="并发测试进度"):
future.result()
if results:
response_times = [r[0] for r in results]
total_tokens = sum(r[1] for r in results)
total_time = max(response_times) # 并发测试的总时间取最长的
print(f"\n并发测试结果:")
print(f"- 总完成请求数: {len(results)}")
print(f"- 总测试时间: {total_time:.2f}秒")
print(f"- 平均响应时间: {statistics.mean(response_times):.2f}秒")
print(f"- 系统吞吐量: {total_tokens/total_time:.1f} tokens/秒")
print(f"- QPS (每秒查询数): {len(results)/total_time:.2f}")
return len(results)/total_time
return 0
def test_long_context(self, context_length=50000):
"""
测试长上下文处理能力
"""
print(f"\n=== 长上下文测试 ===")
print(f"生成 {context_length} 字符的长文本...")
# 生成一个长文本(这里用重复文本来模拟)
long_text = "这是一段测试文本," * (context_length // 10)
long_text = long_text[:context_length]
prompt = f"请总结以下文本的核心内容:\n\n{long_text}\n\n要求:用200字以内总结。"
print("发送长文本请求...")
start_time = time.time()
resp_time, tokens = self.send_request(prompt, max_tokens=200)
end_time = time.time()
if resp_time:
print(f"\n长文本测试结果:")
print(f"- 输入文本长度: {context_length} 字符")
print(f"- 总处理时间: {resp_time:.2f}秒")
print(f"- 实际生成tokens: {tokens:.0f}")
print(f"- 处理速度: {context_length/resp_time:.0f} 字符/秒")
# 监控显存峰值(需要结合前面的监控脚本)
print(f"\n提示:请同时运行GPU监控脚本观察长文本处理时的显存峰值")
return resp_time
return 0
def run_full_test_suite(self):
"""
运行完整的测试套件
"""
print("开始GLM-4-9B-Chat-1M性能压测")
print("=" * 50)
results = {}
# 1. 短文本测试
results['short_text_tps'] = self.test_single_short_request(num_requests=10)
# 等待一下,让系统冷却
time.sleep(5)
# 2. 并发测试
results['qps'] = self.test_concurrent_requests(num_concurrent=3, requests_per_user=3)
# 等待一下
time.sleep(5)
# 3. 长文本测试(可以根据你的显存大小调整长度)
results['long_text_time'] = self.test_long_context(context_length=20000)
print("\n" + "=" * 50)
print("压测总结报告:")
print("=" * 50)
for key, value in results.items():
if 'tps' in key or 'qps' in key:
print(f"{key}: {value:.2f}")
elif 'time' in key:
print(f"{key}: {value:.2f}秒")
return results
if __name__ == "__main__":
# 创建测试器实例
tester = GLMStressTester("http://localhost:8080")
# 运行完整测试
results = tester.run_full_test_suite()
4.3 运行压测并解读结果
运行这个压测脚本:
python stress_test.py
你会看到类似这样的输出:
开始GLM-4-9B-Chat-1M性能压测
==================================================
=== 短文本单请求测试 ===
发送 10 个请求...
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████更多推荐

所有评论(0)