mcpField
T
transformers-bio-nlp

transformers-bio-nlp

github.com/jaechang-hitsデータ・データベース38467 回インストール6 日前に更新
リポジトリ

transformers-bio-nlp について

生物医学テキストを分析する研究者や開発者向けに、HuggingFace Transformers を使った生物医学 NLP を解説するガイドです。領域特化モデルを用いた抽出、分類、質問応答、生成、埋め込み、ファインチューニングを扱います。

主な機能

  1. 01生物医学固有表現認識
  2. 02抄録と文の分類
  3. 03抽出型質問応答
  4. 04生物医学テキスト生成
  5. 05検索用の文埋め込み
  6. 06ラベル付きデータでの微調整

活用シーン

  1. 01抄録から遺伝子、疾患、薬剤を抽出
  2. 02主題や臨床転帰で文献を絞り込み
  3. 03生物医学テキストから回答を検索
  4. 04意味的類似度で文献を順位付け

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill transformers-bio-nlp

インストール後、Claude Code で/transformers-bio-nlpを入力して読み込まれたか確認します。

詳細

生物医学 NLP 向け Transformers

概要

HuggingFace Transformers では、生物医学分野の 500 以上の言語モデルを読み込み、実行し、ファインチューニングするための統一 API が提供されています。主要な生物医学モデルである BioBERT(PubMed の抄録と PMC の全文で学習)、PubMedBERT(PubMed のデータのみを使って一から学習)、BioGPT(PubMed で学習した生成モデル)、BioMedLM は、生物医学分野の NER、関係抽出、質問応答において、汎用 BERT を大幅に上回る性能を発揮します。pipeline() の抽象化により、トークン化、推論、後処理を 1 回の呼び出しで処理できます。タスク固有のラベル付きデータ(例:化学物質・疾患の NER 用 BC5CDR)であれば、単一 GPU で 1 時間以内にファインチューニングできます。datasets ライブラリを使えば、標準的な生物医学ベンチマークに直接アクセスできます。

使用する場面

  • 生物医学分野の抄録から遺伝子名、疾患への言及、薬剤名、化学物質を抽出する(NER)
  • 抄録をトピック別に分類するほか、臨床転帰の感情やシステマティックレビュー用の PICO 要素を分類する
  • 抽出型 QA(BioASQ 形式)を使って、生物医学文献に関する具体的な質問に回答する
  • BioGPT または BioMedLM を使って、生物医学テキストから仮説や要約を生成する
  • 事前学習済みの生物医学モデルを、カスタムのラベル付きデータセット(例:研究室で作成したアノテーション)でファインチューニングする
  • 文献全体を対象とした意味的類似性検索のために、生物医学分野の文をベクトル化する
  • 高速なルール拡張 NER には spaCy + en_core_sci_lg を、依存構造解析には Stanza を使用する

前提条件

  • Python パッケージ:transformers、torch、datasets、accelerate、sentencepiece
  • GPU:ファインチューニングには強く推奨されます。単一のテキストであれば、CPU での推論も実用的です
  • データ要件:生物医学分野のプレーンテキスト文字列。ファインチューニングには、BIO/IOB 形式のアノテーション付きデータが必要です
pip install transformers torch datasets accelerate sentencepiece
# For GPU (CUDA 11.8)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

クイックスタート

from transformers import pipeline

# Named entity recognition with BioBERT
ner = pipeline("ner", model="allenai/scibert_scivocab_cased",
               aggregation_strategy="simple")

text = "BRCA1 mutations are associated with increased risk of breast cancer and ovarian cancer."
entities = ner(text)
for ent in entities:
    print(f"  {ent['word']:20s} {ent['entity_group']:10s} score={ent['score']:.3f}")

コア API

モジュール 1:固有表現認識(NER)

事前学習済みの NER モデルを使って、生物医学分野のエンティティを抽出します。

from transformers import pipeline, AutoTokenizer, AutoModelForTokenClassification

