パスワードを忘れた? アカウント作成

yasuokaさんのトモダチの日記みんなの日記も見てね。 最新から新しい日記やタレこみを確認できますよ。

15423437 journal
人工知能

yasuokaの日記: 日本語・中国語・タイ語の係り受け解析モジュールesuparリリース(仮)

日記 by yasuoka

9月14日一昨日昨日の日記の手法を一まとめにして、esuparというpython3モジュールとしてリリース(仮)した。日本語と中国語(簡化字・繁体字および文言文/漢文)とタイ語の係り受け解析がおこなえる。Linux系OSなら

$ pip3 install esupar --user

一発でインストール可能なはずだ。インストールがうまくいったら、まずは「太郎は花子が読んでいる本を次郎に渡した」を係り受け解析してみよう。

$ python3
>>> import esupar
>>> nlp=esupar.load("ja")
>>> doc=nlp("太郎は花子が読んでいる本を次郎に渡した")
>>> print(doc)
1    太郎    _    PROPN    _    _    12    nsubj    _    SpaceAfter=No
2    は    _    ADP    _    _    1    case    _    SpaceAfter=No
3    花子    _    PROPN    _    _    5    nsubj    _    SpaceAfter=No
4    が    _    ADP    _    _    3    case    _    SpaceAfter=No
5    読ん    _    VERB    _    _    8    acl    _    SpaceAfter=No
6    で    _    SCONJ    _    _    5    mark    _    SpaceAfter=No
7    いる    _    AUX    _    _    5    aux    _    SpaceAfter=No
8    本    _    NOUN    _    _    12    obj    _    SpaceAfter=No
9    を    _    ADP    _    _    8    case    _    SpaceAfter=No
10    次郎    _    PROPN    _    _    12    obl    _    SpaceAfter=No
11    に    _    ADP    _    _    10    case    _    SpaceAfter=No
12    渡し    _    VERB    _    _    0    root    _    SpaceAfter=No
13    た    _    AUX    _    _    12    aux    _    _

>>> import deplacy
>>> deplacy.render(doc,Japanese=True)
太郎 PROPN ═╗<════════╗ nsubj(主語)
は   ADP   <╝         ║ case(格表示)
花子 PROPN ═╗<══╗     ║ nsubj(主語)
が   ADP   <╝   ║     ║ case(格表示)
読ん VERB  ═╗═╗═╝<╗   ║ acl(連体修飾節)
で   SCONJ <╝ ║   ║   ║ mark(標識)
いる AUX   <══╝   ║   ║ aux(動詞補助成分)
本   NOUN  ═╗═════╝<╗ ║ obj(目的語)
を   ADP   <╝       ║ ║ case(格表示)
次郎 PROPN ═╗<╗     ║ ║ obl(斜格補語)
に   ADP   <╝ ║     ║ ║ case(格表示)
渡し VERB  ═╗═╝═════╝═╝ root(親)
た   AUX   <╝           aux(動詞補助成分)

esupar.loadのパラメータは、"ja"が日本語、"zh"が現代中国語、"lzh"が古典中国語、"th"がタイ語だったりする。まだまだチューニングが不十分なので、解析精度はイマイチだが、ぜひ試しに使ってみてほしい。

15422438 journal
中国

yasuokaの日記: chinese-bert-wwm-ext-uposによる現代中国語の係り受け解析

日記 by yasuoka

昨日の日記の手法をchinese-bert-wwm-ext-uposに適用して、現代中国語の係り受け解析モデルを試作してみた。Google Colaboratoryで動かしてみよう。

!pip install 'transformers>=4.7.0' 'supar>=1.1.1' 'deplacy>=2.0.1'
from transformers import AutoModelForTokenClassification,AutoTokenizer,TokenClassificationPipeline
from transformers.file_utils import cached_path,hf_bucket_url
from supar import Parser
brt="KoichiYasuoka/chinese-bert-wwm-ext-upos"
mdl=AutoModelForTokenClassification.from_pretrained(brt)
tkz=AutoTokenizer.from_pretrained(brt)
pos=TokenClassificationPipeline(model=mdl,tokenizer=tkz,aggregation_strategy="simple")
prs=Parser.load(cached_path(hf_bucket_url(brt,"supar.model")))
def nlp(s):
  d=pos(s)
  e=prs.predict([[t["word"].replace(" ","") for t in d]])
  e.sentences[0].values[3]=tuple([t["entity_group"] for t in d])
  e.sentences[0].values[9]=tuple(["SpaceAfter=No" if t["end"]==u["start"] else "_" for t,u in zip(d,d[1:])]+["_"])
  return e
