自然言語生成(NLG: Natural Language Generation)において,文を構成する最小単位と,それらに課される制約をどのようにモデル化するかは重要な課題である.特に学習用途や言語処理システムでは,「正しい文」を生成するだけでなく,「なぜそれが正しいのか」を説明可能な構造であることが求められる1 2.
本稿では,ドイツ語文3を対象とし,Swift による実装を想定しながら,動詞中心 (verb-centered) の設計思想に基づいて文生成を行う最小構成モデルを考察する4.
具体的には,いくつかの段階を経て,以下の文章を定型文ではない形で生成することを目的とする.
Ich sehe ihn.
その過程で必要な過程を用語とコードを使いながら詳説する.
本稿には注釈が多く存在するが,大半が学術的な厳密性を考慮するために追加されたものであるため,飛ばして読んでもらって構わない.
動詞について
まずはじめに,ドイツ語(に限らず多くの言語)では,文の構造は動詞が支配的である.どの動詞を主文の動詞(主動詞)として選択するかによって,文に現れる要素がほぼ決定される5.このため,本稿では文を「名詞や語順から組み立てる」のではなく,主動詞を最初に決定し,そこから文全体を展開するという方針を採用する.
この動詞中心のアプローチにより,意味的にもっともらしいが統語的に破綻した文を生成することを避け,文法的に成立した文のみを生成することが可能になる.
主動詞の決定
今回の主動詞は sehenとする.
動詞sehenには様々な意味がある67が,本稿では最も基本的な視覚による知覚,すなわち「目で対象を見た」「対象が視界に入った」という用法8に焦点を当てる.この語義9を主動詞sehenに固定し,冒頭に述べた単純な主文10を生成する.
Ich sehe ihn.
この文11を,文法的・意味的制約に基づく構成物として分解し,再構成可能な形で捉えることを目標とする.一見シンプルだが,この文には「文として成立するために最低限必要な要素」がすべて含まれており,本稿では,それらを分解 → モデル化 → 再構成12する流れを紹介する.
主動詞が要求するもの
動詞によっては文が成りたつために最低限必要な要素として項 (argument)13が存在する.これら項は動詞とその語義に依存するため,動詞を定義するときに一緒に宣言してしまうことが望ましい.
「知覚」の意味でsehenを使う場合,項は以下の2つとなる:
・見る人 → 主語(subject),『誰が(何が)』見るのか
・見られる対象 → 目的語 (object),特に(accusative object)『誰を(何を)』見るのか
このとき,動詞によってとれる主語や目的語にも制約が生まれる14が,本稿ではひとまず無視する.
実装
以下では,文生成の流れを擬似コードに近い形で示す.
これらは実際にコンパイラが通るかどうかは目的としない.
まずは動詞から
必要最低限の実装としては以下の通り.
// 動詞を表す最小単位
// lemma は辞書形(不定形)を表す
struct Verb {
let lemma: String
}
// 今回の主動詞
let sehen: Verb = Verb(lemma: "sehen")
ここから必要に応じて拡張していく方法で実装する.
項構造をコードで表す
ひとまず動詞sehenが要求するものだけ実装しておく.
// 動詞が要求する項(argument)
enum Argument {
case subject // 主語
case accusativeObject // 対格目的語
}
例えば,accusativeObjectではなくobject(.accusative)のように格1516を取る目的語として定義してもいいかもしれない17.
enum Argument {
case subject
case object(Kasus)
}
// 格は英語でcaseだが、Swiftの予約語との混乱を避けるため独語名で定義
enum Kasus {
case nominativ
case genetiv
case dativ
case accusativ
}
動詞と項構造の対応
動詞自身が「何を必要とするか」を知っている設計にする.
struct Verb {
let lemma: String
let arguments: [Argument]
}
// sehen の知覚用法を想定
let sehen: Verb = Verb(
lemma: "sehen",
arguments: [
.subject(.person),
.accusativeObject(.person)
]
)
また,ドイツ語の動詞はその文章の主語の数(すう)と性別(男性・女性・中性),および時制や法に則り変化(conjugate)する.今回は動詞の構造体に主語と時制,法をとるメソッド.conjugated()があるものとする.
// 時制(今回は現在)
let tense: Tense = .present
// 法(今回は直接法)
let mode: Mode = .indicative
// Linke Klammer
let lk: String = sehen.conjugated(subject,tense,mode)
名詞の定義
次に,名詞を定義する.
主語・目的語に使う名詞の最小モデル
ここで,名詞の種類についても軽く定義しておく.こうすることで,項を決定する際にフィルタが機能する.
enum EntityType {
case person
case animal
case artifact
}
上記に基づき,以下のようにNounを定義する.18
struct Noun {
let lemma: String
let entityType: EntityType
}
let ich: Noun = Noun(lemma: "ich",entityType: .person)
ここまでで,必要な構造体・辞書型の定義はおわり.
動詞に基づき項を決定する
定義した構造体・辞書型に基づいて適切な項を選択して文を生成する.
主語の選択
まずは,動詞sehenの項構造argumentsから「主語が必要か」を確認する.
var requiredSubjectType: EntityType? = nil
for argument in sehen.arguments {
if case .subject(let subjectType) = argument {
requiredSubjectType = subjectType
break
}
}
つぎに,requiredSubjectTypeに基づき,subjectを決定する.ここで、nounsという幾つかの名詞が格納された配列を考えて、そこから合致するものを取り出す操作として実装する。
let nouns: [Noun] = [
Noun(lemma: "ich", entityType: .person),
...
Noun(lemma: "ihn",entityType: .person),
...
]
// 主語が存在しない場合もあるのでOptional()
let subject: Noun?
if let subjectType = requiredSubjectType {
// 主語候補を意味的タイプで絞り込む
let candidates = nouns.filter { $0.entityType == subjectType }
// 候補があれば選択,なければフォールバック
subject = candidates.randomElement()
?? Noun(lemma: "ich",entityType: .person)
} else {
// 主語を要求しない動詞
subject = nil
}
ここでは,以下の判断をしている:
- 動詞が主語を要求しているか
- 要求しているなら,意味的に合うものを選ぶ
なお,一文で書くと以下の通り:
クロージャを使った書き方
```swift // compactMap -> nil以外を取り出す // first -> 最初の要素を取り出す if let subjectType = sehen.arguments.compactMap({ arg -> EntityType? in if case .subject(let t) = arg { return t } return nil }).first { subject = nouns .filter { $0.entityType == subjectType } .randomElement() ?? Noun(lemma: "ich",entityType: .person) } else { subject = nil } ```目的語の選択
// 目的語が存在しない場合もあるのでOptional()
let object: Noun?
if sehen.arguments.contains(.accusativeObject(.person)) {
object = nouns.randomElement()
?? Noun(lemma: "ihn",entityType: .person)
} else {
object = nil
}
本来であれば,代名詞の中から"er"(he)を選択し,そのあと適切に格変化をして"ihn"(him)を得る過程が必要だが,今回は省略して次回以降に回す.
ここまで,選択した動詞とその語義の解釈に必要な項について決定した
あとは,どのように文章を並べたら統語的に成立するかを考える
語順,そして文の完成
Feldermodell に沿って配置
ドイツ語主文では,以下の枠組み19がよく使われる.
| 名称 | 日本語 | 説明 |
|---|---|---|
| Vorfeld | 前域 | 主語・目的語・副詞句など(1要素) |
| Linke Klammer | 左文枠 | 定動詞(V2) |
| Mittelfeld | 中域 | 残りの項・副詞句 |
| Rechte Klammer | 右文枠 | 非定動詞(分離動詞・分詞など) |
| Nachfeld | 後域 | 補文・関係文など |
文は構造体struct Sentenceとして定義するのが妥当ではあるが,今回は簡易的に以下のように実装した.
// Vorfeld
let vf: String = subject?.lemma ?? ""
// Linke Klammer
let lk: String = sehen.conjugated(subject,tense,mode)
// Mittelfeld
let mf: String = object?.lemma ?? ""
// 今回は使用しない
let rk: String = ""
let nf: String = ""
最後に文として出力する.
let sentence: String = [vf,lk,mf,rk,nf]
.filter { !$0.isEmpty }
.joined(separator: " ")
+ "."
print(sentence)
// Ich sehe ihn.
まとめ
この記事では,以下を使って最小のドイツ語文を構造から生成した.
- 動詞中心設計
- 項構造(argument structure)
- 意味的制約(entity type)
- Feldermodell による語順
今後は今回扱った名詞・動詞以外の品詞(Part of Speech)以外の単語(形容詞など)を追加していくことになるが、それらも適切な選択制約を課すことで意味的に非文にならないように生成していくことが肝となる。次回以降はまずは今回おざなりになっている名詞・動詞の実装についてもう少し整えていくこととする。
-
学術的な用語でいうところの意味的(Semantically)には合っていても統語的(Syntactically)に誤った文章(いわゆる非文)を生成しても意味がない(特に初学者にはその間違いがわからない).
例: "Me sees his"-> 意味的にはOK,統語的にはNG. "I see him."が意味的・頭語的に正しい文章. ↩ -
統語的にはOKでも意味的にはナンセンスな文章として有名なのが言語学者・ノーム・チョムスキーによる「Colorless green ideas sleep furiously」(直訳: 色無き緑の考えが猛烈に眠る). ↩
-
大学で第二外国語として独語を選択していたのと個人的に興味があるため. ↩
-
ついでに言語学的な知識も少し蓄えられるようなるべく学術的に正しい記述を心がけたつもりである. ↩
-
具体的には,動詞は次の点を規定する.1.どんな要素が必要か(主語・目的語などの必須項),2.それらはどの格で現れるか(主格・対格・与格など),3.どこに配置されるか(有限動詞の位置,目的語の配置など) ↩
-
日本語では見る/観る/視る,英語でもsee/look/watch/observe/glanceなどがあるように厳密には同じ視覚的な知覚であっても意図的かどうか(意思性:volitionality,志向性:intentionality)や方向性(directionality)等で実際には意味(semantic)が異なる.加えて,"I see"単体で対格目的語がない場合だとそれは「私は見た」というよりは比喩的拡張により「理解した」という用法に近づいてしまう(認知的・認識的解釈).本稿での"sehen"は英語でいうところの"see"の元来の意味,すなわち専門的に言えば「非意図的」で「非方向性」を持つ用法としたいため、対格目的語は必須. ↩
-
動詞が内在的に持つ性質のことを語彙的アスペクト(lexical aspect,Aktionsart)と呼ぶ.今回のsehenは語彙的アスペクトでいうと状態(State)に分類される. ↩
-
意味的用法(semantic reading). ↩
-
語義(word sense,lexical sense).語義を固定することで解釈が定まる. ↩
-
今回の文章は主文(Main clause)のなかでも平叙文(declarative main clause)と呼ばれるものである.その他に疑問文(interrogative main clause)や命令文(imperative main clause)があり,それらによっては転置(主語と述語の入れ替え)が起こったり主語が省略されたりする.また,主文は述べる話題についての話者の態度・評価(modality)を決定する. ↩
-
英訳するとI see him. ↩
-
さながら某漫画の錬金術のようである(分解,理解,再構築) ↩
-
この「動詞が要求する必須要素」の集合を 項構造(argument structure) と呼ぶ.
sehenの場合は本文通り,知覚者と知覚対象を項として持つ2項動詞である.一方,schlafen(「寝る」)の場合は行為主体/経験主体のみを項としてもつ1項動詞,regnen(「雨が降る」)のような非人称動詞に至っては意味的な項は存在さず,統語的要請としてのダミー主語(虚主語,expletive)としてのesが現れるにすぎない. ↩ -
例えば,動詞が sagen(「言う」に相当)である場合,比喩的・拡張的な用法(「目は口ほどに物を言う」「歴史が物語る」など)を除けば,主語は原則として 人間(あるいは人間に準じる発話主体) に限定される.
また,sehen の場合においても,目的語として抽象的な対象(例えば「真実」など)を取ると,単純な視覚的知覚という解釈よりも,「真実に気づいた」といった 認識的(epistemic)解釈に誘導されやすい.
このように,対象とする動詞およびその語義に基づく解釈を固定したい場合には,主語や目的語(さらにはその他の項についても同様に)に対して,**一定の選択制約(selectional restrictions)**を設けることが有効である. ↩ -
**格(case)**とは,名詞句(noun phrase)が文中でどのような統語的役割を担っているかを示す形式的マーカーである.ドイツ語には四つの格が存在し,例えば主格(nominativ)は典型的に主語を標示する. ↩
-
格体系は,ドイツ語初学者が躓きやすい点としてよく知られている(もう一つの大きな障壁は動詞の活用である).英語では,名詞に付随する形式的区別として主に 定冠詞 the と不定冠詞 a/an を覚えればよかったのに対し,ドイツ語では名詞がもつ 文法性(gramatical gender,男性・女性・中性) と 四つの格 の組み合わせに応じて,冠詞や形容詞の形が変化するため,学習負荷が大きくなる. ↩
-
今後,生成器を仕上げていく上でどちらにしろ格を定義することは必須 ↩
-
実際には、"ich"のような人称代名詞と一般名詞は分けて考えた方がいいが、ここでは簡潔にするためこのように定義している。 ↩
-
位相的フィールドモデル(topological field model)を指す.日本語では枠構造ともいう.それぞれの場(feld)に入る要素は定まっており,例えばMittelfeld内の要素の順序はTeKaMoLoの原則に基づいて決定できる.なお,強調したい要素に応じて語順を変えることはある. ↩