# BioBERT fine-tuned for NER (genes, diseases, chemicals)
# Common choices:
#   "allenai/scibert_scivocab_cased"  — scientific NER
#   "d4data/biomedical-ner-all"       — multi-entity biomedical NER
#   "pruas/BENT-PubMedBERT-NER-Gene"  — gene-specific NER
ner_pipe = pipeline(
    "ner",
    model="d4data/biomedical-ner-all",
    aggregation_strategy="simple",  # merge subword tokens into words
    device=-1  # -1=CPU, 0=GPU
)

abstracts = [
    "Imatinib inhibits the BCR-ABL1 tyrosine kinase and is first-line treatment for CML.",
    "EGFR mutations in non-small cell lung cancer predict response to erlotinib.",
]

for text in abstracts:
    entities = ner_pipe(text)
    print(f"\nText: {text[:60]}...")
    for e in entities:
        print(f"  [{e['entity_group']}] '{e['word']}' (score={e['score']:.2f})")
# Manual tokenization + inference for batch processing
from transformers import AutoTokenizer, AutoModelForTokenClassification
import torch

model_name = "allenai/scibert_scivocab_cased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(model_name)
model.eval()

text = "Metformin activates AMPK and reduces hepatic glucose production in type 2 diabetes."
inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)

with torch.no_grad():
    outputs = model(**inputs)

logits = outputs.logits  # shape: (1, seq_len, n_labels)
predictions = logits.argmax(dim=-1)[0]
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
labels = [model.config.id2label[p.item()] for p in predictions]

for token, label in zip(tokens[1:-1], labels[1:-1]):  # skip [CLS] and [SEP]
    if label != "O":
        print(f"  {token:20s} {label}")
モジュール 2:テキスト分類

生物医学分野の抄録または文を分類します。

from transformers import pipeline

# Zero-shot classification — no fine-tuning needed
zs_clf = pipeline("zero-shot-classification",
                  model="facebook/bart-large-mnli",
                  device=-1)

abstract = """
This randomized controlled trial evaluated the efficacy of pembrolizumab versus
chemotherapy in patients with advanced non-small-cell lung cancer. Overall survival
was significantly improved in the pembrolizumab arm (HR=0.60, 95% CI 0.41-0.89).
"""

candidate_labels = ["clinical trial", "basic research", "meta-analysis", "review"]
result = zs_clf(abstract, candidate_labels)
print("Zero-shot classification:")
for label, score in zip(result["labels"], result["scores"]):
    print(f"  {label:20s}: {score:.3f}")
# Fine-tuned sentiment/outcome classification
from transformers import pipeline

# Example: classify clinical outcome sentiment
clf = pipeline("text-classification",
               model="pruas/BENT-PubMedBERT-NER-Gene",  # use appropriate task-specific model
               device=-1)

sentences = [
    "Treatment significantly improved overall survival (p<0.001).",
    "No statistically significant difference was observed between groups.",
]
results = clf(sentences)
for sent, result in zip(sentences, results):
    print(f"  [{result['label']} | {result['score']:.2f}] {sent[:50]}...")
モジュール 3:生物医学分野の質問応答

生物医学テキストの文章から回答を抽出します。

from transformers import pipeline

# Extractive QA: find answer span within context
qa_pipe = pipeline(
    "question-answering",
    model="sultan/BioM-ELECTRA-Large-SQuAD2",  # biomedical QA model
    device=-1
)

context = """
BRCA1 is a tumor suppressor gene located on chromosome 17q21. Pathogenic variants
in BRCA1 confer a lifetime breast cancer risk of 50-72% and ovarian cancer risk
of 44-46%. BRCA1 protein functions in DNA double-strand break repair via
homologous recombination.
"""

questions = [
    "What chromosome is BRCA1 located on?",
    "What is the lifetime breast cancer risk from BRCA1 variants?",
    "What DNA repair pathway does BRCA1 participate in?",
]

for q in questions:
    result = qa_pipe(question=q, context=context)
    print(f"Q: {q}")
    print(f"A: {result['answer']} (score={result['score']:.3f})\n")
モジュール 4:BioGPT によるテキスト生成

生物医学テキスト、仮説、要約を生成します。

from transformers import AutoTokenizer, BioGptForCausalLM
import torch

