中條 美冬

1646044200

Transformersライブラリを使用してPythonでフェイクニュース検出器を構築する方法

Pythonでのフェイクニュースの検出

偽のニュースデータセットを探索し、ワードクラウドやngramなどのデータ分析を実行し、トランスフォーマーライブラリを使用してPythonで偽のニュース検出器を構築するためにBERTトランスフォーマーを微調整します。

フェイクニュースとは、虚偽または誤解を招くような主張をニュースとして意図的に放送することであり、その発言は意図的に欺瞞的です。

新聞、タブロイド紙、雑誌は、デジタルニュースプラットフォーム、ブログ、ソーシャルメディアフィード、および多数のモバイルニュースアプリケーションに取って代わられています。ニュース組織は、加入者に最新の情報を提供することにより、ソーシャルメディアとモバイルプラットフォームの使用の増加から恩恵を受けました。

消費者は現在、最新ニュースに即座にアクセスできます。これらのデジタルメディアプラットフォームは、世界の他の地域との接続が容易であるために注目を集めており、ユーザーは、民主主義、教育、健康、研究、歴史などのアイデアや討論トピックについて話し合い、共有することができます。デジタルプラットフォーム上の偽のニュースアイテムはますます人気が高まっており、政治的および経済的利益などの利益のために使用されています。

この問題はどれくらい大きいですか?

インターネット、ソーシャルメディア、デジタルプラットフォームが広く使用されているため、誰もが不正確で偏った情報を広める可能性があります。フェイクニュースの拡散を防ぐことはほとんど不可能です。虚偽のニュースの配信は急増しています。これは、政治などの1つのセクターに限定されるものではなく、スポーツ、健康、歴史、娯楽、科学と研究などが含まれます。

ソリューション

虚偽のニュースと正確なニュースを認識して区別することが重要です。1つの方法は、専門家にすべての情報を決定して事実を確認させることですが、これには時間がかかり、共有できない専門知識が必要です。次に、機械学習と人工知能ツールを使用して、偽のニュースの識別を自動化できます。

オンラインニュース情報には、さまざまな非構造化形式のデータ(ドキュメント、ビデオ、オーディオなど)が含まれますが、ここではテキスト形式のニュースに焦点を当てます。機械学習自然言語処理の進歩により、記事やステートメントの誤解を招くような誤った性格を認識できるようになりました。

すべての媒体で偽のニュースを検出するために、いくつかの調査と実験が行われています。

このチュートリアルの主な目標は次のとおりです。

  • フェイクニュースのデータセットを調べて分析します。
  • フェイクニュースを可能な限り正確に区別できる分類器を構築します。

コンテンツの表は次のとおりです。

  • 序章
  • この問題はどれくらい大きいですか?
  • ソリューション
  • データ探索
    • クラスの分布
  • 分析のためのデータクリーニング
  • 探索的データ分析
    • シングルワードクラウド
    • 最も頻繁なバイグラム(2単語の組み合わせ)
    • 最も頻繁なトリグラム(3語の組み合わせ)
  • BERTを微調整して分類器を構築する
    • データの準備
    • データセットのトークン化
    • モデルのロードと微調整
    • モデル評価
  • 付録:Kaggleの送信ファイルの作成
  • 結論

データ探索

この作業では、Kaggleのフェイクニュースデータセットを利用して、信頼できないニュース記事をフェイクニュースとして分類しました。次の特性を含む完全なトレーニングデータセットがあります。

  • id:ニュース記事の一意のID
  • title:ニュース記事のタイトル
  • author:ニュース記事の著者
  • text:記事のテキスト; 不完全である可能性があります
  • label:1(信頼できないまたは偽物)または0(信頼できる)で示される、信頼できない可能性のあるものとして記事をマークするラベル。

これは、特定のニュース記事が信頼できるかどうかを予測する必要があるバイナリ分類の問題です。

Kaggleアカウントをお持ちの場合は、そこにあるWebサイトからデータセットをダウンロードして、ZIPファイルを抽出するだけです。

また、データセットをGoogleドライブにアップロードしました。ここで取得するか、ライブラリを使用してgdownGoogleColabまたはJupyterノートブックに自動的にダウンロードできます。

$ pip install gdown
# download from Google Drive
$ gdown "https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t"
Downloading...
From: https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t
To: /content/fake-news.zip
100% 48.7M/48.7M [00:00<00:00, 74.6MB/s]

ファイルを解凍します。

$ unzip fake-news.zip

現在の作業ディレクトリには、、、、の3つのファイルが表示されtrain.csvます。これはtest.csv、ほとんどのチュートリアルでsubmit.csv使用します。train.csv

必要な依存関係のインストール:

$ pip install transformers nltk pandas numpy matplotlib seaborn wordcloud

注:ローカル環境にいる場合は、必ずPyTorch for GPUをインストールしてください。適切にインストールするには、このページにアクセスしてください。

分析に不可欠なライブラリをインポートしましょう。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

NLTKコーパスとモジュールは、標準のNLTKダウンローダーを使用してインストールする必要があります。

import nltk
nltk.download('stopwords')
nltk.download('wordnet')

フェイクニュースデータセットは、さまざまな著者のオリジナルおよび架空の記事のタイトルとテキストで構成されています。データセットをインポートしましょう:

# load the dataset
news_d = pd.read_csv("train.csv")
print("Shape of News data:", news_d.shape)
print("News data columns", news_d.columns)

出力:

 Shape of News data: (20800, 5)
 News data columns Index(['id', 'title', 'author', 'text', 'label'], dtype='object')

データセットは次のようになります。

# by using df.head(), we can immediately familiarize ourselves with the dataset. 
news_d.head()

出力:

id	title	author	text	label
0	0	House Dem Aide: We Didn’t Even See Comey’s Let...	Darrell Lucus	House Dem Aide: We Didn’t Even See Comey’s Let...	1
1	1	FLYNN: Hillary Clinton, Big Woman on Campus - ...	Daniel J. Flynn	Ever get the feeling your life circles the rou...	0
2	2	Why the Truth Might Get You Fired	Consortiumnews.com	Why the Truth Might Get You Fired October 29, ...	1
3	3	15 Civilians Killed In Single US Airstrike Hav...	Jessica Purkiss	Videos 15 Civilians Killed In Single US Airstr...	1
4	4	Iranian woman jailed for fictional unpublished...	Howard Portnoy	Print \nAn Iranian woman has been sentenced to...	1

20,800行あり、5列あります。text列のいくつかの統計を見てみましょう:

#Text Word startistics: min.mean, max and interquartile range

txt_length = news_d.text.str.split().str.len()
txt_length.describe()

出力:

count    20761.000000
mean       760.308126
std        869.525988
min          0.000000
25%        269.000000
50%        556.000000
75%       1052.000000
max      24234.000000
Name: text, dtype: float64

title列の統計:

#Title statistics 

title_length = news_d.title.str.split().str.len()
title_length.describe()

