パスワードを忘れた? アカウント作成
15701900 journal
人工知能

yasuokaの日記: deberta-base-japanese-aozora-ud-headとufal.chu-liu-edmondsによる国語研長単位係り受け解析

日記 by yasuoka

昨日の日記で試作したdeberta-base-japanese-aozora-ud-headに対し、ufal.chu-liu-edmondsを使って係り受け解析木を解くプログラムを書いてみた。ちょっと長くなってしまったのだが、Google Colaboratoryで動かしてみよう。

!pip install transformers ufal.chu-liu-edmonds deplacy

class TransformersUD(object):
  def __init__(self,bert):
    import os
    from transformers import (AutoTokenizer,AutoModelForQuestionAnswering,
      AutoModelForTokenClassification,AutoConfig,TokenClassificationPipeline)
    self.tokenizer=AutoTokenizer.from_pretrained(bert)
    self.model=AutoModelForQuestionAnswering.from_pretrained(bert)
    x=AutoModelForTokenClassification.from_pretrained
    if os.path.isdir(bert):
      d,t=x(os.path.join(bert,"deprel")),x(os.path.join(bert,"tagger"))
    else:
      from transformers.file_utils import hf_bucket_url
      c=AutoConfig.from_pretrained(hf_bucket_url(bert,"deprel/config.json"))
      d=x(hf_bucket_url(bert,"deprel/pytorch_model.bin"),config=c)
      s=AutoConfig.from_pretrained(hf_bucket_url(bert,"tagger/config.json"))
      t=x(hf_bucket_url(bert,"tagger/pytorch_model.bin"),config=s)
    self.deprel=TokenClassificationPipeline(model=d,tokenizer=self.tokenizer,
      aggregation_strategy="simple")
    self.tagger=TokenClassificationPipeline(model=t,tokenizer=self.tokenizer)
  def __call__(self,text):
    import numpy,torch,ufal.chu_liu_edmonds
    w=[(t["start"],t["end"],t["entity_group"]) for t in self.deprel(text)]
    z,n={t["start"]:t["entity"].split("|") for t in self.tagger(text)},len(w)
    r,m=[text[s:e] for s,e,p in w],numpy.full((n+1,n+1),numpy.nan)
    v=self.tokenizer(r,add_special_tokens=False)["input_ids"]
    for i,t in enumerate(v):
      q=[self.tokenizer.cls_token_id]+t+[self.tokenizer.sep_token_id]
      c=[q]+v[0:i]+[[self.tokenizer.mask_token_id]]+v[i+1:]+[[q[-1]]]
      b=[len(sum(c[0:j+1],[])) for j in range(len(c))]
      d=self.model(input_ids=torch.tensor([sum(c,[])]),
        token_type_ids=torch.tensor([[0]*b[0]+[1]*(b[-1]-b[0])]))
      s,e=d.start_logits.tolist()[0],d.end_logits.tolist()[0]
      for j in range(n):
        m[i+1,0 if i==j else j+1]=s[b[j]]+e[b[j+1]-1]
    h=ufal.chu_liu_edmonds.chu_liu_edmonds(m)[0]
    u="# text = "+text.replace("\n"," ")+"\n"
    for i,(s,e,p) in enumerate(w,1):
      u+="\t".join([str(i),r[i-1],"_",z[s][0][2:],"_","|".join(z[s][1:]),
        str(h[i]),p,"_","_" if i<n and w[i][0]<e else "SpaceAfter=No"])+"\n"
    return u+"\n"

nlp=TransformersUD("KoichiYasuoka/deberta-base-japanese-aozora-ud-head")
doc=nlp("全学年にわたって小学校の国語の教科書に挿し絵が用いられている")
import deplacy
deplacy.render(doc,Japanese=True)
deplacy.serve(doc,port=None)

「全学年にわたって小学校の国語の教科書に挿し絵が用いられている」を解析してみたところ、私(安岡孝一)の手元では以下の結果になった。

全学年     NOUN ═╗<══════╗ obl(斜格補語)
にわたって ADP  <╝       ║ case(格表示)
小学校     NOUN ═╗<╗     ║ nmod(体言による連体修飾語)
の         ADP  <╝ ║     ║ case(格表示)
国語       NOUN ═╗═╝<╗   ║ nmod(体言による連体修飾語)
の         ADP  <╝   ║   ║ case(格表示)
教科書     NOUN ═╗═══╝<╗ ║ obl(斜格補語)
に         ADP  <╝     ║ ║ case(格表示)
挿し絵     NOUN ═╗<══╗ ║ ║ nsubj(主語)
が         ADP  <╝   ║ ║ ║ case(格表示)
用い       VERB ═╗═╗═╝═╝═╝ root(親)
られ       AUX  <╝ ║       aux(動詞補助成分)
ている     AUX  <══╝       aux(動詞補助成分)

# text = 全学年にわたって小学校の国語の教科書に挿し絵が用いられている
1    全学年    _    NOUN    _    _    11    obl    _    SpaceAfter=No
2    にわたって    _    ADP    _    _    1    case    _    SpaceAfter=No
3    小学校    _    NOUN    _    _    5    nmod    _    SpaceAfter=No
4    の    _    ADP    _    _    3    case    _    SpaceAfter=No
5    国語    _    NOUN    _    _    7    nmod    _    SpaceAfter=No
6    の    _    ADP    _    _    5    case    _    SpaceAfter=No
7    教科書    _    NOUN    _    _    11    obl    _    SpaceAfter=No
8    に    _    ADP    _    _    7    case    _    SpaceAfter=No
9    挿し絵    _    NOUN    _    _    11    nsubj    _    SpaceAfter=No
10    が    _    ADP    _    _    9    case    _    SpaceAfter=No
11    用い    _    VERB    _    _    0    root    _    SpaceAfter=No
12    られ    _    AUX    _    _    11    aux    _    SpaceAfter=No
13    ている    _    AUX    _    _    11    aux    _    SpaceAfter=No

SVGで可視化すると、こんな感じ。どうやらちゃんと解析できているようだ。ただ、語境界の検知に関しては、かなり手を抜いているので、そのあたりのチューニングは必要だと思う。ふーむ、この方向で進めて行けば、何とかなるかな。

この議論は、yasuoka (21275)によって ログインユーザだけとして作成されたが、今となっては 新たにコメントを付けることはできません。
typodupeerror

「毎々お世話になっております。仕様書を頂きたく。」「拝承」 -- ある会社の日常

読み込み中...