ゼロベースのエントリNLPニューステキスト分類_Task4

従来の機械学習とは異なり、ディープラーニングは特徴抽出機能だけでなく、完全な分類機能も提供します。このタスクは主に、ディープラーニングを使用してテキスト表現を完了する方法を示します。
この章では、主にFastTextを使用して、深層学習の単語ベクトルの表現を完成させます。FastTextは、埋め込みレイヤーを介して単語を密空間にマッピングし、埋め込みレイヤー空間内の文内のすべての単語を平均して分類作業を完了します。したがって、FastTextレイヤーは、入力レイヤー、非表示レイヤー、出力レイヤーの3層ニューラルネットワークです。
ここに画像の説明を挿入
次の図は、Kerasを使用して実装されたFastTextネットワーク構造です
ここに画像の説明を挿入
。FastTextによって完了した単語テキスト分類のコードと解釈は次のとおりです。FastTextの学習は、コードの再現によって完了します

サードパーティのモジュールをインポートする

import pandas as pd
from sklearn.metrics import f1_score
from sklearn.model_selection import StratifiedKFold  # 这可以保证每一折分布一致
import fasttext

ここでエラーを報告するには、「pip install fasttext」を使用します。
解決策は、最初にfasttextのサードパーティインストールパッケージをダウンロードしてから、インストールするローカルパスを指定することです。
ウェブサイトのナビゲーション:https: //www.lfd.uci.edu/~gohlke/pythonlibs/#fasttext
installationコマンド:pip install fasttext-0.9.2-cp38-cp38-win_amd64.whl(インストールファイルを現在の環境のパスに配置する必要があります)

分類モデル

マシンへの負担を軽減するために、15,000のトレーニングサンプルデータがインポートされます

train_df = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\train_set.csv',
                       sep='\t', nrows=15000)

FastTextで必要な形式に変換します。デフォルトでは、ラベルは__label__という文字列が前に付いた単語であると想定しています

train_df['label_ft'] = '__label__' + train_df['label'].astype(str)

最初の10,000個のトレーニングサンプルのテキストと新しいラベルを取得して、FastText形式に適した新しいトレーニングセットを作成します

train_df[['text', 'label_ft']].iloc[:-5000].to_csv('train.csv', index=None, header=None, sep='\t')

トレーニングデータ、学習率は1、n-gramの数は2、各エポックのレコードの行が出力され、単語頻度のしきい値は1、回数は25、そして損失関数は階層的なソフトマックスを選択

model = fasttext.train_supervised('train.csv', lr=1.0, wordNgrams=2, verbose=2,
                                  minCount=1, epoch=25, loss='hs')
'''
fasttext.train_supervised() - 训练一个监督模型,返回一个模型对象
参数详解:
    input - 训练数据文件路径
    lr - 学习率
    dim - 向量维度
    ws - cbow模型时使用
    epoch - 次数
    minCount - 词频阈值,小于该值在初始化时会被过滤
    minCountLabel - 类别阈值,类别小于改值初始化时会被过滤
    minn - 构造subword时最小char个数
    maxn - 构造subword时最大char个数
    neg - 负采样
    wordNgrams - n-gram个数,组成词语的长度
    loss - 损失函数类型,softmax, ns:负采样, hs:分层softmax
    bucket - 词扩充大小,[A, B]:A语料中包含的词向量,B不在语料中的词向量
    thread - 线程个数,每个线程处理输入数据的一段,0号线程负责loss输出
    lrUpdateRate - 学习率更新
    t - 负采样阈值
    label - 类别前缀
    pretrainedVectors - 预训练的词向量文件路径,如果word出现在文件夹中初始化不再随机
    verbose - 日志显示
        verbose = 0 为不在标准输出流输出日志信息 
        verbose = 1 为输出进度条记录 
        verbose = 2 为每个epoch输出一行记录
'''

検証データを予測して精度を計算する