出力:

count    20242.000000
mean        12.420709
std          4.098735
min          1.000000
25%         10.000000
50%         13.000000
75%         15.000000
max         72.000000
Name: title, dtype: float64

トレーニングセットとテストセットの統計は次のとおりです。

  • このtext属性の単語数は多く、平均760語で、75%が1000語を超えています。
  • title属性は平均12語の短いステートメントであり、そのうちの75%は約15語です。

私たちの実験は、テキストとタイトルの両方を一緒に使用することです。

クラスの分布

両方のラベルのプロットを数える:

sns.countplot(x="label", data=news_d);
print("1: Unreliable")
print("0: Reliable")
print("Distribution of labels:")
print(news_d.label.value_counts());

出力:

1: Unreliable
0: Reliable
Distribution of labels:
1    10413
0    10387
Name: label, dtype: int64

ラベルの配布

print(round(news_d.label.value_counts(normalize=True),2)*100);

出力:

1    50.0
0    50.0
Name: label, dtype: float64

信頼できない記事(偽物または1)の数は10413であり、信頼できる記事(信頼できるまたは0)の数は10387です。記事のほぼ50%は偽物です。したがって、精度メトリックは、分類器を構築するときにモデルがどの程度うまく機能しているかを測定します。

分析のためのデータクリーニング

このセクションでは、データセットをクリーンアップして分析を行います。

  • 未使用の行と列を削除します。
  • null値の代入を実行します。
  • 特殊文字を削除します。
  • ストップワードを削除します。
# Constants that are used to sanitize the datasets 

column_n = ['id', 'title', 'author', 'text', 'label']
remove_c = ['id','author']
categorical_features = []
target_col = ['label']
text_f = ['title', 'text']
# Clean Datasets
import nltk
from nltk.corpus import stopwords
import re
from nltk.stem.porter import PorterStemmer
from collections import Counter

ps = PorterStemmer()
wnl = nltk.stem.WordNetLemmatizer()

stop_words = stopwords.words('english')
stopwords_dict = Counter(stop_words)

# Removed unused clumns
def remove_unused_c(df,column_n=remove_c):
    df = df.drop(column_n,axis=1)
    return df

# Impute null values with None
def null_process(feature_df):
    for col in text_f:
        feature_df.loc[feature_df[col].isnull(), col] = "None"
    return feature_df

def clean_dataset(df):
    # remove unused column
    df = remove_unused_c(df)
    #impute null values
    df = null_process(df)
    return df

# Cleaning text from unused characters
def clean_text(text):
    text = str(text).replace(r'http[\w:/\.]+', ' ')  # removing urls
    text = str(text).replace(r'[^\.\w\s]', ' ')  # remove everything but characters and punctuation
    text = str(text).replace('[^a-zA-Z]', ' ')
    text = str(text).replace(r'\s\s+', ' ')
    text = text.lower().strip()
    #text = ' '.join(text)    
    return text

## Nltk Preprocessing include:
# Stop words, Stemming and Lemmetization
# For our project we use only Stop word removal
def nltk_preprocess(text):
    text = clean_text(text)
    wordlist = re.sub(r'[^\w\s]', '', text).split()
    #text = ' '.join([word for word in wordlist if word not in stopwords_dict])
    #text = [ps.stem(word) for word in wordlist if not word in stopwords_dict]
    text = ' '.join([wnl.lemmatize(word) for word in wordlist if word not in stopwords_dict])
    return  text

上記のコードブロック:

  • 人間の言語と相互作用するPythonアプリケーションを開発するための有名なプラットフォームであるNLTKをインポートしました。次に、re正規表現をインポートします。
  • からストップワードをインポートしnltk.corpusます。単語を扱うとき、特にセマンティクスを検討するときは、、、、など"but"、ステートメントに重要な意味を追加しない一般的な単語を削除する必要がある場合があります。"can""we"
  • PorterStemmerNLTKでステミングワードを実行するために使用されます。ステマーは、形態学的接辞の単語を取り除き、単語の語幹のみを残します。
  • WordNetLemmatizer()レンマ化のためにNLTKライブラリからインポートします。Lemmatizationはステミングよりもはるかに効果的です。これは、単語の削減を超えて、言語の語彙全体を評価し、語形変化の終わりを削除して、見出語として知られる単語のベースまたは辞書形式を返すことを目的として、形態素解析を単語に適用します。
  • stopwords.words('english')NLTKでサポートされているすべての英語のストップワードのリストを見てみましょう。
  • remove_unused_c()関数は、未使用の列を削除するために使用されます。
  • None関数を使用してnull値を代入しますnull_process()
  • 関数内で、関数をclean_dataset()呼び出します。この関数は、データのクリーニングを担当します。remove_unused_c()null_process()
  • 未使用の文字からテキストを削除するために、clean_text()関数を作成しました。
  • 前処理には、ストップワードの削除のみを使用します。nltk_preprocess()そのための関数を作成しました。

textおよびの前処理title

# Perform data cleaning on train and test dataset by calling clean_dataset function
df = clean_dataset(news_d)
# apply preprocessing on text through apply method by calling the function nltk_preprocess
df["text"] = df.text.apply(nltk_preprocess)
# apply preprocessing on title through apply method by calling the function nltk_preprocess
df["title"] = df.title.apply(nltk_preprocess)
# Dataset after cleaning and preprocessing step
df.head()

出力:

title	text	label
0	house dem aide didnt even see comeys letter ja...	house dem aide didnt even see comeys letter ja...	1
1	flynn hillary clinton big woman campus breitbart	ever get feeling life circle roundabout rather...	0
2	truth might get fired	truth might get fired october 29 2016 tension ...	1
3	15 civilian killed single u airstrike identified	video 15 civilian killed single u airstrike id...	1
4	iranian woman jailed fictional unpublished sto...	print iranian woman sentenced six year prison ...	1

探索的データ分析

このセクションでは、以下を実行します。

  • 単変量分析:テキストの統計分析です。そのためにワードクラウドを使用します。ワードクラウドは、最も一般的な用語が最も重要なフォントサイズで表示される、テキストデータの視覚化アプローチです。
  • 二変量解析:ここでは、バイグラムとトリグラムが使用されます。ウィキペディアによると:「n-gramは、テキストまたはスピーチの特定のサンプルからのn個のアイテムの連続したシーケンスです。アプリケーションによると、アイテムは音素、音節、文字、単語、または塩基対です。n-gram通常、テキストまたは音声コーパスから収集されます。」

シングルワードクラウド

最も頻繁に使用される単語は、ワードクラウド内で太字の大きなフォントで表示されます。このセクションでは、データセット内のすべての単語に対してワードクラウドを実行します。

WordCloudライブラリwordcloud()関数が使用され、ワー​​ドgenerate()クラウドイメージの生成に使用されます。

from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt

