Ahogrammer

Deep Dive Into NLP, ML and Cloud

バイオ医療分野と固有表現認識

最近、職場の同僚が「医療/製薬分野に自然言語処理を使えないか」というような話をしていた。私自身はその分野にそれほど関心が高かったわけではないが、固有表現認識系の論文で医療/化学ドメインに対する取り組みが行われているのは今までに目にしていた。ちょうど良い機会なので、知識のシェアのために簡単にまとめておく。

バイオ分野と情報抽出

最近のバイオ医療分野の課題として、提出される論文数が非常に多い点を挙げられる。どのくらい多いのかというと、医学分野の文献のデータベースであるPubMedには、毎年数十万件の文献が追加されていることから、その数が窺い知れる。

提出される論文数が多いことで、論文のアブストラクトだけ読んで全体像を把握するのも困難になっている。こういう状況だと、有用な実験結果が報告されていても、それを見逃して自身の研究に活かすことができないということが起きる。

そういうわけで、大量の文献から必要な情報だけ抽出する技術が求められている。これはここ数年の問題というわけではなく、少なくとも十数年前から問題になっている。

情報抽出に機械学習が必要な理由

テキストからの情報抽出には、抽出のためのテンプレートを人手で作成しておき、テンプレートとのマッチングによって情報を抽出するということが行われてきた。この方法はテンプレートを作り込めば結構使えるのだが、バイオ分野では新しい用語が次々と増えるためテンプレートの更新が必要になるという状況がある。しかし、テンプレートを更新できるような知識を持った人材を確保しておくのは難しいため、最近ではなるべく人手をかけずに済むように機械学習が使われる。

情報抽出と固有表現認識

機械学習を使ったテキストからの情報抽出では、最初に固有表現認識が行われることが多い。その目的は、テキストからバイオ分野の固有表現を自動的に認識して分類することにある。使われる固有表現タイプとしては、遺伝子、化学物質、タンパク質、病名といったタイプがあり、抽出後は関係認識や知識ベースの構築、知識発見といった下流タスクで使うことができる。

バイオ分野固有の問題

バイオ分野の情報抽出でも最初に固有表現認識を行うことが多いわけだが、分野特有の問題がある。以下は「バイオ自然言語処理のための機械学習技術」からの引用だが、3つの問題を取り上げている。

  1. 機能をそのまま説明的に記述したような固有表現
  2. 固有表現がand, orなどの接続詞で長くつながった表現
  3. 短い略称名となっている固有表現

最初の問題の例として引用元ではadenylate cyclase activating polypeptide 1(アデニル酸シクラーゼ活性化ポリペプチド1)を挙げている。この表現は、その全体が一つの固有表現でありつつ、adenylate cyclase(アデニル酸シクラーゼ)という固有表現がネストされているという点にある

2つ目の例として、alpha- and beta-globin(αグロビンとβグロビン)を挙げている。固有表現としてはαグロビンとβグロビンの2つを抽出したいわけだが、このような形式になっていると2つを抽出するのは難しい。

ここまでの2つに共通する難しさとして、固有表現であるにもかかわらず、大文字で始まっていない点を挙げられる。基本的に英語では固有表現は大文字から始まるというルールがあり、最近の固有表現認識器ではその情報を利用しているため、大文字でない場合は認識精度が落ちてしまう。これは以前作ったリアルタイム固有表現認識で確かめられる。

f:id:Hironsan:20190520100151p:plain

最後の問題の例として、IL2を挙げている。これはタンパク質Interleukin 2の略称名となっている。この難しさとしては、認識そのものの難しさに加えて、認識後の正規化にある。どういうことかというと、IL2をタンパク質として認識するだけでなく、Interleukin 2と同じ対象を指していることを明らかにする必要がある。これは、Entity Linkingというタスクに近い。

手法の概要

以前は人間が素性を定義してSVMやCRFを使って認識していたが、現在は研究ベースではニューラルネットワークが使われることが多くなっている。モデルとしてはBiLSTM-CRFをベースにしたモデルが使われることが多い点は通常の固有表現認識と同様となっている。

私見ではあるが、バイオ分野の場合、少ないデータから学習できることを目指した研究が多いように感じる。これは、バイオ分野のテキストにアノテーションをするのは専門的な知識が必要であり、そのような専門家を確保するのが難しい点が関係しているのだと思われる。そういうわけで、転移学習やマルチタスク学習といった手法を使って学習データの少なさを補っているように感じる。