doc=nlp("下雨天和星期一总是让我沮丧")
import deplacy
deplacy.render(doc)
deplacy.serve(doc,port=None)

「下雨天和星期一总是让我沮丧」を係り受け解析してみたところ、私(安岡孝一)の手元では以下の結果になった。

下雨 NOUN  <╗       compound
天   PART  ═╝═╗═╗<╗ nsubj
和   CCONJ <╗ ║ ║ ║ cc
星期 NOUN  ═╝<╝ ║ ║ conj
一   NUM   <════╝ ║ nummod
总   ADV   <════╗ ║ advmod
是让 VERB  ═══╗═╝═╝ root
我   PRON  <╗ ║     nsubj
沮丧 ADJ   ═╝<╝     ccomp

1    下雨    _    NOUN    _    _    2    compound    _    SpaceAfter=No
2    天    _    PART    _    _    7    nsubj    _    SpaceAfter=No
3    和    _    CCONJ    _    _    4    cc    _    SpaceAfter=No
4    星期    _    NOUN    _    _    2    conj    _    SpaceAfter=No
5    一    _    NUM    _    _    2    nummod    _    SpaceAfter=No
6    总    _    ADV    _    _    7    advmod    _    SpaceAfter=No
7    是让    _    VERB    _    _    0    root    _    SpaceAfter=No
8    我    _    PRON    _    _    9    nsubj    _    SpaceAfter=No
9    沮丧    _    ADJ    _    _    7    ccomp    _    _

SVGで可視化すると、こんな感じ。「天」=nummod⇒「一」はどう考えても変で、「星期」=nummod⇒「一」とすべきだろう。また、「我」⇐nsubj=「沮丧」は「是让」=obj⇒「我」とした上で、「是让」=ccomp⇒「沮丧」をxcompにしたいところだ。うーん、このあたり、どうすれば精度を上げられるかな。

15421517 journal
人工知能

yasuokaの日記: roberta-base-thai-syllable-uposによるタイ語の係り受け解析

日記 by yasuoka

9月11日一昨日の日記の手法を合わせた上に、SuParの助けを借りて、タイ語の係り受け解析モデルを試作してみた。Google Colaboratoryで動かしてみよう。

!pip install transformers'>='4.7.0 supar'>='1.1.1 deplacy'>='2.0.1
from transformers import AutoModelForTokenClassification,AutoTokenizer,TokenClassificationPipeline
from transformers.file_utils import cached_path,hf_bucket_url
from supar import Parser
brt="KoichiYasuoka/roberta-base-thai-syllable-upos"
mdl=AutoModelForTokenClassification.from_pretrained(brt)
tkz=AutoTokenizer.from_pretrained(brt)
pos=TokenClassificationPipeline(model=mdl,tokenizer=tkz,aggregation_strategy="simple")
prs=Parser.load(cached_path(hf_bucket_url(brt,"supar.model")))
def nlp(s):
  d=pos(s)
  e=prs.predict([[t["word"] for t in d]])
  e.sentences[0].values[3]=tuple([t["entity_group"] for t in d])
  e.sentences[0].values[9]=tuple(["SpaceAfter=No" if t["end"]==u["start"] else "_" for t,u in zip(d,d[1:])]+["_"])
  return e
doc=nlp("หลายหัวดีกว่าหัวเดียว")
import deplacy
deplacy.render(doc,WordRight=True)
deplacy.serve(doc,port=None)

「หลายหัวดีกว่าหัวเดียว」を係り受け解析してみたところ、私(安岡孝一)の手元では以下の結果になった。

   det       ╔> DET  หลาย
advmod ╔════>╚═ NOUN หัว
  root ╚═╔═════ ADJ  ดี
  case   ║ ╔══> ADP  กว่า
   obl   ╚>╚═╔═ NOUN หัว
  amod       ╚> ADJ  เดียว

