Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -202,10 +202,10 @@ def cb_sample(src):
|
|
| 202 |
pool=member_data if src=="成员数据(训练集)" else non_member_data
|
| 203 |
s=pool[np.random.randint(len(pool))]; m=s['metadata']
|
| 204 |
tm={'calculation':'基础计算','word_problem':'应用题','concept':'概念问答','error_correction':'错题订正'}
|
| 205 |
-
md=("| 字段
|
| 206 |
-
" |\n|
|
| 207 |
-
" |\n|
|
| 208 |
-
" |\n|
|
| 209 |
return md, clean_text(s.get('question','')), clean_text(s.get('answer',''))
|
| 210 |
|
| 211 |
|
|
@@ -243,16 +243,16 @@ def cb_attack(idx, src, target):
|
|
| 243 |
pl,pc=("训练成员","🔴") if pred else ("非训练成员","🟢")
|
| 244 |
al,ac=("训练成员","🔴") if is_mem else ("非训练成员","🟢")
|
| 245 |
if correct and pred and is_mem:
|
| 246 |
-
v="⚠️ **攻击成功:隐私泄露**\n\n
|
| 247 |
elif correct:
|
| 248 |
-
v="✅ **判定正确
|
| 249 |
else:
|
| 250 |
-
v="🛡️ **防御成功
|
| 251 |
-
res=(v+"\n\n**
|
| 252 |
-
"|
|
| 253 |
"| 身份 | "+pc+" "+pl+" | "+ac+" "+al+" |\n"
|
| 254 |
-
"|
|
| 255 |
-
qtxt="**
|
| 256 |
return qtxt, gauge, res
|
| 257 |
|
| 258 |
|
|
@@ -266,21 +266,19 @@ def cb_eval(model):
|
|
| 266 |
k=EVAL_KEY.get(model,"baseline"); acc=EVAL_ACC.get(model,bl_acc)
|
| 267 |
q=EVAL_POOL[np.random.randint(len(EVAL_POOL))]; ok=q.get(k,q.get('baseline',False))
|
| 268 |
ic="✅ 正确" if ok else "❌ 错误"
|
| 269 |
-
note="\n\n>
|
| 270 |
-
return ("**
|
| 271 |
-
"|
|
| 272 |
-
"|
|
| 273 |
-
"|
|
| 274 |
|
| 275 |
|
| 276 |
-
# ══════════════
|
| 277 |
|
| 278 |
CSS = """
|
| 279 |
-
/* 1.
|
| 280 |
body {
|
| 281 |
background-color: #f1f5f9 !important;
|
| 282 |
-
background-image: radial-gradient(#cbd5e1 1px, transparent 1px) !important;
|
| 283 |
-
background-size: 24px 24px !important;
|
| 284 |
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important;
|
| 285 |
}
|
| 286 |
.gradio-container {
|
|
@@ -288,14 +286,14 @@ body {
|
|
| 288 |
margin: 40px auto !important;
|
| 289 |
}
|
| 290 |
|
| 291 |
-
/* 2.
|
| 292 |
.title-area {
|
| 293 |
background: #ffffff;
|
| 294 |
-
padding:
|
| 295 |
border-radius: 12px;
|
| 296 |
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
|
| 297 |
-
margin-bottom:
|
| 298 |
-
border-left: 6px solid #2563eb; /*
|
| 299 |
text-align: left;
|
| 300 |
}
|
| 301 |
.title-area h1 {
|
|
@@ -314,27 +312,27 @@ body {
|
|
| 314 |
|
| 315 |
/* 3. 核心大招:死死锁住所有标签页的大小,防止跳动 */
|
| 316 |
.tabitem {
|
| 317 |
-
background:
|
| 318 |
border-radius: 0 0 12px 12px !important;
|
| 319 |
border: 1px solid #e2e8f0 !important;
|
| 320 |
border-top: none !important;
|
| 321 |
-
box-shadow: 0 4px
|
| 322 |
padding: 32px 40px !important;
|
| 323 |
|
| 324 |
-
/* 让
|
| 325 |
height: 760px !important;
|
| 326 |
max-height: 760px !important;
|
| 327 |
overflow-y: auto !important;
|
| 328 |
overflow-x: hidden !important;
|
| 329 |
}
|
| 330 |
|
| 331 |
-
/*
|
| 332 |
.tabitem::-webkit-scrollbar { width: 6px; }
|
| 333 |
.tabitem::-webkit-scrollbar-track { background: transparent; }
|
| 334 |
.tabitem::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
|
| 335 |
.tabitem::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
|
| 336 |
|
| 337 |
-
/* 4. Tab 导航栏拟
|
| 338 |
.tab-nav {
|
| 339 |
border-bottom: none !important;
|
| 340 |
gap: 4px !important;
|
|
@@ -345,7 +343,7 @@ body {
|
|
| 345 |
padding: 12px 24px !important;
|
| 346 |
font-weight: 600 !important;
|
| 347 |
color: #64748b !important;
|
| 348 |
-
background: #
|
| 349 |
border: 1px solid #e2e8f0 !important;
|
| 350 |
border-bottom: none !important;
|
| 351 |
border-radius: 10px 10px 0 0 !important;
|
|
@@ -363,7 +361,7 @@ body {
|
|
| 363 |
box-shadow: 0 -4px 6px -2px rgba(0,0,0,0.02) !important;
|
| 364 |
}
|
| 365 |
|
| 366 |
-
/* 5. 内部
|
| 367 |
.prose h2 {
|
| 368 |
font-size: 1.3rem !important;
|
| 369 |
color: #0f172a !important;
|
|
@@ -379,7 +377,7 @@ body {
|
|
| 379 |
margin-top: 1.5em !important;
|
| 380 |
}
|
| 381 |
|
| 382 |
-
/* 6. 高级数据表格
|
| 383 |
.prose table {
|
| 384 |
width: 100% !important;
|
| 385 |
border-collapse: separate !important;
|
|
@@ -406,7 +404,7 @@ body {
|
|
| 406 |
.prose tr:last-child td { border-bottom: none !important; }
|
| 407 |
.prose tr:hover td { background: #f0f9ff !important; }
|
| 408 |
|
| 409 |
-
/* 7. 纯色
|
| 410 |
button.primary {
|
| 411 |
background: #2563eb !important;
|
| 412 |
color: white !important;
|
|
@@ -423,7 +421,7 @@ button.primary:hover {
|
|
| 423 |
box-shadow: 0 6px 10px -1px rgba(37, 99, 235, 0.3) !important;
|
| 424 |
}
|
| 425 |
|
| 426 |
-
/* 8. 提示/警报框
|
| 427 |
.prose blockquote {
|
| 428 |
border-left: 4px solid #3b82f6 !important;
|
| 429 |
background: #eff6ff !important;
|
|
@@ -434,161 +432,165 @@ button.primary:hover {
|
|
| 434 |
margin: 1.5em 0 !important;
|
| 435 |
}
|
| 436 |
|
|
|
|
| 437 |
footer { display: none !important; }
|
| 438 |
"""
|
| 439 |
|
| 440 |
with gr.Blocks(title="MIA攻防研究", theme=gr.themes.Base(), css=CSS) as demo:
|
| 441 |
|
| 442 |
gr.HTML("""<div class="title-area">
|
| 443 |
-
<h1>
|
| 444 |
-
<p>Membership Inference Attack & Defense on Educational LLM
|
| 445 |
</div>""")
|
| 446 |
|
| 447 |
-
# ═══════ Tab 1
|
| 448 |
-
with gr.Tab("
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
)
|
| 489 |
-
with gr.Column():
|
| 490 |
-
gr.Markdown(
|
| 491 |
-
"## 🗂️ 任务类型分布\n\n"
|
| 492 |
-
"| 任务类别 | 数据数量 | 占比权重 |\n|---|---|---|\n"
|
| 493 |
-
"| 🧮 基础计算 | 800 | 40% |\n| 📝 应用题 | 600 | 30% |\n| 🧠 概念问答 | 400 | 20% |\n| ✍️ 错题订正 | 200 | 10% |\n"
|
| 494 |
-
)
|
| 495 |
-
gr.Markdown("## 🔍 数据样例浏览提取")
|
| 496 |
with gr.Row(equal_height=True):
|
| 497 |
with gr.Column(scale=2):
|
| 498 |
-
d_src = gr.Radio(["成员数据(训练集)","非成员数据(测试集)"], value="成员数据(训练集)", label="
|
| 499 |
-
d_btn = gr.Button("
|
| 500 |
d_meta = gr.Markdown()
|
| 501 |
with gr.Column(scale=3):
|
| 502 |
-
d_q = gr.Textbox(label="
|
| 503 |
-
d_a = gr.Textbox(label="
|
| 504 |
d_btn.click(cb_sample, [d_src], [d_meta, d_q, d_a])
|
| 505 |
|
| 506 |
-
# ═══════ Tab 3
|
| 507 |
-
with gr.Tab("
|
| 508 |
-
gr.Markdown("##
|
| 509 |
-
"
|
| 510 |
with gr.Row(equal_height=True):
|
| 511 |
with gr.Column(scale=2):
|
| 512 |
a_target = gr.Radio([u"基线模型 (Baseline)",u"标签平滑 (\u03b5=0.02)",u"标签平滑 (\u03b5=0.2)",
|
| 513 |
u"输出扰动 (\u03c3=0.01)",u"输出扰动 (\u03c3=0.015)",u"输出扰动 (\u03c3=0.02)"],
|
| 514 |
-
value=u"基线模型 (Baseline)", label="
|
| 515 |
a_src = gr.Radio(["成员数据(训练集)","非成员数据(测试集)"], value="成员数据(训练集)", label="数据来源")
|
| 516 |
-
a_idx = gr.Slider(0, 999, step=1, value=12, label="
|
| 517 |
-
a_btn = gr.Button("
|
| 518 |
a_qtxt = gr.Markdown()
|
| 519 |
with gr.Column(scale=3):
|
| 520 |
-
a_gauge = gr.Plot(label="Loss位置判定
|
| 521 |
a_res = gr.Markdown()
|
| 522 |
a_btn.click(cb_attack, [a_idx, a_src, a_target], [a_qtxt, a_gauge, a_res])
|
| 523 |
|
| 524 |
-
# ═══════ Tab 4
|
| 525 |
-
with gr.Tab("
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
with gr.Column():
|
| 531 |
-
gr.Markdown(
|
| 532 |
-
"## ⚙️ 防御机制技术说明\n\n"
|
| 533 |
-
"| 维度 | 标签平滑 (Label Smoothing) | 输出扰动 (Output Perturbation) |\n|---|---|---|\n"
|
| 534 |
-
"| **阶段** | 训练期 | 推理期 |\n"
|
| 535 |
-
"| **原理** | 软化标签降低记忆 | Loss加噪遮蔽信号 |\n"
|
| 536 |
-
"| **需重训** | 是 | 否 |\n"
|
| 537 |
-
"| **效用** | 取决于参数 | 无损耗 |\n"
|
| 538 |
-
"| **部署** | 训练时介入 | 即插即用 API |\n\n"
|
| 539 |
-
"**标签平滑公式**: `y_smooth = (1 - ε) * y_onehot + ε / V`\n\n"
|
| 540 |
-
"**输出扰动公式**: `L_perturbed = L_original + N(0, σ²)`\n"
|
| 541 |
-
)
|
| 542 |
-
|
| 543 |
-
gr.Markdown("## 🏔️ Loss分布形态对比\n### 1. 三个模型(训练期防御效果)\n\n> 蓝色=成员,红色=非成员。两色重叠(Overlap)越多 = 攻击者越难区分")
|
| 544 |
gr.Plot(value=fig_loss_dist())
|
| 545 |
-
gr.Markdown("###
|
| 546 |
gr.Plot(value=fig_perturb_dist())
|
| 547 |
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 551 |
with gr.Row(equal_height=True):
|
| 552 |
with gr.Column(): gr.Plot(value=fig_acc_bar())
|
| 553 |
with gr.Column(): gr.Plot(value=fig_tradeoff())
|
| 554 |
-
gr.Markdown("##
|
| 555 |
with gr.Row(equal_height=True):
|
| 556 |
with gr.Column(scale=1):
|
| 557 |
e_model = gr.Radio([u"基线模型",u"标签平滑 (\u03b5=0.02)",u"标签平滑 (\u03b5=0.2)",
|
| 558 |
-
u"输出扰动 (\u03c3=0.01)",u"输出扰动 (\u03c3=0.015)",u"输出扰动 (\u03c3=0.02)"], value=u"基线模型", label="选择
|
| 559 |
-
e_btn = gr.Button("
|
| 560 |
with gr.Column(scale=2):
|
| 561 |
e_res = gr.Markdown()
|
| 562 |
e_btn.click(cb_eval, [e_model], [e_res])
|
| 563 |
|
| 564 |
-
# ═══════ Tab 6
|
| 565 |
-
with gr.Tab("
|
| 566 |
-
gr.Markdown(
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
)
|
| 593 |
|
| 594 |
demo.launch()
|
|
|
|
| 202 |
pool=member_data if src=="成员数据(训练集)" else non_member_data
|
| 203 |
s=pool[np.random.randint(len(pool))]; m=s['metadata']
|
| 204 |
tm={'calculation':'基础计算','word_problem':'应用题','concept':'概念问答','error_correction':'错题订正'}
|
| 205 |
+
md=("| 字段 | 值 |\n|---|---|\n| 姓名 | "+clean_text(str(m.get('name','')))+
|
| 206 |
+
" |\n| 学号 | "+clean_text(str(m.get('student_id','')))+
|
| 207 |
+
" |\n| 班级 | "+clean_text(str(m.get('class','')))+
|
| 208 |
+
" |\n| 成绩 | "+clean_text(str(m.get('score','')))+" 分 |\n| 类型 | "+tm.get(s.get('task_type',''),'')+" |\n")
|
| 209 |
return md, clean_text(s.get('question','')), clean_text(s.get('answer',''))
|
| 210 |
|
| 211 |
|
|
|
|
| 243 |
pl,pc=("训练成员","🔴") if pred else ("非训练成员","🟢")
|
| 244 |
al,ac=("训练成员","🔴") if is_mem else ("非训练成员","🟢")
|
| 245 |
if correct and pred and is_mem:
|
| 246 |
+
v="⚠️ **攻击成功:隐私泄露**\n\n模型对该样本过于熟悉(Loss < 阈值),攻击者成功判定为训练数据。"
|
| 247 |
elif correct:
|
| 248 |
+
v="✅ **判定正确**\n\n攻击者的判定与真实身份一致。"
|
| 249 |
else:
|
| 250 |
+
v="🛡️ **防御成功**\n\n攻击者的判定错误,防御起到了保护作用。"
|
| 251 |
+
res=(v+"\n\n**攻击目标**: "+lbl+" | **AUC**: "+f"{auc_v:.4f}"+"\n\n"
|
| 252 |
+
"| | 攻击者判定 | 真实身份 |\n|---|---|---|\n"
|
| 253 |
"| 身份 | "+pc+" "+pl+" | "+ac+" "+al+" |\n"
|
| 254 |
+
"| Loss | "+f"{loss:.4f}"+" | 阈值: "+f"{thr:.4f}"+" |\n")
|
| 255 |
+
qtxt="**样本 #"+str(idx)+"**\n\n"+clean_text(sample.get('question',''))[:500]
|
| 256 |
return qtxt, gauge, res
|
| 257 |
|
| 258 |
|
|
|
|
| 266 |
k=EVAL_KEY.get(model,"baseline"); acc=EVAL_ACC.get(model,bl_acc)
|
| 267 |
q=EVAL_POOL[np.random.randint(len(EVAL_POOL))]; ok=q.get(k,q.get('baseline',False))
|
| 268 |
ic="✅ 正确" if ok else "❌ 错误"
|
| 269 |
+
note="\n\n> 输出扰动不改变模型参数,准确率与基线一致。" if u"\u03c3" in model else ""
|
| 270 |
+
return ("**"+model+"** (准确率: "+f"{acc:.1f}%"+")\n\n"
|
| 271 |
+
"| 项目 | 内容 |\n|---|---|\n"
|
| 272 |
+
"| 类型 | "+q['type_cn']+" |\n| 题目 | "+q['question']+" |\n"
|
| 273 |
+
"| 正确答案 | "+q['answer']+" |\n| 判定 | "+ic+" |"+note)
|
| 274 |
|
| 275 |
|
| 276 |
+
# ══════════════ 极致干净、高度统一的 CSS 皮肤 ══════════════
|
| 277 |
|
| 278 |
CSS = """
|
| 279 |
+
/* 1. 干净的背景与字体体系 */
|
| 280 |
body {
|
| 281 |
background-color: #f1f5f9 !important;
|
|
|
|
|
|
|
| 282 |
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important;
|
| 283 |
}
|
| 284 |
.gradio-container {
|
|
|
|
| 286 |
margin: 40px auto !important;
|
| 287 |
}
|
| 288 |
|
| 289 |
+
/* 2. 抛弃深蓝渐变,采用清爽的白色主标题面板 */
|
| 290 |
.title-area {
|
| 291 |
background: #ffffff;
|
| 292 |
+
padding: 30px 40px;
|
| 293 |
border-radius: 12px;
|
| 294 |
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
|
| 295 |
+
margin-bottom: 20px;
|
| 296 |
+
border-left: 6px solid #2563eb; /* 左侧科技蓝修饰线 */
|
| 297 |
text-align: left;
|
| 298 |
}
|
| 299 |
.title-area h1 {
|
|
|
|
| 312 |
|
| 313 |
/* 3. 核心大招:死死锁住所有标签页的大小,防止跳动 */
|
| 314 |
.tabitem {
|
| 315 |
+
background: #ffffff !important;
|
| 316 |
border-radius: 0 0 12px 12px !important;
|
| 317 |
border: 1px solid #e2e8f0 !important;
|
| 318 |
border-top: none !important;
|
| 319 |
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05) !important;
|
| 320 |
padding: 32px 40px !important;
|
| 321 |
|
| 322 |
+
/* 就是这两行代码,让你的每一页大小绝对一致 */
|
| 323 |
height: 760px !important;
|
| 324 |
max-height: 760px !important;
|
| 325 |
overflow-y: auto !important;
|
| 326 |
overflow-x: hidden !important;
|
| 327 |
}
|
| 328 |
|
| 329 |
+
/* 美化内页的滚动条,让它看起来更高级 */
|
| 330 |
.tabitem::-webkit-scrollbar { width: 6px; }
|
| 331 |
.tabitem::-webkit-scrollbar-track { background: transparent; }
|
| 332 |
.tabitem::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
|
| 333 |
.tabitem::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
|
| 334 |
|
| 335 |
+
/* 4. Tab 导航栏的极简拟物设计 */
|
| 336 |
.tab-nav {
|
| 337 |
border-bottom: none !important;
|
| 338 |
gap: 4px !important;
|
|
|
|
| 343 |
padding: 12px 24px !important;
|
| 344 |
font-weight: 600 !important;
|
| 345 |
color: #64748b !important;
|
| 346 |
+
background: #f1f5f9 !important;
|
| 347 |
border: 1px solid #e2e8f0 !important;
|
| 348 |
border-bottom: none !important;
|
| 349 |
border-radius: 10px 10px 0 0 !important;
|
|
|
|
| 361 |
box-shadow: 0 -4px 6px -2px rgba(0,0,0,0.02) !important;
|
| 362 |
}
|
| 363 |
|
| 364 |
+
/* 5. 内部排版(去掉默认的黑粗体,改为高级灰黑) */
|
| 365 |
.prose h2 {
|
| 366 |
font-size: 1.3rem !important;
|
| 367 |
color: #0f172a !important;
|
|
|
|
| 377 |
margin-top: 1.5em !important;
|
| 378 |
}
|
| 379 |
|
| 380 |
+
/* 6. 高级数据表格 */
|
| 381 |
.prose table {
|
| 382 |
width: 100% !important;
|
| 383 |
border-collapse: separate !important;
|
|
|
|
| 404 |
.prose tr:last-child td { border-bottom: none !important; }
|
| 405 |
.prose tr:hover td { background: #f0f9ff !important; }
|
| 406 |
|
| 407 |
+
/* 7. 纯色扁平化高级按钮 */
|
| 408 |
button.primary {
|
| 409 |
background: #2563eb !important;
|
| 410 |
color: white !important;
|
|
|
|
| 421 |
box-shadow: 0 6px 10px -1px rgba(37, 99, 235, 0.3) !important;
|
| 422 |
}
|
| 423 |
|
| 424 |
+
/* 8. 提示/警报框 */
|
| 425 |
.prose blockquote {
|
| 426 |
border-left: 4px solid #3b82f6 !important;
|
| 427 |
background: #eff6ff !important;
|
|
|
|
| 432 |
margin: 1.5em 0 !important;
|
| 433 |
}
|
| 434 |
|
| 435 |
+
/* 隐藏底部水印 */
|
| 436 |
footer { display: none !important; }
|
| 437 |
"""
|
| 438 |
|
| 439 |
with gr.Blocks(title="MIA攻防研究", theme=gr.themes.Base(), css=CSS) as demo:
|
| 440 |
|
| 441 |
gr.HTML("""<div class="title-area">
|
| 442 |
+
<h1>教育大模型中的成员推理攻击及其防御研究</h1>
|
| 443 |
+
<p>Membership Inference Attack & Defense on Educational LLM</p>
|
| 444 |
</div>""")
|
| 445 |
|
| 446 |
+
# ═══════ Tab 1 ═══════
|
| 447 |
+
with gr.Tab("实验总览"):
|
| 448 |
+
gr.Markdown(
|
| 449 |
+
"## 研究背景与目标\n\n"
|
| 450 |
+
"大语言模型在教育领域的应用日益广泛(如AI数学辅导),模型训练不可避免地接触学生敏感数据。"
|
| 451 |
+
"**成员推理攻击 (MIA)** 可判断某条数据是否参与了训练,构成隐私威胁。\n\n"
|
| 452 |
+
"本研究基于 **" + model_name + "** 微调的数学辅导模型,验证MIA风险的存在性,"
|
| 453 |
+
"并探索 **标签平滑**(训练期)与 **输出扰动**(推理期)两类防御策略的有效性及其对模型效用的影响。\n\n---")
|
| 454 |
+
|
| 455 |
+
gr.Markdown("## 实验核心指标\n")
|
| 456 |
+
gr.Markdown(
|
| 457 |
+
"| 策略 | AUC | 准确率 | 说明 |\n|---|---|---|---|\n"
|
| 458 |
+
"| **基线(无防御)** | **" + f"{bl_auc:.4f}" + "** | " + f"{bl_acc:.1f}%" + " | 攻击风险基准 |\n"
|
| 459 |
+
"| " + u"LS(\u03b5=0.02)" + " | " + f"{s002_auc:.4f}" + " | " + f"{s002_acc:.1f}%" + " | 训练期防御 |\n"
|
| 460 |
+
"| " + u"LS(\u03b5=0.2)" + " | " + f"{s02_auc:.4f}" + " | " + f"{s02_acc:.1f}%" + " | 训练期防御 |\n"
|
| 461 |
+
"| " + u"OP(\u03c3=0.01)" + " | " + f"{op001_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | 推理期防御 |\n"
|
| 462 |
+
"| " + u"OP(\u03c3=0.015)" + " | " + f"{op0015_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | 推理期防御 |\n"
|
| 463 |
+
"| " + u"OP(\u03c3=0.02)" + " | " + f"{op002_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | 推理期防御 |\n\n"
|
| 464 |
+
"> AUC越接近0.5 = 防御越有效 | 准确率越高 = 模型效用越好\n\n---")
|
| 465 |
+
|
| 466 |
+
gr.Markdown(
|
| 467 |
+
"## 实验流程\n\n"
|
| 468 |
+
"| 阶段 | 内容 | 方法 |\n|---|---|---|\n"
|
| 469 |
+
"| 1. 数据准备 | 2000条数学辅导对话 | 模板化生成,含姓名/学号/成绩 |\n"
|
| 470 |
+
"| 2. 基线训练 | " + model_name + " + LoRA | 标准微调(r=8, alpha=16, 10 epochs) |\n"
|
| 471 |
+
"| 3. 防御训练 | " + u"\u03b5=0.02 / \u03b5=0.2" + " | 两组标签平滑参数分别训练 |\n"
|
| 472 |
+
"| 4. 攻击测试 | 3个模型 + 3组扰动 | Loss阈值判定,AUC评估 |\n"
|
| 473 |
+
"| 5. 效用评估 | 300道数学题 | 6种配置分别测试准确率 |\n"
|
| 474 |
+
"| 6. 综合分析 | 隐私-效用权衡 | 定量对比与可视化 |\n")
|
| 475 |
+
|
| 476 |
+
# ═══════ Tab 2 ═══════
|
| 477 |
+
with gr.Tab("数据与模型"):
|
| 478 |
+
gr.Markdown(
|
| 479 |
+
"## 实验数据集\n\n"
|
| 480 |
+
"| 数据组 | 数量 | 用途 | 说明 |\n|---|---|---|---|\n"
|
| 481 |
+
"| 成员数据 | 1000条 | 模型训练 | 模型会\"记住\",Loss偏低 |\n"
|
| 482 |
+
"| 非成员数据 | 1000条 | 攻击对照 | 模型\"没见过\",Loss偏高 |\n\n"
|
| 483 |
+
"> 两组数据格式完全相同(均含隐私字段),这是MIA实验的标准设置——攻击者无法从格式区分\n\n"
|
| 484 |
+
"| 任务类型 | 数量 | 占比 |\n|---|---|---|\n"
|
| 485 |
+
"| 基础计算 | 800 | 40% |\n| 应用题 | 600 | 30% |\n| 概念问答 | 400 | 20% |\n| 错题订正 | 200 | 10% |\n")
|
| 486 |
+
gr.Markdown("### 数据样例浏览")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
with gr.Row(equal_height=True):
|
| 488 |
with gr.Column(scale=2):
|
| 489 |
+
d_src = gr.Radio(["成员数据(训练集)","非成员数据(测试集)"], value="成员数据(训练集)", label="数据来源")
|
| 490 |
+
d_btn = gr.Button("随机提取样本", variant="primary")
|
| 491 |
d_meta = gr.Markdown()
|
| 492 |
with gr.Column(scale=3):
|
| 493 |
+
d_q = gr.Textbox(label="学生提问", lines=4, interactive=False)
|
| 494 |
+
d_a = gr.Textbox(label="标准回答", lines=4, interactive=False)
|
| 495 |
d_btn.click(cb_sample, [d_src], [d_meta, d_q, d_a])
|
| 496 |
|
| 497 |
+
# ═══════ Tab 3 ═══════
|
| 498 |
+
with gr.Tab("攻击与防御验证"):
|
| 499 |
+
gr.Markdown("## 成员推理攻击交互演示\n\n"
|
| 500 |
+
"选择攻击目标和数据来源,系统实时计算Loss并判定成员身份。通过切换不同目标形成对照实验。")
|
| 501 |
with gr.Row(equal_height=True):
|
| 502 |
with gr.Column(scale=2):
|
| 503 |
a_target = gr.Radio([u"基线模型 (Baseline)",u"标签平滑 (\u03b5=0.02)",u"标签平滑 (\u03b5=0.2)",
|
| 504 |
u"输出扰动 (\u03c3=0.01)",u"输出扰动 (\u03c3=0.015)",u"输出扰动 (\u03c3=0.02)"],
|
| 505 |
+
value=u"基线模型 (Baseline)", label="攻击目标")
|
| 506 |
a_src = gr.Radio(["成员数据(训练集)","非成员数据(测试集)"], value="成员数据(训练集)", label="数据来源")
|
| 507 |
+
a_idx = gr.Slider(0, 999, step=1, value=12, label="样本 ID")
|
| 508 |
+
a_btn = gr.Button("执行成员推理攻击", variant="primary", size="lg")
|
| 509 |
a_qtxt = gr.Markdown()
|
| 510 |
with gr.Column(scale=3):
|
| 511 |
+
a_gauge = gr.Plot(label="Loss位置判定")
|
| 512 |
a_res = gr.Markdown()
|
| 513 |
a_btn.click(cb_attack, [a_idx, a_src, a_target], [a_qtxt, a_gauge, a_res])
|
| 514 |
|
| 515 |
+
# ═══════ Tab 4 ═══════
|
| 516 |
+
with gr.Tab("防御效果分析"):
|
| 517 |
+
gr.Markdown("## MIA攻击AUC对比\n\n> 柱子越矮 = AUC越低 = 攻击越难成功 = 防御越有效")
|
| 518 |
+
gr.Plot(value=fig_auc_bar())
|
| 519 |
+
|
| 520 |
+
gr.Markdown("## Loss分布对比\n### 三个模型(训练期防御效果)\n\n> 蓝色=成员,红色=非成员。两色重叠越多 = 攻击者越难区分")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
gr.Plot(value=fig_loss_dist())
|
| 522 |
+
gr.Markdown("### 输出扰动效果(推理期防御)\n\n> 在基线模型Loss上加噪声,随噪声增大分布更加重叠")
|
| 523 |
gr.Plot(value=fig_perturb_dist())
|
| 524 |
|
| 525 |
+
gr.Markdown(
|
| 526 |
+
"## 完整实验数据\n\n"
|
| 527 |
+
"| 策略 | 类型 | AUC | 准确率 | AUC变化 |\n|---|---|---|---|---|\n"
|
| 528 |
+
"| 基线 | — | " + f"{bl_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | — |\n"
|
| 529 |
+
"| " + u"LS(\u03b5=0.02)" + " | 训练期 | " + f"{s002_auc:.4f}" + " | " + f"{s002_acc:.1f}%" + " | " + f"{s002_auc-bl_auc:+.4f}" + " |\n"
|
| 530 |
+
"| " + u"LS(\u03b5=0.2)" + " | 训练期 | " + f"{s02_auc:.4f}" + " | " + f"{s02_acc:.1f}%" + " | " + f"{s02_auc-bl_auc:+.4f}" + " |\n"
|
| 531 |
+
"| " + u"OP(\u03c3=0.01)" + " | 推理期 | " + f"{op001_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | " + f"{op001_auc-bl_auc:+.4f}" + " |\n"
|
| 532 |
+
"| " + u"OP(\u03c3=0.015)" + " | 推理期 | " + f"{op0015_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | " + f"{op0015_auc-bl_auc:+.4f}" + " |\n"
|
| 533 |
+
"| " + u"OP(\u03c3=0.02)" + " | 推理期 | " + f"{op002_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | " + f"{op002_auc-bl_auc:+.4f}" + " |\n\n"
|
| 534 |
+
"## 防御机制说明\n\n"
|
| 535 |
+
"| 维度 | 标签平滑 | 输出扰动 |\n|---|---|---|\n"
|
| 536 |
+
"| 阶段 | 训练期 | 推理期 |\n"
|
| 537 |
+
"| 原理 | 软化标签降低记忆 | Loss加噪遮蔽信号 |\n"
|
| 538 |
+
"| 需重训 | 是 | 否 |\n"
|
| 539 |
+
"| 效用影响 | 取决于参数 | 无 |\n"
|
| 540 |
+
"| 部署 | 训练时介入 | 即插即用 |\n\n"
|
| 541 |
+
"**标签平滑**: y_smooth = (1 - " + u"\u03b5" + ") * y_onehot + " + u"\u03b5" + " / V\n\n"
|
| 542 |
+
"**输出扰动**: L_perturbed = L_original + N(0, " + u"\u03c3" + u"\u00b2" + ")\n")
|
| 543 |
+
|
| 544 |
+
for fn, cap in [("fig1_loss_distribution_comparison.png","Loss分布对比"),
|
| 545 |
+
("fig2_privacy_utility_tradeoff_fixed.png","隐私-效用权衡"),
|
| 546 |
+
("fig3_defense_comparison_bar.png","防御策略AUC对比")]:
|
| 547 |
+
p = os.path.join(BASE_DIR,"figures",fn)
|
| 548 |
+
if os.path.exists(p):
|
| 549 |
+
gr.Markdown("### "+cap); gr.Image(value=p, show_label=False, height=420)
|
| 550 |
+
|
| 551 |
+
# ═══════ Tab 5 ═══════
|
| 552 |
+
with gr.Tab("效用评估"):
|
| 553 |
+
gr.Markdown("## 模型效用测试\n\n> 基于300道数学测试题评估各策略对模型实际能力的影响")
|
| 554 |
with gr.Row(equal_height=True):
|
| 555 |
with gr.Column(): gr.Plot(value=fig_acc_bar())
|
| 556 |
with gr.Column(): gr.Plot(value=fig_tradeoff())
|
| 557 |
+
gr.Markdown("### 在线效用演示\n\n从测试题库中随机抽取,查看不同模型/策略的作答情况。")
|
| 558 |
with gr.Row(equal_height=True):
|
| 559 |
with gr.Column(scale=1):
|
| 560 |
e_model = gr.Radio([u"基线模型",u"标签平滑 (\u03b5=0.02)",u"标签平滑 (\u03b5=0.2)",
|
| 561 |
+
u"输出扰动 (\u03c3=0.01)",u"输出扰动 (\u03c3=0.015)",u"输出扰动 (\u03c3=0.02)"], value=u"基线模型", label="选择模型")
|
| 562 |
+
e_btn = gr.Button("随机抽题测试", variant="primary")
|
| 563 |
with gr.Column(scale=2):
|
| 564 |
e_res = gr.Markdown()
|
| 565 |
e_btn.click(cb_eval, [e_model], [e_res])
|
| 566 |
|
| 567 |
+
# ═══════ Tab 6 ═══════
|
| 568 |
+
with gr.Tab("研究结论"):
|
| 569 |
+
gr.Markdown(
|
| 570 |
+
"## 核心研究发现\n\n---\n\n"
|
| 571 |
+
"### 一、教育大模型存在可量化的MIA风险\n\n"
|
| 572 |
+
"基线模型 AUC = **" + f"{bl_auc:.4f}" + "** > 0.5,成员平均Loss (" + f"{bl_m_mean:.4f}"
|
| 573 |
+
+ ") < 非成员 (" + f"{bl_nm_mean:.4f}" + "),模型对训练数据存在可利用的记忆效应。\n\n---\n\n"
|
| 574 |
+
"### 二、标签平滑(训练期防御)\n\n"
|
| 575 |
+
"| 参数 | AUC | 准确率 | 分析 |\n|---|---|---|---|\n"
|
| 576 |
+
"| 基线 | " + f"{bl_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | 无防御 |\n"
|
| 577 |
+
"| " + u"\u03b5=0.02" + " | " + f"{s002_auc:.4f}" + " | " + f"{s002_acc:.1f}%" + " | 正则化提升泛化 |\n"
|
| 578 |
+
"| " + u"\u03b5=0.2" + " | " + f"{s02_auc:.4f}" + " | " + f"{s02_acc:.1f}%" + " | 防御增强 |\n\n---\n\n"
|
| 579 |
+
"### 三、输出扰动(推理期防御)\n\n"
|
| 580 |
+
"| 参数 | AUC | AUC降幅 | 准确率 |\n|---|---|---|---|\n"
|
| 581 |
+
"| " + u"\u03c3=0.01" + " | " + f"{op001_auc:.4f}" + " | " + f"{bl_auc-op001_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " |\n"
|
| 582 |
+
"| " + u"\u03c3=0.015" + " | " + f"{op0015_auc:.4f}" + " | " + f"{bl_auc-op0015_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " |\n"
|
| 583 |
+
"| " + u"OP(\u03c3=0.02)" + " | " + f"{op002_auc:.4f}" + " | " + f"{bl_auc-op002_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " |\n\n"
|
| 584 |
+
"零效用损失,适合已部署系统的后期加固。\n\n---\n\n"
|
| 585 |
+
"### 四、隐私-效用权衡总结\n\n"
|
| 586 |
+
"| 策略 | AUC | 准确率 | 隐私 | 效用 |\n|---|---|---|---|---|\n"
|
| 587 |
+
"| 基线 | " + f"{bl_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | 风险最高 | 基准 |\n"
|
| 588 |
+
"| " + u"LS(\u03b5=0.02)" + " | " + f"{s002_auc:.4f}" + " | " + f"{s002_acc:.1f}%" + " | 降低 | 提升 |\n"
|
| 589 |
+
"| " + u"LS(\u03b5=0.2)" + " | " + f"{s02_auc:.4f}" + " | " + f"{s02_acc:.1f}%" + " | 显著降低 | 可接受 |\n"
|
| 590 |
+
"| " + u"OP(\u03c3=0.02)" + " | " + f"{op002_auc:.4f}" + " | " + f"{bl_acc:.1f}%" + " | 显著降低 | 不变 |\n\n"
|
| 591 |
+
"两类策略机制互补:标签平滑从训练阶段降低记忆,输出扰动从推理阶段遮蔽信号。可根据实际需求灵活选择。\n")
|
| 592 |
+
|
| 593 |
+
gr.HTML("<div style='text-align:center;color:#94a3b8;font-size:.82rem;padding:16px 0 8px'>"
|
| 594 |
+
"</div>")
|
|
|
|
| 595 |
|
| 596 |
demo.launch()
|