[自然言語NLP]TensorFlowはLSTMを使用して感情分析タスクを実装します

自然言語感情分析

ご存知のように、人間の自然言語には、人々の感情(悲しみ、幸福など)の表現、人々の気分(燃え尽き症候群、うつ病など)の表現、人々の好み(好き、憎しみなど)の表現など、豊かな感情の色が含まれています。機械を使用してこれらの感情的な傾向を自動的に分析することは、企業が消費者が製品についてどのように感じているかを理解し、製品改善の基礎を提供するのに役立つだけでなく、企業がビジネスパートナーの態度を分析してより良いビジネス上の意思決定を行うのにも役立ちます。

感情分析タスクを分類問題として定義できます。つまり、テキスト入力が与えられると、マシンはテキストの分析、処理、一般化、および推論の後に結論を自動的に出力します。

一般的な感情分析タスク

  • ポジティブ:喜び、幸福、驚き、期待などのポジティブな感情を表現します。
  • ネガティブ:悲しみ、悲しみ、怒り、パニックなどのネガティブなネガティブな感情を示します。
  • その他:他の種類の感情を示します

ディープニューラルネットワークが感情分析タスクを完了します

一般的なアプローチは、最初に単語をベクトルに変換し、次に文の各単語をベクトル化し、このベクトルを使用して感情分析タスクを表すことです。

まず、文中のすべての単語ベクトルの埋め込み方向と逆方向を加算して平均し、結果の重み付き埋め込みベクトルを文全体のベクトル表現として使用しますが、この方法ではいくつかの問題が発生します。

  • 可変長の文:自然言語の文は長さが異なることがよくありますが、ほとんどのニューラルネットワークは同じ長さのテンソルの入力を受け入れます
  • 我喜欢你結合されたセマンティクス:重み付けされた埋め込みベクトルを使用すると、合計などの異なる単語の順序の影響などのセマンティクス情報が失われます。你喜欢我重み付けされている場合、これら2つの文の表現ベクトルは同じですが、明らかにこれら2つの文のセマンティクスはとても違う

可変長文の処理を
設定することによりmax_seq_len、ニューラルネットワークが処理できるテキストの最大長を制御するために使用されます。文の長さが十分でない場合はパディングを使用でき、文が長すぎる場合は切り捨てを使用できます。

画像-20220114182805600

  • max_seq_lenより長い文の場合、通常、テンソルに入力できるように文を切り捨てます。文の切り捨てのプロセスには注意が必要です。文の最初の部分を切り捨てる方が後者よりも優れている場合もあれば、その逆の場合もあります。もちろん、他の切り捨て方法もあります。興味のある読者は、ここでは繰り返さない関連情報を読むことができます。
  • 文の長さがmax_seq_len未満の文の場合、通常、特別な単語を使用して文をパディングします。これは、パディングと呼ばれるプロセスです。「私、愛、人工、知性」という文を想定すると、max_seq_len = 6の場合、2つの可能な充填方法があります。
    • フォワードフィル:「[パッド]、[パッド]、私、愛、人工、知性」
    • 埋め戻し:「私、愛、人工、知性、[パッド]、[パッド]」

リカレントニューラルネットワークRNN

RNNネットワークは、一般的なユーザー指向のシーケンスモデルであり、自然言語の文やその他の時系列信号をモデル化できます。RNNネットワークの構造を次の図に示します。

画像-20220114182954136

文ベクトル全体を異なる単語ベクトルに分割し、各単語ベクトルをベクトルで表します。まず、画像のIをメモリ用のネットワークに入力し、次に出力を次のセルに送信します。時間。スライスの単語ベクトルは、最後のセルまで一緒にモデル化され、その後、ベクトルが出力されます。

長短期記憶ネットワーク(LSTM)

RNNは時系列データや自然言語を処理できますが、ネットワークモデルが小さく、より効果的な情報を保持できないという問題があります。文が長すぎる場合、LSTMはこの問題を解決でき、このネットワークモデルは忘却と記憶を学習できます。 、選択的学習、記憶、前の文の忘れ。

画像-20220114183459760

  • 入力ゲート:リカレントニューラルネットワークRNNと長短期記憶ネットワークLSTM-図22、入力信号のどれだけが融合されるかを制御します。
  • Oblivion Gate:、リカレントニューラルネットワークRNNと長短期記憶ネットワークLSTM-図23過去の記憶がどれだけ融合されるかを制御します。
  • 出力ゲート:リカレントニューラルネットワークRNNと長短期記憶ネットワークLSTM-図24、最終的に出力されるメモリの量を制御します。
  • ユニットステータス:リカレントニューラルネットワークRNNと長短期記憶ネットワークLSTM-図25

画像-20220114183536181

LSTMは感情分析タスクを実装します

長短期記憶ネットワークの助けを借りて、感情分析タスクを非常に簡単に実行できます。以下に示すように。文ごとに、最初にこれらの文を切り捨ててパディングすることで固定長のベクトルに変換します。次に、長短期記憶ネットワークを使用して、各文が左から右に読み取られます。読み取りが完了したら、長短期記憶ネットワークの最後の出力メモリを文全体の意味情報として使用し、このベクトルを直接入力として使用し、分類のために分類レイヤーに送信して、ニューラルを完成させます。感情分析問題のためのネットワーク構築。金型。

画像-20220114183645100

完全なコード

1.コーパスデータをロードします

"""
 * Created with PyCharm
 * 作者: 阿光
 * 日期: 2022/1/13
 * 时间: 23:29
 * 描述:
"""
import random
import re
import tarfile

import numpy as np
import requests


