yxccai commited on
Commit
7460c5d
·
verified ·
1 Parent(s): 09d9105

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -86
app.py CHANGED
@@ -1,69 +1,110 @@
 
 
 
 
1
  import gradio as gr
2
  import torch
3
  import gc
4
- from transformers import AutoTokenizer, AutoModelForCausalLM
5
  import os
 
 
6
 
7
- # 清理内存
 
8
  torch.cuda.empty_cache()
9
  gc.collect()
10
 
11
- # 设置环境变量
12
- os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"
 
 
 
13
 
14
- # 模型名称
15
- model_name = "yxccai/text-style-converter"
 
 
 
 
16
 
17
- # 全局变量存储模型
18
  tokenizer = None
19
  model = None
20
 
 
21
  def load_model():
22
- """延迟加载模型"""
 
 
 
 
 
23
  global tokenizer, model
24
-
 
25
  if tokenizer is None or model is None:
26
  try:
27
- print("正在加载tokenizer...")
 
28
  tokenizer = AutoTokenizer.from_pretrained(
29
- model_name,
30
  trust_remote_code=True,
31
- use_fast=False # 使用慢速tokenizer减少内存
32
  )
33
-
34
- print("正在加载模型...")
35
- model = AutoModelForCausalLM.from_pretrained(
36
- model_name,
37
- torch_dtype=torch.float16, # 使用半精度
38
- device_map="cpu", # 强制使用CPU
39
- low_cpu_mem_usage=True, # 启用低内存模式
40
- trust_remote_code=True,
41
- load_in_8bit=False, # 在CPU上不使用量化
42
- offload_folder="./offload", # 设置offload文件夹
43
- )
44
-
45
- # 设置pad_token
46
  if tokenizer.pad_token is None:
47
  tokenizer.pad_token = tokenizer.eos_token
48
-
49
- print("模型加载完成!")
50
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  except Exception as e:
 
 
52
  print(f"模型加载失败: {str(e)}")
53
  return False
54
-
55
  return True
56
 
57
- def convert_text_style(input_text):
58
- """文本风格转换函数"""
59
- if not input_text.strip():
60
- return "请输入要转换的文本"
61
-
62
- # 检查模型是否加载
 
 
 
 
63
  if not load_model():
64
- return "模型加载失败,请稍后重试"
65
-
66
  try:
 
67
  prompt = f"""以下是一个文本风格转换任务,请将书面化、技术性的输入文本转换为自然、口语化的表达方式。
68
 
69
  ### 输入文本:
@@ -71,78 +112,62 @@ def convert_text_style(input_text):
71
 
72
  ### 输出文本:
73
  """
74
-
75
- # 编码输入
76
  inputs = tokenizer(
77
- prompt,
78
  return_tensors="pt",
79
- max_length=1024, # 限制输入长度
80
  truncation=True,
81
- padding=True
82
  )
83
-
84
- # 生成回答
85
- with torch.no_grad(): # 不计算梯度节省内存
 
 
86
  outputs = model.generate(
87
- inputs.input_ids,
88
- attention_mask=inputs.attention_mask,
89
- max_new_tokens=300, # 减少生成长度
90
  temperature=0.7,
91
  do_sample=True,
92
  pad_token_id=tokenizer.eos_token_id,
93
  eos_token_id=tokenizer.eos_token_id,
 
94
  num_return_sequences=1,
95
- no_repeat_ngram_size=2
96
  )
97
-
98
- # 解码输出
99
- full_response = tokenizer.decode(outputs[0], skip_special_tokens=True)
100
-
101
- # 提取生成的部分
102
- if "### 输出文本:" in full_response:
103
- response = full_response.split("### 输出文本:")[-1].strip()
104
- else:
105
- response = full_response[len(prompt):].strip()
106
-
107
- # 清理内存
108
- del inputs, outputs
109
- torch.cuda.empty_cache()
110
- gc.collect()
111
-
112
- return response if response else "抱歉,未能生成有效回答"
113
-
114
  except Exception as e:
 
 
115
  return f"生成过程中出现错误: {str(e)}"
116
 
117
- # 创建Gradio接口 - 修复版本兼容性问题
 