1    หลาย    _    DET    _    _    2    det    _    SpaceAfter=No
2    หัว    _    NOUN    _    _    3    advmod    _    SpaceAfter=No
3    ดี    _    ADJ    _    _    0    root    _    SpaceAfter=No
4    กว่า    _    ADP    _    _    5    case    _    SpaceAfter=No
5    หัว    _    NOUN    _    _    3    obl    _    SpaceAfter=No
6    เดียว    _    ADJ    _    _    5    amod    _    _

SVGで可視化すると、こんな感じ。「หัว」⇐advmod=「ดี」を除いて、まずまずの解析結果だ。ただ、このままだと、ちょっと使いにくいので、さて、どういう形でパッケージ化したらいいかな。

15418219 journal
人工知能

yasuokaの日記: bert-base-japanese-uposとTokenClassificationPipelineでおこなう日本語形態素解析

日記 by yasuoka

昨日の日記の手法を使って、bert-base-japanese-uposのトークナイザもBertTokenizerFastに入れ換えてみたところ、TokenClassificationPipelineの結果が改善された。Transformersを最新版に更新しつつ、ちょっとやってみよう。

$ pip3 install -U transformers
$ python3
>>> from transformers import AutoModelForTokenClassification,AutoTokenizer,TokenClassificationPipeline
>>> brt="KoichiYasuoka/bert-base-japanese-upos"
>>> mdl=AutoModelForTokenClassification.from_pretrained(brt)
>>> tkz=AutoTokenizer.from_pretrained(brt)
>>> nlp=TokenClassificationPipeline(model=mdl,tokenizer=tkz,aggregation_strategy="simple")
>>> d=nlp(inputs="國境の長いトンネルを拔けると雪國であつた。難儀な難儀は難儀する。")
>>> print(d)
[{'entity_group': 'NOUN', 'score': 0.99924845, 'word': '國境', 'start': 0, 'end': 2}, {'entity_group': 'ADP', 'score': 0.9997904, 'word': 'の', 'start': 2, 'end': 3}, {'entity_group': 'ADJ', 'score': 0.995852, 'word': '長い', 'start': 3, 'end': 5}, {'entity_group': 'NOUN', 'score': 0.9995555, 'word': 'トンネル', 'start': 5, 'end': 9}, {'entity_group': 'ADP', 'score': 0.9998084, 'word': 'を', 'start': 9, 'end': 10}, {'entity_group': 'VERB', 'score': 0.99934673, 'word': '拔ける', 'start': 10, 'end': 13}, {'entity_group': 'CCONJ', 'score': 0.9946812, 'word': 'と', 'start': 13, 'end': 14}, {'entity_group': 'NOUN', 'score': 0.9560932, 'word': '雪國', 'start': 14, 'end': 16}, {'entity_group': 'AUX', 'score': 0.9979013, 'word': 'で', 'start': 16, 'end': 17}, {'entity_group': 'AUX', 'score': 0.9907406, 'word': 'あつた', 'start': 17, 'end': 20}, {'entity_group': 'PUNCT', 'score': 0.9998325, 'word': '。', 'start': 20, 'end': 21}, {'entity_group': 'ADJ', 'score': 0.9873648, 'word': '難儀', 'start': 21, 'end': 23}, {'entity_group': 'AUX', 'score': 0.99952304, 'word': 'な', 'start': 23, 'end': 24}, {'entity_group': 'NOUN', 'score': 0.99909914, 'word': '難儀', 'start': 24, 'end': 26}, {'entity_group': 'ADP', 'score': 0.99976534, 'word': 'は', 'start': 26, 'end': 27}, {'entity_group': 'VERB', 'score': 0.99604756, 'word': '難儀', 'start': 27, 'end': 29}, {'entity_group': 'AUX', 'score': 0.99927384, 'word': 'する', 'start': 29, 'end': 31}, {'entity_group': 'PUNCT', 'score': 0.99983144, 'word': '。', 'start': 31, 'end': 32}]

さすがに読みにくいので、単語(word)と品詞(entity_group)を抜き出してみよう。

