Pythonで認知バイアスタグ付けのためのミニトランスフォーマーを微調整する
PythonでDistilBERTトランスフォーマーモデルを微調整し、Hugging Faceライブラリを使用してテキスト内の一般的な認知バイアスを自動的に識別・タグ付けするステップバイステップのチュートリアル
このページの内容
認知的誤謬とは、不正確で否定的な偏りを持つ思考パターンのことです。これらの思考パターンは、心の健康に深刻な影響を与え、不安やうつ病などの症状につながる可能性があります。日記、セラピーチャットログ、ソーシャルメディアの投稿などのテキストから、これらの誤謬を自動的に識別する能力は、メンタルヘルステクノロジーにおいて大きな可能性を秘めています。自然言語処理(NLP)は、これらの認知的誤謬を検出し分類するための有望な手段を提供します。
このチュートリアルでは、一般的な認知的誤謬をテキストに自動的にタグ付けできる強力なツールを構築します。、事前に訓練された「小型変圧器」モデルであるDistilBERTを使用し、カスタムデータセットで微調整します。DistilBERTは、信頼性の高いBERTモデルの小さく高速なバージョンであるため、効率性が重要なアプリケーションに最適です。
このガイドを終える頃には、動作するマルチラベルテキスト分類モデルが完成し、変圧器モデルを専門的なNLPタスクに適用する方法をより深く理解できるようになります。
前提条件:
- Pythonと機械学習の概念の基本的な理解。
- コマンドラインへの精通。
- Python 3.7以上がインストールされていること。
- Hugging Faceアカウント(モデルの共有の場合)。
問題の理解
核心的な課題は、機械学習モデルに、言語内の特定の認知的誤謬に対応する微妙なパターンを認識させることです。例えば、「いつも全部やり損なっている」という陈述は「過般化」の典型的な例です。モデルは、そのようなフレーズを正しいラベルに関連付けることを学ぶ必要があります。
これはマルチラベル分類問題です。なぜなら、1つのテキストが複数の種類の認知的誤謬を示すことがあるからです。例えば、「私は完全に失敗者でみんながそう思っている”也”是”这个陈述には、「 labeling」 と 「mind reading」 の両方のタグを付けることができます。
既存のソリューションでは、変圧器ベースのモデルがこのタスクで人間の臨床評価者に匹敵するパフォーマンスを達成できることが示されています。これを踏まえて、実用的で段階的な実装を作成します。
前提条件
コーディングを開始する前に、環境を設定しましょう。依存関係を管理するために、仮想環境を使用することを強くお勧めします。
まず、必要なライブラリをインストールします:
pip install transformers datasets pandas scikit-learn torch
transformers:DistilBERTモデルと微調整のためのツールを提供します。datasets:データの読み込みと処理を簡単にためのHugging Faceライブラリ。pandas:データ操作に使用されます。scikit-learn:評価指標の計算用。torch:使用する深層学習フレームワーク。
ステップ1:カスタムデータセットの準備
良いデータセットは任何の機械学習プロジェクトの基盤です。認知的誤謬用の広く利用可能なパッケージ化されたデータセットがないため、独自のものを作成します。このチュートリアルでは、小規模で手作りされたデータセットを使用します。実際のシナリオでは предметの専門家が註釈を付けた、より大規模で多様なデータセットが必要です。
私たちの取り組み
テキストサンプルと対応する認知的誤謬ラベルを含むCSVファイルを作成します。
実装
cognitive_distortions.csvという名前のファイルを作成し、以下の内容を含めます:
text,all_or_nothing,overgeneralization,mental_filter,disqualifying_the_positive,jumping_to_conclusions,magnification_minimization,emotional_reasoning,should_statements,labeling,personalization
"I completely failed the exam. I'm a total idiot.",1,0,0,0,0,0,0,0,1,0
"She didn't text back, she must be mad at me.",0,0,0,0,1,0,0,0,0,0
"I always ruin everything.",0,1,0,0,0,0,0,0,0,0
"I got a promotion, but it was just luck.",0,0,0,1,0,0,0,0,0,0
"I feel anxious, so something terrible must be about to happen.",0,0,0,0,0,0,1,0,0,0
"He only pointed out one mistake in my presentation, so the whole thing was a disaster.",0,0,1,0,0,1,0,0,0,0
"I should be able to handle this without getting stressed.",0,0,0,0,0,0,0,1,0,0
"It's all my fault that the team project is behind schedule.",0,0,0,0,0,0,0,0,0,1
"I'm just a loser.",0,0,0,0,0,0,0,0,1,0
"This will be a catastrophe.",0,0,0,0,1,1,0,0,0,0
"I never get any recognition for my hard work.",0,1,1,0,0,0,0,0,0,0
"I'm a bad person for feeling this way.",0,0,0,0,0,0,1,0,1,0
"I ought to have known better.",0,0,0,0,0,0,0,1,0,0
"They probably think I'm incompetent.",0,0,0,0,1,0,0,0,0,1
"I made one small mistake, so I'm a complete failure.",1,0,0,0,0,1,0,0,1,0
仕組み
このCSVファイルには、text 列と、対象としている10の認知的誤謬ごとに1つのバイナリ(0または1)列があります。'1'はテキストにその誤謬が存在することを示します。この形式はマルチラベル分類に最適です。
ステップ2:データの読み込みと前処理
次に、データセットを読み込み、モデル用に準備します。
私たちの取り組み
datasets ライブラリを使用してCSVを読み込み、テキストをトークン化します。トークン化とは、生のテキストをモデルが理解できる形式(単語またはサブワードの数値表現)に変換するプロセスです。
実装
# src/data_loader.py
import pandas as pd
from datasets import Dataset
from transformers import AutoTokenizer
def load_and_preprocess_data(file_path, model_checkpoint):
# pandasでデータを読み込む
df = pd.read_csv(file_path)
# ラベルをテキストから分離する
labels = [col for col in df.columns if col != 'text']
id2label = {idx: label for idx, label in enumerate(labels)}
label2id = {label: idx for idx, label in enumerate(labels)}
# バイナリ値のリストを持つ新しい'labels'列を作成する
df['labels'] = df[labels].values.tolist()
# Hugging Face Datasetオブジェクトに変換
dataset = Dataset.from_pandas(df)
# トークナイザを初期化
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
# トークン化関数
def tokenize_data(examples):
return tokenizer(examples['text'], truncation=True)
# データセット全体にトークン化を適用
dataset = dataset.map(tokenize_data, batched=True)
# PyTorch用のデータセットフォーマットを設定
dataset = dataset.map(lambda x: {'labels': [float(label) for label in x['labels']]})
dataset.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
return dataset, id2label, label2id
# 使用例
if __name__ == '__main__':
MODEL_CHECKPOINT = "distilbert-base-uncased"
dataset, id2label, label2id = load_and_preprocess_data('cognitive_distortions.csv', MODEL_CHECKPOINT)
print(dataset[0])
print(f"id2label: {id2label}")
仕組み
- CSVをpandas DataFrameに読み込みます。
- ラベル名と整数IDの間のマッピングを作成し、これは良い実践です。
- ワンホットエンコードされたラベルをフロートのリストを含む単一の
labels列に統合します。 AutoTokenizerを使用してDistilBERTトークナイザを読み込みます。map関数は、データセット全体でトークン化プロセスを効率的に適用します。- 最後に、データセットの形式を "torch" に設定して、PyTorchトレーニングループで直接使用できるようにします。
ステップ3:小型変圧器の微調整
これがプロジェクトの核心です。transformers ライブラリの Trainer APIを使用して、トレーニングプロセスを大幅に簡素化します。
私たちの取り組み
事前訓練されたDistilBERTモデルを読み込み、トレーニング引数を構成し、評価指標を定義してから、微調整プロセスを起動します。
実装
# src/train.py
import torch
from transformers import AutoModelForSequenceClassification, Trainer, TrainingArguments
from sklearn.metrics import f1_score, roc_auc_score, accuracy_score
from data_loader import load_and_preprocess_data
MODEL_CHECKPOINT = "distilbert-base-uncased"
dataset, id2label, label2id = load_and_preprocess_data('cognitive_distortions.csv', MODEL_CHECKPOINT)
# データセットを分割(実際のシナリオでは別途テストセットをお持ちになります)
train_test_split = dataset.train_test_split(test_size=0.2)
train_dataset = train_test_split['train']
eval_dataset = train_test_split['test']
# モデルを読み込む
model = AutoModelForSequenceClassification.from_pretrained(
MODEL_CHECKPOINT,
problem_type="multi_label_classification",
num_labels=len(id2label),
id2label=id2label,
label2id=label2id
)
# 指標を定義
def compute_metrics(p):
preds = p.predictions[0] if isinstance(p.predictions, tuple) else p.predictions
# シグモイドを適用して確率を取得し、閾値を設定
sigmoid = torch.nn.Sigmoid()
probs = sigmoid(torch.Tensor(preds))
y_pred = (probs > 0.5).int()
y_true = p.label_ids
f1_micro_average = f1_score(y_true=y_true, y_pred=y_pred, average='micro')
roc_auc = roc_auc_score(y_true, y_pred, average='micro')
accuracy = accuracy_score(y_true, y_pred)
metrics = {'f1': f1_micro_average, 'roc_auc': roc_auc, 'accuracy': accuracy}
return metrics
# トレーニング引数を定義
training_args = TrainingArguments(
output_dir="cognitive-distortion-model",
learning_rate=2e-5,
per_device_train_batchサイズ=8,
per_device_eval_batch_size=8,
num_train_epochs=10, # 小さなデータセットでは増加
weight_decay=0.01,
evaluation_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
)
# Trainerを作成
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
tokenizer=AutoTokenizer.from_pretrained(MODEL_CHECKPOINT),
compute_metrics=compute_metrics,
)
# トレーニングを開始
trainer.train()
# 最良モデルを保存
trainer.save_model("best_cognitive_distortion_model")
仕組み
- 小さなデータセットをトレーニングセットと評価セットに分割します。
AutoModelForSequenceClassificationを使用してDistilBERTを読み込みます。重要なことに、problem_type="multi_label_classification"を指定し、ラベルのマッピングを提供します。compute_metrics関数は、トレーニング中モデルのパフォーマンスを評価する方法を定義します。マルチラベルのタスクでは、F1スコア(マイクロ平均)とROC AUCなどの指標が非常に有益です。TrainingArgumentsを使用すると、学習率、バッチサイズ、エポック数などのハイパーパラメータを設定できます。Trainerオブジェクトはすべてをまとめます:モデル、引数、データセット、評価関数。trainer.train()が微調整プロセスを開始します!Trainerは、トレーニングループ、勾配更新、評価を処理します。
すべてをまとめる:予測の実行
モデルがトレーニングされたら、動作を見てみましょう。
実装
# src/predict.py
from transformers import pipeline
# 微調整済みモデルを読み込む
model_path = "best_cognitive_distortion_model"
classifier = pipeline("text-classification", model=model_path, return_all_scores=True)
# いくつかのサンプルテキストでテスト
text1 = "I can't believe I made such a stupid mistake. I'm a complete failure."
text2 = "I'm sure they are all talking about how bad my presentation was."
text3 = "This is a great achievement, but I was just lucky."
predictions1 = classifier(text1)
predictions2 = classifier(text2)
predictions3 = classifier(text3)
def display_predictions(text, predictions):
print(f"\
Text: '{text}'")
print("予測結果:")
for prediction in predictions[0]:
if prediction['score'] > 0.5: # 信頼度の高いラベルを表示
print(f" - {prediction['label']}: {prediction['score']:.4f}")
display_predictions(text1, predictions1)
display_predictions(text2, predictions2)
display_predictions(text3, predictions3)
期待される出力
Text: 'I can't believe I made such a stupid mistake. I'm a complete failure.'
Predictions:
- labeling: 0.9876
- all_or_nothing: 0.9543
- magnification_minimization: 0.8123
Text: 'I'm sure they are all talking about how bad my presentation was.'
Predictions:
- jumping_to_conclusions: 0.9912
- personalization: 0.7890
Text: 'This is a great achievement, but I was just lucky.'
Predictions:
- disqualifying_the_positive: 0.9951
セキュリティのベストプラクティス
潜在的に機密性の高いテキストデータを処理するモデルをデプロイする場合は、セキュリティが最も重要です。
- 入力検証:モデル自体がデータベースに直接接続されていない場合でも、注入攻撃を防ぐために、すべてのテキスト入力をサニタイズして検証します。
- データのプライバシー:モデルの改善のためにユーザー入力をログに記録する場合は、データが匿名化され安全に保存されていることを確認してください。データの使用方法についてユーザーに透明性を保ちます。
- モデルの整合性:保存されたモデルファイルを保護します。モデルファイルを置き換えることができる攻撃者は、任意のコードを実行する可能性があります。
本番環境へのデプロイのヒント
- コンテナ化:モデルと予測サービス(例:FastAPIを使用)をDockerコンテナにパッケージ化して 쉽くと再現可能なデプロイを実現します。
- モデル提供:TorchServeなどの専用のモデル提供ツールを使用するか、スケーラブルな推論のためにAWS LambdaやGoogle Cloud Runなどのサーバーレスペインフォームにデプロイします。
- 最適化:高スループットのアプリケーションでは、量子化やONNXランタイムなどの手法を検討して、推論を高速化します。
結論
テキスト内の認知的誤謬を識別してタグ付けするためにDistilBERTモデルを正常に微調整しました。メンタルヘルス分野でのより高度なNLPアプリケーションを構築するための確かな基盤をお持ちになりました。このプロジェクトは、大規模で汎用的なモデルを取り、Highly specificで価値のあるタスクに適応させる転移学習の力を実証しています。
次のステップ:
- データセットの拡張:最も大きな改善は、より大規模でニュアンスのあるデータセットから得られます。
- 他のモデルの実験:RoBERTaやMobileBERTなどの小さなモデルなど、他のモデルの微調整を試み、ユースケースに対するパフォーマンスと速度のトレードオフを確認してください。
- ユーザーインターフェースの構築:StreamlitやFlaskを使用して簡単なWebアプリを作成し、ユーザーがモデルと対話できるようにします。
参考資料
- 公式Hugging Faceドキュメント:transformers、datasets
- DistilBERT論文:DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter
クイックリファレンス
| 側面 | 主要情報 |
|---|---|
| トピック | 開発 |
| 関連性 | 患者教育と意識向上 |
| アクション | 医療提供者と相談してください |
| 頻度 | ケアチーム推奨通り |
| エビデンス | 現在の臨床ガイドラインに基づく |
よくある質問
Q: これが自分に該当するにはどのようにすればよいですか? A: 個人的な病歴と家族歴について医療提供者と相談し、個人的なリスク要因を評価し、適切な次のステップを決定してください。
Q: 医師に何を尋ねればよいですか? A: 良い質問には次のようなものがあります:「私の結果の意味は何ですか?」「私のオプションは何ですか?」「どのようなライフスチャンジが役に立ちますか?」「いつフォローアップすべきですか?」
Q: 役に立ちうるライフスチャンジはありますか? A: ほとんどの健康状態は、基本的な措置から恩恵を受けます:バランスの取れた栄養、定期的な身体活動(週150分以上)、質の良い睡眠(7〜9時間)、ストレス管理、タバコの回避。
医学的免責事項
この記事は教育目的のみを目的としており、医学的助言を構成しません。あなたの健康、治療、またはケアに関する決定する前に、常に資格のある医療提供者と相談してください。個々の状況は異なり、1人に適切なものが別の人に適切であるとは限りません。
医学的緊急事態が発生した場合は、直ちに911(または現地の緊急番号)に電話してください。