model_name = "microsoft/biogpt"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = BioGptForCausalLM.from_pretrained(model_name)
model.eval()

prompt = "The role of VEGF in tumor angiogenesis"
inputs = tokenizer(prompt, return_tensors="pt")

with torch.no_grad():
    outputs = model.generate(
        **inputs,
        max_new_tokens=100,
        num_beams=5,
        early_stopping=True,
        no_repeat_ngram_size=3,
        pad_token_id=tokenizer.eos_token_id,
    )

generated = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(f"Generated:\n{generated}")
モジュール 5:意味検索用の文の埋め込み

類似性検索やクラスタリングのために、生物医学テキストをベクトル化します。

from transformers import AutoTokenizer, AutoModel
import torch
import numpy as np

def mean_pooling(model_output, attention_mask):
    """Mean pooling across token embeddings."""
    token_embeddings = model_output.last_hidden_state
    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    return (token_embeddings * input_mask_expanded).sum(1) / input_mask_expanded.sum(1)

# PubMedBERT for biomedical sentence embeddings
model_name = "microsoft/BiomedNLP-BiomedBERT-base-uncased-abstract-fulltext"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
model.eval()

sentences = [
    "BRCA1 is involved in DNA double-strand break repair.",
    "Homologous recombination requires BRCA1 and BRCA2.",
    "Metformin inhibits hepatic gluconeogenesis via AMPK.",
]

inputs = tokenizer(sentences, padding=True, truncation=True,
                   max_length=512, return_tensors="pt")
with torch.no_grad():
    outputs = model(**inputs)

embeddings = mean_pooling(outputs, inputs["attention_mask"])
embeddings = torch.nn.functional.normalize(embeddings, p=2, dim=1).numpy()

# Compute cosine similarity
from numpy.linalg import norm
sim_01 = np.dot(embeddings[0], embeddings[1])
sim_02 = np.dot(embeddings[0], embeddings[2])
print(f"Similarity (BRCA1 repair vs. HR): {sim_01:.3f}")
print(f"Similarity (BRCA1 repair vs. Metformin): {sim_02:.3f}")
モジュール 6:カスタムデータによるファインチューニング

ラベル付き NER データセットを使って、生物医学モデルをファインチューニングします。

from transformers import (AutoTokenizer, AutoModelForTokenClassification,
                           TrainingArguments, Trainer, DataCollatorForTokenClassification)
from datasets import Dataset
import numpy as np

# Example: minimal NER fine-tuning setup
model_name = "microsoft/BiomedNLP-BiomedBERT-base-uncased-abstract"
label_list = ["O", "B-GENE", "I-GENE", "B-DISEASE", "I-DISEASE"]
id2label = {i: l for i, l in enumerate(label_list)}
label2id = {l: i for i, l in enumerate(label_list)}

tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(
    model_name, num_labels=len(label_list), id2label=id2label, label2id=label2id
)

# Training arguments
training_args = TrainingArguments(
    output_dir="./biomed_ner_finetuned",
    num_train_epochs=3,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=32,
    warmup_steps=100,
    weight_decay=0.01,
    logging_dir="./logs",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
)

print(f"Model ready for fine-tuning: {model_name}")
print(f"Labels: {label_list}")
# trainer = Trainer(model=model, args=training_args, ...)
# trainer.train()

重要な概念

生物医学テキストのトークン化

生物医学テキストには、特殊なトークン(遺伝子記号、薬剤名、化学物質の SMILES、数値)が含まれており、WordPiece や BPE のトークナイザーでは予想外の分割が発生します。たとえば、「BRCA1」は ["BR", "##CA", "##1"] に分割されます。このようなサブワード分割は分類タスクには影響しませんが、NER には影響します。pipeline() で aggregation_strategy="simple" または "first" を使い、サブワードに対する予測を単語レベルにまとめ直してください。

BIO ラベリング方式

NER では BIO(Begin-Inside-Outside)タグ付けを使用します。B-GENE は遺伝子名の最初のトークン、I-GENE はその続きのトークン、O はエンティティ以外のトークンを示します。ファインチューニング時は、最初のサブワード以外のラベルを -100(損失関数で無視される値)に設定し、ラベルをサブワードトークンに対応付けます。