118
  iface = gr.Interface(
119
  fn=convert_text_style,
120
  inputs=gr.Textbox(
121
- label="输入文本",
122
- placeholder="请输入需要转换为口语化的书面文本...",
123
- lines=3
124
- ),
125
- outputs=gr.Textbox(
126
- label="输出文本",
127
- lines=3
128
  ),
 
129
  title="中文文本风格转换API",
130
  description="将书面化、技术性文本转换为自然、口语化表达",
131
  examples=[
132
  ["乙醇的检测方法包括酸碱度检查。"],
133
- ["本品为薄膜衣片,除去包衣后显橙红色。"]
134
  ],
135
- cache_examples=False, # 不缓存示例
136
- flagging_mode="never" # 修复:使用flagging_mode替代allow_flagging
137
  )
138
 
139
- # 启动应用 - 移除不兼容的参数
140
  if __name__ == "__main__":
141
- print("正在启动应用...")
142
- iface.launch(
143
- server_name="0.0.0.0",
144
- server_port=7860,
145
- share=False,
146
- debug=False
147
- # 移除了enable_queue和max_threads参数
148
- )
 
1
+ # ────────────────────────────────────────────────────────────────────────────────
2
+ # app.py (CPU-only 版:先加载 float32 基座 LLaMA-8B,再叠入 LoRA Adapter)
3
+ # ────────────────────────────────────────────────────────────────────────────────
4
+
5
  import gradio as gr
6
  import torch
7
  import gc
 
8
  import os
9
+ from transformers import AutoTokenizer, LlamaForCausalLM
10
+ from peft import PeftModel
11
 
12
+ # ─────────────────────── 1. 释放可能的显存/内存 ───────────────────────
13
+ # 对于 CPU-only,可以留着,也不会报错
14
  torch.cuda.empty_cache()
15
  gc.collect()
16
 
17
+ # ─────────────────────── 2. 配置区域 ───────────────────────
18
+
19
+ # (A)Adapter 仓库 ID:LoRA 权重所在的 Hugging Face Repo
20
+ # 这个仓库里只有 adapter_model.safetensors + adapter_config.json + tokenizer 文件
21
+ ADAPTER_REPO = "yxccai/text-style-converter"
22
 
23
+ # (B)基座模型 ID(去掉了 -bnb-4bit 后缀,改用 float32 版)
24
+ # 原 adapter_config.json 里提到的 "unsloth/deepseek-r1-distill-llama-8b-unsloth-bnb-4bit"
25
+ # 在 CPU-only 环境下不能加载 4bit bitsandbytes,所以我们要改为:
26
+ # "unsloth/deepseek-r1-distill-llama-8b"
27
+ # 如果您本地没有这个仓库,可以换成“decapoda-research/llama-7b-hf”或其他您能在 CPU 上跑通的模型。
28
+ BASE_MODEL_ID = "unsloth/deepseek-r1-distill-llama-8b"
29
 
30
+ # 全局变量:Tokenizer + Model
31
  tokenizer = None
32
  model = None
33
 
34
+ # ─────────────────────── 3. 加载模型的函数 ───────────────────────
35
  def load_model():
36
+ """
37
+ CPU-only 逻辑:
38
+ 1. 先从 Adapter 仓库加载 Tokenizer(里面有 tokenizer.json 等文件)。
39
+ 2. 再用 LlamaForCausalLM 从 float32 版基座模型加载到 CPU。
40
+ 3. 然后用 PeftModel.from_pretrained(...) 将 LoRA Adapter 权重叠加到基座上。
41
+ """
42
  global tokenizer, model
43
+
44
+ # 如果 tokenizer/model 还未加载,则执行加载逻辑
45
  if tokenizer is None or model is None:
46
  try:
47
+ # ── 3.1 加载 Tokenizer ──
48
+ print("正在加载 Tokenizer(来自 LoRA 仓库)…")
49
  tokenizer = AutoTokenizer.from_pretrained(
50
+ ADAPTER_REPO,
51
  trust_remote_code=True,
52
+ use_fast=False,
53
  )
54
+ # 如果 pad_token 不存在,就用 eos_token 代替
 
 
 
 
 
 
 
 
 
 
 
 
55
  if tokenizer.pad_token is None:
56
  tokenizer.pad_token = tokenizer.eos_token