# initialize the word cloud
wordcloud = WordCloud( background_color='black', width=800, height=600)
# generate the word cloud by passing the corpus
text_cloud = wordcloud.generate(' '.join(df['text']))
# plotting the word cloud
plt.figure(figsize=(20,30))
plt.imshow(text_cloud)
plt.axis('off')
plt.show()

出力:

フェイクニュースデータ全体のWordCloud

信頼できるニュース専用のワードクラウド:

true_n = ' '.join(df[df['label']==0]['text']) 
wc = wordcloud.generate(true_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

出力:

信頼できるニュースのためのワードクラウド

フェイクニュース専用のワードクラウド:

fake_n = ' '.join(df[df['label']==1]['text'])
wc= wordcloud.generate(fake_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

出力:

フェイクニュースのためのワードクラウド

最も頻繁なバイグラム(2単語の組み合わせ)

N-gramは、文字または単語のシーケンスです。文字ユニグラムは1つの文字で構成され、バイグラムは一連の2文字で構成されます。同様に、単語N-gramは一連のn個の単語で構成されます。「団結」という言葉は1グラム(ユニグラム)です。「米国」という言葉の組み合わせは2グラム(バイグラム)、「ニューヨーク市」は3グラムです。

信頼できるニュースで最も一般的なバイグラムをプロットしてみましょう。

def plot_top_ngrams(corpus, title, ylabel, xlabel="Number of Occurences", n=2):
  """Utility function to plot top n-grams"""
  true_b = (pd.Series(nltk.ngrams(corpus.split(), n)).value_counts())[:20]
  true_b.sort_values().plot.barh(color='blue', width=.9, figsize=(12, 8))
  plt.title(title)
  plt.ylabel(ylabel)
  plt.xlabel(xlabel)
  plt.show()
plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Bigrams', "Bigram", n=2)

フェイクニュースのトップバイグラム

フェイクニュースで最も一般的なバイグラム:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Bigrams', "Bigram", n=2)

フェイクニュースのトップバイグラム

最も頻繁なトリグラム(3語の組み合わせ)

信頼できるニュースに関する最も一般的なトリグラム:

plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Trigrams', "Trigrams", n=3)

フェイクニュースで最も一般的なトリグラム

今のフェイクニュースの場合:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Trigrams', "Trigrams", n=3)

フェイクニュースで最も一般的なトリグラム

上記のプロットは、両方のクラスがどのように見えるかについてのいくつかのアイデアを示しています。次のセクションでは、トランスフォーマーライブラリを使用して偽のニュース検出器を構築します。

BERTを微調整して分類器を構築する

このセクションでは、トランスフォーマーライブラリを使用して偽のニュース分類子を作成するために、BERTチュートリアルの微調整からコードを広範囲に取得します。したがって、より詳細な情報については、元のチュートリアルに進むことができます。

トランスフォーマーをインストールしなかった場合は、次のことを行う必要があります。

$ pip install transformers

必要なライブラリをインポートしましょう:

import torch
from transformers.file_utils import is_tf_available, is_torch_available, is_torch_tpu_available
from transformers import BertTokenizerFast, BertForSequenceClassification
from transformers import Trainer, TrainingArguments
import numpy as np
from sklearn.model_selection import train_test_split

import random

環境を再起動しても、結果を再現可能にしたいと考えています。

def set_seed(seed: int):
    """
    Helper function for reproducible behavior to set the seed in ``random``, ``numpy``, ``torch`` and/or ``tf`` (if
    installed).

    Args:
        seed (:obj:`int`): The seed to set.
    """
    random.seed(seed)
    np.random.seed(seed)
    if is_torch_available():
        torch.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        # ^^ safe to call this function even if cuda is not available
    if is_tf_available():
        import tensorflow as tf

        tf.random.set_seed(seed)

set_seed(1)

使用するモデルは次のbert-base-uncasedとおりです。

# the model we gonna train, base uncased BERT
# check text classification models here: https://huggingface.co/models?filter=text-classification
model_name = "bert-base-uncased"
# max sequence length for each document/sentence sample
max_length = 512

トークナイザーのロード:

# load the tokenizer
tokenizer = BertTokenizerFast.from_pretrained(model_name, do_lower_case=True)

データの準備

次に、、、および列NaNから値をクリーンアップしましょう。textauthortitle

news_df = news_d[news_d['text'].notna()]
news_df = news_df[news_df["author"].notna()]
news_df = news_df[news_df["title"].notna()]

次に、データセットをPandasデータフレームとして受け取り、テキストとラベルのトレイン/検証分割をリストとして返す関数を作成します。

def prepare_data(df, test_size=0.2, include_title=True, include_author=True):
  texts = []
  labels = []
  for i in range(len(df)):
    text = df["text"].iloc[i]
    label = df["label"].iloc[i]
    if include_title:
      text = df["title"].iloc[i] + " - " + text
    if include_author:
      text = df["author"].iloc[i] + " : " + text
    if text and label in [0, 1]:
      texts.append(text)
      labels.append(label)
  return train_test_split(texts, labels, test_size=test_size)

train_texts, valid_texts, train_labels, valid_labels = prepare_data(news_df)

上記の関数は、データフレームタイプのデータセットを取得し、トレーニングセットと検証セットに分割されたリストとしてそれらを返します。に設定include_titleすると、トレーニングに使用する列に列がTrue追加されます。に設定すると、テキストにも列が追加されます。titletextinclude_authorTrueauthor

ラベルとテキストの長さが同じであることを確認しましょう。

print(len(train_texts), len(train_labels))
print(len(valid_texts), len(valid_labels))

出力:

14628 14628
3657 3657

データセットのトークン化

BERTトークナイザーを使用して、データセットをトークン化してみましょう。

# tokenize the dataset, truncate when passed `max_length`, 
# and pad with 0's when less than `max_length`
train_encodings = tokenizer(train_texts, truncation=True, padding=True, max_length=max_length)
valid_encodings = tokenizer(valid_texts, truncation=True, padding=True, max_length=max_length)

エンコーディングをPyTorchデータセットに変換します。

class NewsGroupsDataset(torch.utils.data.Dataset):
    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels

    def __getitem__(self, idx):
        item = {k: torch.tensor(v[idx]) for k, v in self.encodings.items()}
        item["labels"] = torch.tensor([self.labels[idx]])
        return item

    def __len__(self):
        return len(self.labels)

# convert our tokenized data into a torch Dataset
train_dataset = NewsGroupsDataset(train_encodings, train_labels)
valid_dataset = NewsGroupsDataset(valid_encodings, valid_labels)

モデルのロードと微調整

BertForSequenceClassificationBERTトランスフォーマーモデルのロードに使用します。

# load the model
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)

num_labels二項分類なので2に設定します。以下の関数は、各検証ステップの精度を計算するためのコールバックです。

from sklearn.metrics import accuracy_score

def compute_metrics(pred):
  labels = pred.label_ids
  preds = pred.predictions.argmax(-1)
  # calculate accuracy using sklearn's function
  acc = accuracy_score(labels, preds)
  return {
      'accuracy': acc,
  }

トレーニングパラメータを初期化しましょう:

training_args = TrainingArguments(
    output_dir='./results',          # output directory
    num_train_epochs=1,              # total number of training epochs
    per_device_train_batch_size=10,  # batch size per device during training
    per_device_eval_batch_size=20,   # batch size for evaluation
    warmup_steps=100,                # number of warmup steps for learning rate scheduler
    logging_dir='./logs',            # directory for storing logs
    load_best_model_at_end=True,     # load the best model when finished training (default metric is loss)
    # but you can specify `metric_for_best_model` argument to change to accuracy or other metric
    logging_steps=200,               # log & save weights each logging_steps
    save_steps=200,
    evaluation_strategy="steps",     # evaluate each `logging_steps`
)

を10に設定しましたper_device_train_batch_sizeが、GPUが収まる限り高く設定する必要があります。logging_stepsandを200に設定しsave_stepsます。これは、評価を実行し、200のトレーニングステップごとにモデルの重みを保存することを意味します。

 利用可能なトレーニングパラメータの詳細については、このページを確認 してください。

トレーナーをインスタンス化しましょう:

trainer = Trainer(
    model=model,                         # the instantiated Transformers model to be trained
    args=training_args,                  # training arguments, defined above
    train_dataset=train_dataset,         # training dataset
    eval_dataset=valid_dataset,          # evaluation dataset
    compute_metrics=compute_metrics,     # the callback that computes metrics of interest
)

モデルのトレーニング:

# train the model
trainer.train()

GPUによっては、トレーニングが完了するまでに数時間かかります。Colabの無料バージョンを使用している場合は、NVIDIA TeslaK80で1時間かかるはずです。出力は次のとおりです。

***** Running training *****
  Num examples = 14628
  Num Epochs = 1
  Instantaneous batch size per device = 10
  Total train batch size (w. parallel, distributed & accumulation) = 10
  Gradient Accumulation steps = 1
  Total optimization steps = 1463
 [1463/1463 41:07, Epoch 1/1]
Step	Training Loss	Validation Loss	Accuracy
200		0.250800		0.100533		0.983867
400		0.027600		0.043009		0.993437
600		0.023400		0.017812		0.997539
800		0.014900		0.030269		0.994258
1000	0.022400		0.012961		0.998086
1200	0.009800		0.010561		0.998633
1400	0.007700		0.010300		0.998633
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-200
Configuration saved in ./results/checkpoint-200/config.json
Model weights saved in ./results/checkpoint-200/pytorch_model.bin
<SNIPPED>
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-1400
Configuration saved in ./results/checkpoint-1400/config.json
Model weights saved in ./results/checkpoint-1400/pytorch_model.bin

Training completed. Do not forget to share your model on huggingface.co/models =)

