NeMo Curator は、日本のソブリン LLM の構築や更新のためのデータセットを準備するために、最近、日本語をサポートする多言語ドメイン分類器をリリースしました。ドメイン固有の LLM を構築している LLM グループが 5 つ以上あり、このチュートリアルは研究者やエンジニアの方に初歩的なガイダンスをご紹介します。
金融や医療大規模言語 GPT モデルをトレーニングするためには、領域分類モデルが必要になります。領域分類モデルは、以下の点で重要な役割を果たします。
- 膨大なテキストデータの整理と分析
インターネット、ソーシャル メディア、企業の内部文書、学術論文など、さまざまなソースからテキスト データが急増しています。これらのデータを手動で分析するのは非常に時間がかかります。テキスト領域分類モデルは、大量のテキスト データを自動的に分類し、重要な情報を迅速に抽出する手助けをします。 - 情報の検索とフィルタリングの効率化
テキスト領域分類モデルを使うことで、ユーザーは特定のトピックやカテゴリに関連する情報を効率的に検索できます。例えば、ニュース記事を「スポーツ」「政治」「エンタメ」などのカテゴリに分類することによって、関心のある領域の記事を簡単にフィルタリングできます。 - 感情分析や意図推測の支援
テキスト領域分類モデルは、単にトピックやカテゴリを分けるだけでなく、テキストの感情 (ポジティブ、ネガティブ、ニュートラル) や意図 (質問、苦情、提案) を分類することにも利用されます。これにより、企業は顧客のフィードバックを自動的に分析し、顧客満足度の向上に役立てることができます。 - 自動化による効率化
手作業でのテキスト分類は非常に時間と労力がかかりますが、テキスト領域分類モデルはそのプロセスを自動化し、大規模なデータセットでも効率的に分類が行えます。例えば、スパム メールを自動的に振り分けたり、大量の顧客レビューをポジティブあるいはネガティブに分類したりできます。 - 品質向上とエラー削減
人間による分類作業にはミスが伴うことがありますが、テキスト領域分類モデルは一貫性を持って正確に分類を行います。これにより、分類作業の品質が向上し、エラーを減らすことができます。 - マーケティングやターゲティング戦略の強化
テキスト領域分類を使って、消費者の意見やニーズ、傾向を分類することで、マーケティング戦略を改善することができます。例えば、製品レビューを分析し、特定の製品に対する消費者の感情を把握したり、特定の属性に基づいてターゲット層をセグメント化したりできます。 - 多言語対応
テキスト領域分類モデルは、複数の言語に対応できる場合があります。これにより、異なる言語で書かれたテキストを自動的に分類し、国際的なデータを効率的に分析することができます。 - 検索エンジンやコンテンツ推薦システムの強化
テキスト領域分類モデルは、検索エンジンやコンテンツ推薦システムに組み込まれることが多いです。例えば、ユーザーが興味を持ちそうなコンテンツを予測して推薦したり、検索結果をユーザーの意図に合った形で提供したりするために、テキスト分類が活用されます。 - 法務やコンプライアンスの支援
企業や組織では、大量の契約書や規制文書、法的文書を取り扱っています。テキスト領域分類モデルを使用することで、これらの文書を迅速に分類し、リスクのある文書や重要な契約条件を特定することができます。
モデルの概要
このモデルは、ドキュメントを以下のような 27 のドメイン クラスのいずれかに分類するテキスト分類モデルです:
「アダルト」、「芸術と娯楽」、「自動車と乗り物」、「美容とフィットネス」、「書籍と文学」、「ビジネスと工業」、「コンピューターと電子機器」、「金融」、「食品と飲料」、「ゲーム」、「健康」、「趣味とレジャー」、「家庭と園芸」、「インターネットと通信」、「仕事と教育」、「法律と政府」、「ニュース」、「オンライン コミュニティ」、「人々と社会」、「ペットと動物」、 「不動産」、「科学」、「センシティブな主題」、「ショッピング」、「スポーツ」、「旅行と交通」
モデル アーキテクチャ
モデル アーキテクチャは Deberta V3 ベースに基づいて構築しました。コンテキストの長さは 512 トークンです。
モデルのトレーニングの詳細
- トレーニング データ: Google Cloud の Natural Language API を使用してラベル付けされた 100 万件の Common Crawl サンプル
- Wikipedia-API を使用してキュレートされた 50 万件の Wikepedia 記事
トレーニング手順
モデルは、疑似ラベルと Google Cloud API の組み合わせによってラベル付けされた Wikipedia と Common Crawl データを使用して複数ラウンド (Multiple Rounds) でトレーニングしました。詳細は「DeBERTa」をご参照ください。また以下の関連情報を参考にしてください。
- DeBERTa で DeepSpeed を使用して大規模モデルのトレーニングを高速化する方法に関するブログ
- DeBERTa を使用した機械学習によるカスタマー サービスの強化に関するブログ
- Deberta For Sequence Classification は、こちらのサンプル スクリプトとノートブックでサポートされています。
- TFDeberta For Sequence Classification は、こちらのサンプル スクリプトとノートブックでサポートされています。
- テキスト分類タスク ガイド
モデルの使い方
1. パッケージのインストールと導入
まず、transformers パッケージのインストールを実行します。
# need this version's transformers
!pip install transformers==4.33.3
次に、いくつかのパッケージを導入します。
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION']='python'
import gc
import json
import time
import math
import string
import pickle
import random
import warnings
import matplotlib.pyplot as plt
from pylab import rcParams
import scipy as sp
import numpy as np
import pandas as pd
from tqdm import tqdm
import torch
import torch.nn as nn
from torch.nn import Parameter
import torch.nn.functional as F
from torch.optim import Adam, SGD, AdamW
from torch.utils.data import DataLoader, Dataset
import torch.optim as optim
import tokenizers
import transformers
print(f"tokenizers.__version__: {tokenizers.__version__}")
print(f"transformers.__version__: {transformers.__version__}")
from transformers import AutoTokenizer, AutoModel, AutoConfig
from transformers import get_linear_schedule_with_warmup, get_cosine_schedule_with_warmup
%env TOKENIZERS_PARALLELISM=false
os.environ["TOKENIZERS_PARALLELISM"] = "false"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
import warnings
warnings.filterwarnings("ignore")
2. モデルの名前の指定
モデルの名前 (パス) を指定します。それとともに、目標ドメイン分類の 27 種類のセットも指定します。
model_path = 'https://huggingface.co/nvidia/multilingual-domain-classifier'
batch_size = 64
num_workers = 16
max_chars = 2000
out_dim = 27
class CFG:
model="microsoft/mdeberta-v3-base"
fc_dropout=0.2
max_len = 512
labels = ['Adult', 'Arts_and_Entertainment', 'Autos_and_Vehicles', 'Beauty_and_Fitness', 'Books_and_Literature', 'Business_and_Industrial', 'Computers_and_Electronics', 'Finance', 'Food_and_Drink', 'Games', 'Health', 'Hobbies_and_Leisure', 'Home_and_Garden', 'Internet_and_Telecom', 'Jobs_and_Education', 'Law_and_Government', 'News', 'Online_Communities', 'People_and_Society', 'Pets_and_Animals', 'Real_Estate', 'Reference', 'Science', 'Sensitive_Subjects', 'Shopping', 'Sports', 'Travel_and_Transportation']
3. データセットのクラスの定義
配置パラメーターに基づいて、モデルの入力テキストを処理するためのクラスを準備します。
from transformers.models.deberta_v2 import DebertaV2TokenizerFast
tokenizer = DebertaV2TokenizerFast.from_pretrained(CFG.model)
CFG.tokenizer = tokenizer
def prepare_input(cfg, text):
inputs = cfg.tokenizer.encode_plus(
text,
return_tensors=None,
add_special_tokens=True,
max_length=CFG.max_len,
pad_to_max_length=True,
truncation=True
)
for k, v in inputs.items():
inputs[k] = torch.tensor(v, dtype=torch.long)
return inputs
class TrainDataset(Dataset):
def __init__(self, cfg, df):
self.cfg = cfg
self.text = df['text'].values
self.labels = df[labels].values
def __len__(self):
return len(self.text)
def __getitem__(self, item):
text = self.text[item][:max_chars]
inputs = prepare_input(self.cfg, text)
label = self.labels[item]
label = torch.tensor(label, dtype=torch.float)
return {'input_ids' : inputs['input_ids'],
'attention_mask' : inputs['attention_mask'],
'labels' : label}
def collate(inputs):
mask_len = int(inputs["attention_mask"].sum(axis=1).max())
for k, v in inputs.items():
# CPMP: no need to truncate labels
if k != 'labels':
inputs[k] = inputs[k][:,:mask_len]
return inputs
4. 分類モデルの定義
ドメイン分類に特化したモデル CustomModel クラスを定義します。
class CustomModel(nn.Module):
def __init__(self, cfg, config_path=None, pretrained=False):
super().__init__()
self.cfg = cfg
if config_path is None:
self.config = AutoConfig.from_pretrained(cfg.model, output_hidden_states=True)
else:
self.config = torch.load(config_path)
if pretrained:
self.model = AutoModel.from_pretrained(cfg.model, config=self.config)
else:
self.model = AutoModel(self.config)
self.fc_dropout = nn.Dropout(cfg.fc_dropout)
self.fc = nn.Linear(self.config.hidden_size, out_dim)
self._init_weights(self.fc)
def _init_weights(self, module):
if isinstance(module, nn.Linear):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.bias is not None:
module.bias.data.zero_()
elif isinstance(module, nn.Embedding):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.padding_idx is not None:
module.weight.data[module.padding_idx].zero_()
elif isinstance(module, nn.LayerNorm):
module.bias.data.zero_()
module.weight.data.fill_(1.0)
def feature(self, input_ids, attention_mask):
outputs = self.model(input_ids=input_ids, attention_mask=attention_mask)
last_hidden_states = outputs[0]
return last_hidden_states
def forward(self, batch):
feature = self.feature(batch['input_ids'], batch['attention_mask'])
output = self.fc(self.fc_dropout(feature))
return output
5. テストセットの定義
テスト データセットのクラスを定義します。
class TestDataset(Dataset):
def __init__(self, cfg, df):
self.cfg = cfg
self.text = df['text'].values
def __len__(self):
return len(self.text)
def __getitem__(self, item):
text = self.text[item][:max_chars]
inputs = prepare_input(self.cfg, text)
return {'input_ids' : inputs['input_ids'],
'attention_mask' : inputs['attention_mask']}
6. モデルの初期化
モデルを初期化して、GPU メモリにロードします。
model = CustomModel(CFG, config_path=None, pretrained=True)
model = model.to(device)
sd = torch.load(os.path.join(model_path), map_location='cpu')
sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}
model.load_state_dict(sd, strict=True)
7. 例文の用意
ドメイン分類のための入力テキスト例文を用意します。
docs = ['''
主体としての自己はあらゆる行動や思考の原点であるが、客体的な自己は物質的自己、精神的自己、社会的自己の3つから構成される。カレン・ホーナイは「自己」を現実にいる人間の心理的かつ身体的な総体としての現実的自己、さらに潜在的な可能性を持つ実在的自己、さらに理想化された自己の3つに分けており、神経症が理想化された自己によって実在的自己を見失った状態であると考える。
人間にとって自己は成長とともに獲得するものである。社会心理学の自己過程論によれば、幼児期においては自己意識は持たないが、鏡に映し出された自身の姿などを知覚することによる自覚事態、自分という存在の概念化による自己概念の獲得、自己概念の評価的側面である自尊心の獲得、そして自己の存在を他者に示す自己開示や自己呈示の実施などを経て自己を段階的に発展させる。
自己の内容は複雑であり、内省を行ったとしても行動や感情の理由がわからない場合もある。これは内省の合理性や論理性、また内省によって動員される経験的知識や文化的背景が思考に強く影響するために因果関係が正確とは限らないためである。ベムの自己知覚理論は自分のことは自分がもっともよく知っているとする常識を否定し、自己の知覚と他者の知覚は基本的に変わらないことを示した理論である。
言語面からの「自己 (self)」の研究も進んでおり、認知言語学とその隣接諸科学の複合的観点から、言語面に見るselfの正体を明らかにしている。
'''
,
'''
津波(つなみ、英語: Tsunami)は、地震や火山活動、山体崩壊に起因する海底・海岸地形の自然環境の急変により、海洋に生じる大規模な波の伝播現象である。まれに隕石衝突が原因となったり、湖で発生したりすることもある。なお、津波(tsunami)は通常は地殻変動要因の現象を指し、気象要因の現象、特にプラウドマン共鳴により増幅された海洋長波は気象津波として区別する[1]。
1波1波の間隔である波長が非常に長く、波高が巨大になりやすいことが特徴である。地震による津波では波長600 km、波高5 m超のものが生じた事がある(津波が陸上に達するとこの値は大きく変わる)[2]。
津波という現象は、例えるならば大量の海水による洪水の様な現象[3]であり、気象など他の要因で生じる波とは性質が大きく異なる。大きな津波は浮遊物と共に陸深くに浸入し、沿岸住民の水死や市街・村落の破壊など、種々の災害を発生させる。
''',
'''
最年少受賞者はエイドリアン・ブロディの29歳、最年少候補者はジャッキー・クーパーの9歳。最年長受賞者、最年長候補者は、アンソニー・ホプキンスの83歳。
最多受賞者は3回受賞のダニエル・デイ=ルイス。2回受賞経験者はスペンサー・トレイシー、フレドリック・マーチ、ゲイリー・クーパー、ダスティン・ホフマン、トム・ハンクス、ジャック・ニコルソン(助演男優賞も1回受賞している)、ショーン・ペン、アンソニー・ホプキンスの8人。なお、マーロン・ブランドも2度受賞したが、2度目の受賞を拒否している。最多候補者はスペンサー・トレイシー、ローレンス・オリヴィエの9回。
死後に受賞したのはピーター・フィンチが唯一。ほか、ジェームズ・ディーン、スペンサー・トレイシー、マッシモ・トロイージ、チャドウィック・ボーズマンが死後にノミネートされ、うち2回死後にノミネートされたのはディーンのみである。
非白人(黒人)で初めて受賞したのはシドニー・ポワチエであり、英語以外の演技で受賞したのはロベルト・ベニーニである。
''',
]
#len(docs) = 3
8. モデルで予測する
検証用データセットを導入して、次々にモデルに送って、予測を行います。
df = pd.DataFrame({'text':docs})
dataset_valid = TestDataset(CFG, df)
loader_valid = torch.utils.data.DataLoader(dataset_valid, batch_size=batch_size, shuffle=False, num_workers=num_workers)
model.eval()
LOGITS = []
with torch.no_grad():
for batch in tqdm(loader_valid):
inputs = collate(batch)
for k, v in inputs.items():
inputs[k] = v.to(device)
out = model(inputs)[:,0,:]
LOGITS.append(out.detach().cpu())
PROBS = torch.sigmoid(torch.cat(LOGITS)).numpy()
preds = [labels[i] for i in PROBS.argmax(1)]
print(preds)
9. 予測の日本語レベルへの変換
モデルの予測の出力は以下のとおりです。
['People_and_Society', 'Sensitive_Subjects', 'Arts_and_Entertainment']
もちろん、以下の辞書を用いて、英語レベルから簡単に日本語レベルへ変更することも可能です。
en2jpdict={'Adult': 'アダルト', 'Arts_and_Entertainment': '芸術と娯楽', 'Autos_and_Vehicles': '自動車と乗り物', 'Beauty_and_Fitness': '美容とフィットネス', 'Books_and_Literature': '書籍と文学', 'Business_and_Industrial': 'ビジネスと工業', 'Computers_and_Electronics': 'コンピュータと電子機器', 'Finance': '金融', 'Food_and_Drink': '食品と飲料', 'Games': 'ゲーム', 'Health': '健康', 'Hobbies_and_Leisure': '趣味とレジャー', 'Home_and_Garden': '家庭と園芸', 'Internet_and_Telecom': 'インターネットと通信', 'Jobs_and_Education': '仕事と教育', 'Law_and_Government': '法律と政府', 'News': 'ニュース', 'Online_Communities': 'オンラインコミュニティ', 'People_and_Society': '人々と社会', 'Pets_and_Animals': 'ペットと動物', 'Real_Estate': '不動産', 'Reference': '参考文献', 'Science': '科学', 'Sensitive_Subjects': 'デリケートな主題', 'Shopping': 'ショッピング', 'Sports': 'スポーツ', 'Travel_and_Transportation': '旅行と交通'}
jppreds = [en2jpdict[enlabel] for enlabel in preds]
print(jppreds)
出力は以下のとおりです。
['人々と社会', 'デリケートな主題', '芸術と娯楽']
まとめ
テキスト領域分類モデルは、膨大な量のテキスト データを効率的に処理し、分析し、意思決定をサポートするために不可欠なツールです。これにより、企業や組織はデータに基づいたインサイトを迅速に得ることができ、領域 ChatGPT の開発に伴い、業務の効率化や質の向上、顧客満足度の向上など、さまざまな利点を享受できます。
関連情報
- SDK: NVIDIA NeMo
- 技術ブログ: NeMo Curator を使った日本語データのキュレーション
- ソリューション概要: NVIDIA NeMo 概要
- 動画: 生成 AI モデルの開発と展開のための NVIDIA NeMo フレームワーク