最近はBERTのバイオ分野版であるBioBERTもリリースされているので、今後はBioBERTベースの手法が多く出てくる可能性が高い。

github.com

BioNLP

最後にBioNLPについて書いておく。BioNLPはACLのワークショップの一つであり、バイオ医療分野の自然言語処理にフォーカスしているので、この分野のサーベイをしたい場合はまず当たると良いのではないかと思う。

aclweb.org

また、BioNLPではShared Taskが行われることがある。今まで2009, 2011, 2013, 2016で行われ、今年も開催される。今年のBioNLP 2019では、MEDIQAという医療ドメインでのテキスト推論と質問の含意関係認識を行うタスクが行われる。詳細は以下を参照。

sites.google.com

こちらはEMNLPのワークショップで行われるBioNLPのShared Task。固有表現認識や関係抽出といった情報抽出系のタスクが行われる。詳細は以下を参照。

2019.bionlp-ost.org

参考資料

入門 AWS Step Functions

最近は仕事の一つとして、機械学習用のワークフローを作成しています。ワークフローを作成するサービスやソフトウェアはいくつかありますが、それら中でもAWS Step Functionsを使おうと考えています。今回の記事は、AWS Step Functionsについて調べたことを簡単にまとめた内容となっています。

Step Functionsとは?

AWS Step Functionsとは、ワークフローを定義して、実行・管理できるマネージドサービスです。AWS上の各サービスをコンポーネントとしてワークフローを定義することができます。また、定義したワークフローは、以下のようなグラフィカルなコンソールで確認できます。

f:id:Hironsan:20190515084114p:plain

Step Functionsで何ができるか?

Step Functionsを使うことで、さまざまなタスクで構成される複雑なワークフローを簡単に定義できます。たとえば、画像を複数のフォーマットに変換し、拡大縮小してAmazon Rekognitionで分析するプロセスは、各タスクをLambda関数で記述し、ワークフローとして定義することで、簡単に実行できます。

f:id:Hironsan:20190515085319p:plain
Ref: https://cloudacademy.com/lab/introduction-aws-step-functions/

Step Functionsがなぜ必要か?

Step Functionsを使うことで、各コンポーネントを再利用可能な形で書くことができます。Lambdaだけでワークフローを書こうとすると、一つのLambda関数内にすべての処理を書くか、Lambda関数内から別のLambda関数を呼ぶ必要があります。一つのLambda関数で書くとメンテナンスが難しくなるという欠点があり、Lambda関数内から別の関数を呼び出すと、関数間が密結合になり、再利用しにくい関数になるという欠点があります。

Step Functionsの料金

Step Functionsは状態遷移ごとに課金されます。最初の4000回の状態遷移については一月の無料枠の範囲内なので課金されません。それ以降は状態遷移あたりに課金されます。リージョンによって金額は異なるのですが、バージニア北部の場合、1000回の状態遷移で0.025 USDが課金されます。金額の詳細は以下を参照すると良いでしょう。

aws.amazon.com

Step Functionsの使い方

ワークフローの定義は、Amazon States Languageを使って行います。Amazon States Languageを使うことで、ステートマシンをJSON形式で宣言的に記述することができます。たとえば、以下のように記述します。

{
  "Comment": "A Hello World example of the Amazon States Language using a Pass state",
  "StartAt": "HelloWorld",
  "States": {
    "HelloWorld": {
      "Type": "Pass",
      "Result": "Hello World!",
      "End": true
    }
  }
}

JSONで書くと一見複雑に見えるのですが、図にすると以下のようにシンプルです。

f:id:Hironsan:20190516083706p:plain

このJSONで記述したステートマシンには、状態とその間の関係を記述していきます。状態はStatesの中に書いていきます。上のJSONの場合は状態としてHelloWorldだけが存在しています。StartAtにはステートマシンの開始状態を指定します。今回の場合はHelloWorldステートから始まるということを示しています。End: trueがある場合は実行を停止します。

Typeは状態のタイプを指定するフィールドです。上の場合はタイプとしてPassが指定されていますが、これは入力に何もせずに出力するという意味があります。ResultはPass状態からの出力を書くフィールドで、今回の場合は「Hello World!」が出力されます。

もう少し複雑な例について見てみましょう。以下の例では状態が複数含まれています。

