Spaces:
Build error
Build error
[BIOBERT-FTM] Add/Update Space files (2025-10-17T20:54:49.835623+00:00)
Browse files- README.md +17 -6
- app.py +129 -0
- requirements.txt +6 -0
- space_env_hints.json +5 -0
README.md
CHANGED
|
@@ -1,12 +1,23 @@
|
|
| 1 |
---
|
| 2 |
-
title: BIOBERT
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
|
|
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: BIOBERT-FTM Demo
|
| 3 |
+
emoji: 🧬
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: blue
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 4.44.0
|
| 8 |
+
python_version: 3.10
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
+
license: apache-2.0
|
| 12 |
+
models:
|
| 13 |
+
- Milad96/BIOBERT-FTM-mlm
|
| 14 |
+
- Milad96/BIOBERT-FTM-tasks
|
| 15 |
---
|
| 16 |
|
| 17 |
+
# BIOBERT-FTM — Gradio Space
|
| 18 |
+
|
| 19 |
+
Interactive demo for **Fill‑Mask (MLM)** and **Bio‑NER (genes)** powered by:
|
| 20 |
+
- Tokenizer/MLM: `Milad96/BIOBERT-FTM-mlm`
|
| 21 |
+
- NER model: `Milad96/BIOBERT-FTM-tasks/ner-spyysalo_bc2gm_corpus`
|
| 22 |
+
|
| 23 |
+
> Tip: GPU is optional but recommended. This Space reads public model weights from the Hub.
|
app.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BIOBERT-FTM — Gradio Space App
|
| 2 |
+
import os, json
|
| 3 |
+
import torch
|
| 4 |
+
import gradio as gr
|
| 5 |
+
from transformers import AutoTokenizer, AutoConfig, AutoModelForTokenClassification, pipeline
|
| 6 |
+
|
| 7 |
+
# ---- Model sources (override via Space Secrets or env) ----
|
| 8 |
+
TOKENIZER_REPO = os.getenv("MLM_MODEL_REPO_ID", "Milad96/BIOBERT-FTM-mlm")
|
| 9 |
+
TASK_MODEL_REPO = os.getenv("TASK_MODEL_REPO_ID", "Milad96/BIOBERT-FTM-tasks")
|
| 10 |
+
NER_SUBFOLDER = os.getenv("NER_SUBFOLDER", "ner-spyysalo_bc2gm_corpus")
|
| 11 |
+
|
| 12 |
+
DEVICE = 0 if torch.cuda.is_available() else -1
|
| 13 |
+
|
| 14 |
+
tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_REPO, use_fast=True)
|
| 15 |
+
config = AutoConfig.from_pretrained(TASK_MODEL_REPO, subfolder=NER_SUBFOLDER)
|
| 16 |
+
model = AutoModelForTokenClassification.from_pretrained(
|
| 17 |
+
TASK_MODEL_REPO, subfolder=NER_SUBFOLDER, torch_dtype=torch.float32
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
ner = pipeline(
|
| 21 |
+
"token-classification",
|
| 22 |
+
model=model,
|
| 23 |
+
tokenizer=tokenizer,
|
| 24 |
+
device=DEVICE,
|
| 25 |
+
aggregation_strategy="simple"
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
fill_mask = pipeline(
|
| 29 |
+
"fill-mask",
|
| 30 |
+
model=TOKENIZER_REPO,
|
| 31 |
+
tokenizer=TOKENIZER_REPO,
|
| 32 |
+
device=DEVICE
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
EXAMPLE_TEXTS = [
|
| 36 |
+
"Mutations in BRCA1 and TP53 are frequently reported in breast cancer.",
|
| 37 |
+
"The expression of EGFR and KRAS was quantified by qPCR.",
|
| 38 |
+
"BRCA2 interacts with RAD51 during homologous recombination.",
|
| 39 |
+
]
|
| 40 |
+
|
| 41 |
+
MASK_EXAMPLES = [
|
| 42 |
+
"SARS-CoV-2 infects [MASK] epithelial cells in the respiratory tract.",
|
| 43 |
+
"Dexamethasone is commonly used to treat [MASK] inflammation.",
|
| 44 |
+
]
|
| 45 |
+
|
| 46 |
+
def run_fill_mask(text: str, topk: int = 5):
|
| 47 |
+
if not text or "[MASK]" not in text:
|
| 48 |
+
return "Input must contain [MASK] token.", f"Device: {'cuda' if DEVICE==0 else 'cpu'}"
|
| 49 |
+
try:
|
| 50 |
+
res = fill_mask(text, top_k=int(topk))
|
| 51 |
+
if isinstance(res, dict): # older transformers may return dict for top_k=1
|
| 52 |
+
res = [res]
|
| 53 |
+
lines = []
|
| 54 |
+
for p in res:
|
| 55 |
+
seq = p.get("sequence", "")
|
| 56 |
+
score = float(p.get("score", 0.0))
|
| 57 |
+
lines.append(f"→ {seq} (score={score:.4f})")
|
| 58 |
+
return "\n".join(lines), f"Device: {'cuda' if DEVICE==0 else 'cpu'}"
|
| 59 |
+
except Exception as e:
|
| 60 |
+
return f"⚠️ Error: {e}", f"Device: {'cuda' if DEVICE==0 else 'cpu'}"
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def run_ner(text: str, score_threshold: float = 0.50):
|
| 64 |
+
if not text:
|
| 65 |
+
return "", "[]"
|
| 66 |
+
try:
|
| 67 |
+
preds = ner(text)
|
| 68 |
+
if not isinstance(preds, list):
|
| 69 |
+
preds = []
|
| 70 |
+
spans = []
|
| 71 |
+
for s in preds:
|
| 72 |
+
try:
|
| 73 |
+
sc = float(s.get("score", 0.0))
|
| 74 |
+
if sc < float(score_threshold):
|
| 75 |
+
continue
|
| 76 |
+
start = int(s.get("start", 0))
|
| 77 |
+
end = int(s.get("end", 0))
|
| 78 |
+
spans.append({
|
| 79 |
+
"entity": s.get("entity_group") or s.get("entity") or "",
|
| 80 |
+
"start": start,
|
| 81 |
+
"end": end,
|
| 82 |
+
"text": text[start:end],
|
| 83 |
+
"score": sc
|
| 84 |
+
})
|
| 85 |
+
except Exception:
|
| 86 |
+
# Skip any malformed span safely
|
| 87 |
+
continue
|
| 88 |
+
# Markdown summary
|
| 89 |
+
if spans:
|
| 90 |
+
lines = [f"Found {len(spans)} spans:"]
|
| 91 |
+
for sp in spans:
|
| 92 |
+
lines.append(
|
| 93 |
+
f"- [{sp['entity']}] {sp['text']} (start={sp['start']}, end={sp['end']}, score={sp['score']:.4f})"
|
| 94 |
+
)
|
| 95 |
+
md = "\n".join(lines)
|
| 96 |
+
else:
|
| 97 |
+
md = "No spans above threshold."
|
| 98 |
+
return md, json.dumps(spans, ensure_ascii=False, indent=2)
|
| 99 |
+
except Exception as e:
|
| 100 |
+
return f"⚠️ Error: {e}", "[]"
|
| 101 |
+
|
| 102 |
+
with gr.Blocks(title="BIOBERT-FTM Demo", theme=gr.themes.Default()) as demo:
|
| 103 |
+
gr.Markdown("""
|
| 104 |
+
# 🧬 BIOBERT-FTM — Demo
|
| 105 |
+
**Fill‑Mask** (MLM) and **Bio‑NER** (Gene) demo powered by your fine‑tuned checkpoints.
|
| 106 |
+
""")
|
| 107 |
+
|
| 108 |
+
with gr.Tabs():
|
| 109 |
+
with gr.TabItem("Fill-Mask"):
|
| 110 |
+
inp_mask = gr.Textbox(label="Input (must contain [MASK])", value=MASK_EXAMPLES[0])
|
| 111 |
+
topk = gr.Slider(1, 10, value=5, step=1, label="Top‑K")
|
| 112 |
+
btn = gr.Button("Run Fill-Mask")
|
| 113 |
+
out_txt = gr.Textbox(label="Predictions", lines=6)
|
| 114 |
+
out_meta = gr.Textbox(label="Meta")
|
| 115 |
+
btn.click(run_fill_mask, inputs=[inp_mask, topk], outputs=[out_txt, out_meta])
|
| 116 |
+
gr.Examples(MASK_EXAMPLES, inputs=[inp_mask])
|
| 117 |
+
|
| 118 |
+
with gr.TabItem("NER (Genes)"):
|
| 119 |
+
inp = gr.Textbox(label="Input text", value=EXAMPLE_TEXTS[0])
|
| 120 |
+
thr = gr.Slider(0, 1, value=0.50, step=0.01, label="Score threshold")
|
| 121 |
+
go = gr.Button("Run NER")
|
| 122 |
+
out_md = gr.Markdown()
|
| 123 |
+
out_json = gr.JSON()
|
| 124 |
+
go.click(run_ner, inputs=[inp, thr], outputs=[out_md, out_json])
|
| 125 |
+
gr.Examples(EXAMPLE_TEXTS, inputs=[inp])
|
| 126 |
+
|
| 127 |
+
if __name__ == "__main__":
|
| 128 |
+
# When running inside Spaces, just `python app.py` is enough.
|
| 129 |
+
demo.queue().launch()
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
transformers==4.57.1
|
| 2 |
+
torch>=2.3
|
| 3 |
+
accelerate>=0.28.0
|
| 4 |
+
gradio>=4.29.0,<5
|
| 5 |
+
huggingface_hub>=0.23.0
|
| 6 |
+
numpy
|
space_env_hints.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"MLM_MODEL_REPO_ID": "Milad96/BIOBERT-FTM-mlm",
|
| 3 |
+
"TASK_MODEL_REPO_ID": "Milad96/BIOBERT-FTM-tasks",
|
| 4 |
+
"NER_SUBFOLDER": "ner-spyysalo_bc2gm_corpus"
|
| 5 |
+
}
|