hellokawei commited on
Commit
26dc72e
·
verified ·
1 Parent(s): 1cbae1b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +444 -424
app.py CHANGED
@@ -1,436 +1,456 @@
1
  import gradio as gr
 
2
  import pandas as pd
3
- import plotly.express as px
4
- import plotly.graph_objects as go
5
- from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
6
- import torch
7
- import time
8
- import numpy as np
9
-
10
- # 初始化模型
11
- def load_models():
12
- """加载三个不同的文本生成模型"""
13
- models = {}
14
-
15
- try:
16
- # 模型1: GPT-2 (轻量级)
17
- models['gpt2'] = {
18
- 'pipeline': pipeline("text-generation", model="gpt2", max_new_tokens=50),
19
- 'name': 'GPT-2',
20
- 'description': '经典的自回归语言模型,适合短文本生成'
21
- }
22
-
23
- # 模型2: DistilGPT-2 (更快速)
24
- models['distilgpt2'] = {
25
- 'pipeline': pipeline("text-generation", model="distilgpt2", max_new_tokens=50),
26
- 'name': 'DistilGPT-2',
27
- 'description': '轻量化的GPT-2,速度更快但质量略低'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
-
30
- # 模型3: OpenELM (苹果开源模型)
31
- models['openelm'] = {
32
- 'pipeline': pipeline("text-generation", model="apple/OpenELM-270M", max_new_tokens=50, trust_remote_code=True),
33
- 'name': 'OpenELM-270M',
34
- 'description': '苹果开源的轻量级语言模型'
35
- }
36
-
37
- except Exception as e:
38
- print(f"模型加载错误: {e}")
39
- # 备用方案:只使用最基础的模型
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  try:
41
- models['gpt2'] = {
42
- 'pipeline': pipeline("text-generation", model="gpt2", max_new_tokens=30),
43
- 'name': 'GPT-2',
44
- 'description': '经典的自回归语言模型'
45
- }
46
- models['distilgpt2'] = {
47
- 'pipeline': pipeline("text-generation", model="distilgpt2", max_new_tokens=30),
48
- 'name': 'DistilGPT-2',
49
- 'description': '轻量化版本'
50
- }
51
- # 第三个模型用简单的替代
52
- models['openelm'] = {
53
- 'pipeline': pipeline("text-generation", model="gpt2", max_new_tokens=20),
54
- 'name': 'GPT-2-Variant',
55
- 'description': '备用模型配置'
56
- }
57
- except Exception as e2:
58
- print(f"备用模型加载也失败: {e2}")
59
- # 最终备用:至少确保有一个模型可用
60
- models['gpt2'] = {
61
- 'pipeline': None,
62
- 'name': 'GPT-2',
63
- 'description': '模型加载失败'
64
- }
65
-
66
- return models
67
-
68
- # 全局加载模型
69
- MODELS = load_models()
70
-
71
- # GRACE评估��据
72
- GRACE_DATA = {
73
- 'GPT-2': {
74
- 'Generalization': 8.5,
75
- 'Relevance': 7.8,
76
- 'Artistry': 7.2,
77
- 'Efficiency': 6.5
78
- },
79
- 'DistilGPT-2': {
80
- 'Generalization': 7.8,
81
- 'Relevance': 7.5,
82
- 'Artistry': 6.8,
83
- 'Efficiency': 9.2
84
- },
85
- 'OpenELM-270M': {
86
- 'Generalization': 6.5,
87
- 'Relevance': 7.0,
88
- 'Artistry': 6.5,
89
- 'Efficiency': 8.8
90
- }
91
- }
92
-
93
- def generate_text_with_model(model_key, prompt, max_length=50):
94
- """使用指定模型生成文本"""
95
- try:
96
- start_time = time.time()
97
-
98
- if model_key not in MODELS or MODELS[model_key]['pipeline'] is None:
99
- return "模型未找到或加载失败", 0
100
-
101
- result = MODELS[model_key]['pipeline'](
102
- prompt,
103
- max_new_tokens=min(max_length, 50),
104
- num_return_sequences=1,
105
- temperature=0.7,
106
- do_sample=True,
107
- pad_token_id=50256,
108
- truncation=True,
109
- return_full_text=False
110
- )
111
-
112
- end_time = time.time()
113
- generation_time = end_time - start_time
114
-
115
- if result and len(result) > 0:
116
- generated_text = prompt + result[0]['generated_text']
117
  else:
118
- generated_text = "生成失败"
119
-
120
- return generated_text, generation_time
121
-
122
- except Exception as e:
123
- return f"生成错误: {str(e)}", 0
124
-
125
- def create_radar_chart():
126
- """创建GRACE维度雷达图"""
127
- dimensions = ['Generalization', 'Relevance', 'Artistry', 'Efficiency']
128
-
129
- fig = go.Figure()
130
-
131
- for model_name, scores in GRACE_DATA.items():
132
- values = [scores[dim] for dim in dimensions]
133
- values.append(values[0]) # 闭合图形
134
-
135
- fig.add_trace(go.Scatterpolar(
136
- r=values,
137
- theta=dimensions + [dimensions[0]],
138
- fill='toself',
139
- name=model_name,
140
- line=dict(width=2)
141
- ))
142
-
143
- fig.update_layout(
144
- polar=dict(
145
- radialaxis=dict(
146
- visible=True,
147
- range=[0, 10]
148
- )),
149
- showlegend=True,
150
- title="GRACE 框架模型评估对比",
151
- height=500
152
- )
153
 
154
- return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
- def create_performance_chart():
157
- """创建性能对比柱状图"""
158
- df = pd.DataFrame(GRACE_DATA).T.reset_index()
159
- df.rename(columns={'index': 'Model'}, inplace=True)
160
-
161
- fig = px.bar(
162
- df.melt(id_vars=['Model'], var_name='Dimension', value_name='Score'),
163
- x='Model',
164
- y='Score',
165
- color='Dimension',
166
- barmode='group',
167
- title="各维度详细评分对比",
168
- height=400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  )
170
-
171
- return fig
172
 
173
- def arena_interface(prompt, max_length):
174
- """Arena页面的核心功能"""
175
- if not prompt.strip():
176
- return "请输入提示词", "请输入提示词", "请输入提示词", "请输入有效的提示词"
177
-
178
- results = {}
179
- times = {}
180
-
181
- for model_key in MODELS.keys():
182
- text, gen_time = generate_text_with_model(model_key, prompt, max_length)
183
- results[model_key] = text
184
- times[model_key] = gen_time
185
-
186
- # 格式化输出
187
- output1 = f"**{MODELS['gpt2']['name']}** (生成时间: {times.get('gpt2', 0):.2f}s)\n\n{results.get('gpt2', '生成失败')}"
188
- output2 = f"**{MODELS['distilgpt2']['name']}** (生成时间: {times.get('distilgpt2', 0):.2f}s)\n\n{results.get('distilgpt2', '生成失败')}"
189
- output3 = f"**{MODELS['openelm']['name']}** (生成时间: {times.get('openelm', 0):.2f}s)\n\n{results.get('openelm', '生成失败')}"
190
-
191
- # 生成对比分析
192
- analysis = f"""
193
- ## 生成结果分析
194
-
195
- ### 速度对比
196
- - GPT-2: {times.get('gpt2', 0):.2f}秒
197
- - DistilGPT-2: {times.get('distilgpt2', 0):.2f}秒
198
- - OpenELM: {times.get('openelm', 0):.2f}秒
199
-
200
- ### 质量评估
201
- 根据GRACE框架,不同模型在各维度的表现存在差异:
202
- - **效率性**: DistilGPT-2和OpenELM表现优异
203
- - **泛化性**: GPT-2具有最强的通用性
204
- - **相关性**: 各模型在相关性上表现相近
205
- """
206
-
207
- return output1, output2, output3, analysis
208
-
209
- # 创建Gradio界面
210
- def create_app():
211
- with gr.Blocks(title="文本生成模型对比评估", theme=gr.themes.Soft()) as app:
212
- gr.Markdown("# 🤖 文本生成模型对比评估系统\n基于GRACE框架的多模型横向对比分析")
213
-
214
- with gr.Tabs():
215
- # LLM Benchmark 选项卡
216
- with gr.Tab("📊 LLM Benchmark"):
217
- gr.Markdown("## GRACE框架评估结果")
218
- gr.Markdown("""
219
- 本项目选择了三个不同特点的文本生成模型进行对比:
220
- - **GPT-2**: 经典的自回归语言模型,通用性强
221
- - **DistilGPT-2**: 轻量化版本,效率优先
222
- - **DialoGPT-medium**: 对话场景优化模型
223
- """)
224
-
225
- with gr.Row():
226
- with gr.Column():
227
- radar_plot = gr.Plot(value=create_radar_chart(), label="GRACE维度雷达图")
228
- with gr.Column():
229
- bar_plot = gr.Plot(value=create_performance_chart(), label="详细评分对比")
230
-
231
- gr.Markdown("""
232
- ### GRACE维度说明
233
- - **G (Generalization)**: 模型的泛化能力和适用范围
234
- - **R (Relevance)**: 输出内容与输入的相关性
235
- - **A (Artistry)**: 生成内容的创意性和表现力
236
- - **E (Efficiency)**: 模型的运行效率和响应速度
237
- """)
238
-
239
- # 评估数据表格
240
- df_scores = pd.DataFrame(GRACE_DATA).T
241
- gr.Dataframe(value=df_scores, label="详细评分数据")
242
 
243
- # Arena 选项卡
244
- with gr.Tab("🏟️ Arena"):
245
- gr.Markdown("## 模���对战场 - 实时对比测试")
246
- gr.Markdown("输入相同的提示词,查看三个模型的不同输出结果")
247
-
248
- with gr.Row():
249
- with gr.Column():
250
- prompt_input = gr.Textbox(
251
- label="输入提示词",
252
- placeholder="例如:写一个关于人工智能的短故事...",
253
- lines=3
254
- )
255
- max_length_slider = gr.Slider(
256
- minimum=50,
257
- maximum=200,
258
- value=100,
259
- step=10,
260
- label="最大生成长度"
261
- )
262
- generate_btn = gr.Button("🚀 生成对比", variant="primary")
263
-
264
- with gr.Row():
265
- model1_output = gr.Markdown(label="GPT-2 输出")
266
- model2_output = gr.Markdown(label="DistilGPT-2 输出")
267
- model3_output = gr.Markdown(label="OpenELM 输出")
268
-
269
- analysis_output = gr.Markdown(label="对比分析")
270
-
271
- generate_btn.click(
272
- fn=arena_interface,
273
- inputs=[prompt_input, max_length_slider],
274
- outputs=[model1_output, model2_output, model3_output, analysis_output]
275
- )
276
 
277
- # 预设示例
278
- gr.Examples(
279
- examples=[
280
- ["人工智能的未来发展趋势是什么?", 100],
281
- ["请写一个关于友谊的小故事", 150],
282
- ["解释什么是深度学习", 120]
283
- ],
284
- inputs=[prompt_input, max_length_slider]
285
- )
286
 
287
- # Report 选项卡
288
- with gr.Tab("📋 Report"):
289
- report_content = """
290
- # 文本生成模型对比评估报告
291
-
292
- ## 1. 模型及类别选择
293
-
294
- ### 选择的模型类型
295
- 本项目选择了**文本生成模型**作为研究对象,这类模型在自然语言处理领域具有重要地位。
296
-
297
- ### 对比模型介绍
298
- 我们选择了三个具有代表性的文本生成模型:
299
-
300
- 1. **GPT-2**: OpenAI开发的经典自回归语言模型
301
- - 用途:通用文本生成、续写、创作
302
- - 特点:模型结构成熟,生成质量稳定
303
-
304
- 2. **DistilGPT-2**: GPT-2的轻量化版本
305
- - 用途:快速文本生成,资源受限环境
306
- - 特点:模型体积小,推理速度快
307
-
308
- 3. **DialoGPT-medium**: 微软开发的对话生成模型
309
- - 用途:对话系统、聊天机器人
310
- - 特点:针对对话场景优化
311
-
312
- ### 选取标准
313
- - **多样性**: 涵盖不同的优化目标(通用性、效率、专业性)
314
- - **可比性**: 都属于文本生成模型,具有相同的输入输出格式
315
- - **实用性**: 都有良好的社区支持和文档
316
-
317
- ## 2. 系统实现细节
318
-
319
- ### 系统架构
320
- ```mermaid
321
- graph TD
322
- A[用户输入] --> B[Gradio界面]
323
- B --> C[模型调度��]
324
- C --> D[GPT-2]
325
- C --> E[DistilGPT-2]
326
- C --> F[DialoGPT]
327
- D --> G[结果聚合]
328
- E --> G
329
- F --> G
330
- G --> H[GRACE评估]
331
- H --> I[可视化展示]
332
- ```
333
-
334
- ### 技术实现
335
- - **框架**: Gradio + Transformers
336
- - **模型加载**: 使用HuggingFace Pipeline
337
- - **并发处理**: 顺序调用各模型确保稳定性
338
- - **评估框架**: 基于GRACE标准的量化评估
339
-
340
- ## 3. GRACE 评估维度定义
341
-
342
- 我们选择了四个关键维度进行评估:
343
-
344
- ### G - Generalization (泛化性)
345
- - **定义**: 模型适应不同输入类型和任务的能力
346
- - **评估标准**:
347
- - 能否处理不同领域的文本
348
- - 对输入长度的适应性
349
- - 多语言支持能力
350
-
351
- ### R - Relevance (相关性)
352
- - **定义**: 生成内容与输入提示的匹配度
353
- - **评估标准**:
354
- - 语义一致性
355
- - 主题连贯性
356
- - 逻辑合理性
357
-
358
- ### A - Artistry (创新表现力)
359
- - **定义**: 生成内容的创意性和表达质量
360
- - **评估标准**:
361
- - 语言表达的丰富性
362
- - 创意思维的体现
363
- - 文本流畅度
364
-
365
- ### E - Efficiency (效率性)
366
- - **定义**: 模型的运行效率和资源消耗
367
- - **评估标准**:
368
- - 推理速度
369
- - 内存占用
370
- - 能耗表现
371
-
372
- ## 4. 结果与分析
373
-
374
- ### 测试样例结果
375
-
376
- | 输入提示 | GPT-2 | DistilGPT-2 | DialoGPT |
377
- |---------|-------|-------------|----------|
378
- | "人工智能的未来" | 详细阐述AI发展趋势 | 简洁概括主要方向 | 以对话形式讨论 |
379
- | "写个故事" | 完整叙事结构 | 快速故事梗概 | 互动式故事发展 |
380
- | "解释概念" | 学术化解释 | 通俗易懂说明 | 问答式解释 |
381
-
382
- ### GRACE维度评分分析
383
-
384
- **GPT-2优势**:
385
- - 泛化性最强 (8.5/10)
386
- - 适应性广,通用性好
387
- - 生成质量稳定
388
-
389
- **DistilGPT-2优势**:
390
- - 效率性最高 (9.2/10)
391
- - 响应速度快
392
- - 资源消耗低
393
-
394
- **DialoGPT优势**:
395
- - 相关性最好 (8.8/10)
396
- - 对话场景表现突出
397
- - 交互体验佳
398
-
399
- ### 综合分析
400
- 1. **任务适配性**: GPT-2在通用任务中表现最佳
401
- 2. **性能效率**: DistilGPT-2在资源受限环境下更优
402
- 3. **专业场景**: DialoGPT在对话应用中具有明显优势
403
-
404
- ## 5. 合作与反思
405
-
406
- ### 团队成员分工
407
-
408
- **成员1 (负责模型集成与Arena功能)**:
409
- - 学习内容: HuggingFace Transformers库的使用,模型加载和推理优化
410
- - 负责内容: GPT-2和DistilGPT-2模型集成,Arena界面开发
411
- - 遇到困难: 模型加载内存优化,并发推理的稳定性处理
412
-
413
- **成员2 (负责评估框架与可视化)**:
414
- - 学习内容: GRACE评估框架,数据可视化技术,Gradio界面设计
415
- - 负责内容: DialoGPT模型集成,Benchmark页面开发,报告撰写
416
- - 遇到困难: 评估标准的量化,雷达图的动态生成
417
-
418
- ### 项目收获
419
- 1. **技术能力**: 掌握了端到端的AI应用开发流程
420
- 2. **评估思维**: 学会了系统性的模型评估方法
421
- 3. **团队协作**: 提高了分工合作和版本控制能力
422
-
423
- ### 改进方向
424
- 1. 增加更多模型类型的对比
425
- 2. 引入用户反馈机制
426
- 3. 优化界面交互体验
427
- 4. 加入更多评估维度
428
- """
429
- gr.Markdown(report_content)
430
-
431
- return app
432
-
433
- # 启动应用
434
- if __name__ == "__main__":
435
- app = create_app()
436
- app.launch(share=True)
 
1
  import gradio as gr
2
+ from gradio_leaderboard import Leaderboard, ColumnFilter, SelectColumns
3
  import pandas as pd
4
+ from apscheduler.schedulers.background import BackgroundScheduler
5
+ import os
6
+ import json
7
+ from transformers import AutoModelForCausalLM, AutoTokenizer
8
+ import torch # 导入 torch
9
+
10
+ # 从现有的 src 导入,这些我们无法修改,但需要继续使用其提供的功能
11
+ from src.about import (
12
+ CITATION_BUTTON_LABEL,
13
+ CITATION_BUTTON_TEXT,
14
+ EVALUATION_QUEUE_TEXT, # 这个可能不再需要,但保留以防万一
15
+ INTRODUCTION_TEXT,
16
+ LLM_BENCHMARKS_TEXT,
17
+ TITLE,
18
+ )
19
+ from src.display.css_html_js import custom_css
20
+
21
+ # =====================================================================
22
+ # **重要修改开始:直接在 app.py 中定义 GRACE 相关的类和函数**
23
+ # =====================================================================
24
+
25
+ from enum import Enum
26
+ from typing import NamedTuple, List
27
+
28
+ class Column(NamedTuple):
29
+ name: str
30
+ type: str
31
+ displayed_by_default: bool = True
32
+ never_hidden: bool = False
33
+ hidden: bool = False
34
+ filterable: bool = True
35
+
36
+ class AutoEvalColumn(Enum):
37
+ model = Column("Model", "str", displayed_by_default=True, never_hidden=True)
38
+ model_type = Column("Model type", "str", displayed_by_default=True)
39
+ precision = Column("Precision", "str", displayed_by_default=False)
40
+ params = Column("Params (B)", "number", displayed_by_default=True)
41
+ license = Column("License", "str", displayed_by_default=False)
42
+ still_on_hub = Column("On Hub", "boolean", displayed_by_default=True, hidden=True)
43
+
44
+ # GRACE 框架新增列
45
+ generalization_score = Column("G: 泛化性", "number", displayed_by_default=True, filterable=True)
46
+ relevance_score = Column("R: 相关性", "number", displayed_by_default=True, filterable=True)
47
+ artistry_score = Column("A: 创新表现力", "number", displayed_by_default=True, filterable=True)
48
+ consistency_score = Column("C: 一致性", "number", displayed_by_default=True, filterable=True)
49
+ efficiency_score = Column("E: 效率性", "number", displayed_by_default=True, filterable=True)
50
+
51
+ def fields(cls: type) -> List[Column]:
52
+ return [c.value for c in cls if isinstance(c.value, Column)]
53
+
54
+ class ModelType(Enum):
55
+ LanguageModeling = "语言生成模型"
56
+ ImageGeneration = "图像生成模型"
57
+ Unknown = "未知"
58
+
59
+ def to_str(self, sep: str = " : ") -> str:
60
+ return f"{self.name}{sep}{self.value}"
61
+
62
+ class WeightType(Enum):
63
+ Original = NamedTuple("Original", [("name", str)])("Original")
64
+ Lora = NamedTuple("Lora", [("name", str)])("Lora")
65
+
66
+ class Precision(Enum):
67
+ float16 = NamedTuple("float16", [("name", str)])("float16")
68
+ bfloat16 = NamedTuple("bfloat16", [("name", str)])("bfloat16")
69
+ Unknown = NamedTuple("Unknown", [("name", str)])("Unknown")
70
+
71
+ COLS = fields(AutoEvalColumn)
72
+ BENCHMARK_COLS = [
73
+ AutoEvalColumn.model.value,
74
+ AutoEvalColumn.params.value,
75
+ AutoEvalColumn.generalization_score.value,
76
+ AutoEvalColumn.relevance_score.value,
77
+ AutoEvalColumn.artistry_score.value,
78
+ AutoEvalColumn.consistency_score.value,
79
+ AutoEvalColumn.efficiency_score.value,
80
+ ]
81
+ EVAL_COLS = [c.name for c in fields(AutoEvalColumn)]
82
+ EVAL_TYPES = [c.type for c in fields(AutoEvalColumn)]
83
+
84
+ # 简化 get_leaderboard_df 和 get_evaluation_queue_df
85
+ # 由于我们是手动比较,而不是自动评估,这些函数更多是用于显示模拟数据
86
+ def get_leaderboard_df(eval_results_path: str, eval_requests_path: str, cols: list, benchmark_cols: list) -> pd.DataFrame:
87
+ print("使用模拟数据填充排行榜。")
88
+ # 这里我们不再尝试从文件读取,直接生成模拟数据
89
+ all_results = [
90
+ {
91
+ "Model": "Gemma 2B Instruct", # 使用友好的名称
92
+ "Model type": ModelType.LanguageModeling.to_str(),
93
+ "Precision": Precision.float16.value.name,
94
+ "Params (B)": 2.0,
95
+ "License": "apache-2.0",
96
+ "On Hub": True,
97
+ "G: 泛化性": 0.0, # 初始为0,等待用户输入
98
+ "R: 相关性": 0.0,
99
+ "A: 创新表现力": 0.0,
100
+ "C: 一致性": 0.0,
101
+ "E: 效率性": 0.0,
102
+ },
103
+ {
104
+ "Model": "Phi-2", # 使用友好的名称
105
+ "Model type": ModelType.LanguageModeling.to_str(),
106
+ "Precision": Precision.float16.value.name,
107
+ "Params (B)": 2.7,
108
+ "License": "mit",
109
+ "On Hub": True,
110
+ "G: 泛化性": 0.0,
111
+ "R: 相关性": 0.0,
112
+ "A: 创新表现力": 0.0,
113
+ "C: 一致性": 0.0,
114
+ "E: 效率性": 0.0,
115
+ },
116
+ {
117
+ "Model": "GPT-Neo 125M", # 使用友好的名称
118
+ "Model type": ModelType.LanguageModeling.to_str(),
119
+ "Precision": Precision.float16.value.name,
120
+ "Params (B)": 0.125,
121
+ "License": "apache-2.0",
122
+ "On Hub": True,
123
+ "G: 泛化性": 0.0,
124
+ "R: 相关性": 0.0,
125
+ "A: 创新表现力": 0.0,
126
+ "C: 一致性": 0.0,
127
+ "E: 效率性": 0.0,
128
  }
129
+ ]
130
+ df = pd.DataFrame(all_results)
131
+ # DataFrame 进行必要的处理,例如排序 (这里不需要排序因为分数是0)
132
+ return df
133
+
134
+ def get_evaluation_queue_df(eval_requests_path: str, eval_cols: list):
135
+ # 评估队列不再是主要功能,返回空 DataFrame
136
+ empty_df = pd.DataFrame(columns=eval_cols)
137
+ return empty_df, empty_df, empty_df
138
+
139
+ # =====================================================================
140
+ # **重要修改结束**
141
+ # =====================================================================
142
+
143
+ # 假设 src.envs 中的 API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN 可用
144
+ # 如果 TOKEN 未在 src.envs 中定义,您需要在 Hugging Face Space Secrets 中设置 HF_TOKEN。
145
+ # 这里为了能运行,我们直接使用 os.getenv 获取 TOKEN。
146
+ TOKEN = os.getenv("HF_TOKEN") # 确保您的 Space Secrets 中设置了 HF_TOKEN
147
+ # 假设这些路径是可写的,但在此场景下,我们不再依赖它们来存储评估结果
148
+ EVAL_REQUESTS_PATH = "./eval_requests"
149
+ EVAL_RESULTS_PATH = "./eval_results"
150
+ # 对于演示,我们不需要实际的 API 调用来重启 Space 或提交任务
151
+ # 所以我们可以创建一个模拟的 API 类
152
+ class MockAPI:
153
+ def restart_space(self, repo_id: str):
154
+ print(f"MockAPI: Restarting space {repo_id}. (No actual restart for demo)")
155
+ class MockSubmit:
156
+ def add_new_eval(self, *args):
157
+ # 这个函数不再用于实际提交,可以返回一个消息
158
+ return "在此演示中,模型已预先加载,无需提交新评估。"
159
+
160
+ API = MockAPI()
161
+ add_new_eval = MockSubmit().add_new_eval
162
+ REPO_ID = os.getenv("HF_SPACE_ID", "your-org/your-space-name") # 从环境变量获取 Space ID,或者设置默认值
163
+
164
+ # 预加载模型和分词器
165
+ # 考虑到免费 Space 的资源限制,这里选择较小的模型
166
+ MODELS_TO_COMPARE = [
167
+ {"id": "google/gemma-2b-it", "name": "Gemma 2B Instruct"},
168
+ {"id": "microsoft/phi-2", "name": "Phi-2"},
169
+ {"id": "EleutherAI/gpt-neo-125m", "name": "GPT-Neo 125M"}, # 更小的模型,确保加载
170
+ ]
171
+
172
+ # 用于存储加载的模型和分词器
173
+ loaded_models = {}
174
+
175
+ def load_models():
176
+ global loaded_models
177
+ for model_info in MODELS_TO_COMPARE:
178
+ model_id = model_info["id"]
179
+ model_name = model_info["name"]
180
+ print(f"正在加载模型: {model_name} ({model_id})...")
181
  try:
182
+ # 尝试加载模型到 GPU (cuda) 或 CPU (cpu)
183
+ device = "cuda" if torch.cuda.is_available() else "cpu"
184
+ print(f"模型 {model_id} 将加载到 {device}")
185
+
186
+ tokenizer = AutoTokenizer.from_pretrained(model_id, token=TOKEN)
187
+ # 使用 torch.float16 或 torch.bfloat16 减少内存使用
188
+ if device == "cuda":
189
+ model = AutoModelForCausalLM.from_pretrained(
190
+ model_id,
191
+ torch_dtype=torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16,
192
+ token=TOKEN
193
+ ).to(device)
194
+ else: # CPU
195
+ model = AutoModelForCausalLM.from_pretrained(model_id, token=TOKEN)
196
+
197
+ loaded_models[model_id] = {"model": model, "tokenizer": tokenizer, "name": model_name}
198
+ print(f"成功加载模型: {model_name}")
199
+ except Exception as e:
200
+ print(f"加载模型 {model_name} ({model_id}) 失败: {e}")
201
+ # 如果加载失败,将该模型从比较列表中移除
202
+ # 或者将其模型对象设置为 None,以便在推理时跳过
203
+ loaded_models[model_id] = None # 表示加载失败
204
+
205
+ # 在应用程序启动时加载模型
206
+ # 注意:在 Gradio Blocks 的 launch() 之前调用,确保模型在界面初始化前加载
207
+ load_models()
208
+
209
+
210
+ # 模型生成函数
211
+ def generate_text(prompt, max_new_tokens=100):
212
+ outputs = {}
213
+ for model_info in MODELS_TO_COMPARE: # 迭代 MODELS_TO_COMPARE 确保顺序和输出框对应
214
+ model_id = model_info["id"]
215
+ model_name = model_info["name"]
216
+ model_data = loaded_models.get(model_id) # 从 loaded_models 获取数据
217
+
218
+ if model_data: # 确保模型已成功加载
219
+ model = model_data["model"]
220
+ tokenizer = model_data["tokenizer"]
221
+
222
+ try:
223
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
224
+ # print(f"Generating with {model_name} on device: {model.device}")
225
+ # 调整 generation_config 参数以获得更好的可控性
226
+ generated_ids = model.generate(
227
+ **inputs,
228
+ max_new_tokens=max_new_tokens,
229
+ do_sample=True, # 启用采样
230
+ temperature=0.7, # 控制生成文本的随机性
231
+ top_k=50, # 从概率最高的k个词中选择
232
+ top_p=0.95, # 累积概率达到p的词中选择
233
+ pad_token_id=tokenizer.eos_token_id, # 处理 pad token
234
+ eos_token_id=tokenizer.eos_token_id # 结束标志
235
+ )
236
+ generated_text = tokenizer.decode(generated_ids[0], skip_special_tokens=True)
237
+ outputs[model_name] = generated_text
238
+ except Exception as e:
239
+ outputs[model_name] = f"生成失败: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  else:
241
+ outputs[model_name] = "模型未加载或加载失败。"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
+ # 按照 MODELS_TO_COMPARE 的顺序返回结果
244
+ ordered_outputs = [outputs.get(m["name"], "模型未加载或加载失败。") for m in MODELS_TO_COMPARE]
245
+ return ordered_outputs # 返回一个列表,对应多个输出框
246
+
247
+ # 更新排行榜数据函数
248
+ def update_leaderboard(g_score, r_score, a_score, c_score, e_score, model_idx):
249
+ global LEADERBOARD_DF
250
+ # 假设模型的索引与 MODELS_TO_COMPARE 列表中的顺序一致
251
+ # 在实际应用中,您可能需要更健壮的方式来匹配模型
252
+ if model_idx is not None and 0 <= model_idx < len(MODELS_TO_COMPARE):
253
+ model_name_to_update = MODELS_TO_COMPARE[model_idx]["name"]
254
+ # 找到 DataFrame 中对应的行
255
+ row_index = LEADERBOARD_DF[LEADERBOARD_DF['Model'] == model_name_to_update].index
256
+ if not row_index.empty:
257
+ # 更新 GRACE 分数 (这里假设是从 0.0-1.0 的分数,Gradio 滑块可能输出 0-100)
258
+ # 如果 Gradio 滑块输出 0-100,需要除以 100 转换为 0-1.0
259
+ LEADERBOARD_DF.loc[row_index, 'G: 泛化性'] = g_score / 100.0
260
+ LEADERBOARD_DF.loc[row_index, 'R: 相关性'] = r_score / 100.0
261
+ LEADERBOARD_DF.loc[row_index, 'A: 创新表现力'] = a_score / 100.0
262
+ LEADERBOARD_DF.loc[row_index, 'C: 一致性'] = c_score / 100.0
263
+ LEADERBOARD_DF.loc[row_index, 'E: 效率性'] = e_score / 100.0
264
+ # 重新排序排行榜 (如果需要根据某个分数排序,例如泛化性)
265
+ LEADERBOARD_DF = LEADERBOARD_DF.sort_values(by="G: 泛化性", ascending=False).reset_index(drop=True)
266
+ return LEADERBOARD_DF
267
+ return LEADERBOARD_DF # 返回更新后的 DataFrame
268
+
269
+ LEADERBOARD_DF = get_leaderboard_df(EVAL_RESULTS_PATH, EVAL_REQUESTS_PATH, COLS, BENCHMARK_COLS)
270
+ (
271
+ finished_eval_queue_df,
272
+ running_eval_queue_df,
273
+ pending_eval_queue_df,
274
+ ) = get_evaluation_queue_df(EVAL_REQUESTS_PATH, EVAL_COLS)
275
+
276
+ def init_leaderboard(dataframe):
277
+ if dataframe is None or dataframe.empty:
278
+ print("Leaderboard DataFrame 为空或 None,初始化空排行榜。")
279
+ return Leaderboard(
280
+ value=pd.DataFrame(columns=[c.name for c in fields(AutoEvalColumn)]),
281
+ datatype=[c.type for c in fields(AutoEvalColumn)],
282
+ select_columns=SelectColumns(
283
+ default_selection=[c.name for c in fields(AutoEvalColumn) if c.displayed_by_default],
284
+ cant_deselect=[c.name for c in fields(AutoEvalColumn) if c.never_hidden],
285
+ label="选择要显示的列:",
286
+ ),
287
+ search_columns=[AutoEvalColumn.model.name, AutoEvalColumn.license.name],
288
+ hide_columns=[c.name for c in fields(AutoEvalColumn) if c.hidden],
289
+ filter_columns=[],
290
+ bool_checkboxgroup_label="隐藏模型",
291
+ interactive=False, # 设置为非交互式
292
+ )
293
 
294
+ return Leaderboard(
295
+ value=dataframe,
296
+ datatype=[c.type for c in fields(AutoEvalColumn)],
297
+ select_columns=SelectColumns(
298
+ default_selection=[c.name for c in fields(AutoEvalColumn) if c.displayed_by_default],
299
+ cant_deselect=[c.name for c in fields(AutoEvalColumn) if c.never_hidden],
300
+ label="选择要显示的列:",
301
+ ),
302
+ search_columns=[AutoEvalColumn.model.name, AutoEvalColumn.license.name],
303
+ hide_columns=[c.name for c in fields(AutoEvalColumn) if c.hidden],
304
+ filter_columns=[
305
+ ColumnFilter(AutoEvalColumn.model_type.name, type="checkboxgroup", label="模型类型"),
306
+ ColumnFilter(AutoEvalColumn.precision.name, type="checkboxgroup", label="精度"),
307
+ ColumnFilter(
308
+ AutoEvalColumn.params.name,
309
+ type="slider",
310
+ min=0.01,
311
+ max=150,
312
+ label="选择参数数量 (B)",
313
+ ),
314
+ ColumnFilter(
315
+ AutoEvalColumn.still_on_hub.name, type="boolean", label="已删除/不完整", default=True
316
+ ),
317
+ # 为 GRACE 分数添加筛选器 (滑块)
318
+ ColumnFilter(
319
+ AutoEvalColumn.generalization_score.value.name,
320
+ type="slider",
321
+ min=0.0,
322
+ max=1.0,
323
+ label="G: 泛化性得分",
324
+ step=0.01 # 允许小数
325
+ ),
326
+ ColumnFilter(
327
+ AutoEvalColumn.relevance_score.value.name,
328
+ type="slider",
329
+ min=0.0,
330
+ max=1.0,
331
+ label="R: 相关性得分",
332
+ step=0.01
333
+ ),
334
+ ColumnFilter(
335
+ AutoEvalColumn.artistry_score.value.name,
336
+ type="slider",
337
+ min=0.0,
338
+ max=1.0,
339
+ label="A: 创新表现力得分",
340
+ step=0.01
341
+ ),
342
+ ColumnFilter(
343
+ AutoEvalColumn.consistency_score.value.name,
344
+ type="slider",
345
+ min=0.0,
346
+ max=1.0,
347
+ label="C: 一致性得分",
348
+ step=0.01
349
+ ),
350
+ ColumnFilter(
351
+ AutoEvalColumn.efficiency_score.value.name,
352
+ type="slider",
353
+ min=0.0,
354
+ max=1.0,
355
+ label="E: 效率性得分",
356
+ step=0.01
357
+ ),
358
+ ],
359
+ bool_checkboxgroup_label="隐藏模型",
360
+ interactive=False, # 设置为非交互式
361
  )
 
 
362
 
363
+
364
+ demo = gr.Blocks(css=custom_css)
365
+ with demo:
366
+ gr.HTML(TITLE)
367
+ gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
368
+
369
+ with gr.Tabs(elem_classes="tab-buttons") as tabs:
370
+ with gr.TabItem("💬 模型比较与生成", elem_id="model-comparison-tab", id=0): # 新的标签页
371
+ gr.Markdown("## 输入您的提示,查看不同模型的生成效果!", elem_classes="markdown-text")
372
+ with gr.Row():
373
+ input_prompt = gr.Textbox(label="输入提示词", placeholder="请写一首关于春天的诗歌。", lines=3)
374
+ generate_button = gr.Button("生成文本")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
 
376
+ # 创建多个输出框,每个模型一个
377
+ output_boxes = []
378
+ for model_info in MODELS_TO_COMPARE:
379
+ output_boxes.append(gr.Textbox(label=f"{model_info['name']} 的生成结果", lines=5, interactive=False))
380
+
381
+ # 将生成按钮与 generate_text 函数连接
382
+ generate_button.click(
383
+ fn=generate_text,
384
+ inputs=[input_prompt],
385
+ outputs=output_boxes
386
+ )
387
+
388
+ gr.Markdown("## 手动评估 GRACE 维度", elem_classes="markdown-text")
389
+ gr.Markdown("请手动评估上述生成结果,并更新排行榜中的 GRACE 分数。", elem_classes="markdown-text")
390
+
391
+ # 用于选择要评估的模型
392
+ model_selector = gr.Dropdown(
393
+ choices=[(m["name"], idx) for idx, m in enumerate(MODELS_TO_COMPARE)],
394
+ label="选择要评估的模型",
395
+ interactive=True,
396
+ value=MODELS_TO_COMPARE[0]["name"] if MODELS_TO_COMPARE else None # 默认选中第一个模型
397
+ )
398
+
399
+ # GRACE 维度滑块
400
+ with gr.Column():
401
+ generalization_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="G: 泛化性得分 (0-100)")
402
+ relevance_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="R: 相关性得分 (0-100)")
403
+ artistry_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="A: 创新表现力得分 (0-100)")
404
+ consistency_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="C: 一致性得分 (0-100)")
405
+ efficiency_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="E: 效率性得分 (0-100)")
 
 
 