val_pred_fasttext = [model.predict(x)[0][0].split('__')[-1] for x in train_df.iloc[-5000:]['text']]
'''
由于FastText单个预测值返回的是一个元组,元组包括标签列表和概率列表,如:
    (('__label__4',), array([0.99362451]))
所以我们在提取预测类别值的时候提前加上切片操作,将词标签的值取出;
然后按照'__'对词标签进行分割,从而获取实际预测到的类别值

模型单例预测函数代码:
def model.predict(self, text, k=1, threshold=0.0):
  """
  模型预测,给定文本预测分类
  @param text:       字符串, 需要utf-8
  @param k:          返回标签的个数
  @param threshold   概率阈值, 大于该值才返回
  @return 标签列表, 概率列表
  """
  pass
'''

print(f1_score(train_df['label'].values[-5000:].astype(str), val_pred_fasttext, average='macro'))

f1_scoreは約0.82です。

精度を向上させるためにトレーニングサンプルの数を増やすようにしてください

train_df_big = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\train_set.csv',
                           sep='\t', nrows=75000)
train_df_big['label_ft'] = '__label__' + train_df_big['label'].astype(str)
train_df_big[['text', 'label_ft']].iloc[:50000].to_csv('train_big.csv', index=None, header=None, sep='\t')
model_big = fasttext.train_supervised('train_big.csv', lr=1.0, wordNgrams=2, verbose=2,
                                      minCount=1, epoch=25, loss='hs')
val_pred_fasttext_big = [model_big.predict(x)[0][0].split('__')[-1] for x in train_df_big.iloc[-50000:]['text']]
print(f1_score(train_df_big['label'].values[-50000:].astype(str), val_pred_fasttext_big, average='macro'))

スコアは0.944に達しました。

相互検証が10%オフ

各フォールドはトレーニングにデータの9/10を使用し、検証には1/10を使用します。
各フォールドの分割により、ラベルの分布がデータセット全体の分布と一致することを確認する必要があり
ます。StratifiedKFoldを使用してトレーニングセットを10のフォールドに分割し、異なるフォールドを個別に保存してみてください検証セットとして使用される場合のトレーニングセットと検証セット

train_df = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\train_set.csv', sep='\t')
skf = StratifiedKFold(n_splits=10)  # 确保分出的折与原始集分布相同
for n_fold, (train_index, val_index) in enumerate(skf.split(train_df['text'], train_df['label'])):
    # enumerate()函数用于将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标,一般用在for循环当中
    print(f'the {n_fold} data split...')
    train_X, train_y, val_X, val_y = train_df['text'].iloc[train_index], train_df['label'][train_index], \
                                     train_df['text'].iloc[val_index], train_df['label'][val_index]
    # 把标签转化成FastText能训练的形式
    train_y = '__label__' + train_y.astype(str)
    train_data = pd.DataFrame(list(zip(train_X.values, train_y.values)))
    train_data.to_csv(f'data/fasttext_skf10_datasplit/train_split{n_fold}.csv',
                      index=None, header=['text', 'label_ft'], sep='\t')
    test_data = pd.DataFrame(list(zip(val_X.values, val_y.values)))
    test_data.to_csv(f'data/fasttext_skf10_datasplit/test_split{n_fold}.csv',
                     index=None, header=['text', 'label'], sep='\t')

10分割交差検定を使用してパラメーターを調整する

print('starting K10 cross-validation training:')
# val_f1用于存放10次验证集的f1_score
val_f1 = []
for n_fold in range(10):
    model = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split{n_fold}.csv',
                                      lr=1.0, wordNgrams=2, verbose=2, minCount=1, epoch=25, loss='softmax')
    val_df = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split{n_fold}.csv', sep='\t')
    val_pred = [model.predict(x)[0][0].split('__')[-1] for x in val_df['text']]
    val_f1.append(f1_score(val_df['label'].values.astype(str), val_pred, average='macro'))
    print(f'the f1_score of {n_fold}training is:', val_f1[n_fold])