Loading best model from ./results/checkpoint-1400 (score: 0.010299865156412125).
TrainOutput(global_step=1463, training_loss=0.04888018785440506, metrics={'train_runtime': 2469.1722, 'train_samples_per_second': 5.924, 'train_steps_per_second': 0.593, 'total_flos': 3848788517806080.0, 'train_loss': 0.04888018785440506, 'epoch': 1.0})

モデル評価

load_best_model_at_endに設定されているためTrue、トレーニングが完了すると、最適なウェイトがロードされます。検証セットを使用して評価してみましょう。

# evaluate the current model after training
trainer.evaluate()

出力:

***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
 [183/183 02:11]
{'epoch': 1.0,
 'eval_accuracy': 0.998632759092152,
 'eval_loss': 0.010299865156412125,
 'eval_runtime': 132.0374,
 'eval_samples_per_second': 27.697,
 'eval_steps_per_second': 1.386}

モデルとトークナイザーの保存:

# saving the fine tuned model & tokenizer
model_path = "fake-news-bert-base-uncased"
model.save_pretrained(model_path)
tokenizer.save_pretrained(model_path)

上記のセルを実行すると、モデルの構成と重みを含む新しいフォルダーが表示されます。予測を実行するfrom_pretrained()場合は、モデルをロードしたときに使用した方法を使用するだけで、準備は完了です。

次に、記事のテキストを引数として受け取り、それが偽物であるかどうかを返す関数を作成しましょう。

def get_prediction(text, convert_to_label=False):
    # prepare our text into tokenized sequence
    inputs = tokenizer(text, padding=True, truncation=True, max_length=max_length, return_tensors="pt").to("cuda")
    # perform inference to our model
    outputs = model(**inputs)
    # get output probabilities by doing softmax
    probs = outputs[0].softmax(1)
    # executing argmax function to get the candidate label
    d = {
        0: "reliable",
        1: "fake"
    }
    if convert_to_label:
      return d[int(probs.argmax())]
    else:
      return int(probs.argmax())

モデルが推論を実行するのを見たことがないという例を取り上げ、test.csvそれを確認しました。これは、ニューヨークタイムズの実際の記事です。

real_news = """
Tim Tebow Will Attempt Another Comeback, This Time in Baseball - The New York Times",Daniel Victor,"If at first you don’t succeed, try a different sport. Tim Tebow, who was a Heisman   quarterback at the University of Florida but was unable to hold an N. F. L. job, is pursuing a career in Major League Baseball. <SNIPPED>
"""

元のテキストは完全な記事であるため、コピーする場合はColab環境にあります。それをモデルに渡して、結果を見てみましょう。

get_prediction(real_news, convert_to_label=True)

出力:

reliable

付録:Kaggleの送信ファイルの作成

このセクションでは、のすべての記事を予測しtest.csvて提出ファイルを作成し、Kaggleコンテストのテストセットでの正確性を確認します。

# read the test set
test_df = pd.read_csv("test.csv")
# make a copy of the testing set
new_df = test_df.copy()
# add a new column that contains the author, title and article content
new_df["new_text"] = new_df["author"].astype(str) + " : " + new_df["title"].astype(str) + " - " + new_df["text"].astype(str)
# get the prediction of all the test set
new_df["label"] = new_df["new_text"].apply(get_prediction)
# make the submission file
final_df = new_df[["id", "label"]]
final_df.to_csv("submit_final.csv", index=False)

著者、タイトル、記事のテキストを連結した後、get_prediction()関数を新しい列に渡して列を埋め、メソッドをlabel使用to_csv()してKaggleの送信ファイルを作成します。これが私の提出スコアです:

提出スコア

プライベートおよびパブリックのリーダーボードで99.78%および100%の精度が得られました。すごい!

結論

了解しました。チュートリアルは終了です。このページをチェックして、微調整できるさまざまなトレーニングパラメータを確認できます。

微調整用のカスタムのフェイクニュースデータセットがある場合は、サンプルのリストをトークン化ツールに渡すだけで済みます。その後、他のコードを変更することはありません。

ここで完全なコードを確認するか、ここでColab環境を確認してください。

What is GEEK