def download():
    corpus_url = "https://dataset.bj.bcebos.com/imdb%2FaclImdb_v1.tar.gz"
    web_request = requests.get(corpus_url)
    corpus = web_request.content

    with open("./aclImdb_v1.tar.gz", "wb") as f:
        f.write(corpus)

    f.close()


# download()


def load_imdb(is_training):
    data_set = []
    for label in ["pos", "neg"]:
        with tarfile.open("./aclImdb_v1.tar.gz") as tarf:
            path_pattern = "aclImdb/train/" + label + "/.*\.txt$" if is_training \
                else "aclImdb/test/" + label + "/.*\.txt$"
            path_pattern = re.compile(path_pattern)
            tf = tarf.next()
            while tf != None:
                if bool(path_pattern.match(tf.name)):
                    sentence = tarf.extractfile(tf).read().decode()
                    sentence_label = 0 if label == 'neg' else 1
                    data_set.append((sentence, sentence_label))
                tf = tarf.next()
    return data_set


def data_preprocess(corpus):
    data_set = []
    for sentence, sentence_label in corpus:
        sentence = sentence.strip().lower()
        sentence = sentence.split(" ")
        data_set.append((sentence, sentence_label))
    return data_set


# 构造词典,统计每个词的频率,并根据频率将每个词转换为一个整数id
def build_dict(corpus):
    word_freq_dict = dict()
    for sentence, _ in corpus:
        for word in sentence:
            if word not in word_freq_dict:
                word_freq_dict[word] = 0
            word_freq_dict[word] += 1
    word_freq_dict = sorted(word_freq_dict.items(), key=lambda x: x[1], reverse=True)
    word2id_dict = dict()
    word2id_freq = dict()
    word2id_dict['[oov]'] = 0
    word2id_freq[0] = 1e10
    word2id_dict['[pad]'] = 1
    word2id_freq[1] = 1e10
    for word, freq in word_freq_dict:
        word2id_dict[word] = len(word2id_dict)
        word2id_freq[word2id_dict[word]] = freq
    return word2id_freq, word2id_dict


# 把语料转换为id序列
def convert_corpus_to_id(corpus, word2id_dict):
    data_set = []
    for sentence, sentence_label in corpus:
        sentence = [word2id_dict[word] if word in word2id_dict \
                        else word2id_dict['[oov]'] for word in sentence]
        data_set.append((sentence, sentence_label))
    return data_set


# 编写一个迭代器,每次调用这个迭代器都会返回一个新的batch,用于训练或者预测
def build_batch(word2id_dict, corpus, batch_size, epoch_num, max_seq_len, shuffle=True):
    sentence_batch = []
    sentence_label_batch = []
    for _ in range(epoch_num):
        if shuffle:
            random.shuffle(corpus)
        for sentence, sentence_label in corpus:
            sentence_sample = sentence[:min(max_seq_len, len(sentence))]
            if len(sentence_sample) < max_seq_len:
                for _ in range(max_seq_len - len(sentence_sample)):
                    sentence_sample.append(word2id_dict['[pad]'])
            sentence_batch.append(sentence_sample)
            sentence_label_batch.append([sentence_label])
            if len(sentence_batch) == batch_size:
                yield np.array(sentence_batch).astype("int64"), np.array(sentence_label_batch).astype("int64")
                sentence_batch = []
                sentence_label_batch = []
    if len(sentence_batch) == batch_size:
        yield np.array(sentence_batch).astype("int64"), np.array(sentence_label_batch).astype("int64")


def get_data():
    train_corpus = load_imdb(True)
    test_corpus = load_imdb(False)
    train_corpus = data_preprocess(train_corpus)
    test_corpus = data_preprocess(test_corpus)
    word2id_freq, word2id_dict = build_dict(train_corpus)
    vocab_size = len(word2id_freq)
    train_corpus = convert_corpus_to_id(train_corpus, word2id_dict)
    test_corpus = convert_corpus_to_id(test_corpus, word2id_dict)
    train_datasets = build_batch(word2id_dict,
                                 train_corpus[:1000], batch_size=64, epoch_num=64, max_seq_len=30)
    return train_datasets

2.LSTMネットワークモデルを定義します

"""
 * Created with PyCharm
 * 作者: 阿光
 * 日期: 2022/1/13
 * 时间: 23:45
 * 描述:
"""
import keras
from tensorflow import nn
from tensorflow.keras.layers import *


class Model(keras.Model):
    def __init__(self):
        super(Model, self).__init__()
        self.embedding = Embedding(input_dim=252173,
                                   output_dim=256)
        self.lstm = LSTM(128)
        self.fc = Dense(2, activation=nn.softmax)

    def call(self, inputs):
        x = self.embedding(inputs)
        x = self.lstm(x)
        x = self.fc(x)
        return x

3.トレーニングデータ

"""
 * Created with PyCharm
 * 作者: 阿光
 * 日期: 2022/1/13
 * 时间: 23:57
 * 描述:
"""
import tensorflow as tf
from keras import Input

import lstm
from model import Model

models = Model()
models.build(input_shape=(1, 50))
models.call(Input(shape=50))
models.summary()

train_datasets = lstm.get_data()

models.compile(optimizer='adam',
               loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
               metrics=['accuracy'])

# 权重保存路径
checkpoint_path = "./weight/cp.ckpt"

# 回调函数,用户保存权重
save_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,
                                                   save_best_only=True,
                                                   save_weights_only=True,
                                                   monitor='loss',
                                                   verbose=1)

history = models.fit(train_datasets,
                     epochs=5,
                     callbacks=[save_callback])

おすすめ

転載: blog.csdn.net/m0_47256162/article/details/122500197