ChatGPTに相談しました
「BERT」を試したいと思っていました。
「BERT」は自然言語処理モデルの一つで、2018年にGoogleが発表した論文で登場しました。
しかし、自分は「Python」を使う際、何かを見ないとデータフレームを作るコードも書けないレベルです。
「ChatGPT」に相談しました。
Attention is All you need. このタイトルの論文のことを教えてくれますか。
「Attention Is All You Need」とは、2017年にGoogle Brainチームによって発表された、自然言語処理タスクにおけるニューラルネットワークの新しいアーキテクチャである「Transformer」を提案した論文のタイトルです。
この論文では、従来のリカレントニューラルネットワーク(RNN)や畳み込みニューラルネットワーク(CNN)に代わる新しいアーキテクチャとして、Transformerを提案しています。Transformerは、Attention機構を利用することで、従来のモデルよりも高速で並列化が容易なモデルとなっています。
(以下略)
Transformerを使った「BERT」とは何でしょう。
「BERT(Bidirectional Encoder Representations from Transformers)」は、Transformerアーキテクチャを使用した自然言語処理モデルの一つであり、2018年にGoogleが発表した論文で提案されました。
(中略)
BERTは、事前学習においてMasked Language Model(MLM)とNext Sentence Prediction(NSP)の2つのタスクを用いて学習を行います。MLMでは、文中の一部の単語をマスクし、その単語を予測することで単語の文脈的な表現を学習します。NSPでは、2つの文が与えられた場合に、それらが文書内の連続した文かどうかを予測することで、文の関係性を学習します。
BERTは、テキスト分類、文書生成、質問応答などの自然言語処理タスクに幅広く使用されています。
Google CollabでBERTを試したいです
先に言っておくと、分類精度は80%に届かずに終わっています。
フローの確認と精度向上は今後の課題です。
BERTっぽいフローが動かせたので、今回は次につなげるためのメモです。
Google ColaboratoryでBERTを試したいです。
Google Colabは、クラウド上でJupyter Notebookを実行できるサービスです。BERTを試すには、Google Colabを使用することができます。以下の手順に従って、BERTをColabで実行することができます。
- Google Colabにアクセスします。
- 「新しいノートブックを作成」をクリックして、新しいノートブックを作成します。
- ランタイムをGPUに設定します。メニューの「ランタイム」->「ランタイムのタイプを変更」からGPUを選択します。
- 必要なパッケージをインストールします。以下のコードをノートブックの最初のセルに入力して実行します。
!pip install torch
!pip install transformers
5.必要なパッケージをインストールします。
以下のコードをノートブックの最初のセルに入力して実行します。
from transformers import BertModel
model = BertModel.from_pretrained('bert-base-uncased')
テストに使えるデータはありますか
テスト用に日本語で使えるテキストデータはありますか。
BERTは元々英語の自然言語処理タスクにおいて訓練されたモデルですが、日本語にも適用することができます。日本語のテキストデータを用いてBERTを試すことができます。以下は、日本語のテキストデータを収集できるオープンソースのデータセットの例です。
(以下略)
データセットをいくつか教えてもらいましたが、リンク先が「404」などデータが入手できませんでした。
聞き方を変えました。
livedoorコーパスは使えませんか。
はい、livedoorコーパスはBERTの日本語テキストデータセットとして非常によく使用されています。livedoorコーパスは、日本のポータルサイト「livedoor」が公開した、ニュース記事のテキストデータが含まれるデータセットです。各記事には、ニュースのカテゴリ、タイトル、本文が含まれています。
livedoorコーパスは、以下のリンクから入手できます。 https://www.rondhuit.com/download.html#ldcc
livedoorコーパスは、テキスト分類、テキスト生成などの自然言語処理タスクのためのトレーニング用データセットとして広く使用されています。BERTを含む多くの日本語自然言語処理モデルのトレーニングにも使用されています。また、livedoorコーパスのデータフォーマットは、一般的な日本語のテキストフォーマットとして使用されることも多いため、BERTのテストにも適しています。
テストコードを教えてくれますか
ありがとうございます。 Google Collabでlivedoorコーパスを使い、テストするコードを教えてくれますか。
はい、Google Colabを使用して、livedoorコーパスを使ってBERTのテストを行うための基本的な手順を以下に示します。
- livedoorコーパスのダウンロード livedoorコーパスをダウンロードしてGoogle Colabの環境にアップロードします。
- 必要なライブラリのインストール BERTのテストに必要なライブラリをインストールします。
- livedoorコーパスの読み込み livedoorコーパスを読み込み、トレーニングデータとテストデータに分割します。
- BERTモデルの準備 事前学習済みの日本語BERTモデルを読み込みます。
- テキストデータの前処理 BERTモデルに入力するために、テキストデータを前処理します。
(各項目ごとに教えてもらったコードは以下)
教えてもらったコードが以下です。
# livedoorコーパスのダウンロード
!wget https://www.rondhuit.com/download/ldcc-20140209.tar.gz
!tar -zxvf ldcc-20140209.tar.gz
# 必要なライブラリのインストール
!pip install transformers
!pip install sentencepiece
# livedoorコーパスの読み込み
import os
import glob
# livedoorコーパスのフォルダ名
ldcc_dir = "text/"
categories = [
"dokujo-tsushin",
"it-life-hack",
"kaden-channel",
"livedoor-homme",
"movie-enter",
"peachy",
"smax",
"sports-watch",
"topic-news"
]
# テキストを格納する配列
texts = []
labels = []
# カテゴリごとにテキストを読み込む
for category_id, category in enumerate(categories):
files = glob.glob(os.path.join(ldcc_dir, category, "*.txt"))
for file in files:
with open(file, "r", encoding="utf-8") as f:
text = f.read()
texts.append(text)
labels.append(category_id)
# データをトレーニング用とテスト用に分割
from sklearn.model_selection import train_test_split
train_texts, test_texts, train_labels, test_labels = train_test_split(texts, labels, test_size=0.2, random_state=42)
print("Number of training texts: ", len(train_texts))
print("Number of test texts: ", len(test_texts))
# BERTモデルの準備
from transformers import BertJapaneseTokenizer, BertForSequenceClassification
# BERT tokenizerの読み込み
tokenizer = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
# BERTモデルの読み込み
model = BertForSequenceClassification.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking', num_labels=len(categories))
# テキストデータの前処理
def preprocess_text(texts, labels, max_length):
# テキストをtokenizerで符号化
encodings = tokenizer(texts, truncation=True, padding=True, max_length=max_length)
# 符号化されたテキストをPyTorchのテンソルに変換
input_ids = torch
各手順ごとにPythonコードを教えてもらいましたが、パッケージのインストールや関数の定義をスキップされたりし、質問を重ねていたら、途中から会話の連続性が保てなくなりました。
聞き方を変えました。
まずコーパスのデータを変換してくれますか
こんにちは。
昨日はありがとうございました。
こんにちは。どういたしまして。何かご質問がありますか?
ありがとうございます。
まず、BERTに読み込ませるように、livedoorコーパスのデータを変換してくれますか。
Google Collabでを使います。
はい、LivedoorコーパスをBERTに入力するためには、テキストデータをトークナイズして、入力形式に変換する必要があります。以下は、Google Colabでの実行例です。
1.Livedoorコーパスのダウンロード
!wget https://www.rondhuit.com/download/ldcc-20140209.tar.gz
!tar -zxvf ldcc-20140209.tar.gz
2.必要なライブラリのインストール
!pip install transformers
3.前処理の関数定義
import torch
import numpy as np
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
def preprocess_text(texts, labels, max_length):
encodings = tokenizer(texts, truncation=True, padding=True, max_length=max_length)
input_ids = torch.tensor(encodings['input_ids'])
attention_masks = torch.tensor(encodings['attention_mask'])
labels = torch.tensor(labels)
return input_ids, attention_masks, labels
4.テキストデータの読み込みと前処理
import os
data_dir = 'text'
categories = os.listdir(data_dir)
max_length = 512
all_texts = []
all_labels = []
for i, cat in enumerate(categories):
cat_dir = os.path.join(data_dir, cat)
file_list = os.listdir(cat_dir)
for file_name in file_list:
file_path = os.path.join(cat_dir, file_name)
with open(file_path, 'r') as f:
text = f.read()
all_texts.append(text)
all_labels.append(i)
input_ids, attention_masks, labels = preprocess_text(all_texts, all_labels, max_length)
これで、入力データをinput_ids
とattention_masks
とlabels
の3つのテンソルに変換することができました。
入力データの内容の一部を確認したいです
コードの設定、例えば変数の定義をスキップされるなど、一部の処理が抜けることがあります。
その場合は、教えてもらったコードをペーストして確認しました。
入力データの内容の一部を確認したいです。
入力データの一部を確認するには、以下のようにコードを追加してください。
# 最初の1つのデータを表示
print('Original Text: ', train_texts[0])
print('Tokenized Text: ', tokenizer.tokenize(train_texts[0]))
print('Token IDs: ', tokenizer.convert_tokens_to_ids(tokenizer.tokenize(train_texts[0])))
print('Label: ', train_labels[0])
このコードを実行すると、最初の1つのトレーニングデータのテキスト、トークン化されたテキスト、トークンID、およびラベルが表示されます。必要に応じて、train_texts
、train_labels
、test_texts
、およびtest_labels
のインデックスを変更して、他のデータを表示することができます。
NameError: name ‘train_texts’ is not defined というエラーが出ました。
先ほど教えてもらった以下のコードでtrain_textsは生成 していますか?
import os
data_dir = ‘text’
categories = os.listdir(data_dir)
max_length = 512
all_texts = []
all_labels = []
for i, cat in enumerate(categories):
cat_dir = os.path.join(data_dir, cat)
file_list = os.listdir(cat_dir)
for file_name in file_list:
file_path = os.path.join(cat_dir, file_name)
with open(file_path, ‘r’) as f:
text = f.read()
all_texts.append(text)
all_labels.append(i)
input_ids, attention_masks, labels = preprocess_text(all_texts, all_labels, max_length)
エラーの原因は、 train_texts
を定義していないためです。 以下のように、 all_texts
を train_texts
に変更してください。
import os
data_dir = 'text'
categories = os.listdir(data_dir)
max_length = 512
train_texts = []
train_labels = []
for i, cat in enumerate(categories):
cat_dir = os.path.join(data_dir, cat)
file_list = os.listdir(cat_dir)
for file_name in file_list:
file_path = os.path.join(cat_dir, file_name)
with open(file_path, 'r') as f:
text = f.read()
train_texts.append(text)
train_labels.append(i)
input_ids, attention_masks, labels = preprocess_text(train_texts, train_labels, max_length)
入力データの内容の一部を確認できました。
# 最初の1つのデータを表示
print('Original Text: ', train_texts[0])
print('Tokenized Text: ', tokenizer.tokenize(train_texts[0]))
print('Token IDs: ', tokenizer.convert_tokens_to_ids(tokenizer.tokenize(train_texts[0])))
print('Label: ', train_labels[0])
Original Text: http://news.livedoor.com/article/detail/6491565/
2012-04-22T00:51:00+0900
西田敏行も思わず涙ぐむ「父から娘」への手紙
家族の愛を瑞々しく描いた長編アニメーション映画『ももへの手紙』が21日に公開。
(中略)
Tokenized Text: ['http', ':', '/', '/', 'news', '.', 'lived',
(中略)
Token IDs: [8299, 1024, 1013, 1013, 2739, 1012,
(中略)
train_labels の数はいくつでしょうか。
train_labels
の数は、カテゴリの数に等しいはずです。今回の場合、livedoorニュースコーパスは9つのカテゴリからなるので、train_labels
の数も9になるはずです。以下のコードで確認できます。
len(set(train_labels))
このコードを実行すると、train_labels
の数が9であることが分かります。
その通り、「9」になりました。
len(set(train_labels))
9
次にBERTを使って分類してくれますか
では次に、
上記で作成したをinput_idsとattention_masksとlabelsを使って
BERTを使った分類シミュレーションができるのでしょうか。
はい、そのようになります。入力データを準備したら、BERTを使って分類タスクを実行できます。BERTは、PyTorchやTensorFlowなどの深層学習フレームワークを使用して実装することができます。以下は、PyTorchを使用してBERT分類器を実装するための一般的な手順です。
- PyTorchとtransformersパッケージをインストールします。
- transformersパッケージからBERTの分類器モデルをロードします。
- 入力データをtransformersパッケージのtokenizerでトークン化します。
- トークン化されたデータを入力として、BERTモデルに渡して特徴量を抽出します。
- 特徴量を入力として、分類器をトレーニングし、テストします。
- トレーニングしたモデルを保存します。
これらの手順を具体的に説明することもできますが、先に進む前に、どの深層学習フレームワークを使用しているかを教えていただけますか?
input_idsとattention_masksとlabels は先ほど作成してもらいましたよね? PyTorch を使ってBERTを使った分類シミュレーションをお願いできますか。
はい、以下のコードを使用してPyTorchを使ったBERTの分類シミュレーションを行うことができます
import torch
from torch.utils.data import TensorDataset, random_split
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler
from transformers import BertTokenizer, BertForSequenceClassification, AdamW
# GPUが利用可能かどうかをチェック
if torch.cuda.is_available():
# GPUを指定
device = torch.device("cuda")
print('There are %d GPU(s) available.' % torch.cuda.device_count())
print('We will use the GPU:', torch.cuda.get_device_name(0))
else:
print('No GPU available, using the CPU instead.')
device = torch.device("cpu")
# モデルのロード
model = BertForSequenceClassification.from_pretrained(
"bert-base-uncased", # モデルの事前学習済みパラメータの名称
num_labels = len(categories), # カテゴリ数を設定
output_attentions = False, # モデルの出力にAttentionが含まれるかどうかを指定
output_hidden_states = False, # モデルの出力に隠れ状態が含まれるかどうかを指定
)
# GPUに転送
model.to(device)
# バッチサイズを設定
batch_size = 8
# データセットを作成
dataset = TensorDataset(input_ids, attention_masks, labels)
# データセットを訓練データとテストデータに分割
train_size = int(0.9 * len(dataset))
val_size = len(dataset) - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
# データローダを作成
train_dataloader = DataLoader(
train_dataset,
sampler = RandomSampler(train_dataset),
batch_size = batch_size
)
validation_dataloader = DataLoader(
val_dataset,
sampler = SequentialSampler(val_dataset),
batch_size = batch_size
)
# 最適化関数を設定
optimizer = AdamW(model.parameters(),
lr = 2e-5, # 学習率
eps = 1e-8 # 逆伝播中の数値安定性のためのパラメータ
)
# エポック数を設定
epochs = 2
# 学習
for epoch_i in range(0, epochs):
# 訓練モードに設定
model.train()
# 訓練データを使用してモデルを訓練
for step, batch in enumerate(train_dataloader):
# バッチをGPUに転送
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
# モデルにバッチを入力し、出力を取得
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
このコードを実行すると、train_labels
の数が9であることが分かります。
(追加で)結果を表示させたいです
教えてもらったコードでは、結果を出力(表示)部分がないことがわかったので、追加してもらうことにしました。
# モデルにバッチを入力し、出力を取得
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
上記の後の結果を表示できますか。
もちろんです。以下のように、 outputs
からloss
とlogits
を取得し、それぞれを表示できます。
loss = outputs.loss
logits = outputs.logits
print('Loss:', loss.item())
print('Logits:', logits)
ただし、このコードは上記のコードと一緒になるように配置する必要があります。つまり、for
ループの中にあり、各バッチに対して実行される必要があります。
「ただし、このコードは上記のコードと一緒になるように配置する必要があります。つまり、forループの中にあり、各バッチに対して実行される必要があります。」
どういう意味でしょうか。
前提として、上記のコードはバッチサイズを指定してデータをミニバッチに分割し、各バッチに対して順伝播と逆伝播を行うようになっています。
そのため、上記のコードを動作させるためには、バッチを分割する for ループの中で、各バッチの入力データと正解データを用意し、上記のコードで順伝播と逆伝播を実行する必要があります。つまり、以下のように for ループの中に上記のコードを配置する必要があります。
for step, batch in enumerate(train_dataloader):
# バッチをGPUに転送
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
# モデルにバッチを入力し、出力を取得
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
# 損失を計算し、逆伝播を実行し、勾配を更新
loss = outputs[0]
loss.backward()
optimizer.step()
optimizer.zero_grad()
# 進捗を表示
if step % 100 == 0:
print('Batch {:>5,} of {:>5,}. Loss: {:.4f}'.format(step, len(train_dataloader), loss.item()))
つまり、バッチを用意する for ループの中で、上記のコードを実行することで、各バッチに対して順伝播と逆伝播を行い、パラメータを更新することができます。
全体のコードはこうなりますか
ということは、全体のコードは以下になりますか。
for step, batch in enumerate(train_dataloader):
# バッチをGPUに転送
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
# モデルにバッチを入力し、出力を取得
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
# 損失を計算し、逆伝播を実行し、勾配を更新
loss = outputs[0]
loss.backward()
optimizer.step()
optimizer.zero_grad()
# 進捗を表示
if step % 100 == 0:
print(‘Batch {:>5,} of {:>5,}. Loss: {:.4f}’.format(step, len(train_dataloader), loss.item()))
はい、その通りです。ただし、前提として、このコードは前段階でBERTの事前学習済みモデルの読み込み、トークナイザーの定義、データの前処理などが実行されている必要があります。また、このコードは学習を行うためのもので、テストデータに対して評価を行うためのコードは別途必要となります。
実行できました。
import torch
from torch.utils.data import TensorDataset, random_split
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler
from transformers import BertTokenizer, BertForSequenceClassification, AdamW
# GPUが利用可能かどうかをチェック
if torch.cuda.is_available():
# GPUを指定
device = torch.device("cuda")
print('There are %d GPU(s) available.' % torch.cuda.device_count())
print('We will use the GPU:', torch.cuda.get_device_name(0))
else:
print('No GPU available, using the CPU instead.')
device = torch.device("cpu")
# モデルのロード
model = BertForSequenceClassification.from_pretrained(
"bert-base-uncased", # モデルの事前学習済みパラメータの名称
num_labels = len(categories), # カテゴリ数を設定
output_attentions = False, # モデルの出力にAttentionが含まれるかどうかを指定
output_hidden_states = False, # モデルの出力に隠れ状態が含まれるかどうかを指定
)
# GPUに転送
model.to(device)
# バッチサイズを設定
batch_size = 8
# データセットを作成
dataset = TensorDataset(input_ids, attention_masks, labels)
# データセットを訓練データとテストデータに分割
train_size = int(0.9 * len(dataset))
val_size = len(dataset) - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
# データローダを作成
train_dataloader = DataLoader(
train_dataset,
sampler = RandomSampler(train_dataset),
batch_size = batch_size
)
validation_dataloader = DataLoader(
val_dataset,
sampler = SequentialSampler(val_dataset),
batch_size = batch_size
)
# 最適化関数を設定
optimizer = AdamW(model.parameters(),
lr = 2e-5, # 学習率
eps = 1e-8 # 逆伝播中の数値安定性のためのパラメータ
)
# エポック数を設定
epochs = 3
# 学習。出力するコードがなかったので以下追加する(質問後1回変更)
for step, batch in enumerate(train_dataloader):
# バッチをGPUに転送
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
# モデルにバッチを入力し、出力を取得
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
# 損失を計算し、逆伝播を実行し、勾配を更新
loss = outputs[0]
loss.backward()
optimizer.step()
optimizer.zero_grad()
# 進捗を表示
if step % 100 == 0:
print('Batch {:>5,} of {:>5,}. Loss: {:.4f}'.format(step, len(train_dataloader), loss.item()))
上記コードを実行した結果が以下です。
There are 1 GPU(s) available.
We will use the GPU: Tesla T4
Some weights of the model checkpoint at bert-base-uncased were not used when initializing BertForSequenceClassification: ['cls.seq_relationship.bias', 'cls.predictions.bias', 'cls.predictions.transform.LayerNorm.weight', 'cls.predictions.transform.dense.weight', 'cls.predictions.transform.dense.bias', 'cls.seq_relationship.weight', 'cls.predictions.decoder.weight', 'cls.predictions.transform.LayerNorm.bias']
- This IS expected if you are initializing BertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
- This IS NOT expected if you are initializing BertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-uncased 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.
Batch 0 of 830. Loss: 2.3860
Batch 100 of 830. Loss: 1.7307
Batch 200 of 830. Loss: 1.3120
Batch 300 of 830. Loss: 0.9764
Batch 400 of 830. Loss: 0.6516
Batch 500 of 830. Loss: 0.7210
Batch 600 of 830. Loss: 0.9155
Batch 700 of 830. Loss: 0.8436
Batch 800 of 830. Loss: 1.0028
カテゴリ分類精度「%」を出せますか
Batch 800 of 830. Loss: 0.5027 と出力されました。
どう解釈すればいいでしょか。
この出力は、800バッチ目のトレーニング中の損失(loss)が0.5027であることを示しています。一般的に、損失が小さいほど、トレーニングが正確に行われていると言えます。ただし、損失が小さくても、過学習(overfitting)が発生している可能性があるため、慎重に評価する必要があります。
先ほど教えてもらったコードを実行済みです。出力の中からカテゴリ分類精度を「%」で出せますか?
すみません、先程は分類精度を出すためのコードを書き忘れてしまいました。以下のように、テストデータを用いて分類精度を求めるコードを追加してから再度実行してください。
# テストデータを用いてモデルの評価を行う
model.eval()
eval_loss, eval_accuracy = 0, 0
nb_eval_steps, nb_eval_examples = 0, 0
for batch in validation_dataloader:
batch = tuple(t.to(device) for t in batch)
with torch.no_grad():
outputs = model(input_ids=batch[0],
token_type_ids=None,
attention_mask=batch[1],
labels=batch[2])
# ロスと精度を累積
tmp_eval_loss, logits = outputs[:2]
eval_loss += tmp_eval_loss.mean().item()
eval_accuracy += flat_accuracy(logits, batch[2])
nb_eval_examples += batch[0].size(0)
nb_eval_steps += 1
print("Test Accuracy: {0:.2f}%".format(eval_accuracy/nb_eval_steps*100))
このコードは、テストデータをバッチ毎にモデルに入力して、ロスと精度を計算し、それらを累積していきます。最終的に、累積されたロスと精度から、全体のテストデータに対する平均ロスと分類精度が計算され、出力されます。分類精度は、{0:.2f}%
の部分がフォーマットされた文字列で出力されます。ここで、{0:.2f}
は、小数点以下2桁までの浮動小数点数として出力することを示しています。最後に、%
を付けることで、パーセント表示になります。
実行できました
先ほどのコードの末尾に追記すればいいですか。
はい、以下のコードを末尾に追記すれば、カテゴリ分類の精度を出すことができます。
# モデルの評価モードに切り替える
model.eval()
# 評価時の損失と正解数
eval_loss, eval_accuracy = 0, 0
nb_eval_steps, nb_eval_examples = 0, 0
# すべてのバッチについて評価を実行
for batch in validation_dataloader:
# バッチをGPUに転送
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
# 逆伝播を無効にする
with torch.no_grad():
# モデルにバッチを入力し、出力を取得
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask)
# 損失を計算
logits = outputs[0]
logits = logits.detach().cpu().numpy()
label_ids = b_labels.to('cpu').numpy()
tmp_eval_accuracy = accuracy(logits, label_ids)
# 正解数と評価済みのデータ数を更新
eval_accuracy += tmp_eval_accuracy
nb_eval_examples += b_input_ids.size(0)
nb_eval_steps += 1
# 精度を出力
print("Validation Accuracy: {:.2f}%".format(eval_accuracy/nb_eval_examples*100))
ただし、このコードは上記のコードと一緒になるように配置する必要があります。つまり、for
ループの中にあり、各バッチに対して実行される必要があります。
エラーなく実行できました。
## (以下追加追加1回目)
# テストデータを用いてモデルの評価を行う
model.eval()
eval_loss, eval_accuracy = 0, 0
nb_eval_steps, nb_eval_examples = 0, 0
for batch in validation_dataloader:
batch = tuple(t.to(device) for t in batch)
with torch.no_grad():
outputs = model(input_ids=batch[0],
token_type_ids=None,
attention_mask=batch[1],
labels=batch[2])
# ロスと精度を累積
tmp_eval_loss, logits = outputs[:2]
eval_loss += tmp_eval_loss.mean().item()
eval_accuracy += flat_accuracy(logits, batch[2])
nb_eval_examples += batch[0].size(0)
nb_eval_steps += 1
print("Test Accuracy: {0:.2f}%".format(eval_accuracy/nb_eval_steps*100))
## (以下追加追加1回目)ここまで
上記コードの出力結果が以下です。
Test Accuracy: 77.28%
実際には、エラーの内容を質問し、コードの修正を繰り返しています。
このコードが適切な内容なのかは、今後確認するつもりです。
精度はもっと上げられると思いますが、一連の処理をエラー出さずに実行できたので、”初BERT”はここまでとしました。