見出し画像

amazon_reviews_multilingual_JP_v1_00.tsv.gzがダウンロードできなくなったので代わりのデータを使う(Advanced Python 2ディープラーニングによる自然言語処理のサンプルコードを例に)

Advanced Python 2 ディープラーニングによる自然言語処理という本を読み終えました。機械学習なんもやったことないのにいきなりLLM沼に飛び込んだ僕みたいな人間にとって、すごくわかりやすくていい本でした。

途中の説明を省略せずに進めてくれるので、非常に分かりやすい。AllenNLPという今は開発が終了してしまったライブラリを使ってはいるのですが、古典NNからRNN、BERTへとの流れを基本的に同じ形式のコードで追っていくので、概念を理解しやすかったです。

さて、この4章と7章で、アマゾンから提供されているレビューテキストのデータセットを使って評判分析を実践する内容が書かれています。データセットを https://s3.amazonaws.com/amazon-reviews-pds/tsv/amazon_reviews_multilingual_JP_v1_00.tsv.gz からダウンロードして使うようにサンプルコードが書かれているのですが、このデータセットがいまはダウンロード出来なくなっています。

代わりに、似た内容のデータセットを使って分析することにしました。具体的には、Hugging Faceに公開されていた以下のデータを使わせていただきました。

データをダウンロードして整形する部分を、以下の様に変更します。

データセットのセットアップ

テキスト

# データセットの出力ディレクトリを作成
!mkdir -p data/amazon_reviews
# データセットをダウンロード
!wget -q -O data/amazon_reviews/amazon_reviews_multilingual_JP_v1_00.tsv.gz "https://s3.amazonaws.com/amazon-reviews-pds/tsv/amazon_reviews_multilingual_JP_v1_00.tsv.gz"
# データセットを解凍し、data/amazon_reviewsに展開
!gunzip data/amazon_reviews/amazon_reviews_multilingual_JP_v1_00.tsv.gz

import csv
import json
import os
import random
import warnings
from bs4 import BeautifulSoup

# csvライブラリのフィールドの最大サイズを変更
csv.field_size_limit(1000000)
# BeautifulSoupの出力する警告を抑制
warnings.filterwarnings("ignore", category=UserWarning, module="bs4")

# データセットをファイルから読み込む
data = []
with open("data/amazon_reviews/amazon_reviews_multilingual_JP_v1_00.tsv") as f:
    reader = csv.reader(f, delimiter="\t")
    # 1行目はヘッダなので無視する
    next(reader)
    for r in reader:
        # レビューのテキストを取得
        review_body = r[13]
        # レビューのテキストからHTMLタグを除去
        review_body = BeautifulSoup(review_body, "html.parser").get_text()
        # 評価の値を取得
        ratings = int(r[7])
        # 評価が2以下の場合に否定的、4以上の場合に肯定的と扱う
        if ratings <= 2:
            data.append(dict(text=review_body, label="negative"))
        elif ratings >= 4:
            data.append(dict(text=review_body, label="positive"))

# データセットから50,000件をランダムに抽出する
random.seed(1)
random.shuffle(data)
data = data[:50000]

# データセットの80%を訓練データ、10%を検証データ、10%をテストデータとして用いる
split_data = {}
eval_size = int(len(data) * 0.1)
split_data["test"] = data[:eval_size]
split_data["validation"] = data[eval_size:eval_size * 2]
split_data["train"] = data[eval_size * 2:]

# 行区切りJSON形式でデータセットを書き込む
for fold in ("train", "validation", "test"):
    out_file = os.path.join("data/amazon_reviews", "amazon_reviews_{}.jsonl".format(fold))
    with open(out_file, mode="w") as f:
        for item in split_data[fold]:
            json.dump(item, f, ensure_ascii=False)
            f.write("\n")

修正