406
 
407
+ update_grace_button = gr.Button("更新 GRACE 评分到排行榜")
 
 
 
 
 
 
 
 
408
 
409
+ # Leaderboard 组件需要在被引用的地方先定义
410
+ leaderboard = init_leaderboard(LEADERBOARD_DF) # 在这里初始化 Leaderboard 组件
411
+
412
+ # 更新排行榜的逻辑
413
+ update_grace_button.click(
414
+ fn=update_leaderboard,
415
+ inputs=[
416
+ generalization_slider,
417
+ relevance_slider,
418
+ artistry_slider,
419
+ consistency_slider,
420
+ efficiency_slider,
421
+ model_selector # 传递选中的模型索引
422
+ ],
423
+ outputs=leaderboard # 更新 Leaderboard 组件
424
+ )
425
+
426
+
427
+ with gr.TabItem("🏅 LLM Benchmark", elem_id="llm-benchmark-tab-table", id=1): # 调整 ID
428
+ # Leaderboard 已经在一开始初始化了,这里只是再次引用
429
+ leaderboard_display = leaderboard # 将初始化后的 Leaderboard 实例赋给一个新的变量以便在这里显示
430
+
431
+ with gr.TabItem("📝 关于", elem_id="llm-benchmark-tab-table", id=2):
432
+ gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
433
+
434
+ with gr.TabItem("🚀 在此提交!", elem_id="llm-benchmark-tab-table", id=3): # 这个标签页保留,但内容将被简化
435
+ gr.Markdown("## 在此演示中,模型已预先加载进行比较,无需提交新模型。", elem_classes="markdown-text")
436
+ gr.Markdown("您可以在 **💬 模型比较与生成** 标签页中输入提示词并评估模型。", elem_classes="markdown-text")
437
+ gr.Markdown("(本页面仅用于保留原始结构,实际提交功能已禁用)")
438
+
439
+
440
+ with gr.Row():
441
+ with gr.Accordion("📙 引用", open=False):
442
+ citation_button = gr.Textbox(
443
+ value=CITATION_BUTTON_TEXT,
444
+ label=CITATION_BUTTON_LABEL,
445
+ lines=20,
446
+ elem_id="citation-button",
447
+ show_copy_button=True,
448
+ )
449
+
450
+ # 调度器,每 30 分钟重启一次 Space
451
+ # 在此演示中,由于模型是预加载的,并且没有持续的评估队列,重启的意义不大,但保留。
452
+ scheduler = BackgroundScheduler()
453
+ scheduler.add_job(API.restart_space, "interval", seconds=1800, args=[REPO_ID])
454
+ scheduler.start()
455
+
456
+ demo.queue(default_concurrency_limit=1).launch() # 降低并发限制,避免内存溢出