自然言語処理とSAS (3)

0

こんにちは!SAS Institute Japanの堀内です。今回も自然言語処理について紹介いたします。

前回の投稿では、実際にSASを使って日本語の文章を扱う自然言語処理の例を解説しました。
最終回の本投稿ではその応用編として、自然言語処理の代表的なタスクとSASによる実装方法を紹介します。なお、ここでいうタスクとは「定式化され一般に共有された課題」といった意味になります。自然言語処理には複数のタスクがあり、タスクごとに、共通する部分はあるとはいえ、問題解決のアプローチ方法は基本的に大きく異なります。SASには各タスクごとに専用のアクションセット1が容易されています。

要約タスク

その名の通り文章を要約するタスクです。SASではtextSummarizeアクションセットで対応可能です。
ここでは、NHKのニュース解説記事「気になる頭痛・めまい 天気が影響?対処法は?」(https://www.nhk.or.jp/kaisetsu-blog/700/471220.html) の本文を5センテンスで要約してみましょう。

import swat
conn = swat.CAS('mycashost.com', 5570, 'username', 'password')
conn.builtins.loadActionSet(actionSet='textSummarization')
conn.textSummarization.textSummarize(addEllipses=False,
                                     corpusSummaries=dict(name='corpusSummaries', compress=False, replace=True),
                                     documentSummaries=dict(name='documentSummaries', compress=False, replace=True),
                                     id='Id',
                                     numberOfSentences=5,
                                     table={'name':CFG.in_cas_table_name},
                                     text='text',
                                     useTerms=True,
                                     language='JAPANESE')
conn.table.fetch(table={'name': 'corpusSummaries'})

numberOfSentencesで要約文のセンテンス数を指定しています。結果は以下の通りです。

'まず体調の変化や天気、気温・湿度・気圧などの日記をつけ、本当に天気が影響しているのか、どういうときに不調になるのかパターンを把握すると役立ちます。 
気温・湿度以外にも、気圧が、体調の悪化や、ときに病気の引き金になることもあります。 
私たちの体は、いつも耳の奥にある内耳にあると言われている気圧センサーで、気圧の変化を調整しています。 
ただ、天気の体への影響を研究している愛知医科大学佐藤客員教授にお話ししを伺ったところ、「台風最接近の前、つまり、気圧が大きく低下する前に、頭が痛いなど体調が悪くなる人は多い」ということです。 
内耳が敏感な人は、わずかな気圧の変化で過剰に反応し、脳にその情報を伝えるので、脳がストレスを感じ、体のバランスを整える自律神経が乱れ、血管が収縮したり、筋肉が緊張するなどして、その結果、頭痛・めまいなどの体に様々な不調につながっているのです。'

重要なセンテンスが抽出されていることが分かります。

 

テキスト分類タスク

文章をいくつかのカテゴリに分類するタスクです。その内、文章の印象がポジティブなのかネガティブなのか分類するものをセンチメント分析と呼びます。ここでは日本語の有価証券報告書の文章をポジティブかネガティブか判定してみます。使用するデータセットは以下になります。

https://github.com/chakki-works/chABSA-dataset

(なお、こちらのデータセットには文章ごとにポジティブかネガティブかを示す教師ラベルは元々付与されておりませんが、文章内の特定のフレーズごとに付与されているスコアを合算することで教師ラベルを合成しております。その結果、ポジティブ文章は1670文章、ネガティブ文章は1143文章、合計2813文章になりました。教師ラベルの合成方法詳細はこちらのブログをご覧ください。)
pandasデータフレームにデータを格納した状態を確認してみましょう。

df = pd.read_csv(CFG.local_input_file_path)
display(df)

先ほどのpandasデータフレームはCAS2にアップロードしておきます。

conn.upload(df, casout=dict(name=CFG.in_cas_table_name, promote = False, replace=True))

それでは実際に判定してみましょう。まずはsentimentAnalysisアクションセットを使ってみます。

sentimentAnalysisアクションセット

conn.builtins.loadActionSet(actionSet='sentimentAnalysis')
conn.sentimentAnalysis.applySent(casOut={'name':CFG.out_cas_table_name, 'replace':True}, 
                                 language='JAPANESE',
                                 docId='Id',
                                 table={'name':CFG.in_cas_table_name},
                                 text='text')
conn.table.fetch(table={'name': CFG.out_cas_table_name})

文章ごとにスコアが計算されています。スコアが0.5よりも大きいとポジティブ、小さいとネガティブ、0.5ちょうどであればニュートラル、という分類になります。今回はニュートラルはデータに存在していないため、ニュートラルと予測したものは一律ネガティブに変換します。それでは精度はどうでしょうか?

F1マイクロスコアで0.657でした。何も訓練をしていない状態であることを考慮すれば、まずまずの結果と言えます。

それでは次にBERTをfine-tuningして予測してみましょう。

BERT

BERTとは、Bidirectional Encoder Representation from Transformersの略で、「Transformerによる双方向エンコード表現」と訳されるディープラーニングモデルの一種で、自然言語処理の様々なタスクにおいて高い精度を出せることで知られています。なお、Transformerとは、Self-Attentionと呼ばれる自己注意機構とPosition-wise Feed Forward Networksと呼ばれる位置単位順伝播ネットワークからなる新しいタイプのディープラーニングモデルで、トークンとトークンの関係性に効率的に注意を払えるようになったことで、自然言語処理で用いられるディープラーニングモデルの代表格になりました。またこれらのディープラーニングモデルは予めWikipediaなどの大量のテキストデータでpre-trainと呼ばれる事前学習が施されており、それを手元のデータで追加学習(fine-tuning)することで更に高い精度を発揮することができます。

SASでBERTを使う場合はDLPy3というライブラリを使います。DLPyでは、Hugging Faceという、多数のpre-train済みTransformerモデルを公開しているサイトから任意のモデルを呼び出して利用することができます。今回は東北大学乾研究室がpre-trainのうえ公開している'cl-tohoku/bert-base-japanese'という日本語に対応したBERTを使用します。

# コンフィグ
class CFG:
    cas_table_name = 'BLOG_NLP_SAS_CHABSA'
    local_input_file_path = '/local/path/to/chABSA/chABSA_fsa.csv'
    cache_dir = '/local/path/to/transformers/'
    server_dir = '/server/path/to/'
    check_point = 'cl-tohoku/bert-base-japanese'
    max_seq_len = 512
    mini_batch_size = 2
    learning_rate = 12e-5
    max_epochs = 15
    freeze_base_model = True
    last_frozen_layer = 'encoder10_ln2'
 
from dlpy.transformers.bert_model import BERT_Model
from dlpy.transformers.bert_utils import bert_prepare_data
 
# BERTモデルの定義
bert = BERT_Model(conn,
                  cache_dir=CFG.cache_dir,
                  name=CFG.check_point,
                  n_classes=2,
                  num_hidden_layers=12,
                  max_seq_len=CFG.max_seq_len,
                  verbose=True)
 
# 訓練データとテストデータの分割
inputs = df['text'].to_list()
targets = df['target'].to_list()
num_tgt_var, train, test = bert_prepare_data(conn,
                                             bert.get_tokenizer(),
                                             input_a=inputs,
                                             target=targets,
                                             train_fraction=0.8,
                                             segment_vocab_size=bert.get_segment_size(),
                                             classification_problem=bert.get_problem_type(),
                                             max_seq_len=CFG.max_seq_len,
                                             verbose=True)

次にBERTモデルのコンパイルを行います。これにより、CFG.cache_dirで指定したディレクトリにBERTの重みファイルが格納されます。

bert.compile(num_target_var=num_tgt_var)

重みファイルはサーバー側にコピーしたうえで、BERTモデルにロードします。

copyfile(os.path.join(CFG.cache_dir, 'cl-tohoku/bert-base-japanese.kerasmodel.h5'),
os.path.join(CFG.server_dir, 'bert-base-japanese.kerasmodel.h5'))
bert.load_weights(CFG.server_dir + 'bert-base-japanese.kerasmodel.h5',
                  num_target_var=num_tgt_var,
                  freeze_base_model=CFG.freeze_base_model,
                  last_frozen_layer=CFG.last_frozen_layer,
                  use_gpu=False)

これで訓練開始前の準備が整いました。訓練を開始します。

# オプティマイザーの設定
bert.set_optimizer_parameters(max_epochs=CFG.max_epochs, 
                              mini_batch_size=CFG.mini_batch_size,
                              learning_rate=CFG.learning_rate)
# 訓練開始
bert.fit(train,
         data_specs=bert.get_data_spec(num_tgt_var),
         optimizer=bert.get_optimizer(),
         text_parms=bert.get_text_parameters(),
         seed=42,
         save_best_weights=True)

ラーニング・カーブを確認します。

bert.plot_training_history();

 

訓練Lossはしっかりと下がっていますね。それではテストデータに対して予測をし、精度を確認していきます。

res = bert.predict(test, bert.get_text_parameters(), use_best_weights=True)
res

誤分類率は7.279029%ということで精度は申し分ないようです。F1マイクロスコアとプロットも確認してみましょう。

F1マイクロスコアは0.927となり、先ほどのsentimentAnalysisアクションセットよりも大幅に改善したことが分かります。このようにBERTを使うと精度が大幅に向上することがあります。さすがはBERT、といったところでしょうか。

なお、日本語を扱ったものではありませんが、このあたりの実装を解説している動画がありましたので参考までにリンクを貼っておきます。

Introduction to BERT and how to implement it in SAS Viya:

BERT for Text Classification on SAS Viya:

その他

ここではどのようなタスクに対応する場合においてもあると嬉しい自然言語処理の機能を紹介します。

正規表現とLITIの比較

以下のテキストから、"SAS Insitute Japan", "SASインスティチュート", "SASインスティチュート・ジャパン"という名称だけを抽出したい場合はどのようにすれば良いでしょうか?

デロイトトーマツグループは、地球温暖化などの気候変動が銀行の経営に与える影響を分析するサービスを始める。米分析ソフト大手のSASインスティチュートと組み、水害などの自然災害が取引先企業の拠点に及ぼす被害額を算出。取引先企業に対する融資判断への活用を促す。気候変動開示に対する圧力が強まるなか、分析の高度化に向けた支援に力を入れる。
タイヤに設置したセンサーで路面の滑りやすさのほか、空気圧や摩耗状態、荷重といった情報などを取得する。収集したデータをAIなどで分析。走行中の車両のタイヤが止まる力や限界値を推測できる。収集したデータを解析するソフトはSAS Institute Japan(東京・港)と構築した。
データ分析のソフトウエアやクラウドサービスを手掛けるSAS Institute Japanは2019年2月5日、ビジネス戦略説明会を開催した。堀田徹哉社長は19年に注力するテーマとして、(1)コア・ビジネス領域の成長(2)カスタマーリレーションの強化(3)将来への準備と社会貢献を挙げた。
兵庫県尼崎市は23日、全市民約46万人分の個人情報が入ったUSBメモリーを委託業者が紛失したと発表した。名前や住所、生年月日、住民税額や、児童手当と生活保護の受給世帯の口座情報などが含まれるという。

(出典:
https://www.nikkei.com/article/DGKKZO74824300W1A810C2EE9000/
https://www.nikkei.com/article/DGXMZO55398310X00C20A2XA0000/
https://www.nikkei.com/article/DGXMZO40957060W9A200C1000000/
https://www.asahi.com/articles/ASQ6R3TSCQ6RPIHB005.html)

正規表現を使う場合は以下のように書きます。

SAS(?: Institute|インスティチュート)(?:ジャパン|・ジャパン| Japan)?

正規表現に慣れていればどうということではないのですが、慣れていないと中々難しく感じることもあるのではないでしょうか?VTA4のLITI構文を使うとより直感的に抽出条件を記載することが可能です。LITIとはLanguage Interpretation and Text Interpretaionの略で、テキスト情報をルールベースの論理式で表現するSAS独自のテキスト・マイニング機能を提供しています。以下はVTAのLITI構文エディタを開いた画面になります。

L_sas_enとL_sas_jpという2つのコンセプトを使って対象のテキストを抽出しています。
各コンセプトは以下の通りです。

L_sas_enコンセプトには"SAS Institute"と"SAS Institute Japan"を抽出するよう定義されており、L_sas_jpコンセプトには"SASインスティチュート・ジャパン"と"SASインスティチュート"を抽出するよう定義されております。書き方は至ってシンプルですね。

またVTAのLITI構文にはREGEXというメソッドもあり、正規表現をそのまま書くことも可能です。

正規表現に習熟したユーザーはこのほうが好みでしょう。

言語判定

扱うテキストデータが日本語のみ、英語のみ、という場合は良いのですが、複数の言語が混在しているケースも結構あるかと思います。テキストデータを言語ごとに分別したいときに便利なのがidentifyLanguageアクションセットです。
読み込むデータは以下のように多言語になります。いずれも「僕は耳と目を閉じ、口を噤んだ人間になろうと考えたんだ。」という一文を表しています。上から、英語、日本語、中国語、ベトナム語、韓国語、スウェーデン語、ノルウェー語、西フリジア語、オランダ語、ドイツ語、ウクライナ語、ロシア語、フィンランド語、ヒンディー語になります。

identifyLanguageアクションセットを使って、こられの言語を正しく判別できるかやってみましょう。

import swat
conn = swat.CAS('mycashost.com', 5570, 'username', 'password')
conn.builtins.loadActionSet(actionSet='textManagement')
conn.textManagement.identifyLanguage(casOut=dict(name=CFG.out_cas_table_name, replace=True),
                                     docId='Id',
                                     table=dict(name=CFG.in_cas_table_name),
                                     text='text')
conn.table.fetch(table=dict(name=CFG.out_cas_table_name))

 

結果は以下の通りです。

各記号については、en:英語、ja:日本語、zh:中国語、vi:ベトナム語、ko:韓国語、sv:スウェーデン語、no:ノルウェー語、nl:オランダ語、de:ドイツ語、ru:ロシア語、fi:フィンランド語、hi:ヒンディー語という対応になっています。全て正解ですね。

西フリジア語とウクライナ語は現時点ではidentifyLanguageアクションセットの対応言語にはなっていないため、結果テーブルからはドロップされています。西フリジア語とオランダ語、ウクライナ語とロシア語は、一見して違いを判断することがとても難しいように思えますが、identifyLanguageアクションセットは誤判断することなくしっかりと区別をつけてくれていることが分かります。

 

以上、自然言語処理の代表的なタスクとSASによる実装方法の紹介でした。
SASによる自然言語処理に興味を持っていただけたら幸いです。


1. アクションセット: SAS Viyaが提供する各種メソッドを盛り込んだパッケージのことで、SASプログラミング言語の他、Python、R、Luaから呼び出して利用することができる。

2. CAS: SAS Cloud Analytic Servicesの略で、SAS Viyaのインメモリ分散並列処理機構のこと。

3. DLPy: SAS ViyaのPython向けDeep Learning API。シンプルな記法でディープラーニングモデルのアーキテクチャを記述することが可能。

4. VTA: Visual Text Analyticsの略で、SAS Viya製品群の内テキスト・マイニングを担当する製品。

Share

About Author


Advanced Analytics COE ソリューションズ・アーキテクト

医療機関および製薬企業勤務を経て、SAS Japanに入社。主に医療データ分析と自然言語処理を担当。

Leave A Reply

Back to Top