{
  "Comment": "An example of the Amazon States Language using a choice state.",
  "StartAt": "FirstState",
  "States": {
    "FirstState": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:FUNCTION_NAME",
      "Next": "ChoiceState"
    },
    "ChoiceState": {
      "Type" : "Choice",
      "Choices": [
        {
          "Variable": "$.foo",
          "NumericEquals": 1,
          "Next": "FirstMatchState"
        },
        {
          "Variable": "$.foo",
          "NumericEquals": 2,
          "Next": "SecondMatchState"
        }
      ],
      "Default": "DefaultState"
    },

    "FirstMatchState": {
      "Type" : "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:OnFirstMatch",
      "Next": "NextState"
    },

    "SecondMatchState": {
      "Type" : "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:OnSecondMatch",
      "Next": "NextState"
    },

    "DefaultState": {
      "Type": "Fail",
      "Error": "DefaultStateError",
      "Cause": "No Matches!"
    },

    "NextState": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:FUNCTION_NAME",
      "End": true
    }
  }
}

図にすると以下のようになります。図を見ると条件分岐が入っていることがわかります。

f:id:Hironsan:20190516083414p:plain

このステートマシンはStartAtFirstStateが指定されていることから、FirstStateステートから開始されることがわかります。そのFirstStateステートはTypeResourceNextフィールドを持ちます。TypeTaskが指定されていると、このステートで一つの作業が実行されることを表しています。どんな作業が実行されるのかはResourceに指定します。今回の場合はLambda関数が指定されていることがわかります。Nextには次に遷移する状態を指定します。

次の状態であるChoiceStateはそのタイプがChoiceになっていることが確認できます。タイプをChoiceにすることで、ステートマシンに条件分岐を実装できます。Choicesフィールドの中に条件分岐のルールを書き、どれにもマッチしない場合はDefaultで指定した状態に遷移します。

Choicesフィールドの中身を見てみましょう。

{
   "Variable": "$.foo",
   "NumericEquals": 1,
   "Next": "FirstMatchState"
}

Variableフィールドには条件分岐の対象となるデータを指定します。今回の場合は$.fooを指定しているので、ステートマシンの入力からfooフィールドの値を取り出して使うことを示しています。

{
    "foo": 1
}

その次には比較するタイプを指定します。上の例の場合、NumericEqualsを指定しているので、Variableの値が比較条件に指定した値と数値的に等しいかを検証します。比較結果が真であればNextフィールドに指定したステートに遷移します。

残りの部分は、これまでに説明した内容を繰り返し適用しているだけです。

おわりに

今回はAWS Step Functionsの概要について紹介しました。次回の記事ではStep Functionsを使った機械学習/自然言語処理向けのワークフローを構築してみます。

参考資料

文字ベース固有表現認識の手法たち

固有表現認識(NER: Named Entity Recognition)とは、テキストに出現する人名や地名などの固有名詞や、日付や時間などの数値表現を認識する技術です。NERはエンティティリンキングや関係抽出、イベント抽出、共参照解決といった自然言語処理タスクの要素技術として使われるため、常にある程度の研究が行われている分野となっています。

最近よく使われる手法としては、テキストを単語の系列に分解し、それをRNNとCRFを接続したネットワークに入力する手法があります。そういった手法は数多く存在するため個別には紹介しませんが、以前に以下の記事でそのうちの一つの手法について実装しています。

hironsan.hatenablog.com

単語分割を前提とした手法は、単語の切れ目が明示されている言語以外では扱いにくいという問題点があります。たとえば、英語であるなら単語の切れ目は空白で区切られていますが、日本語や中国語にはそのような区切りは存在しません。その結果、NERの性能が単語分割の結果に左右されてしまいます。

そういうわけで、単語分割に依存しない手法が求められるわけです。そういった手法の一つに文字ベースでNERを行うというやり方があるのですが、今回の記事では、いくつかの論文を参照しながらその手法について簡単に紹介したいと思います。

CAN-NER: Convolutional Attention Network for Chinese Named Entity Recognition

この論文では中国語のNERに対する文字ベースのアプローチを提案している。論文で取り上げている中国語のNERの課題として、NERの前段階でWord Segmentationを行うため、Segmentation ErrorとOOV(Out of Vocabulary)が生じる問題を取り上げている。

Segumentation Errorというのは単語分割の誤りのことを指している。日本語の例でいうと、前にニュースのNERをやったときに「米中2カ国」を「米」と「中2」に分割されたことがあった。こういう分割をされると、この時点で「中」を地名として認識することが難しくなる。

