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

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

日記 by yasuoka

一昨日の日記の手法を拡張して、deberta-large-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,c=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.append([q]+v[0:i]+[[self.tokenizer.mask_token_id]]+v[i+1:]+[[q[-1]]])
    b=[[len(sum(x[0:j+1],[])) for j in range(len(x))] for x in c]
    d=self.model(input_ids=torch.tensor([sum(x,[]) for x in c]),
      token_type_ids=torch.tensor([[0]*x[0]+[1]*(x[-1]-x[0]) for x in b]))
    s,e=d.start_logits.tolist(),d.end_logits.tolist()
    for i in range(n):
      for j in range(n):
        m[i+1,0 if i==j else j+1]=s[i][b[i][j]]+e[i][b[i][j+1]-1]
    m[:,0]=numpy.where(m[:,0]==numpy.nanmax(m[:,0]),0,numpy.nan)
    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):
      p="root" if h[i]==0 else "dep" if p=="root" else p
      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-large-japanese-aozora-ud-head")
doc=nlp("うなぎを浜松に食べに行く")
import deplacy
deplacy.render(doc,Japanese=True)
deplacy.serve(doc,port=None)

「うなぎを浜松に食べに行く」を係り受け解析してみたところ、私(安岡孝一)の手元では以下の結果となった。

うなぎ PROPN ═╗<╗     obj(目的語)
を     ADP   <╝ ║     case(格表示)
浜松   PROPN ═╗ ║<══╗ advmod(連用修飾語)
に     ADP   <╝ ║   ║ case(格表示)
食べ   VERB  ═╗═╝<╗ ║ advcl(連用修飾節)
に     ADP   <╝   ║ ║ case(格表示)
行く   VERB  ═════╝═╝ acl(連体修飾節)

# text = うなぎを浜松に食べに行く
1    うなぎ    _    PROPN    _    _    5    obj    _    SpaceAfter=No
2    を    _    ADP    _    _    1    case    _    SpaceAfter=No
3    浜松    _    PROPN    _    _    7    advmod    _    SpaceAfter=No
4    に    _    ADP    _    _    3    case    _    SpaceAfter=No
5    食べ    _    VERB    _    _    7    advcl    _    SpaceAfter=No
6    に    _    ADP    _    _    5    case    _    SpaceAfter=No
7    行く    _    VERB    _    _    0    acl    _    SpaceAfter=No

SVGで可視化すると、こんな感じ。係り受けがちゃんと交差していて素晴らしいのだが、交差部分のラベルがoblではなく「浜松」⇐advmod=「行く」となっていたり、「うなぎ」の品詞がPROPNになっていたりと、あと一息だ。さて、どうチューニングしていけばいいかな。

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

私は悩みをリストアップし始めたが、そのあまりの長さにいやけがさし、何も考えないことにした。-- Robert C. Pike

読み込み中...