57
+
58
+ # ── 3.2 加载基座模型(LLaMA float32 → CPU) ──
59
+ print(f"正在加载基座模型:{BASE_MODEL_ID} (float32 → CPU)…")
60
+ # 注意:这里用 torch_dtype=torch.float32, device_map="cpu"。如果 Model 太大、内存不足,会 OOM。
61
+ base_model = LlamaForCausalLM.from_pretrained(
62
+ BASE_MODEL_ID,
63
+ torch_dtype=torch.float32,
64
+ device_map="cpu",
65
+ low_cpu_mem_usage=True, # 尽量启用低内存占用模式
66
+ trust_remote_code=True,
67
+ )
68
+ print("→ 基座模型加载完成。(注意检查是否被系统 OOM)")
69
+
70
+ # ── 3.3 用 PeftModel 叠加 LoRA Adapter ──
71
+ print(f"正在叠加 LoRA Adapter:{ADAPTER_REPO}…")
72
+ model = PeftModel.from_pretrained(
73
+ base_model,
74
+ ADAPTER_REPO,
75
+ device_map="cpu", # CPU-only 环境
76
+ torch_dtype=torch.float32, # 同样使用 float32
77
+ )
78
+ print("→ LoRA Adapter 已叠加成功。")
79
+
80
+ # (可选)不想更新基座所有参数时,把 base_model 的参数都冻结:
81
+ # model.eval()
82
+ # for param in model.base_model.parameters():
83
+ # param.requires_grad = False
84
+
85
  except Exception as e:
86
+ import traceback
87
+ traceback.print_exc()
88
  print(f"模型加载失败: {str(e)}")
89
  return False
90
+
91
  return True
92
 
93
+
94
+ # ─────────────────────── 4. 文本生成函数 ───────────────────────
95
+ def convert_text_style(input_text: str) -> str:
96
+ """
97
+ 输入一句书面化/技术性的中文,让模型把它转换成自然、口语化的表达方式。
98
+ """
99
+ if not input_text or input_text.strip() == "":
100
+ return "请输入要转换的文本。"
101
+
102
+ # 确保模型已加载
103
  if not load_model():
104
+ return "模型加载失败,请稍后重试。"
105
+
106
  try:
107
+ # 拼一个简单的 Prompt
108
  prompt = f"""以下是一个文本风格转换任务,请将书面化、技术性的输入文本转换为自然、口语化的表达方式。
109
 
110
  ### 输入文本:
 
112
 
113
  ### 输出文本:
114
  """
115
+
116
+ # 分词 & 转 torch.Tensor
117
  inputs = tokenizer(
118
+ prompt,
119
  return_tensors="pt",
120
+ max_length=1024,
121
  truncation=True,
122
+ padding=True,
123
  )
124
+ # 全部放到 CPU 上
125
+ inputs = {k: v.to("cpu") for k, v in inputs.items()}
126
+
127
+ # 生成
128
+ with torch.no_grad():
129
  outputs = model.generate(
130
+ inputs["input_ids"],
131
+ attention_mask=inputs["attention_mask"],
132
+ max_new_tokens=256,
133
  temperature=0.7,
134
  do_sample=True,
135
  pad_token_id=tokenizer.eos_token_id,
136
  eos_token_id=tokenizer.eos_token_id,
137
+ no_repeat_ngram_size=2,
138
  num_return_sequences=1,
 
139
  )
140
+
141
+ # 解码并抽取结果
142
+ full_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
143
+ if "### 输出文本:" in full_text:
144
+ return full_text.split("### 输出文本:")[-1].strip()
145
+ return full_text[len(prompt) :].strip()
146
+
 
 
 
 
 
 
 
 
 
 
147
  except Exception as e:
148
+ import traceback
149
+ traceback.print_exc()
150
  return f"生成过程中出现错误: {str(e)}"
151
 
152
+
153
+ # ─────────────────────── 5. Gradio 界面配置 ───────────────────────
154
  iface = gr.Interface(
155
  fn=convert_text_style,
156
  inputs=gr.Textbox(
157
+ label="输入文本", placeholder="请输入需要转换为口语化的书面文本...", lines=3
 
 
 
 
 
 
158
  ),
159
+ outputs=gr.Textbox(label="输出文本", lines=4),
160
  title="中文文本风格转换API",
161
  description="将书面化、技术性文本转换为自然、口语化表达",
162
  examples=[
163
  ["乙醇的检测方法包括酸碱度检查。"],
164
+ ["本品为薄膜衣片,除去包衣后显橙红色。"],
165
  ],
166
+ cache_examples=False,
167
+ flagging_mode="never",
168
  )
169
 
 
170
  if __name__ == "__main__":
171
+ print("启动 Gradio 应用…")
172
+ # 纯 CPU 环境下,server_name 可以保持默认 "0.0.0.0",port 也是 7860
173
+ iface.launch(server_name="0.0.0.0", server_port=7860, share=False, debug=False)