File size: 5,712 Bytes
bdbecca | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | # app.py —— 永久一键切换:微调 / 测试 / 机器人
import os
import gradio as gr
from transformers import GPT2LMHeadModel, GPT2Tokenizer, TextDataset, DataCollatorForLanguageModeling
from transformers import Trainer, TrainingArguments
import re
import torch
MODEL_DIR = "./fine_tuned_model"
BASE_MODEL = "uer/gpt2-chinese-cluecorpussmall"
# ==================== 微调函数 ====================
def finetune_model(progress=gr.Progress()):
if os.path.exists(MODEL_DIR):
return "已存在微调好的模型,无需重复微调!直接切换到「测试」或「机器人」模式即可。"
progress(0, desc="正在读取家谱文件...")
with open("genealogy.txt", encoding="utf-8") as f:
text = f.read()
# 简单但有效的信息抽取
blocks = re.split(r"\n\d+——|\n故祖考|\n故祖妣|\n孝男|\n孝媳|\n孝孙|\n曾孙|\n外曾孙|\n外玄孙", text)
examples = []
for block in blocks[1:]:
if len(block) < 10:
continue
# 提取姓名
name_match = re.search(r"[\u4e00-\u9fa5]{2,4}", block[:15])
name = name_match.group() if name_match else "某人"
born = re.search(r"生[於于]\s*([^\n地名]+)", block)
died = re.search(r"(死[於于]|卒于|去世于)\s*([^\n地名]+)", block)
place = re.search(r"地名\s*([^\n]+)", block)
born = born.group(1).strip() if born else "未知"
place = place.group(1).strip() if place else "未知"
died = died.group(2).strip() if died else None
examples.append(f"查询: {name}出生时间和地点?\n回答: {name}出生于{born},地点{place}。")
if died:
examples.append(f"查询: {name}去世时间?\n回答: {name}去世于{died}。")
data_text = "\n\n".join(examples)
with open("train.txt", "w", encoding="utf-8") as f:
f.write(data_text)
progress(0.3, desc="加载 tokenizer 和数据集...")
tokenizer = GPT2Tokenizer.from_pretrained(BASE_MODEL)
dataset = TextDataset(tokenizer=tokenizer, file_path="train.txt", block_size=128)
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
progress(0.6, desc="开始微调(预计40–90分钟,请耐心等待勿关闭页面)...")
model = GPT2LMHeadModel.from_pretrained(BASE_MODEL)
training_args = TrainingArguments(
output_dir="./results",
overwrite_output_dir=True,
num_train_epochs=3,
per_device_train_batch_size=2,
save_steps=500,
logging_steps=20,
save_total_limit=1,
)
trainer = Trainer(
model=model,
args=training_args,
data_collator=data_collator,
train_dataset=dataset,
)
trainer.train()
progress(1.0, desc="保存模型...")
model.save_pretrained(MODEL_DIR)
tokenizer.save_pretrained(MODEL_DIR)
return "微调成功!模型已保存。现在可以切换到「测试」或「机器人」模式使用啦!"
# ==================== 推理函数 ====================
def load_model():
if not os.path.exists(MODEL_DIR):
return None, None
tokenizer = GPT2Tokenizer.from_pretrained(MODEL_DIR)
model = GPT2LMHeadModel.from_pretrained(MODEL_DIR)
return model, tokenizer
model, tokenizer = load_model()
def chat(message, history):
if model is None:
return "模型尚未微调完成!请先在上面选择「微调模型」运行一次。"
prompt = "\n".join([f"查询: {h[0]}\n回答: {h[1]}" for h in history if h[1]] + [f"查询: {message}\n回答:"])
inputs = tokenizer.encode(prompt, return_tensors="pt")
outputs = model.generate(
inputs,
max_length=inputs.shape[1] + 120,
do_sample=True,
temperature=0.7,
top_p=0.9,
no_repeat_ngram_size=3,
pad_token_id=tokenizer.eos_token_id
)
reply = tokenizer.decode(outputs[0], skip_special_tokens=True)
return reply.split("回答:")[-1].strip()
# ==================== 主界面 ====================
with gr.Blocks(theme=gr.themes.Soft(), title="冯氏家谱智能查询") as demo:
gr.Markdown("# 冯氏家谱智能查询机器人\n一次上传,永久使用,三个模式一键切换")
mode = gr.Radio(
["微调模型", "测试模型", "正式机器人"],
label="请选择当前模式",
value="正式机器人" if os.path.exists(MODEL_DIR) else "微调模型"
)
with gr.Column(visible=False) as finetune_box:
gr.Markdown("### 第一步:点击下方按钮开始微调(只需执行一次,耐心等待40–90分钟)")
btn = gr.Button("开始微调模型(免费CPU可完成)", variant="primary", size="lg")
output = gr.Textbox(label="微调日志", lines=20)
btn.click(finetune_model, None, output)
with gr.Column(visible=True) as chat_box:
gr.ChatInterface(
fn=chat,
title=None,
description="直接问:冯达尊出生地、冯乔福几个儿子、冯宗德姐妹是谁……",
examples=[
"冯达尊出生时间和地点?",
"冯乔源的孩子有哪些?",
"冯宗福的兄弟姐妹是谁?",
"冯永明是哪一支的?",
"冯仁杰的父亲是谁?"
]
)
def update_interface(choice):
if choice == "微调模型":
return gr.update(visible=True), gr.update(visible=False)
else:
return gr.update(visible=False), gr.update(visible=True)
mode.change(update_interface, mode, [finetune_box, chat_box])
# 启动时自动显示正确界面
demo.launch() |