>>> print([(t["word"],t["entity_group"]) for t in d])
[('國境', 'NOUN'), ('の', 'ADP'), ('長い', 'ADJ'), ('トンネル', 'NOUN'), ('を', 'ADP'), ('拔ける', 'VERB'), ('と', 'CCONJ'), ('雪國', 'NOUN'), ('で', 'AUX'), ('あつた', 'AUX'), ('。', 'PUNCT'), ('難儀', 'ADJ'), ('な', 'AUX'), ('難儀', 'NOUN'), ('は', 'ADP'), ('難儀', 'VERB'), ('する', 'AUX'), ('。', 'PUNCT')]

なかなかいい感じだ。ただ、私(安岡孝一)個人としては、ちゃんとstartとendが出るようになったのが、かなりうれしかったりする。入力文字列との対応関係を取れると、便利なことが多いのだ。まあ、このあたりは目的にもよるのだが、ぜひ使ってみてほしい。

15416907 journal
人工知能

yasuokaの日記: Re: bert-large-japanese-charのトークナイザをBertTokenizerFastで置き換えるには

日記 by yasuoka

昨日の日記の読者から、tokenizers.pre_tokenizers.Split()を御教示いただいた。BertPreTokenizerの代わりに、このSplitをぶち込むことで、未知語も含めてバラバラに文字切りしてしまおう、という算段だ。昨日のmy.char.modelを、Google Colaboratoryで作り直してみよう。

!pip install transformers
from transformers import BertTokenizerFast,AutoModelForMaskedLM
from tokenizers.pre_tokenizers import Sequence,Whitespace,Split
from tokenizers import Regex
tokenizer=BertTokenizerFast.from_pretrained("cl-tohoku/bert-large-japanese-char")
model=AutoModelForMaskedLM.from_pretrained("cl-tohoku/bert-large-japanese-char")
tokenizer.backend_tokenizer.normalizer.handle_chinese_chars=True
tokenizer.backend_tokenizer.normalizer.strip_accents=False
tokenizer.backend_tokenizer.normalizer.lowercase=False
tokenizer.backend_tokenizer.pre_tokenizer=Sequence([Whitespace(),Split(Regex("."),"isolated")])
tokenizer.backend_tokenizer.decoder.prefix=""
tokenizer.backend_tokenizer.model.continuing_subword_prefix=""
tokenizer.backend_tokenizer.model.max_input_chars_per_word=200
tokenizer.save_pretrained("my.char.model")
model.config.tokenizer_class="BertTokenizerFast"
model.save_pretrained("my.char.model")

handle_chinese_charsはFalseでもいい気がするのだが、とりあえず、そのままにしておいた。新しいmy.char.modelを使ってみよう。

import torch
from transformers import AutoTokenizer,AutoModelForMaskedLM
tokenizer=AutoTokenizer.from_pretrained("my.char.model")
model=AutoModelForMaskedLM.from_pretrained("my.char.model")
for r in ["酸素ボンベを充[MASK]する。","スペー[MASK]は♠と♤がある。"]:
  s=tokenizer(r,return_offsets_mapping=True)
  print(s)
  ids=s["input_ids"]
  tokens=tokenizer.convert_ids_to_tokens(ids)
  mask=ids.index(tokenizer.mask_token_id)
  print(tokens,mask)
  inputs=torch.tensor([ids])
  with torch.no_grad():
    outputs=model(inputs)
    pred=outputs[0][0,mask].topk(5)
  for i,t in enumerate(tokenizer.convert_ids_to_tokens(pred.indices)):
    tokens[mask]=t
    print(i+1,tokens)

「酸素ボンベを充[MASK]する。」「スペー[MASK]は♠と♤がある。」を穴埋めさせてみたところ、私(安岡孝一)の手元では以下の結果になった。