よくあるワークフロー

ワークフロー 1:抄録のバッチ NER とエンティティの集約
from transformers import pipeline
import pandas as pd

ner_pipe = pipeline("ner", model="d4data/biomedical-ner-all",
                    aggregation_strategy="simple", device=-1)

abstracts = [
    "Pembrolizumab combined with chemotherapy significantly improved progression-free survival in HER2-positive breast cancer.",
    "Inhibition of EGFR by gefitinib is effective in patients with activating EGFR mutations in exons 19 and 21.",
    "CRISPR-Cas9 editing of the PCSK9 gene in hepatocytes reduces LDL cholesterol in murine models.",
]

records = []
for i, text in enumerate(abstracts):
    entities = ner_pipe(text)
    for e in entities:
        records.append({
            "abstract_id": i,
            "entity": e["word"],
            "type": e["entity_group"],
            "score": round(e["score"], 3),
        })

df = pd.DataFrame(records)
print(df.groupby("type")["entity"].apply(list).to_string())
df.to_csv("extracted_entities.csv", index=False)
print(f"\nExtracted {len(df)} entity mentions across {len(abstracts)} abstracts")
ワークフロー 2:文献検索用の意味的類似性ランキング
from transformers import AutoTokenizer, AutoModel
import torch
import numpy as np

model_name = "microsoft/BiomedNLP-BiomedBERT-base-uncased-abstract-fulltext"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
model.eval()

def embed(texts):
    enc = tokenizer(texts, padding=True, truncation=True,
                    max_length=512, return_tensors="pt")
    with torch.no_grad():
        out = model(**enc)
    vecs = out.last_hidden_state[:, 0, :]  # [CLS] token
    return torch.nn.functional.normalize(vecs, dim=1).numpy()

query = "CRISPR base editing for correction of point mutations in genetic disease"
corpus = [
    "Base editing enables precise single-base changes in genomic DNA without double-strand breaks.",
    "CAR-T cell therapy targets CD19 in B-cell acute lymphoblastic leukemia.",
    "Prime editing uses reverse transcriptase to install targeted edits at specific loci.",
    "RNA interference silences gene expression via RISC-mediated mRNA cleavage.",
]

q_emb = embed([query])
c_emb = embed(corpus)
scores = (q_emb @ c_emb.T).flatten()
ranked = sorted(zip(scores, corpus), reverse=True)

print("Top results:")
for score, text in ranked:
    print(f"  [{score:.3f}] {text[:70]}...")

主なパラメーター

パラメーターモジュール/関数デフォルト範囲/オプション効果
modelpipeline()—HuggingFace のモデル ID 文字列読み込む事前学習済みモデルです。タスクに適合している必要があります
aggregation_strategyNER pipeline"none""none"、"simple"、"first"、"average"サブワードの NER 予測を結合します。単語単位の出力には "simple" を使用します
devicepipeline()-1-1(CPU)、0(GPU 0)、1(GPU 1)推論デバイスです
max_lengthtokenizer512128–2048(モデルによって異なります)最大トークン長です。これを超える入力は切り詰められます
max_new_tokensmodel.generate()201–1000テキスト生成モデルが生成するトークン数です
num_beamsmodel.generate()11–10ビームサーチの幅です。値を大きくすると品質が向上しますが、処理は遅くなります
num_train_epochsTrainingArguments31–10ファインチューニングのエポック数です
per_device_train_batch_sizeTrainingArguments84–32GPU ごとのバッチサイズです。メモリ不足の場合は値を小さくしてください
weight_decayTrainingArguments0.00.01–0.1ファインチューニング時の L2 正則化です