# データセットの出力ディレクトリを作成
!mkdir -p data/amazon_reviews
# データセットをダウンロード
!wget -q -O data/amazon_reviews/amazon_reviews_train_original.jsonl "https://huggingface.co/datasets/SetFit/amazon_reviews_multi_ja/resolve/main/train.jsonl"
!wget -q -O data/amazon_reviews/amazon_reviews_test_original.jsonl "https://huggingface.co/datasets/SetFit/amazon_reviews_multi_ja/resolve/main/test.jsonl"
!wget -q -O data/amazon_reviews/amazon_reviews_validation_original.jsonl "https://huggingface.co/datasets/SetFit/amazon_reviews_multi_ja/resolve/main/validation.jsonl"

import json
import os
import random
import warnings

train_data = []
with open("data/amazon_reviews/amazon_reviews_train_original.jsonl", "r", encoding="utf-8") as f:
  for line in f:
    try:
      train_data.append(json.loads(line))
    except json.JSONDecodeError:
      print(f"Error decoding JSON for line: {line}")
      continue

  for item in train_data:
    if item["label"] <= 1:
      item["label_text"] = "negative"
    elif item["label"] >= 3:
      item["label_text"] = "positive"
    elif item["label"] == 2:
      item["label_text"] = "neutral"
    del item["id"]
    del item["label"]
    item["label"] = item["label_text"]
    del item["label_text"]
  filtered_data = [item for item in train_data if item["label"] != "neutral"]
with open('data/amazon_reviews/amazon_reviews_train.jsonl', 'w', encoding='utf-8') as f:
    for entry in filtered_data:
        json.dump(entry, f, ensure_ascii=False)
        f.write('\n')

validation_data = []
with open("data/amazon_reviews/amazon_reviews_validation_original.jsonl", "r", encoding="utf-8") as f:
  for line in f:
    validation_data.append(json.loads(line))

  for item in validation_data:
    if item["label"] <= 1:
      item["label_text"] = "negative"
    elif item["label"] >= 3:
      item["label_text"] = "positive"
    elif item["label"] == 2:
      item["label_text"] = "neutral"
    del item["id"]
    del item["label"]
    item["label"] = item["label_text"]
    del item["label_text"]
  filtered_data = [item for item in validation_data if item["label"] != "neutral"]
with open('data/amazon_reviews/amazon_reviews_validation.jsonl', 'w', encoding='utf-8') as f:
    for entry in filtered_data:
        json.dump(entry, f, ensure_ascii=False)
        f.write('\n')

test_data = []
with open("data/amazon_reviews/amazon_reviews_test_original.jsonl", "r", encoding="utf-8") as f:
  for line in f:
    test_data.append(json.loads(line))

  for item in test_data:
    if item["label"] <= 1:
      item["label_text"] = "negative"
    elif item["label"] >= 3:
      item["label_text"] = "positive"
    elif item["label"] == 2:
      item["label_text"] = "neutral"
    del item["id"]
    del item["label"]
    item["label"] = item["label_text"]
    del item["label_text"]
  filtered_data = [item for item in test_data if item["label"] != "neutral"]
with open('data/amazon_reviews/amazon_reviews_test.jsonl', 'w', encoding='utf-8') as f:
    for entry in filtered_data:
        json.dump(entry, f, ensure_ascii=False)
        f.write('\n')

とりあえず学習や分析は完走しました。当然、結果の数値はテキストとは異なりますが、とりあえずポジティブ/ネガティブの推論もできました。

訓練結果

"best_epoch": 1,
"peak_worker_0_memory_MB": 6275.7421875,
"peak_gpu_0_memory_MB": 145.58935546875,
"training_duration": "0:02:18.978383",
"epoch": 4,
"training_accuracy": 0.965425,
"training_loss": 0.09962953839227558,
"training_worker_0_memory_MB": 6275.7421875,
"training_gpu_0_memory_MB": 145.58837890625,
"validation_accuracy": 0.8885,
"validation_loss": 0.33407112819701434,
"best_validation_accuracy": 0.899,
"best_validation_loss": 0.24958608490228654

この本を読み終えたことでやる気が出てきたので、次は同じ著者の「大規模言語モデル入門」にチャレンジしようと思います。


この記事が気に入ったらサポートをしてみませんか?