Text Generation
Transformers
Safetensors
Chinese
English
qwen3
transcript-normalization
chinese
qwen3-asr
code-switching
full-finetuning
numbered-lists
numeric-normalization
conversational
text-generation-inference
Instructions to use WIlfLin/S1-mini-Chinese with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use WIlfLin/S1-mini-Chinese with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="WIlfLin/S1-mini-Chinese") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("WIlfLin/S1-mini-Chinese") model = AutoModelForCausalLM.from_pretrained("WIlfLin/S1-mini-Chinese", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use WIlfLin/S1-mini-Chinese with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "WIlfLin/S1-mini-Chinese" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "WIlfLin/S1-mini-Chinese", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/WIlfLin/S1-mini-Chinese
- SGLang
How to use WIlfLin/S1-mini-Chinese with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "WIlfLin/S1-mini-Chinese" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "WIlfLin/S1-mini-Chinese", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "WIlfLin/S1-mini-Chinese" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "WIlfLin/S1-mini-Chinese", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use WIlfLin/S1-mini-Chinese with Docker Model Runner:
docker model run hf.co/WIlfLin/S1-mini-Chinese
Add pre-model letter-spelling normalization helper and usage
Browse files- README.md +31 -0
- input-preprocessing.json +19 -0
- input_preprocessing.py +36 -0
README.md
CHANGED
|
@@ -98,6 +98,37 @@ FP32 主参数和优化器、BF16 autocast,发布权重为 BF16。约 7.52 亿
|
|
| 98 |
历史定义与计数保存在 [history/step400/token-metrics.json](history/step400/token-metrics.json)。
|
| 99 |
上游公开的 94.8% 缺少足够的评分细节,不能声称这些本地指标是官方同口径复现。
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
## 推理示例
|
| 102 |
|
| 103 |
验证环境为 PyTorch 2.10、Transformers 5.3。使用附带 tokenizer/chat template,关闭 thinking,输入带控制行。
|
|
|
|
| 98 |
历史定义与计数保存在 [history/step400/token-metrics.json](history/step400/token-metrics.json)。
|
| 99 |
上游公开的 94.8% 缺少足够的评分细节,不能声称这些本地指标是官方同口径复现。
|
| 100 |
|
| 101 |
+
## 拼读英文的模型前预处理
|
| 102 |
+
|
| 103 |
+
应用可先合并拼读字母,再把文本交给模型。这是应用层规则,**不包含在模型权重中**,也不是生成结束后的替换。
|
| 104 |
+
附带的 [input_preprocessing.py](input_preprocessing.py) 只依赖 Python 标准库(Python 3.11+)。
|
| 105 |
+
|
| 106 |
+
- `C-H-A-T-G-P-T` → `CHATGPT`
|
| 107 |
+
- `A S T R A` → `ASTRA`
|
| 108 |
+
- 保留字母顺序和大小写;`C-L-E-A-U-D-E` 合并为 `CLEAUDE`,不会擅自改成 `Claude`。
|
| 109 |
+
- 通常合并三个及以上单字母;两个大写、空格分隔的字母也可合并,例如 `A I`。
|
| 110 |
+
- 不跨越换行,不改写代码字面量、网址、邮箱和路径。两个字母的连字符表达式 `X-Y` 保持原样。
|
| 111 |
+
|
| 112 |
+
先下载脚本到应用目录:
|
| 113 |
+
|
| 114 |
+
```bash
|
| 115 |
+
hf download WIlfLin/S1-mini-Chinese input_preprocessing.py --local-dir .
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
在构造模型消息之前调用:
|
| 119 |
+
|
| 120 |
+
```python
|
| 121 |
+
from input_preprocessing import normalize_spelled_letters
|
| 122 |
+
|
| 123 |
+
transcript = "我今天试用A S T R A。"
|
| 124 |
+
model_input, spelling_runs = normalize_spelled_letters(transcript)
|
| 125 |
+
# model_input == "我今天试用ASTRA。"
|
| 126 |
+
# 将 model_input 放在下面推理示例的 user 控制行之后,再调用模型。
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
应用的原文模式应跳过这一步。连续字母也可能表示独立变量,规则无法完全判断语义;代码片段会跳过,其他歧义交给模型。
|
| 130 |
+
此前 400 条测试表是原始模型输出,不包含此预处理。权重没有因增加此脚本而变化。
|
| 131 |
+
|
| 132 |
## 推理示例
|
| 133 |
|
| 134 |
验证环境为 PyTorch 2.10、Transformers 5.3。使用附带 tokenizer/chat template,关闭 thinking,输入带控制行。
|
input-preprocessing.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": "spelled_letter_runs-v1",
|
| 3 |
+
"stage": "before model_messages, not after generation",
|
| 4 |
+
"enabled_by_application": true,
|
| 5 |
+
"model_weights_unchanged": true,
|
| 6 |
+
"weights_sha256": "54602b3a2e0c484fe7ae796a4290969d3a1cc58e099c83e59948fe94889150a0",
|
| 7 |
+
"supported": [
|
| 8 |
+
"tight hyphen-separated single letters",
|
| 9 |
+
"horizontal-space-separated single letters"
|
| 10 |
+
],
|
| 11 |
+
"literal_exclusions": [
|
| 12 |
+
"inline/fenced code",
|
| 13 |
+
"URLs",
|
| 14 |
+
"emails",
|
| 15 |
+
"paths",
|
| 16 |
+
"assignments"
|
| 17 |
+
],
|
| 18 |
+
"not_applied_to_published_public400_raw_model_metrics": true
|
| 19 |
+
}
|
input_preprocessing.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Join dictated single-letter runs before the text model, never after it."""
|
| 2 |
+
import re
|
| 3 |
+
|
| 4 |
+
# Horizontal whitespace only: distinct lines/paragraphs are not one spelling run.
|
| 5 |
+
_RUN = re.compile(r'(?<![A-Za-z0-9_./:@+\-])(?>[A-Za-z](?:(?:[-‐‑‒–—]|[ \t\u00a0]+)[A-Za-z])+)(?![A-Za-z0-9_./:@+\-])')
|
| 6 |
+
_LITERAL = re.compile(
|
| 7 |
+
r'```[\s\S]*?(?:```|\Z)|`[^`\n]*(?:`|\Z)'
|
| 8 |
+
r'|https?://[^\s,。!?;、)]+'
|
| 9 |
+
r'|[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}'
|
| 10 |
+
r'|(?:~/|/)[A-Za-z0-9_./~\-]+'
|
| 11 |
+
r'|\b[A-Za-z_]\w*\s*(?:==|!=|<=|>=|:=|[+*/\-]?=)\s*[^;\n,。]+'
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def spelled_letter_runs(text):
|
| 16 |
+
"""Yield unambiguous-enough spelling spans, preserving order and case.
|
| 17 |
+
|
| 18 |
+
Three or more separate letters, or two uppercase space-separated letters.
|
| 19 |
+
A two-letter hyphenated expression such as X-Y is left alone.
|
| 20 |
+
Literal code, paths, URLs and emails are not interpreted as dictation.
|
| 21 |
+
"""
|
| 22 |
+
literals=[m.span() for m in _LITERAL.finditer(text)]
|
| 23 |
+
for match in _RUN.finditer(text):
|
| 24 |
+
a,b=match.span()
|
| 25 |
+
if any(a<end and b>start for start,end in literals):continue
|
| 26 |
+
letters=re.findall('[A-Za-z]',match[0])
|
| 27 |
+
if len(letters)<3 and not (all(c.isupper() for c in letters) and re.search('[ \t\u00a0]',match[0])):continue
|
| 28 |
+
yield a,b,''.join(letters)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def normalize_spelled_letters(text):
|
| 32 |
+
pieces=[];position=0;count=0
|
| 33 |
+
for start,end,word in spelled_letter_runs(text):
|
| 34 |
+
pieces.extend([text[position:start],word]);position=end;count+=1
|
| 35 |
+
pieces.append(text[position:])
|
| 36 |
+
return ''.join(pieces),count
|