また、OOVの問題についてはTwitterやニュースのテキストでNERする際に特に問題になる。新語というのは日々追加されており、NERでもこれらを上手く認識したいのだが、既存の固有表現認識の手法だとOOVに対する認識性能がOOVでない場合と比べてかなり落ちることがわかっている。文字ベースの場合はOOVは単語と比べると少ないため、新語に対しても上手く働くことを期待できる。

モデルとしては、以下のように局所アテンション付きの文字ベースCNNとグローバルアテンション付きのGRUを使ったモデルを構築している。

f:id:Hironsan:20190508084211p:plain
モデルのアーキテクチャ

Neural Chinese Named Entity Recognition via CNN-LSTM-CRF and Joint Training with Word Segmentation

こちらの論文は中国語のNERとWord Segmentationを同時に学習する論文。さきほどの課題に加えて、マルチタスクラーニングにより、NERのデータ量の少なさをカバーする狙いがある。アーキテクチャとしては以下のようになっている。NERの方はよく使われるCNN-BiLSTM-CRFを採用しており、Word Segmentationの方はCNN-CRFとなっている。後者がCNN-BiLSTM-CRFになっていないのが少し不思議な感じがするアーキテクチャ

f:id:Hironsan:20190513131307p:plain

アーキテクチャ以外の工夫としては、データの水増しがある。この論文では、同カテゴリの固有表現を入れ替えて(安倍首相は〜 → 岸田首相は〜)データを水増ししている。それによって性能が上がることが報告されている。かなり簡単なテクニックの割に効果的なので、日本語でやる場合も採用してもいいかもしれない。

Distantly Supervised NER with Partial Annotation Learning and Reinforcement Learning

こちらの論文は、Distant Supervisionを作って作った固有表現のデータを使って固有表現認識するためのモデルを提案している。

Distant Supervisionを使って固有表現認識用のデータを作るには固有表現の辞書を用意しておく必要がある。手法としては用意しておいた固有表現辞書を使って、テキスト中のマッチした部分に自動的にラベル付をするというやり方になる。

Distant Supervisionを使って作った固有表現認識用のデータには、2つの問題がある。一つはデータが不完全(付けるべきところにラベルが付いていない)であるという問題、もう一つはデータがノイジー(付けるべきでないところにラベルが付いている)という問題。論文中だと以下の例を挙げている。要するに、不完全というのは「皮帯」のように付けるべき箇所にラベルを付けられていないという問題で、ノイジーというのは「工装蛙」ではなく「工装」にラベルが付いてしまっているということ。

f:id:Hironsan:20190513132406p:plain

モデルのアーキテクチャについては以下のようになっている。不完全なデータに対してはCRFを拡張することで対応し、ノイジーなデータに対しては、強化学習を使ってノイズを除去することで対応している。

f:id:Hironsan:20190513132725p:plain

Character-based Bidirectional LSTM-CRF with words and characters for Japanese Named Entity Recognition

こちらの論文は、日本語NERに対する文字ベース手法について提案している。手法的には、文字単位で入出力を行いつつ、文字に対応する単語を入力として加えている。たとえば、「東京で〜」というテキストを入力する場合、「東」と「京」に加えて「東京」という単語も入力する。こうすることで、単語分割の問題を緩和、単語の情報も利用する狙いがあるようだ。

f:id:Hironsan:20190513133127p:plain

気になるところもいくつかあるのだが、まず形態素解析のN-BEST解を使った場合にどうなるのかは興味がある。1-BESTだけを使うと結局のところ単語境界の問題から逃れられていない感じがするので、それをさらに緩和するためにN-BESTを使うのはありかもしれない。もう一つ気になるのは、形態素解析の辞書を変更した場合にどうなるか。たとえば、固有表現を多く含むNEologdのような辞書を使ったら結果がどう変化するのかには興味がある。

Character-Based LSTM-CRF with Radical-Level Features for Chinese Named Entity Recognition

こちらの論文も、中国語の固有表現認識に対する文字ベース手法を提案している論文。面白いのは、漢字をその構成要素に分類して、文字分散表現を構築している点。よくあるNERの手法では、単語分散表現を単語分散表現と文字レベルの表現を組み合わせて構築していたが、この論文ではそこでの単語を文字に、文字を漢字の構成要素に分解したと考えられる。中国語や日本語ならではの手法と言えるのではないか。

f:id:Hironsan:20190513134254p:plain