Sentence Similarity
sentence-transformers
ONNX
Safetensors
Chinese
modernbert
embeddings
clinical
healthcare
traditional-chinese
taiwan
medical
fhir
on-premise
text-embeddings-inference
Instructions to use weemed/IlhaEmbed with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- sentence-transformers
How to use weemed/IlhaEmbed with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("weemed/IlhaEmbed") sentences = [ "那是 個快樂的人", "那是 條快樂的狗", "那是 個非常幸福的人", "今天是晴天" ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [4, 4] - Notebooks
- Google Colab
- Kaggle
File size: 24,252 Bytes
a4da60c d5c01d8 8987818 d5c01d8 a4da60c 74f9eed a4da60c d5c01d8 a4da60c d5c01d8 a4da60c d5c01d8 74f9eed a4da60c 75771c4 a4da60c d5c01d8 a4da60c 74f9eed d5c01d8 a4da60c d5c01d8 a4da60c d5c01d8 a4da60c 74f9eed a4da60c 74f9eed a4da60c d5c01d8 a4da60c 74f9eed 0a28746 3ddd653 0a28746 3ddd653 0a28746 74f9eed a4da60c 75771c4 a4da60c 75771c4 a4da60c 74f9eed a4da60c 74f9eed a4da60c d5c01d8 a4da60c 74f9eed a4da60c 75771c4 a4da60c d5c01d8 a4da60c d5c01d8 a4da60c 74f9eed a4da60c d5c01d8 a4da60c 75771c4 a4da60c 74f9eed a4da60c d5c01d8 a4da60c d5c01d8 a4da60c d5c01d8 74f9eed a4da60c d5c01d8 a4da60c d5c01d8 a4da60c 74f9eed d5c01d8 a4da60c d5c01d8 a4da60c d5c01d8 a4da60c 74f9eed a4da60c 74f9eed a4da60c d5c01d8 a4da60c 74f9eed 0a28746 3ddd653 0a28746 3ddd653 0a28746 74f9eed a4da60c d5c01d8 a4da60c d5c01d8 a4da60c d5c01d8 a4da60c 74f9eed a4da60c 74f9eed a4da60c d5c01d8 a4da60c d5c01d8 75771c4 74f9eed a4da60c d5c01d8 a4da60c d5c01d8 a4da60c d5c01d8 a4da60c 74f9eed | 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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | ---
license: apache-2.0
language:
- zh
library_name: sentence-transformers
pipeline_tag: sentence-similarity
tags:
- embeddings
- clinical
- healthcare
- traditional-chinese
- taiwan
- medical
- fhir
- on-premise
- onnx
base_model: ibm-granite/granite-embedding-97m-multilingual-r2
---
# IlhaEmbed
English | [繁體中文](#繁體中文)
A small embedding model for Taiwanese clinical text.
Clinical records in Taiwan are full of local shorthand. `L-CT` is a low-dose lung CT screen, 鈣化 in a checkup context is a coronary artery calcium score, 皮蛇 is shingles (帶狀皰疹), 檳榔 (betel-nut chewing) is a first-class social-history axis alongside tobacco and alcohol, 傷寒 in a checkup note means the typhoid stool specimen is still outstanding (not the disease), 成健 is shorthand for an adult preventive-care checkup, and 定期心內門診-戒菸 packs two facts — ongoing cardiology follow-up and smoking cessation — into a single cell. General-purpose and general Chinese models mostly miss these, because they never saw how doctors, nurses, and care workers in Taiwan actually write. IlhaEmbed was trained for it.
The name is from Ilha Formosa. It reads this island's clinical language.
## Highlights
- **Reads local clinical writing.** Slang, abbreviations, Taigi, handwritten shorthand. Where a general model returns noise, this one usually returns the right concept.
- **Trained on Taiwanese clinical language**, not on any one institution's forms. It reads colloquialisms, appositions, and clinical abbreviations. A caveat worth stating plainly: an institution's *operational* shorthand — near-identical strings like `L-CT` (低劑量胸部電腦斷層, a lung screen) vs `H-CT` (頭部電腦斷層, a head CT) — is where a small int8 model is weakest, and it scores 83/110 on one real register. Fine-tuning that in makes it worse; a concept memory fixes it. See "Reading an institution's own shorthand" below.
- **Runs on-premise.** 38.5 MB, INT8, CPU only. No GPU, no cloud, no API key. Patient data stays in the hospital.
- **Documented provenance.** The released weights and IBM Granite ModernBERT base are identified as
Apache-2.0. Corpus sources, non-published inputs, and their separate rights status are recorded in
the public [source ledger](https://github.com/WeeMed/ilhaembed/blob/main/SOURCES.md).
- **Open model, separate data rights.** The released weights and base model are permissively
licensed. That licence does not grant rights in upstream training or evaluation material.
## What it is for
Turning messy clinical text into structured meaning. Common uses:
- Normalizing clinical text: mapping abbreviations and slang to standard concepts (L-CT to 低劑量胸部電腦斷層).
- Placing dirty data: on import, reading one cell and sending each fact to the field it belongs in (medication, condition, care source, and so on).
- Matching terms and codes: finding the right ICD, LOINC, or drug concept for a surface term.
- Searching across fields: finding a record from the clue at hand, without knowing the exact field name.
In a clinical pipeline built in Taiwan, it handles the "understanding" step: Breeze-ASR-26 for speech, IlhaEmbed for meaning, FHIR for structure.
## Results
Task: jargon top-1. Given a Taiwanese clinical surface term, retrieve its standard concept from a shared pool, self-matches excluded, held out from training. The score is macro-averaged over three semantic registers — slang, abbreviation, and apposition — where each surface form maps to a standard Han concept (皮蛇→帶狀皰疹, L-CT→低劑量胸部電腦斷層, 傷寒→傷寒篩檢糞便檢體). All models use the same method and the same pool. The evaluation implementation is published in [`evaluation/research/card_eval_cpu.py`](https://github.com/WeeMed/ilhaembed/blob/main/evaluation/research/card_eval_cpu.py); its original third-party and institutional evaluation pairs are not redistributed.
| Register | IlhaEmbed (fp32) | IlhaEmbed (int8) | jina-embeddings-v2-base-zh | ckip-base | bge-small-zh |
|---|---:|---:|---:|---:|---:|
| slang (皮蛇→帶狀皰疹) | **0.855** | **0.806** | 0.05 | 0.00 | 0.00 |
| abbrev (L-CT→低劑量胸部電腦斷層) | **0.817** | **0.757** | 0.14 | 0.01 | 0.00 |
| apposition (傷寒→傷寒篩檢糞便檢體) | **0.895** | **0.881** | 0.45 | 0.36 | 0.33 |
| **semantic macro** | **0.856** | **0.815** | 0.21 | 0.13 | 0.11 |
| Taigi-semantic (斷腦筋→中風, Han→Han, v0) | **0.943** | **0.929** | 0.64 | 0.56 | 0.50 |
The int8 column is measured natively via onnxruntime on the artifact published here (`model_int8.onnx`, sha256 `3449f8ba…`); the fp32 column comes from the SentenceTransformer path. The two pipelines differ, so read the int8 figures as the deployment path's own numbers rather than as a quantization delta against fp32. Baseline models are fp32 only, for an apples-to-apples reference point.
An earlier version of this card reported int8 as macro 0.810 / Taigi 0.950. Those came from a weight-interpolated variant that was **not** the model published here, and are withdrawn in favour of the figures above, re-measured on the published artifact itself.
On these local terms the general and general-Chinese models mostly return nothing; this model finds the right concept. It is not meant to top general leaderboards such as MTEB. It does one thing, Taiwanese clinical vocabulary, and it is small enough to run on the ward.
The evaluation methodology and evidence are published, but this is not a one-command reproduction
of the exact reported run: the original third-party and institutional evaluation pairs are not
redistributed. The public repository states the runnable and non-published boundaries explicitly in
[`docs/REPRODUCING.md`](https://github.com/WeeMed/ilhaembed/blob/main/docs/REPRODUCING.md).
### On Taigi, and why it is not folded into that number (nothing is hidden)
A fourth set, `taigi_med_lexicon`, maps a Han term to its **Tâi-lô romanization** (中風 → tiong-hong). Every model, including this one, scores ~0.00 on it — and that is correct: mapping a Han term to a romanized spelling is a **transliteration** task, not semantic retrieval. It belongs to a romanization / ASR model, not a meaning embedder, so it is reported as a diagnostic and kept **out of the semantic macro**; averaging a transliteration score into a semantic benchmark would only produce a meaningless number. (An earlier version of this card called the ~0 a "self-match bug" — that was wrong; only 31/779 surfaces collide with the pool and those are already excluded. The ~0 is the task mismatch.)
The embedder's **Taigi clinical capability is already in the numbers above**: the `slang` register *is* that capability — Taiwanese clinical colloquialisms (皮蛇 for shingles, 檳榔 for betel-nut chewing) mapped to their standard concepts, at 0.855 (fp32). A dedicated Taigi-colloquial → standard-Han-concept set (Han→Han, semantic) is the natural next benchmark to add.
## Usage
```python
# ONNX (deployment path, no torch, CPU)
from tokenizers import Tokenizer
import onnxruntime as ort, numpy as np
tok = Tokenizer.from_file("tokenizer.json")
sess = ort.InferenceSession("model_int8.onnx")
# encode (max_len 32), run, mean-pool, L2-normalize, giving a 384-d vector
```
```python
# sentence-transformers (research path)
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("weemed/IlhaEmbed")
model.encode(["皮蛇", "L-CT", "定期心內門診-戒菸"])
```
384 dimensions, up to 32 tokens. Vocab 25.5k (pruned to Traditional Chinese and clinical). Size 38.5 MB (INT8 ONNX) or 152 MB (fp32 safetensors).
## How it was built
The base model is IBM Granite ModernBERT (Apache-2.0), permissively licensed. A Taiwanese clinical teacher signal supplies the domain knowledge through knowledge distillation, so the student learns to place Taiwanese slang, abbreviations, and Taigi next to their standard concepts.
The base model ships a 180k multilingual BPE vocabulary, most of which Traditional Chinese clinical text never uses. Pruning it to the 25.5k tokens that actually appear cut the size by 68 percent (123 MB to 38.5 MB) with no loss of accuracy: jargon top-1 held, and the real import routing came out bit-identical.
## Reading an institution's own shorthand — use a concept memory, do not fine-tune
The closed set of abbreviations a specific hospital writes on its forms is the hardest case for a small quantized model, and the reason is measurable. Quantizing to int8 perturbs an embedding by a fixed amount (a **noise floor**, 0.44 here). A retrieval decision is only as good as its **margin** over the runner-up, and on this kind of shorthand that margin is 0.14 — the model is deciding inside its own quantization error. Fine-tuning the shorthand into the weights shrinks the margin further while leaving the noise floor unchanged, so it makes things worse, monotonically; 18 weight-space configurations (PTQ variants, fp16, mixed precision, weight interpolation, gamma-migration, QAT, a quantization-constrained LoRA adapter) each either miss full-precision accuracy at a deployable size or trade the general register away for the domain one.
What works is to leave the encoder frozen and hold the vocabulary as data — a small external `surface → concept` memory, read through a gate:
```python
import numpy as np
MEMORY = {"L-CT": "低劑量胸部電腦斷層", "H-CT": "頭部電腦斷層", "皮蛇": "帶狀皰疹"}
surfaces, concepts = list(MEMORY), list(MEMORY.values())
keys = np.stack([encode_one(s) for s in surfaces])
def ground(fragment, tau=0.95):
"""The known concept this fragment is shorthand for, or None -> use the base embedding."""
scores = keys @ encode_one(fragment)
best = int(scores.argmax())
return concepts[best] if scores[best] >= tau else None
```
Two details are load-bearing. **Gate first**: anything below τ passes through exactly as the base encoded it, which is why a memory cannot regress unrelated inputs. **Substitute the concept, not the matched key**: representing a gated fragment by its concept's embedding is what makes the decision high-margin — using the matched surface instead recovers none of the benefit.
Measured on this published artifact, with a 110-surface register:
| | base int8 | + concept memory |
|---|---:|---:|
| institutional shorthand (110 surfaces) | 83/110 (75.5%) | **110/110 (100%)** |
| held-out 20%, surfaces never in the memory | — | **20/22 (90.9%)** |
| general semantic macro (τ=0.99) | 0.815 | **0.815** — unchanged |
| Taigi-semantic | 0.929 | **0.929** — unchanged |
| size | 38.5 MB | **38.5 MB** + a few KB |
Concretely, on a 20-concept probe the base int8 model returns 頭部電腦斷層 for `L-CT` (cos 0.805 — wrong, it is a *lung* screen) and 糖尿病 for 鈣化 (cos 0.384 — wrong). With the memory both ground at 1.000, while 高血壓 / 糖尿病 / 上呼吸道感染 / 心肌梗塞 pass through untouched. [`examples/concept_memory.py`](https://github.com/WeeMed/ilhaembed/blob/main/examples/concept_memory.py) is a runnable reference implementation.
**Build the memory's keys through the same call your queries use.** This model's output depends on the batch a text was embedded in, because a batch pads to its longest member and the padding reaches the real tokens' outputs: the same string embedded inside a large batch and embedded alone are only ~0.88–0.97 similar. Mix the two paths and an exact match scores like a near-miss, and τ quietly stops meaning what it says.
**A lookup out of context is a fabrication.** 鈣化 is a coronary calcium-score exam on a checkup order line and plain tissue calcification in a radiology impression. The gate answers "which known form is this", never "does this reading apply here" — establish the context yourself first.
## Intended use and limits
This is a tool for semantic representation, not a diagnostic system. It offers likely meanings and matches for a person to confirm, and does not decide clinical facts on its own. It is tuned for Traditional Chinese clinical text in Taiwan. General prose and Simplified Chinese are out of scope.
## License
Repository code and released weights are identified as Apache-2.0. Base model: IBM Granite
(Apache-2.0). Training-pair sources and their separate rights status are listed in the public
[`SOURCES.md`](https://github.com/WeeMed/ilhaembed/blob/main/SOURCES.md). Raw third-party pairs are not included. The model licence does not
grant rights in upstream material or replace source-specific permission and legal review.
---
<a name="繁體中文"></a>
# IlhaEmbed(繁體中文)
[English](#ilhaembed) | 繁體中文
一個讀得懂台灣臨床文字的小型語意模型。
台灣的病歷、備註、社區照護表上,有很多在地的寫法。L-CT 是低劑量胸部電腦斷層,健檢紀錄裡的鈣化指的是冠狀動脈鈣化分數,皮蛇是帶狀皰疹,檳榔(嚼檳榔)是和菸酒並列的社會史軸線,健檢紀錄裡的傷寒指的是傷寒篩檢糞便檢體還沒收到(不是這個病),成健是成人預防保健的簡稱,定期心內門診-戒菸則一格裡藏了兩件事——持續心臟科門診追蹤、加上戒菸。這些寫法,通用模型和一般中文模型多半讀不出來,因為它們沒看過台灣的醫師、護理師、照服員實際怎麼寫。IlhaEmbed 是針對這件事訓練的。
名字取自 Ilha Formosa。它專門讀這座島的臨床語言。
## 特點
- **讀得懂在地的臨床寫法。** 行話、縮寫、台語、手寫簡寫。通用模型讀成雜訊的地方,它多半能對到正確的概念。
- **訓練的是台灣的臨床語言**,不是某一家機構的表格。口語、同位語、臨床縮寫都讀得到。但有一件事要說清楚:機構自己的**操作性**簡寫——像 `L-CT`(低劑量胸部電腦斷層,肺癌篩檢)和 `H-CT`(頭部電腦斷層)這種字面幾乎一樣的——正是小型 int8 模型最弱的地方,在一份真實語域上它只有 83/110。把它微調進權重會更差,用概念記憶才修得掉。見下方「讀懂機構自己的簡寫」。
- **完全在地端。** 38.5 MB、INT8、純 CPU。不用 GPU、雲端或 API key,病人資料不離開院內。
- **來源有文件可查。** 釋出權重與 IBM Granite ModernBERT 底座標示為 Apache-2.0;語料來源、未公開輸入及其各自的權利狀態記錄在公開的[來源清冊](https://github.com/WeeMed/ilhaembed/blob/main/SOURCES.md)。
- **模型開放,資料權利分開。** 釋出權重與底座採寬鬆授權;該授權不會授予上游訓練或評估素材的權利。
## 用途
把凌亂的臨床文字整理成有結構的意義。常見的用法:
- 臨床文字正規化:把縮寫、行話對到標準概念(L-CT 對到低劑量胸部電腦斷層)。
- 髒資料歸位:匯入時讀一格內容,把裡面每個事實送到該去的欄位(用藥、疾病、就醫來源等)。
- 術語、代碼比對:幫一個詞找到對應的 ICD、LOINC 或藥品概念。
- 跨欄位搜尋:用手上僅有的線索找到紀錄,不必先知道正確的欄位名稱。
在一條台灣自己的臨床流程裡,它負責「理解」這一段:Breeze-ASR-26 聽打,IlhaEmbed 理解,FHIR 存成結構。
## 成效
測的是 jargon top-1:給一個台灣臨床的表面詞,從共用概念池裡找出對應的標準概念,排除自我匹配,且留作測試。分數是**三個語意語域**(行話 slang、縮寫 abbrev、同位語 apposition)的平均,每個都是「口語/台語/縮寫的漢字表面詞 → 標準漢字概念」(皮蛇→帶狀皰疹、L-CT→低劑量胸部電腦斷層、傷寒→傷寒篩檢糞便檢體)。四個模型用同一套方法、同一個池。評估實作公開於 [`evaluation/research/card_eval_cpu.py`](https://github.com/WeeMed/ilhaembed/blob/main/evaluation/research/card_eval_cpu.py);原始的第三方與機構評估配對不重新散布。
| 語域 | IlhaEmbed(fp32) | IlhaEmbed(int8) | jina-embeddings-v2-base-zh | ckip-base | bge-small-zh |
|---|---:|---:|---:|---:|---:|
| slang(皮蛇→帶狀皰疹) | **0.855** | **0.806** | 0.05 | 0.00 | 0.00 |
| abbrev(L-CT→低劑量胸部電腦斷層) | **0.817** | **0.757** | 0.14 | 0.01 | 0.00 |
| apposition(傷寒→傷寒篩檢糞便檢體) | **0.895** | **0.881** | 0.45 | 0.36 | 0.33 |
| **語意 macro** | **0.856** | **0.815** | 0.21 | 0.13 | 0.11 |
| Taigi-semantic(斷腦筋→中風,漢字→漢字,v0) | **0.943** | **0.929** | 0.64 | 0.56 | 0.50 |
int8 那欄是用 onnxruntime 在這裡發佈的那顆 artifact 上原生量的(`model_int8.onnx`,sha256 `3449f8ba…`);fp32 那欄走的是 SentenceTransformer 管線。兩套管線不同,所以請把 int8 的數字當成部署路徑自己的成績,不要當成對 fp32 的量化落差。基準模型只有 fp32,作為對照。
這張 card 先前把 int8 報成 macro 0.810、Taigi 0.950。那是量在一個**權重內插的變體**上、不是這裡發佈的這顆模型,已經撤掉,改用上面在發佈的 artifact 本身重新量到的數字。
在這些在地詞彙上,通用模型和一般中文模型多半讀不出來,這個模型能對到正確概念。它不是要在通用排行榜(MTEB)上比高下,只把台灣臨床詞彙這一件事做好,而且小到能在病房的機器上跑。
評估方法與證據有公開,但這不是「一行指令重現原始數字」:原始的第三方與機構評估配對不重新散布。公開 repo 在 [`docs/REPRODUCING.md`](https://github.com/WeeMed/ilhaembed/blob/main/docs/REPRODUCING.md) 明列可執行與未公開的邊界。
### 關於台語,以及為什麼它不併進上面那個數字(沒有藏任何東西)
還有第四個集 `taigi_med_lexicon`,它是把漢字詞對到它的**台羅羅馬字**(中風 → tiong-hong)。所有模型(包含這個)在上面都是 ~0.00 —— 而這是**對的**:把漢字對到羅馬拼寫是**音譯**任務、不是語意檢索,那是羅馬字/ASR 模型的工作、不是語意 embedder 的工作。所以它只當診斷用、**不併進語意 macro**;把音譯分數平均進語意 benchmark 只會得到一個沒有意義的數字。(這張 card 之前把那個 ~0 稱作「self-match bug」,那是錯的;只有 31/779 的表面詞會撞到池子、而且早就被排除,~0 是任務錯配。)
這個模型的**台語臨床能力其實就在上面的數字裡**:`slang` 語域正是它 —— 台灣臨床口語(皮蛇=帶狀皰疹、檳榔=嚼檳榔)對到標準概念,fp32 0.855。之後自然要補的是一個專門的「台語口語 → 標準漢字概念」(漢字→漢字、語意)測試集。
## 用法
```python
# ONNX(部署路徑,不需 torch、CPU)
from tokenizers import Tokenizer
import onnxruntime as ort, numpy as np
tok = Tokenizer.from_file("tokenizer.json")
sess = ort.InferenceSession("model_int8.onnx")
# 編碼(max_len 32)、推論、mean-pool、L2 normalize,得到 384 維向量
```
```python
# sentence-transformers(研究路徑)
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("weemed/IlhaEmbed")
model.encode(["皮蛇", "L-CT", "定期心內門診-戒菸"])
```
維度 384,最長 32 個 token。詞表 25.5k(剪過,只留繁體中文和臨床會用到的)。大小 38.5 MB(INT8 ONNX)或 152 MB(fp32 safetensors)。
## 怎麼做的
基礎模型用 IBM Granite ModernBERT(Apache-2.0),授權寬鬆。用台灣臨床的 teacher 訊號做知識蒸餾,讓學生模型學會把台灣的行話、縮寫、台語,擺到對應的標準概念旁邊。
基礎模型原本帶 18 萬詞的多語 BPE 詞表,繁中臨床大多用不到。把它剪到實際會用到的 25.5k,體積少了 68%(123 MB 到 38.5 MB),準確度沒掉:jargon top-1 一樣,實際跑匯入的路由結果逐位相同。
## 讀懂機構自己的簡寫 —— 用概念記憶,不要微調
某一家醫院表格上那組封閉的簡寫,是小型量化模型最難的一關,而且難在哪裡是量得出來的。量化到 int8 會讓向量偏移一個固定的量(**噪音底線**,這裡是 0.44)。而一次檢索的可靠度只等於它對第二名的**餘裕(margin)**——這類簡寫的餘裕是 0.14,也就是模型在自己的量化誤差裡面做決定。把簡寫微調進權重,餘裕還會更小、噪音底線卻不動,所以只會更差,而且是單調地更差;18 種權重空間的做法(各種 PTQ、fp16、混合精度、權重內插、gamma-migration、QAT、量化受限的 LoRA adapter)沒有一種能在可部署的體積下追上全精度,不是追不上就是拿通用語域換掉領域語域。
有效的做法是讓編碼器**凍結不動**,把詞彙當資料放外面 —— 一份小的 `表面詞 → 概念` 記憶,透過一個閘門讀取:
```python
import numpy as np
MEMORY = {"L-CT": "低劑量胸部電腦斷層", "H-CT": "頭部電腦斷層", "皮蛇": "帶狀皰疹"}
surfaces, concepts = list(MEMORY), list(MEMORY.values())
keys = np.stack([encode_one(s) for s in surfaces])
def ground(fragment, tau=0.95):
"""這個片段是哪個已知概念的簡寫;不是就回 None,改用底座的向量。"""
scores = keys @ encode_one(fragment)
best = int(scores.argmax())
return concepts[best] if scores[best] >= tau else None
```
兩個細節是關鍵。**先閘門**:低於 τ 的一律照底座原樣通過,所以加了記憶不可能讓無關的輸入變差。**替換成概念、不是替換成命中的那個 key**:用概念自己的向量來代表被接住的片段,才是讓決定變成高餘裕的原因——換成命中的表面詞,好處會完全消失。
在這顆發佈的 artifact 上、用一份 110 個表面詞的語域量到:
| | 底座 int8 | +概念記憶 |
|---|---:|---:|
| 機構簡寫(110 個表面詞) | 83/110(75.5%) | **110/110(100%)** |
| held-out 20%,記憶裡沒有的表面詞 | — | **20/22(90.9%)** |
| 通用語意 macro(τ=0.99) | 0.815 | **0.815** —— 沒退 |
| Taigi-semantic | 0.929 | **0.929** —— 沒退 |
| 體積 | 38.5 MB | **38.5 MB** +幾 KB |
具體一點:在一個 20 個概念的探針上,底座 int8 把 `L-CT` 讀成頭部電腦斷層(cos 0.805,錯——那是**肺部**篩檢)、把鈣化讀成糖尿病(cos 0.384,錯)。加上記憶之後兩個都以 1.000 接住,而高血壓/糖尿病/上呼吸道感染/心肌梗塞則原樣通過。[`examples/concept_memory.py`](https://github.com/WeeMed/ilhaembed/blob/main/examples/concept_memory.py) 是可執行的參考實作。
**記憶的 key 要用跟 query 同一個呼叫路徑建。** 這個模型的輸出會受它所在的 batch 影響——batch 會 pad 到最長的那一筆,而 padding 會影響到真實 token 的輸出:同一個字串放在大 batch 裡跟單獨嵌入,相似度只有 ~0.88–0.97。兩條路徑混用,完全相同的字串會拿到近似命中的分數,τ 就靜靜地失去了它字面上的意思。
**沒有脈絡的查表就是捏造。** 鈣化在健檢加購欄是冠狀動脈鈣化分數檢查,在影像所見裡是組織鈣化。這個閘門回答的是「這是哪一個已知寫法」,從來不是「這個讀法在這裡成不成立」——脈絡要你自己先確立。
## 適用範圍
這是一個做語意表示的工具,不是診斷系統。它給的是可能的意義和比對,最後由人確認,不會自己下臨床判斷。它針對台灣的繁體中文臨床文字調過,一般文章或簡體中文不在範圍內。
## 授權
Repo 程式碼與釋出權重標示為 Apache-2.0,基礎模型 IBM Granite 也是 Apache-2.0。訓練配對來源及其各自的權利狀態記在公開的 [`SOURCES.md`](https://github.com/WeeMed/ilhaembed/blob/main/SOURCES.md)。原始第三方配對不隨附;模型授權不會授予上游素材的權利,也不能取代逐一來源的許可與法律審查。
|