{'input_ids': [2, 5343, 4159, 998, 1021, 995, 932, 1294, 4, 875, 925, 829, 3], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'offset_mapping': [(0, 0), (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 13), (13, 14), (14, 15), (15, 16), (0, 0)]}
['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '[MASK]', 'す', 'る', '。', '[SEP]'] 8
1 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '填', 'す', 'る', '。', '[SEP]']
2 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '電', 'す', 'る', '。', '[SEP]']
3 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '充', 'す', 'る', '。', '[SEP]']
4 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '給', 'す', 'る', '。', '[SEP]']
5 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '実', 'す', 'る', '。', '[SEP]']
{'input_ids': [2, 963, 996, 1026, 4, 897, 816, 890, 1, 862, 852, 925, 829, 3], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'offset_mapping': [(0, 0), (0, 1), (1, 2), (2, 3), (3, 9), (9, 10), (10, 11), (11, 12), (12, 13), (13, 14), (14, 15), (15, 16), (16, 17), (0, 0)]}
['[CLS]', 'ス', 'ペ', 'ー', '[MASK]', 'は', '♠', 'と', '[UNK]', 'が', 'あ', 'る', '。', '[SEP]'] 4
1 ['[CLS]', 'ス', 'ペ', 'ー', 'ド', 'は', '♠', 'と', '[UNK]', 'が', 'あ', 'る', '。', '[SEP]']
2 ['[CLS]', 'ス', 'ペ', 'ー', 'に', 'は', '♠', 'と', '[UNK]', 'が', 'あ', 'る', '。', '[SEP]']
3 ['[CLS]', 'ス', 'ペ', 'ー', 'ス', 'は', '♠', 'と', '[UNK]', 'が', 'あ', 'る', '。', '[SEP]']
4 ['[CLS]', 'ス', 'ペ', 'ー', 'ト', 'は', '♠', 'と', '[UNK]', 'が', 'あ', 'る', '。', '[SEP]']
5 ['[CLS]', 'ス', 'ペ', 'ー', 'プ', 'は', '♠', 'と', '[UNK]', 'が', 'あ', 'る', '。', '[SEP]']

よし、未知語「♤」に引きずられずに、うまく文字切りできているようだ。KoichiYasuoka/bert-large-japanese-char-extendedKoichiYasuoka/bert-base-japanese-char-extendedのトークナイザも、新しいBertTokenizerFastに入れ替えておいたので、こちらも試してみてほしい。

15416077 journal
人工知能

yasuokaの日記: bert-large-japanese-charのトークナイザをBertTokenizerFastで置き換えるには 2

日記 by yasuoka

とあるイキサツで、cl-tohoku/bert-large-japanese-charのトークナイザを、TransformersのBertTokenizerFastで置き換えてみた。bert-large-japanese-charのトークナイザは文字切りをおこなうのだが、なぜかfugashiを要求していて、正直ちょっと辛いのだ。とりあえずGoogle Colaboratoryで、やってみよう。

!pip install transformers
from transformers import BertTokenizerFast,AutoModelForMaskedLM
tokenizer=BertTokenizerFast.from_pretrained("cl-tohoku/bert-large-japanese-char")
model=AutoModelForMaskedLM.from_pretrained("cl-tohoku/bert-large-japanese-char")
tokenizer.backend_tokenizer.normalizer.handle_chinese_chars=True
tokenizer.backend_tokenizer.normalizer.strip_accents=False
tokenizer.backend_tokenizer.normalizer.lowercase=False
tokenizer.backend_tokenizer.decoder.prefix=""
tokenizer.backend_tokenizer.model.continuing_subword_prefix=""
tokenizer.backend_tokenizer.model.max_input_chars_per_word=200
tokenizer.save_pretrained("my.char.model")
model.config.tokenizer_class="BertTokenizerFast"
model.save_pretrained("my.char.model")

うまくいけばmy.char.modelに新たなモデルが作られる。中のjsonファイルがキモで、pytorch_model.binそのものは変わってないみたいだが、これでfugashiが不要になり、return_offsets_mappingが使えるようになる。ちょっと使ってみよう。

import torch
from transformers import AutoTokenizer,AutoModelForMaskedLM
tokenizer=AutoTokenizer.from_pretrained("my.char.model")
model=AutoModelForMaskedLM.from_pretrained("my.char.model")
s=tokenizer("酸素ボンベを充[MASK]する。",return_offsets_mapping=True)
print(s)
ids=s["input_ids"]
tokens=tokenizer.convert_ids_to_tokens(ids)
mask=ids.index(tokenizer.mask_token_id)
print(tokens,mask)
inputs=torch.tensor([ids])
with torch.no_grad():
  outputs=model(inputs)
  pred=outputs[0][0,mask].topk(5)
for i,t in enumerate(tokenizer.convert_ids_to_tokens(pred.indices)):
  tokens[mask]=t
  print(i+1,tokens)

「酸素ボンベを充[MASK]する。」を穴埋めさせてみたところ、私(安岡孝一)の手元では以下の結果になった。

