コードを書けなくても自然言語処理はしたい
「Pythonはよくわからないけど自然言語処理はしたい」と思い、昨年冬に試したのが以下サイトのコードです。
しかし、コピペしただけではうまく動かず、エラーメッセージが出て先に進めず終わってました。
「ChatGPT」で解決。やはりPythonの基礎知識不足でつまづいていました。
余分な空白があります
「Google Colaboratory」を使います。
動作環境はMacのM1チップ搭載機の「Chrome」です。
最初に試した日本語モデル予測ではまず、
形態素解析のためにJUMAN++をインストール
します。
ここでは、コピペの際に余分なスペースが入ったためか、エラーが出ました。
改行をエスケープするなどの対処が必要でした。
以下コードでインストールできました。
このエラーは、行末のバックスラッシュの後ろに余分な空白があるため、次の行がインデントされてしまい、コマンドの構文が壊れていることを示しています。
以下のように、各行の末尾の空白を削除することで、問題を解決できます。
!wget https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc2/jumanpp-2.0.0-rc2.tar.xz \
&& tar xJvf jumanpp-2.0.0-rc2.tar.xz \
&& rm jumanpp-2.0.0-rc2.tar.xz \
&& cd jumanpp-2.0.0-rc2/ \
&& mkdir bld \
&& cd bld \
&& cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
&& make \
&& sudo make install
OSモジュールを使う必要があります
次にGoogle Driveをマウントし、作成したフォルダに学習モデルを格納するのですが、ルートに配置される状態が続きました。
これも「ChatGPT」で解決しました。
cd
はシェルコマンドであり、Pythonのコマンドではありません。代わりにPythonでカレントディレクトリを変更するには、 os
モジュールを使う必要があります。具体的には、次のように書くことができます。
import os
os.chdir('/content/drive/My Drive/bert/japan_test')
指定された比率でデータを分割します
コードの内容も整理して説明してくれます。
とりあえずコードを動かせるようにし、後から「ChatGPT」に説明してもらいながら、別のデータに流用しようと考えています。
train, valid_test = train_test_split(df, test_size=0.2, shuffle=True, random_state=123, stratify=df[categories])
はどういう処理でしょうか。
このコードは、与えられたデータフレーム(df
)をトレーニング用と検証用に分割するためのコードです。具体的には、train_test_split
関数を使用して、指定された比率でデータを分割しています。
train_test_split
関数のパラメーターには、以下があります。
test_size
:テスト用データの割合を指定します。デフォルトは0.25です。shuffle
:Trueに設定すると、データをシャッフルします。デフォルトはTrueです。random_state
:シード値を設定します。これにより、同じシード値を使用する場合、ランダムに選択されたサンプルが同じになります。stratify
:指定されたカテゴリ列に従って層化サンプリングします。これにより、サンプルがランダムに選択された場合と比較して、カテゴリごとに均等に分布するようになります。
train_test_split
関数は、トレーニング用と検証用の2つのデータフレームを返します。このコードでは、トレーニング用と検証用のデータフレームを train
と valid_test
にそれぞれ代入しています。ただし、valid_test
に代入されるのは、元のデータフレームから取り出されたテスト用データです。
コードの実行結果です。
# JUMAN++によって品詞分解
text = "私は毎朝6時に起きて、*と散歩しています。"
result = jumanpp.analysis(text)
tokenized_text = [mrph.midasi for mrph in result.mrph_list()]
print(tokenized_text)
['私', 'は', '毎朝', '6', '時', 'に', '起きて', '、', '*', 'と', '散歩', 'して', 'い', 'ます', '。']
# 文章の区切れやマスクする部分をBERTに明示的に知らせるために、SEPやMASKを挿入
tokenized_text.insert(0, '[CLS]')
tokenized_text.append('[SEP]')
masked_index = 9
tokenized_text[masked_index] = '[MASK]'
print(tokenized_text)
['[CLS]', '私', 'は', '毎朝', '6', '時', 'に', '起きて', '、', '[MASK]', 'と', '散歩', 'して', 'い', 'ます', '。', '[SEP]']
# 得られたテキストをBERT用に変換
tokens = bert_tokenizer.convert_tokens_to_ids(tokenized_text)
tokens_tensor = torch.tensor([tokens])
# マスクされた部分の予測を実施
model.eval()
with torch.no_grad():
outputs = model(tokens_tensor)
predictions = outputs[0]
_,predicted_indexes = torch.topk(predictions[0, masked_index], k=10)
predicted_tokens = bert_tokenizer.convert_ids_to_tokens(predicted_indexes.tolist())
print(predicted_tokens)
['私', '犬', 'あなた', '[UNK]', '君', '友人', '母', '彼', '僕', '人']
コードを書けなくても記事のカテゴリ分類をしたい
2つ目の記事では、公開データであるlivedoorニュースコーパスを用いて文章分類を行います。
9種類のカテゴリが割り振られており、この分類をBERTで行うモデルを構築します。
こちらも、「Python」の基本がわかっていればもっと早く解決できていました。
「ニュースデータの読み込み」、「学習データ、検証データ、評価データに分割」、「transformersライブラリのインストール」、「モデルの学習」と「評価に必要なライブラリのインポート」はエラーでずに実行できました。
データセットの定義では、エラーが表示され、「ChatGPT」に1行追加してもらうことで対処できました。
# Datasetの定義
class NewsDataset(Dataset):
def init(self, X, y, tokenizer, max_len):
self.X = X
self.y = y
(略)
以下メッセージが出ます。
NameError Traceback (most recent call last)
in ()
1 # Datasetの定義
—-> 2 class NewsDataset(Dataset):
3 def init(self, X, y, tokenizer, max_len):
4 self.X = X
5 self.y = y
NameError: name ‘Dataset’ is not defined
このエラーは、torch.utils.data.Dataset
がインポートされていないことが原因です。 torch.utils.data.Dataset
をインポートすることで、このエラーを修正できます。以下のように先頭に追加してみてください。
from torch.utils.data import Dataset
インポートすることで解決できます
tokenizerの取得のコードも同様に解決です。
「インポートの宣言」、という基本を知っていれば気づく設定でした。
tokenizerの取得
tokenizer = AutoTokenizer.from_pretrained(pretrained)
の部分で以下メッセージが出ました。
NameError Traceback (most recent call last)
in ()
3
4 # tokenizerの取得
—-> 5 tokenizer = AutoTokenizer.from_pretrained(pretrained)
6
7 # Datasetの作成
NameError: name ‘AutoTokenizer’ is not defined
AutoTokenizer
が定義されていないためエラーが出ています。 transformers
ライブラリから AutoTokenizer
をインポートすることで解決できます。
from transformers import AutoTokenizer
# tokenizerの取得
tokenizer = AutoTokenizer.from_pretrained(pretrained)
同様の対処で次々と解決できました。
・・・をコードに追加する必要があります
以下のメッセージの意味がわかりますか。
(略)
—> 29 ‘ids’: torch.LongTensor(ids),
30 ‘mask’: torch.LongTensor(mask),
31 ‘labels’: torch.Tensor(self.y[index])
NameError: name ‘torch’ is not defined
torch
ライブラリがインポートされていないため、エラーが発生しているようです。import torch
を実行してから再度試してみてください。
以下のメッセージの意味もわかりますか。
(略)
3 def init(self, pretrained, drop_rate, otuput_size):
4 super().init()
—-> 5 self.bert = AutoModel.from_pretrained(pretrained)
6 self.drop = torch.nn.Dropout(drop_rate)
7 self.fc = torch.nn.Linear(768, otuput_size) # BERTの出力に合わせて768次元を指定
NameError: name ‘AutoModel’ is not defined
このエラーメッセージは、AutoModelが未定義であるため、BERTClassの定義が失敗したことを示しています。これは、transformersライブラリから必要なクラスをインポートすることができていないことを意味しています。AutoModelをインポートするために、from transformers import AutoModelをコードに追加する必要があります。
以下のメッセージはどうですか。
(略)
—> 20 device = ‘cuda’ if cuda.is_available() else ‘cpu’
21
22 # モデルの学習
NameError: name ‘cuda’ is not defined
このエラーメッセージは、cuda
が定義されていないため、cuda.is_available()
を呼び出すことができないという意味です。cuda
は、NVIDIA GPUを使った計算を行うためのライブラリです。可能であれば、PyTorchのTensorやモデルパラメータをGPU上で計算することで、演算速度を向上させることができます。cuda
が使用できるかどうかを確認するためには、PyTorchの torch.cuda.is_available()
関数を使用します。エラーメッセージが表示された場合は、import torch
の行の下に import torch.cuda as cuda
を追加することで、cuda.is_available()
関数を使用できるようになります。
以下はどうですか。
—> 36 dataloader_train = DataLoader(dataset_train, batch_size=batch_size, shuffle=True)
37 dataloader_valid = DataLoader(dataset_valid, batch_size=len(dataset_valid), shuffle=False)
38
NameError: name ‘DataLoader’ is not defined
NameError
は、指定された名前が現在のスコープ内で定義されていないことを示します。この場合、DataLoader
という名前が定義されていないことを示しています。このエラーが発生する可能性がある原因は、torch.utils.data.DataLoader
がインポートされていないことが挙げられます。DataLoader
を使用するためには、from torch.utils.data import DataLoader
を追加する必要があります
以下も教えてくれますか。
—> 44 s_time = time.time()
NameError: name ‘time’ is not defined
このエラーメッセージは、コードの中で time
モジュールがインポートされていないために生じています。import time
をコードの冒頭に追加して、問題を解決してください。
今度は以下のメッセージが出ました。
—-> 3 fig, ax = plt.subplots(1, 2, figsize=(15, 5))
4 ax[0].plot(x_axis, np.array(log[‘train’]).T[0], label=’train’)
5 ax[0].plot(x_axis, np.array(log[‘valid’]).T[0], label=’valid’)
NameError: name ‘plt’ is not defined
このエラーは、plt
が定義されていないことを示しています。plt
はmatplotlibのライブラリで、データの可視化に使われます。解決するには、以下のようにコードの先頭にimport matplotlib.pyplot as plt
を追加してください。
以下のメッセージも出ました。
—-> 7 ax[0].plot(x_axis, np.array(log[‘train’]).T[0], label=’train’)
8 ax[0].plot(x_axis, np.array(log[‘valid’]).T[0], label=’valid’)
9 ax[0].set_xlabel(‘epoch’)
NameError: name ‘np’ is not defined
このエラーメッセージは、NumPyライブラリが読み込まれていないため、npという名前が定義されていないことを示しています。NumPyを読み込む必要があるので、次のようにコードを追加してください。
import numpy as np
これにより、NumPyライブラリが読み込まれ、npが定義されるようになります。
結果、参考にした記事同様に、評価データで約90%の精度を得ることができました。
# 正解率の算出
dataloader_train = DataLoader(dataset_train, batch_size=1, shuffle=False)
dataloader_valid = DataLoader(dataset_valid, batch_size=1, shuffle=False)
dataloader_test = DataLoader(dataset_test, batch_size=1, shuffle=False)
print(f'正解率(学習データ):{calculate_loss_and_accuracy(model, dataloader_train, device)[1]:.3f}')
print(f'正解率(検証データ):{calculate_loss_and_accuracy(model, dataloader_valid, device)[1]:.3f}')
print(f'正解率(評価データ):{calculate_loss_and_accuracy(model, dataloader_test, device)[1]:.3f}')
正解率(学習データ):0.989
正解率(検証データ):0.898
正解率(評価データ):0.898