Buddha Community

中條 美冬

1646044200

Transformersライブラリを使用してPythonでフェイクニュース検出器を構築する方法

Pythonでのフェイクニュースの検出

偽のニュースデータセットを探索し、ワードクラウドやngramなどのデータ分析を実行し、トランスフォーマーライブラリを使用してPythonで偽のニュース検出器を構築するためにBERTトランスフォーマーを微調整します。

フェイクニュースとは、虚偽または誤解を招くような主張をニュースとして意図的に放送することであり、その発言は意図的に欺瞞的です。

新聞、タブロイド紙、雑誌は、デジタルニュースプラットフォーム、ブログ、ソーシャルメディアフィード、および多数のモバイルニュースアプリケーションに取って代わられています。ニュース組織は、加入者に最新の情報を提供することにより、ソーシャルメディアとモバイルプラットフォームの使用の増加から恩恵を受けました。

消費者は現在、最新ニュースに即座にアクセスできます。これらのデジタルメディアプラットフォームは、世界の他の地域との接続が容易であるために注目を集めており、ユーザーは、民主主義、教育、健康、研究、歴史などのアイデアや討論トピックについて話し合い、共有することができます。デジタルプラットフォーム上の偽のニュースアイテムはますます人気が高まっており、政治的および経済的利益などの利益のために使用されています。

この問題はどれくらい大きいですか?

インターネット、ソーシャルメディア、デジタルプラットフォームが広く使用されているため、誰もが不正確で偏った情報を広める可能性があります。フェイクニュースの拡散を防ぐことはほとんど不可能です。虚偽のニュースの配信は急増しています。これは、政治などの1つのセクターに限定されるものではなく、スポーツ、健康、歴史、娯楽、科学と研究などが含まれます。

ソリューション

虚偽のニュースと正確なニュースを認識して区別することが重要です。1つの方法は、専門家にすべての情報を決定して事実を確認させることですが、これには時間がかかり、共有できない専門知識が必要です。次に、機械学習と人工知能ツールを使用して、偽のニュースの識別を自動化できます。

オンラインニュース情報には、さまざまな非構造化形式のデータ(ドキュメント、ビデオ、オーディオなど)が含まれますが、ここではテキスト形式のニュースに焦点を当てます。機械学習自然言語処理の進歩により、記事やステートメントの誤解を招くような誤った性格を認識できるようになりました。

すべての媒体で偽のニュースを検出するために、いくつかの調査と実験が行われています。

このチュートリアルの主な目標は次のとおりです。

  • フェイクニュースのデータセットを調べて分析します。
  • フェイクニュースを可能な限り正確に区別できる分類器を構築します。

コンテンツの表は次のとおりです。

  • 序章
  • この問題はどれくらい大きいですか?
  • ソリューション
  • データ探索
    • クラスの分布
  • 分析のためのデータクリーニング
  • 探索的データ分析
    • シングルワードクラウド
    • 最も頻繁なバイグラム(2単語の組み合わせ)
    • 最も頻繁なトリグラム(3語の組み合わせ)
  • BERTを微調整して分類器を構築する
    • データの準備
    • データセットのトークン化
    • モデルのロードと微調整
    • モデル評価
  • 付録:Kaggleの送信ファイルの作成
  • 結論

データ探索

この作業では、Kaggleのフェイクニュースデータセットを利用して、信頼できないニュース記事をフェイクニュースとして分類しました。次の特性を含む完全なトレーニングデータセットがあります。

  • id:ニュース記事の一意のID
  • title:ニュース記事のタイトル
  • author:ニュース記事の著者
  • text:記事のテキスト; 不完全である可能性があります
  • label:1(信頼できないまたは偽物)または0(信頼できる)で示される、信頼できない可能性のあるものとして記事をマークするラベル。

これは、特定のニュース記事が信頼できるかどうかを予測する必要があるバイナリ分類の問題です。

Kaggleアカウントをお持ちの場合は、そこにあるWebサイトからデータセットをダウンロードして、ZIPファイルを抽出するだけです。

また、データセットをGoogleドライブにアップロードしました。ここで取得するか、ライブラリを使用してgdownGoogleColabまたはJupyterノートブックに自動的にダウンロードできます。

$ pip install gdown
# download from Google Drive
$ gdown "https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t"
Downloading...
From: https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t
To: /content/fake-news.zip
100% 48.7M/48.7M [00:00<00:00, 74.6MB/s]

ファイルを解凍します。

$ unzip fake-news.zip

現在の作業ディレクトリには、、、、の3つのファイルが表示されtrain.csvます。これはtest.csv、ほとんどのチュートリアルでsubmit.csv使用します。train.csv

必要な依存関係のインストール:

$ pip install transformers nltk pandas numpy matplotlib seaborn wordcloud

注:ローカル環境にいる場合は、必ずPyTorch for GPUをインストールしてください。適切にインストールするには、このページにアクセスしてください。

分析に不可欠なライブラリをインポートしましょう。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

NLTKコーパスとモジュールは、標準のNLTKダウンローダーを使用してインストールする必要があります。

import nltk
nltk.download('stopwords')
nltk.download('wordnet')

フェイクニュースデータセットは、さまざまな著者のオリジナルおよび架空の記事のタイトルとテキストで構成されています。データセットをインポートしましょう:

# load the dataset
news_d = pd.read_csv("train.csv")
print("Shape of News data:", news_d.shape)
print("News data columns", news_d.columns)

出力:

 Shape of News data: (20800, 5)
 News data columns Index(['id', 'title', 'author', 'text', 'label'], dtype='object')

データセットは次のようになります。

# by using df.head(), we can immediately familiarize ourselves with the dataset. 
news_d.head()

出力:

id	title	author	text	label
0	0	House Dem Aide: We Didn’t Even See Comey’s Let...	Darrell Lucus	House Dem Aide: We Didn’t Even See Comey’s Let...	1
1	1	FLYNN: Hillary Clinton, Big Woman on Campus - ...	Daniel J. Flynn	Ever get the feeling your life circles the rou...	0
2	2	Why the Truth Might Get You Fired	Consortiumnews.com	Why the Truth Might Get You Fired October 29, ...	1
3	3	15 Civilians Killed In Single US Airstrike Hav...	Jessica Purkiss	Videos 15 Civilians Killed In Single US Airstr...	1
4	4	Iranian woman jailed for fictional unpublished...	Howard Portnoy	Print \nAn Iranian woman has been sentenced to...	1

20,800行あり、5列あります。text列のいくつかの統計を見てみましょう:

#Text Word startistics: min.mean, max and interquartile range

txt_length = news_d.text.str.split().str.len()
txt_length.describe()

出力:

count    20761.000000
mean       760.308126
std        869.525988
min          0.000000
25%        269.000000
50%        556.000000
75%       1052.000000
max      24234.000000
Name: text, dtype: float64

title列の統計:

#Title statistics 

title_length = news_d.title.str.split().str.len()
title_length.describe()