print('The average f1_score is:', sum(val_f1) / len(val_f1))

長いトレーニングと待機の後...
ここに画像の説明を挿入
10回のトレーニングセッションのスコアは0.93で、これは悪くないことです。

オンライン検証

test_data = pd.read_csv(r'D:\Users\Felixteng\Documents\Pycharm Files\Nlp\data\test_a.csv', sep='\t')
test_pred = [model.predict(x)[0][0].split('__')[-1] for x in test_data['text']]
sub = pd.DataFrame(test_pred, columns=['label'])
sub.to_csv('sub.csv', index=False)

オンライン予測結果のスコアは0.9304で、オンラインとオフラインの差は大きくありません。スコアは悪くありませんが、パラメーターに大きな変化はなく、改善の余地があります。

前後に数回手動でパラメーターを調整してみたがスコアが上がらなかった

val_0 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split0.csv', sep='\t')
model_0 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split0.csv',
                                    lr=1.0, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_0 = [model_0.predict(x)[0][0].split('__')[-1] for x in val_0['text']]
print(f1_score(val_0['label'].values.astype(str), val_pred_0, average='macro'))

test_pred_0 = [model_0.predict(x)[0][0].split('__')[-1] for x in test_data['text']]
sub_0 = pd.DataFrame(test_pred_0, columns=['label'])
sub_0.to_csv('sub_0.csv', index=False)


val_1 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split1.csv', sep='\t')
model_1 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split1.csv',
                                    lr=1.5, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_1 = [model_1.predict(x)[0][0].split('__')[-1] for x in val_1['text']]
print(f1_score(val_1['label'].values.astype(str), val_pred_1, average='macro'))
'''
0.9344292030486819
'''


val_2 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split2.csv', sep='\t')
model_2 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split2.csv',
                                    lr=2, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_2 = [model_2.predict(x)[0][0].split('__')[-1] for x in val_2['text']]
print(f1_score(val_2['label'].values.astype(str), val_pred_2, average='macro'))
'''
0.934281492108054
'''


val_3 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split3.csv', sep='\t')
model_3 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split3.csv',
                                    lr=1.5, wordNgrams=4, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_3 = [model_3.predict(x)[0][0].split('__')[-1] for x in val_3['text']]
print(f1_score(val_3['label'].values.astype(str), val_pred_3, average='macro'))
'''
0.9383561689755379
'''


val_4 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split4.csv', sep='\t')
model_4 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split4.csv',
                                    lr=2.5, wordNgrams=3, verbose=2, minCount=1, epoch=25, loss='softmax')
val_pred_4 = [model_4.predict(x)[0][0].split('__')[-1] for x in val_4['text']]
print(f1_score(val_4['label'].values.astype(str), val_pred_4, average='macro'))
'''
0.9353875257235135
'''


val_5 = pd.read_csv(f'data/fasttext_skf10_datasplit/test_split5.csv', sep='\t')
model_5 = fasttext.train_supervised(f'data/fasttext_skf10_datasplit/train_split5.csv',
                                    lr=2, wordNgrams=4, verbose=2, minCount=1, epoch=30, loss='softmax')
val_pred_5 = [model_5.predict(x)[0][0].split('__')[-1] for x in val_5['text']]
print(f1_score(val_5['label'].values.astype(str), val_pred_5, average='macro'))
'''
0.9354738839095721
'''


test_pred_3 = [model_3.predict(x)[0][0].split('__')[-1] for x in test_data['text']]
sub_3 = pd.DataFrame(test_pred_3, columns=['label'])
sub_3.to_csv('sub_3.csv', index=False)

スコアはすべて0.935前後です。自動パラメーター調整スクリプトの作成に加えて、トレーニングにはより高精度のモデルが必要になる場合があります。

次の章では、ディープラーニングの他のモデルでテキスト分類タスクを引き続き試行します。

おすすめ

転載: blog.csdn.net/Baby1601tree/article/details/107594365