{'input_ids': [2, 5343, 4159, 998, 1021, 995, 932, 1294, 4, 875, 925, 829, 3], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'offset_mapping': [(0, 0), (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 13), (13, 14), (14, 15), (15, 16), (0, 0)]}
['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '[MASK]', 'す', 'る', '。', '[SEP]'] 8
1 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '填', 'す', 'る', '。', '[SEP]']
2 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '電', 'す', 'る', '。', '[SEP]']
3 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '充', 'す', 'る', '。', '[SEP]']
4 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '給', 'す', 'る', '。', '[SEP]']
5 ['[CLS]', '酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '実', 'す', 'る', '。', '[SEP]']

どうやら大丈夫そうだ。なお、同じ方法でKoichiYasuoka/bert-large-japanese-char-extendedKoichiYasuoka/bert-base-japanese-char-extendedのトークナイザも、BertTokenizerFastに入れ替えておいたので、こちらも試してみてほしい。

15415417 journal
人工知能

yasuokaの日記: roberta-base-thai-syllable-uposによるタイ語の形態素解析

日記 by yasuoka

ネットサーフィンしていたところ、VISTEC-depaのサイトで「WangchanBERTa: Pre-trained Thai Language Model」というページを見つけた。タイ語の事前学習モデルを、色々と作成しているらしい。単語切りに際し4種類のアルゴリズムを試しているのだが、私(安岡孝一)が見た感じではsyllable(音節)を元にする手法が良さげである。ただ、wangchanberta-base-wiki-syllableは独自のトークナイザを使っているので、これをTransformersのPreTrainedTokenizerFastにムリヤリ落とし込み、roberta-base-thai-syllableというRobertaモデルを公開した。次に、このモデルをUPOSでファインチューニングして、タイ語の形態素解析(単語切り+品詞付与)モデルroberta-base-thai-syllable-uposを公開した。ちょっと使ってみよう。

$ python3
>>> import torch
>>> from transformers import AutoTokenizer,AutoModelForTokenClassification
>>> tokenizer=AutoTokenizer.from_pretrained("KoichiYasuoka/roberta-base-thai-syllable-upos")
>>> model=AutoModelForTokenClassification.from_pretrained("KoichiYasuoka/roberta-base-thai-syllable-upos")
>>> s="หลายหัวดีกว่าหัวเดียว"
>>> t=tokenizer.tokenize(s)
>>> p=[model.config.id2label[q] for q in torch.argmax(model(tokenizer.encode(s,return_tensors="pt"))[0],dim=2)[0].tolist()[1:-1]]
>>> print(list(zip(t,p)))
[('หลาย', 'DET'), ('หัว', 'NOUN'), ('ดี', 'ADJ'), ('กว่า', 'ADP'), ('หัว', 'NOUN'), ('เดียว', 'ADJ')]

「หลายหัวดีกว่าหัวเดียว」を形態素解析した結果は、どうやら完璧のようだ。ふーむ、この手法の延長線上で、何とかタイ語の係り受け解析もできないかな。

15408305 journal
人工知能

yasuokaの日記: huggingface_hubのInferenceApiでUPOS品詞付与できる各言語モデル

日記 by yasuoka

8月31日の日記で書いたhuggingface_hubのInferenceApiだが、これを使ってUPOS品詞付与できるモデルを、ざっと一覧にしてみた。

InferenceApiは、各モデルのWWWページでも試すことができるし、あるいはhuggingface_hubをインストールしているpython環境であれば

>>> from huggingface_hub.inference_api import InferenceApi
>>> api=InferenceApi("KoichiYasuoka/bert-base-japanese-upos")
>>> r=api(inputs="私の名前は中野です。")
>>> import json
>>> print(json.dumps(r,indent=2,ensure_ascii=False))

のような方法でも試せる。今後もモデルが増えていくと思うので、ぜひぜひ使ってみてほしい。

15404891 journal
人工知能

yasuokaの日記: bert-base-thai-uposによるタイ語の形態素解析

日記 by yasuoka

8月27日の日記に続いて、bert-base-thai-uposも作ってみた。Geotrend/bert-base-th-casedをもとに、Universal DependenciesのUPOSでファインチューニングしたものだ。試しにGoogle Colaboratoryで動かしてみよう。

!pip install transformers
import torch
from transformers import AutoTokenizer,AutoModelForTokenClassification
tokenizer=AutoTokenizer.from_pretrained("KoichiYasuoka/bert-base-thai-upos")
model=AutoModelForTokenClassification.from_pretrained("KoichiYasuoka/bert-base-thai-upos")
s="หลายหัวดีกว่าหัวเดียว"
t=tokenizer.tokenize(s)
p=[model.config.id2label[q] for q in torch.argmax(model(tokenizer.encode(s,return_tensors="pt"))[0],dim=2)[0].tolist()[1:-1]]
print(list(zip(t,p)))

「"หลายหัวดีกว่าหัวเดียว」を形態素解析してみたところ、私(安岡孝一)の手元では以下の結果になった。

[('ห', 'B-DET'), ('##ลา', 'I-DET'), ('##ย', 'I-DET'), ('##ห', 'B-NOUN'), ('##ัว', 'I-NOUN'), ('##ดี', 'ADJ'), ('##ก', 'B-ADP'), ('##ว่า', 'I-ADP'), ('##ห', 'B-NOUN'), ('##ัว', 'I-NOUN'), ('##เ', 'B-ADJ'), ('##ดี', 'I-ADJ'), ('##ย', 'I-ADJ'), ('##ว', 'I-ADJ')]

「##」でブツ切りになっていて読みにくいが、「หลาย」がDET、「หัว」がNOUN、「ดี」がADJ、「กว่า」がADP、「หัว」がNOUN、「เดียว」がADJになっているのがわかる。まあまあの精度ではあるのだが、実はトークナイザに多少問題があって、単語切りがうまくいかない場合もあるようだ。うーん、トークナイザごと鍛え直すしかないかなぁ。

15403474 journal
政府

yasuokaの日記: 戸籍の読み仮名には小書きのカナが使えるのか

日記 by yasuoka

「氏名の読み仮名の法制化に関する研究会」が昨日付けで取りまとめを公開した、との御連絡をいただいた。ざっと読んだ限り、【甲案】【乙案】両論併記になっているものが多い。ただ、小書きのカナについては両論併記にすらなっておらず、議論がまだ煮詰まっていないように、私(安岡孝一)には見える。

「現代仮名遣い」等は,平仮名による表記の規律を定めたものであることから,氏名の読み仮名として戸籍に記載することができる片仮名の範囲については,これらに基づき,現代仮名遣い本文第1の直音(「あ」など),拗音(「きゃ」など),撥音(「ん」)及び促音(「っ」)を片仮名に変換したものとすることが考えられる。また,現代仮名遣いに含まれていないが,先例上,子の名として戸籍に記載することができるとされている小書き(「ぁ」・「ァ」など)及び片仮名についての長音(ー)も,範囲に含めることが考えられる

戸籍統一文字には、小書きのカナとして以下の29字が収録されている。

  • 905390「ァ」
  • 905410「ィ」
  • 905430「ゥ」
  • 905450「ェ」
  • 905470「ォ」
  • 906230「ヵ」
  • 907090「ㇰ」
  • 906240「ヶ」
  • 907100「ㇱ」
  • 907110「ㇲ」
  • 905730「ッ」
  • 907120「ㇳ」
  • 907130「ㇴ」
  • 907140「ㇵ」
  • 907150「ㇶ」
  • 907160「ㇷ」
  • 907190「ㇷ゚」
  • 907170「ㇸ」
  • 907180「ㇹ」
  • 907200「ㇺ」
  • 906050「ャ」
  • 906070「ュ」
  • 906090「ョ」
  • 907210「ㇻ」
  • 907220「ㇼ」
  • 907230「ㇽ」
  • 907240「ㇾ」
  • 907250「ㇿ」
  • 906160「ヮ」

これら29字は、JIS X 0213をもとに収録されたもので、とりあえず戸籍システムで使うことができる。もちろん、戸籍システムで使えるかどうかと、戸籍法として読み仮名に使えるかどうかは、必ずしも一致しない。だからこそ、せめて【甲案】【乙案】を併記できるくらいまでは、議論を煮詰めてほしいのだ。まあ、時間が足りないこともあるのだろうけど、何とかならないものだろうか。

typodupeerror

日々是ハック也 -- あるハードコアバイナリアン

読み込み中...