出力:

count    20242.000000
mean        12.420709
std          4.098735
min          1.000000
25%         10.000000
50%         13.000000
75%         15.000000
max         72.000000
Name: title, dtype: float64

トレーニングセットとテストセットの統計は次のとおりです。

  • このtext属性の単語数は多く、平均760語で、75%が1000語を超えています。
  • title属性は平均12語の短いステートメントであり、そのうちの75%は約15語です。

私たちの実験は、テキストとタイトルの両方を一緒に使用することです。

クラスの分布

両方のラベルのプロットを数える:

sns.countplot(x="label", data=news_d);
print("1: Unreliable")
print("0: Reliable")
print("Distribution of labels:")
print(news_d.label.value_counts());

出力:

1: Unreliable
0: Reliable
Distribution of labels:
1    10413
0    10387
Name: label, dtype: int64

ラベルの配布

print(round(news_d.label.value_counts(normalize=True),2)*100);

出力:

1    50.0
0    50.0
Name: label, dtype: float64

信頼できない記事(偽物または1)の数は10413であり、信頼できる記事(信頼できるまたは0)の数は10387です。記事のほぼ50%は偽物です。したがって、精度メトリックは、分類器を構築するときにモデルがどの程度うまく機能しているかを測定します。

分析のためのデータクリーニング

このセクションでは、データセットをクリーンアップして分析を行います。

  • 未使用の行と列を削除します。
  • null値の代入を実行します。
  • 特殊文字を削除します。
  • ストップワードを削除します。
# Constants that are used to sanitize the datasets 

column_n = ['id', 'title', 'author', 'text', 'label']
remove_c = ['id','author']
categorical_features = []
target_col = ['label']
text_f = ['title', 'text']
# Clean Datasets
import nltk
from nltk.corpus import stopwords
import re
from nltk.stem.porter import PorterStemmer
from collections import Counter

ps = PorterStemmer()
wnl = nltk.stem.WordNetLemmatizer()

stop_words = stopwords.words('english')
stopwords_dict = Counter(stop_words)

# Removed unused clumns
def remove_unused_c(df,column_n=remove_c):
    df = df.drop(column_n,axis=1)
    return df

# Impute null values with None
def null_process(feature_df):
    for col in text_f:
        feature_df.loc[feature_df[col].isnull(), col] = "None"
    return feature_df

def clean_dataset(df):
    # remove unused column
    df = remove_unused_c(df)
    #impute null values
    df = null_process(df)
    return df

# Cleaning text from unused characters
def clean_text(text):
    text = str(text).replace(r'http[\w:/\.]+', ' ')  # removing urls
    text = str(text).replace(r'[^\.\w\s]', ' ')  # remove everything but characters and punctuation
    text = str(text).replace('[^a-zA-Z]', ' ')
    text = str(text).replace(r'\s\s+', ' ')
    text = text.lower().strip()
    #text = ' '.join(text)    
    return text

## Nltk Preprocessing include:
# Stop words, Stemming and Lemmetization
# For our project we use only Stop word removal
def nltk_preprocess(text):
    text = clean_text(text)
    wordlist = re.sub(r'[^\w\s]', '', text).split()
    #text = ' '.join([word for word in wordlist if word not in stopwords_dict])
    #text = [ps.stem(word) for word in wordlist if not word in stopwords_dict]
    text = ' '.join([wnl.lemmatize(word) for word in wordlist if word not in stopwords_dict])
    return  text

上記のコードブロック:

  • 人間の言語と相互作用するPythonアプリケーションを開発するための有名なプラットフォームであるNLTKをインポートしました。次に、re正規表現をインポートします。
  • からストップワードをインポートしnltk.corpusます。単語を扱うとき、特にセマンティクスを検討するときは、、、、など"but"、ステートメントに重要な意味を追加しない一般的な単語を削除する必要がある場合があります。"can""we"
  • PorterStemmerNLTKでステミングワードを実行するために使用されます。ステマーは、形態学的接辞の単語を取り除き、単語の語幹のみを残します。
  • WordNetLemmatizer()レンマ化のためにNLTKライブラリからインポートします。Lemmatizationはステミングよりもはるかに効果的です。これは、単語の削減を超えて、言語の語彙全体を評価し、語形変化の終わりを削除して、見出語として知られる単語のベースまたは辞書形式を返すことを目的として、形態素解析を単語に適用します。
  • stopwords.words('english')NLTKでサポートされているすべての英語のストップワードのリストを見てみましょう。
  • remove_unused_c()関数は、未使用の列を削除するために使用されます。
  • None関数を使用してnull値を代入しますnull_process()
  • 関数内で、関数をclean_dataset()呼び出します。この関数は、データのクリーニングを担当します。remove_unused_c()null_process()
  • 未使用の文字からテキストを削除するために、clean_text()関数を作成しました。
  • 前処理には、ストップワードの削除のみを使用します。nltk_preprocess()そのための関数を作成しました。

textおよびの前処理title

# Perform data cleaning on train and test dataset by calling clean_dataset function
df = clean_dataset(news_d)
# apply preprocessing on text through apply method by calling the function nltk_preprocess
df["text"] = df.text.apply(nltk_preprocess)
# apply preprocessing on title through apply method by calling the function nltk_preprocess
df["title"] = df.title.apply(nltk_preprocess)
# Dataset after cleaning and preprocessing step
df.head()

出力:

title	text	label
0	house dem aide didnt even see comeys letter ja...	house dem aide didnt even see comeys letter ja...	1
1	flynn hillary clinton big woman campus breitbart	ever get feeling life circle roundabout rather...	0
2	truth might get fired	truth might get fired october 29 2016 tension ...	1
3	15 civilian killed single u airstrike identified	video 15 civilian killed single u airstrike id...	1
4	iranian woman jailed fictional unpublished sto...	print iranian woman sentenced six year prison ...	1

探索的データ分析

このセクションでは、以下を実行します。

  • 単変量分析:テキストの統計分析です。そのためにワードクラウドを使用します。ワードクラウドは、最も一般的な用語が最も重要なフォントサイズで表示される、テキストデータの視覚化アプローチです。
  • 二変量解析:ここでは、バイグラムとトリグラムが使用されます。ウィキペディアによると:「n-gramは、テキストまたはスピーチの特定のサンプルからのn個のアイテムの連続したシーケンスです。アプリケーションによると、アイテムは音素、音節、文字、単語、または塩基対です。n-gram通常、テキストまたは音声コーパスから収集されます。」

シングルワードクラウド

最も頻繁に使用される単語は、ワードクラウド内で太字の大きなフォントで表示されます。このセクションでは、データセット内のすべての単語に対してワードクラウドを実行します。

WordCloudライブラリwordcloud()関数が使用され、ワー​​ドgenerate()クラウドイメージの生成に使用されます。

from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt

# initialize the word cloud
wordcloud = WordCloud( background_color='black', width=800, height=600)
# generate the word cloud by passing the corpus
text_cloud = wordcloud.generate(' '.join(df['text']))
# plotting the word cloud
plt.figure(figsize=(20,30))
plt.imshow(text_cloud)
plt.axis('off')
plt.show()

出力:

フェイクニュースデータ全体のWordCloud

信頼できるニュース専用のワードクラウド:

true_n = ' '.join(df[df['label']==0]['text']) 
wc = wordcloud.generate(true_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

出力:

信頼できるニュースのためのワードクラウド

フェイクニュース専用のワードクラウド:

fake_n = ' '.join(df[df['label']==1]['text'])
wc= wordcloud.generate(fake_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

出力:

フェイクニュースのためのワードクラウド

最も頻繁なバイグラム(2単語の組み合わせ)

N-gramは、文字または単語のシーケンスです。文字ユニグラムは1つの文字で構成され、バイグラムは一連の2文字で構成されます。同様に、単語N-gramは一連のn個の単語で構成されます。「団結」という言葉は1グラム(ユニグラム)です。「米国」という言葉の組み合わせは2グラム(バイグラム)、「ニューヨーク市」は3グラムです。

信頼できるニュースで最も一般的なバイグラムをプロットしてみましょう。

def plot_top_ngrams(corpus, title, ylabel, xlabel="Number of Occurences", n=2):
  """Utility function to plot top n-grams"""
  true_b = (pd.Series(nltk.ngrams(corpus.split(), n)).value_counts())[:20]
  true_b.sort_values().plot.barh(color='blue', width=.9, figsize=(12, 8))
  plt.title(title)
  plt.ylabel(ylabel)
  plt.xlabel(xlabel)
  plt.show()
plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Bigrams', "Bigram", n=2)

フェイクニュースのトップバイグラム

フェイクニュースで最も一般的なバイグラム:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Bigrams', "Bigram", n=2)

フェイクニュースのトップバイグラム

最も頻繁なトリグラム(3語の組み合わせ)

信頼できるニュースに関する最も一般的なトリグラム:

plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Trigrams', "Trigrams", n=3)

フェイクニュースで最も一般的なトリグラム

今のフェイクニュースの場合:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Trigrams', "Trigrams", n=3)

フェイクニュースで最も一般的なトリグラム

上記のプロットは、両方のクラスがどのように見えるかについてのいくつかのアイデアを示しています。次のセクションでは、トランスフォーマーライブラリを使用して偽のニュース検出器を構築します。

BERTを微調整して分類器を構築する

このセクションでは、トランスフォーマーライブラリを使用して偽のニュース分類子を作成するために、BERTチュートリアルの微調整からコードを広範囲に取得します。したがって、より詳細な情報については、元のチュートリアルに進むことができます。

トランスフォーマーをインストールしなかった場合は、次のことを行う必要があります。

$ pip install transformers

必要なライブラリをインポートしましょう:

import torch
from transformers.file_utils import is_tf_available, is_torch_available, is_torch_tpu_available
from transformers import BertTokenizerFast, BertForSequenceClassification
from transformers import Trainer, TrainingArguments
import numpy as np
from sklearn.model_selection import train_test_split

import random

環境を再起動しても、結果を再現可能にしたいと考えています。

def set_seed(seed: int):
    """
    Helper function for reproducible behavior to set the seed in ``random``, ``numpy``, ``torch`` and/or ``tf`` (if
    installed).

    Args:
        seed (:obj:`int`): The seed to set.
    """
    random.seed(seed)
    np.random.seed(seed)
    if is_torch_available():
        torch.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        # ^^ safe to call this function even if cuda is not available
    if is_tf_available():
        import tensorflow as tf

        tf.random.set_seed(seed)

set_seed(1)

使用するモデルは次のbert-base-uncasedとおりです。

# the model we gonna train, base uncased BERT
# check text classification models here: https://huggingface.co/models?filter=text-classification
model_name = "bert-base-uncased"
# max sequence length for each document/sentence sample
max_length = 512

トークナイザーのロード:

# load the tokenizer
tokenizer = BertTokenizerFast.from_pretrained(model_name, do_lower_case=True)

データの準備

次に、、、および列NaNから値をクリーンアップしましょう。textauthortitle

news_df = news_d[news_d['text'].notna()]
news_df = news_df[news_df["author"].notna()]
news_df = news_df[news_df["title"].notna()]

次に、データセットをPandasデータフレームとして受け取り、テキストとラベルのトレイン/検証分割をリストとして返す関数を作成します。

def prepare_data(df, test_size=0.2, include_title=True, include_author=True):
  texts = []
  labels = []
  for i in range(len(df)):
    text = df["text"].iloc[i]
    label = df["label"].iloc[i]
    if include_title:
      text = df["title"].iloc[i] + " - " + text
    if include_author:
      text = df["author"].iloc[i] + " : " + text
    if text and label in [0, 1]:
      texts.append(text)
      labels.append(label)
  return train_test_split(texts, labels, test_size=test_size)

train_texts, valid_texts, train_labels, valid_labels = prepare_data(news_df)

上記の関数は、データフレームタイプのデータセットを取得し、トレーニングセットと検証セットに分割されたリストとしてそれらを返します。に設定include_titleすると、トレーニングに使用する列に列がTrue追加されます。に設定すると、テキストにも列が追加されます。titletextinclude_authorTrueauthor

ラベルとテキストの長さが同じであることを確認しましょう。

print(len(train_texts), len(train_labels))
print(len(valid_texts), len(valid_labels))

出力:

14628 14628
3657 3657

データセットのトークン化

BERTトークナイザーを使用して、データセットをトークン化してみましょう。

# tokenize the dataset, truncate when passed `max_length`, 
# and pad with 0's when less than `max_length`
train_encodings = tokenizer(train_texts, truncation=True, padding=True, max_length=max_length)
valid_encodings = tokenizer(valid_texts, truncation=True, padding=True, max_length=max_length)

エンコーディングをPyTorchデータセットに変換します。

class NewsGroupsDataset(torch.utils.data.Dataset):
    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels

    def __getitem__(self, idx):
        item = {k: torch.tensor(v[idx]) for k, v in self.encodings.items()}
        item["labels"] = torch.tensor([self.labels[idx]])
        return item

    def __len__(self):
        return len(self.labels)

# convert our tokenized data into a torch Dataset
train_dataset = NewsGroupsDataset(train_encodings, train_labels)
valid_dataset = NewsGroupsDataset(valid_encodings, valid_labels)

モデルのロードと微調整

BertForSequenceClassificationBERTトランスフォーマーモデルのロードに使用します。

# load the model
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)

num_labels二項分類なので2に設定します。以下の関数は、各検証ステップの精度を計算するためのコールバックです。

from sklearn.metrics import accuracy_score

def compute_metrics(pred):
  labels = pred.label_ids
  preds = pred.predictions.argmax(-1)
  # calculate accuracy using sklearn's function
  acc = accuracy_score(labels, preds)
  return {
      'accuracy': acc,
  }

トレーニングパラメータを初期化しましょう:

training_args = TrainingArguments(
    output_dir='./results',          # output directory
    num_train_epochs=1,              # total number of training epochs
    per_device_train_batch_size=10,  # batch size per device during training
    per_device_eval_batch_size=20,   # batch size for evaluation
    warmup_steps=100,                # number of warmup steps for learning rate scheduler
    logging_dir='./logs',            # directory for storing logs
    load_best_model_at_end=True,     # load the best model when finished training (default metric is loss)
    # but you can specify `metric_for_best_model` argument to change to accuracy or other metric
    logging_steps=200,               # log & save weights each logging_steps
    save_steps=200,
    evaluation_strategy="steps",     # evaluate each `logging_steps`
)

を10に設定しましたper_device_train_batch_sizeが、GPUが収まる限り高く設定する必要があります。logging_stepsandを200に設定しsave_stepsます。これは、評価を実行し、200のトレーニングステップごとにモデルの重みを保存することを意味します。

 利用可能なトレーニングパラメータの詳細については、このページを確認 してください。

トレーナーをインスタンス化しましょう:

trainer = Trainer(
    model=model,                         # the instantiated Transformers model to be trained
    args=training_args,                  # training arguments, defined above
    train_dataset=train_dataset,         # training dataset
    eval_dataset=valid_dataset,          # evaluation dataset
    compute_metrics=compute_metrics,     # the callback that computes metrics of interest
)

モデルのトレーニング:

# train the model
trainer.train()

GPUによっては、トレーニングが完了するまでに数時間かかります。Colabの無料バージョンを使用している場合は、NVIDIA TeslaK80で1時間かかるはずです。出力は次のとおりです。

***** Running training *****
  Num examples = 14628
  Num Epochs = 1
  Instantaneous batch size per device = 10
  Total train batch size (w. parallel, distributed & accumulation) = 10
  Gradient Accumulation steps = 1
  Total optimization steps = 1463
 [1463/1463 41:07, Epoch 1/1]
Step	Training Loss	Validation Loss	Accuracy
200		0.250800		0.100533		0.983867
400		0.027600		0.043009		0.993437
600		0.023400		0.017812		0.997539
800		0.014900		0.030269		0.994258
1000	0.022400		0.012961		0.998086
1200	0.009800		0.010561		0.998633
1400	0.007700		0.010300		0.998633
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-200
Configuration saved in ./results/checkpoint-200/config.json
Model weights saved in ./results/checkpoint-200/pytorch_model.bin
<SNIPPED>
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-1400
Configuration saved in ./results/checkpoint-1400/config.json
Model weights saved in ./results/checkpoint-1400/pytorch_model.bin

Training completed. Do not forget to share your model on huggingface.co/models =)

