<jupyter_start><jupyter_text>PubMedBERTを用いたテキスト分類このノートブックでは、PubMedBertを用いて、テキスト分類をする方法を紹介します。PubMedBERTは大規模な医療系テキストを用いて学習されたモデルです。医療系のタスクにおいては、Wikipediaやニュース記事で学習したBERTよりも高性能となることが期待できます。訳注: 元のノートブックではBioBERTを利用していましたが、PubMedBERTの論文を見る限り、こちらのほうが性能が良かったので置き換えています。- [Domain-Specific Language Model Pretraining for Biomedical Natural Language Processing](https://arxiv.org/abs/2007.15779)  準備  パッケージのインストール<jupyter_code>!pip install -q pandas tensorflow transformers scikit-learn<jupyter_output>[K     |████████████████████████████████| 3.5 MB 5.0 MB/s 
[K     |████████████████████████████████| 6.8 MB 7.5 MB/s 
[K     |████████████████████████████████| 67 kB 2.3 MB/s 
[K     |████████████████████████████████| 895 kB 57.7 MB/s 
[K     |████████████████████████████████| 596 kB 60.9 MB/s 
[?25h<jupyter_text>インポート<jupyter_code>import tensorflow as tf
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from transformers import BertTokenizerFast
from transformers import TFAutoModelForSequenceClassification
from transformers import AutoModelForSequenceClassification
tf.get_logger().setLevel('ERROR')<jupyter_output><empty_output><jupyter_text>データのダウンロードとアップロード今回のデータセットは、Kaggleの以下のページからダウンロードする必要があります。登録してダウンロードし、`mtsamples.csv`をアップロードしましょう。- [Medical Transcriptions](https://www.kaggle.com/tboyle10/medicaltranscriptions)<jupyter_code>from google.colab import files

uploaded = files.upload()<jupyter_output><empty_output><jupyter_text>データの読み込み<jupyter_code>df = pd.read_csv("mtsamples.csv")
df.head()
df["medical_specialty"].value_counts()<jupyter_output><empty_output><jupyter_text>このデータセットを使って、`transcription`から`medical_speciality`を予測するモデルを学習しましょう。データセットは非常に不均衡なので、数の少ないクラスを除去したり、まとめたり、オーバー/アンダーサンプリングするのも1つの手です。今回はそのまま使います。  前処理 `LabelEncoder`を使って、ラベルの文字列を数字に変換します。<jupyter_code>le = LabelEncoder()
df["medical_specialty"] = le.fit_transform(df["medical_specialty"])
df.head()
df.dropna(subset=['transcription'], inplace=True)<jupyter_output><empty_output><jupyter_text>データセットを学習用とテスト用に分割します。<jupyter_code>x_train, x_test, y_train, y_test = train_test_split(
    list(df["transcription"].values),
    list(df["medical_specialty"].values),
    test_size=0.2,
    random_state=2021
)

x_valid, x_test, y_valid, y_test = train_test_split(
    x_test,
    y_test,
    test_size=0.5,
    random_state=2021
)
x_train[0]<jupyter_output><empty_output><jupyter_text>`BERTTokenizerFast.from_pretrained`メソッドでトークナイザーをインスタンス化します。<jupyter_code>model_name = "microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract-fulltext"
tokenizer = BertTokenizerFast.from_pretrained(model_name)<jupyter_output><empty_output><jupyter_text>トークナイザーにテキストを与えて、エンコーディングしましょう。<jupyter_code>MAX_LEN = 128
train_encodings = tokenizer(x_train, truncation=True, padding="max_length", max_length=MAX_LEN)
val_encodings = tokenizer(x_valid, truncation=True, padding="max_length", max_length=MAX_LEN)
test_encodings = tokenizer(x_test, truncation=True, padding="max_length",  max_length=MAX_LEN)<jupyter_output><empty_output><jupyter_text>`tf.data.Dataset`の`from_tensor_slices`メソッドにラベルとエンコーディングした入力を与えて、データセットを作成しましょう。<jupyter_code>train_dataset = tf.data.Dataset.from_tensor_slices((
    dict(train_encodings),
    y_train
))
val_dataset = tf.data.Dataset.from_tensor_slices((
    dict(val_encodings),
    y_valid
))
test_dataset = tf.data.Dataset.from_tensor_slices((
    dict(test_encodings),
    y_test
))
train_dataset = train_dataset.shuffle(len(train_dataset)).batch(8)
val_dataset = val_dataset.batch(8)
test_dataset = test_dataset.batch(8)<jupyter_output><empty_output><jupyter_text>モデルの学習`TFAutoModelForSequenceClassification`を使って分類用のモデルを作成したら、Kerasのfitメソッドを呼び出して学習しましょう。<jupyter_code>model = TFAutoModelForSequenceClassification.from_pretrained(
    model_name,
    num_labels=len(le.classes_),
    from_pt=True
)

callbacks = [
    tf.keras.callbacks.EarlyStopping(
        patience=2,
        restore_best_weights=True
    ),
]

model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=5e-5),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=tf.metrics.SparseCategoricalAccuracy(),
)

model.fit(train_dataset, validation_data=val_dataset, epochs=5, callbacks=callbacks)<jupyter_output>All PyTorch model weights were used when initializing TFBertForSequenceClassification.

Some weights or buffers of the TF 2.0 model TFBertForSequenceClassification were not initialized from the PyTorch model and are newly initialized: ['classifier.weight', 'classifier.bias']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.<jupyter_text>正解率を計算してみましょう。<jupyter_code>_, acc = model.evaluate(test_dataset)
acc<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1329709387413757, 'fraction_numerical': 0.013171649592306083, 'mean_word_length': 8.904761904761905, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '556461', 'license': 'MIT', 'n_tokens_mistral': 2276, 'n_tokens_neox': 2084, 'n_words': 215, 'path': 'ch10/01_BioBERT_Demo.ipynb', 'repo_name': 'oreilly-japan/practical-nlp-ja', 'size': '4783'}