ベストプラクティス

  1. 汎用 BERT ではなく、ドメイン特化型モデルを使用する:PubMed でゼロから学習した PubMedBERT は、生物医学分野の NER で BERT-base を 5~15%上回ります。タスク固有のデータでファインチューニングする前に、必ず生物医学分野の事前学習済みモデルから始めてください。

  2. 本番環境で使用する前にモデルのライセンスを確認する:一部のモデル(BioGPT、BioMedLM)は研究目的に限定されたライセンスです。商用アプリケーションにデプロイする前に、HuggingFace のモデルカードにあるライセンス欄を確認してください。

  3. 単語単位の NER 出力には aggregation_strategy="simple" を使用する:デフォルトの "none" はサブワードトークンを返すため、後処理が難しくなります。"simple" は先頭トークン方式でサブワードトークンを結合します。

  4. 文の途中ではなく、文の境界で切り詰める:512 トークンを超える長い生物医学分野の抄録は、エンコードする前に文の境界で分割してください。文の途中で切り詰めると、切断位置付近のエンティティに対する NER の精度が低下します。

よく使われるレシピ

レシピ:PubMed の抄録から薬剤と疾患のペアを抽出する
from transformers import pipeline
from itertools import product

ner = pipeline("ner", model="d4data/biomedical-ner-all",
               aggregation_strategy="simple", device=-1)

def extract_drug_disease_pairs(text):
    entities = ner(text)
    drugs    = [e["word"] for e in entities if e["entity_group"] in ("DRUG", "CHEMICAL")]
    diseases = [e["word"] for e in entities if e["entity_group"] in ("DISEASE", "CONDITION")]
    return list(product(drugs, diseases))

text = "Imatinib and nilotinib both target BCR-ABL1 in chronic myeloid leukemia and Philadelphia chromosome-positive ALL."
pairs = extract_drug_disease_pairs(text)
print("Drug-Disease pairs:")
for drug, disease in pairs:
    print(f"  {drug} → {disease}")
レシピ:文単位で抄録をフィルタリングする
from transformers import pipeline

clf = pipeline("zero-shot-classification",
               model="facebook/bart-large-mnli", device=-1)

abstracts = [
    "We present a phase 3 randomized controlled trial of semaglutide in type 2 diabetes.",
    "Structural analysis of the SARS-CoV-2 spike protein RBD domain by cryo-EM.",
    "A retrospective cohort study of 1,200 ICU patients during the COVID-19 pandemic.",
]

label_options = ["randomized controlled trial", "observational study", "structural biology", "computational study"]

for abstract in abstracts:
    result = clf(abstract, label_options)
    print(f"Type: {result['labels'][0]} ({result['scores'][0]:.2f})")
    print(f"  {abstract[:70]}...\n")

トラブルシューティング

問題原因解決策
推論中に CUDA out of memory が発生するバッチが GPU の VRAM に対して大きすぎますバッチサイズを小さくします。CPU には device=-1 を使用します。FP16 には model.half() を使用します
NER がサブワードトークン(##CA)を返すaggregation_strategy が設定されていませんpipeline() で aggregation_strategy="simple" を設定します
モデルのダウンロードがタイムアウトするモデルファイルが大きく(1~10 GB)、接続速度が遅いですHF_HUB_OFFLINE=1 を設定し、huggingface-cli download で手動ダウンロードします
長い抄録の末尾で NER がエンティティを見落とす入力が 512 トークンで切り詰められています抄録を文ごとに分割し、それぞれを個別に処理します
ファインチューニングの損失が NaN になる学習率が高すぎるか、勾配爆発が起きていますlearning_rate を 2e-5 に下げ、勾配クリッピング max_grad_norm=1.0 を有効にします
特化したドメインで誤ったエンティティが返される汎用の生物医学モデルがサブドメインに適していませんドメインラベル付きデータでファインチューニングし、より特化したモデル(例:遺伝子のみを対象とする NER)を使用します
BioGPT が同じテキストを繰り返し生成するno_repeat_ngram_size が小さすぎますno_repeat_ngram_size=3 または 4 に設定し、num_beams を増やします

関連スキル

  • pubmed-database — 生物医学 NLP パイプラインの入力となる PubMed の抄録を取得します
  • biorxiv-database — 査読前のプレプリントを取得して NLP 分析に使用します
  • scientific-critical-thinking — 研究上の結論に使用する前に、NLP で抽出したエビデンスの品質を評価します

参考資料

コメント