Loading best model from ./results/checkpoint-1400 (score: 0.010299865156412125).
TrainOutput(global_step=1463, training_loss=0.04888018785440506, metrics={'train_runtime': 2469.1722, 'train_samples_per_second': 5.924, 'train_steps_per_second': 0.593, 'total_flos': 3848788517806080.0, 'train_loss': 0.04888018785440506, 'epoch': 1.0})

モデル評価

load_best_model_at_endに設定されているためTrue、トレーニングが完了すると、最適なウェイトがロードされます。検証セットを使用して評価してみましょう。

# evaluate the current model after training
trainer.evaluate()

出力:

***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
 [183/183 02:11]
{'epoch': 1.0,
 'eval_accuracy': 0.998632759092152,
 'eval_loss': 0.010299865156412125,
 'eval_runtime': 132.0374,
 'eval_samples_per_second': 27.697,
 'eval_steps_per_second': 1.386}

モデルとトークナイザーの保存:

# saving the fine tuned model & tokenizer
model_path = "fake-news-bert-base-uncased"
model.save_pretrained(model_path)
tokenizer.save_pretrained(model_path)

上記のセルを実行すると、モデルの構成と重みを含む新しいフォルダーが表示されます。予測を実行するfrom_pretrained()場合は、モデルをロードしたときに使用した方法を使用するだけで、準備は完了です。

次に、記事のテキストを引数として受け取り、それが偽物であるかどうかを返す関数を作成しましょう。

def get_prediction(text, convert_to_label=False):
    # prepare our text into tokenized sequence
    inputs = tokenizer(text, padding=True, truncation=True, max_length=max_length, return_tensors="pt").to("cuda")
    # perform inference to our model
    outputs = model(**inputs)
    # get output probabilities by doing softmax
    probs = outputs[0].softmax(1)
    # executing argmax function to get the candidate label
    d = {
        0: "reliable",
        1: "fake"
    }
    if convert_to_label:
      return d[int(probs.argmax())]
    else:
      return int(probs.argmax())

モデルが推論を実行するのを見たことがないという例を取り上げ、test.csvそれを確認しました。これは、ニューヨークタイムズの実際の記事です。

real_news = """
Tim Tebow Will Attempt Another Comeback, This Time in Baseball - The New York Times",Daniel Victor,"If at first you don’t succeed, try a different sport. Tim Tebow, who was a Heisman   quarterback at the University of Florida but was unable to hold an N. F. L. job, is pursuing a career in Major League Baseball. <SNIPPED>
"""

元のテキストは完全な記事であるため、コピーする場合はColab環境にあります。それをモデルに渡して、結果を見てみましょう。

get_prediction(real_news, convert_to_label=True)

出力:

reliable

付録:Kaggleの送信ファイルの作成

このセクションでは、のすべての記事を予測しtest.csvて提出ファイルを作成し、Kaggleコンテストのテストセットでの正確性を確認します。

# read the test set
test_df = pd.read_csv("test.csv")
# make a copy of the testing set
new_df = test_df.copy()
# add a new column that contains the author, title and article content
new_df["new_text"] = new_df["author"].astype(str) + " : " + new_df["title"].astype(str) + " - " + new_df["text"].astype(str)
# get the prediction of all the test set
new_df["label"] = new_df["new_text"].apply(get_prediction)
# make the submission file
final_df = new_df[["id", "label"]]
final_df.to_csv("submit_final.csv", index=False)

著者、タイトル、記事のテキストを連結した後、get_prediction()関数を新しい列に渡して列を埋め、メソッドをlabel使用to_csv()してKaggleの送信ファイルを作成します。これが私の提出スコアです:

提出スコア

プライベートおよびパブリックのリーダーボードで99.78%および100%の精度が得られました。すごい!

結論

了解しました。チュートリアルは終了です。このページをチェックして、微調整できるさまざまなトレーニングパラメータを確認できます。

微調整用のカスタムのフェイクニュースデータセットがある場合は、サンプルのリストをトークン化ツールに渡すだけで済みます。その後、他のコードを変更することはありません。

ここで完全なコードを確認するか、ここでColab環境を確認してください。