人間のフレーズからコマンドパラメーターを取得する

私は意図の分類に対処することできましたが、フレーズから追加のパラメーターを抽出するという、より難しいタスクが残りました。 これはタグを使用して行われることを知っています。 sequence_taggingの適用に成功した後、6ギガバイトを超える単語のベクトル表現の辞書を保持する必要があることはあまり嬉しくありません。



ゼロを試みる



Kerasにタガーを実装する例を見つけましが、私の実験の最良の伝統では、そこからコードの断片を無意識にコピーし始めました。 この例では、ニューラルネットワークは入力文字列を単語に分割せずに一連の文字として処理します。 しかし、テキストのさらに下には、埋め込みレイヤーを使用した例があります。 そして、hashing_trickの使用を学んだので、このスキルを使用したいという強い欲求を感じました。



私がやったことは、分類器よりもはるかにゆっくりと訓練されました。 Kerasでデバッグ出力をオンにし、ゆっくりと表示される行を思慮深く見て、Lossの値に注目しました。 それは特に減少しませんでしたが、私には非常に大きく見えました。 そして精度は小さかった。 座って結果を待つのが面倒だったので、Andrew Ngの推奨事項の1つを思い出しました。これは、より小さなトレーニングデータセットでニューラルネットワークを試すことです。 損失が例の数に依存することを考慮すると、良い結果が期待されるかどうかを評価できます。



そのため、トレーニングを停止し、以前のデータの10分の1の新しいトレーニングデータセットを生成し、再びトレーニングを開始しました。 そして、ほぼ即座に、彼は同じ損失と同じ精度を得ました。 ケーススタディの数が増えても改善されないことがわかります。



それでも、私はトレーニングの終了を待って(数秒で分類子が学習したという事実にもかかわらず、約1時間)、試してみることにしました。 seq2seqの場合、トレーニングと実際の作業には異なるモデルが必要なので、さらにコピーする必要があることに気付きました。 私はコードをもう少し深く理解し、次にやるべきことをやめて考えることにしました。



私が選択する前に-再び既製の例を取り上げますが、すでにイニシアチブなしで、 既製のseq2seqを取るか、すでに働いていたツールに戻ります-NERModelのシーケンスタガー。 GloVeなしに忠実。



3つすべてを逆の順序で試すことにしました。



シーケンスタギングのNERモデル



既存のコードを編集したいという欲求は、中を見るとすぐに消えました。 したがって、私は反対に行きました-シーケンスのタグ付けからさまざまなクラスとメソッドを引き出し、gensim.models.Word2Vecを取得してそこにすべてを供給します。 1時間試した後、トレーニングデータセットを作成することができましたが、代わりに使用できる辞書ではありませんでした。 私はnumpyの深さからどこかから来たエラーを見て、このベンチャーを放棄しました。



彼は、 念のため迷子にならないようにしました。



Seq2seq



Seq2Seqのドキュメントでは、調理方法のみが説明されており、使用方法は説明されていません。 を見つけ 、自分で微調整をやり直す必要がありました。 さらに数時間の実験と結果-学習プロセスの精度は0.83に安定しています。 トレーニングデータのサイズに関係なく。 それで、私はどこかで何かを混ぜました。



ここで、この例では、最初は手動トレーニングデータが細かく分割され、次に埋め込みは手動で行われるのが好きではありませんでした。 その結果、1つのKerasモデル、最初にEmbeddding、次にSeq2Seqにねじ込み、1つの大きなデータを準備しました。



それは美しくなりました
model = Sequential() model.add(Embedding(256, TOKEN_REPRESENTATION_SIZE, input_length=INPUT_SEQUENCE_LENGTH)) model.add(SimpleSeq2Seq(input_dim=TOKEN_REPRESENTATION_SIZE, input_length=INPUT_SEQUENCE_LENGTH, hidden_dim=HIDDEN_LAYER_DIMENSION, output_dim=output_dim, output_length=ANSWER_MAX_TOKEN_LENGTH, depth=1)) model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
      
      





しかし、美しさは保存されませんでした-ネットワークの動作は変更されていません。



別のcommit 、3番目のオプションに進みます。



手動でSeq2seq



最初は、すべてを正直にコピーして、そのまま実行しようとしました。 入力は元のフレーズの一連の文字であり、出力はスペースでつなぎ合わせてタグのリストを取得できる一連の文字である必要があります。 精度は良さそうです。 ニューラルネットワークは、タグのスペルを開始すると、エラーなしで最後まで書き込むことをすぐに学習したためです。 しかし、タグ自体は、期待した結果とはまったく一致しませんでした。



小さな変更を行います-結果は文字のシーケンスではなく、最終リストから入力されたタグのシーケンスである必要があります。 精度はすぐに低下しました-ネットワークが対処していないことが正直に明らかになったからです。



それにもかかわらず、私はネットワークのトレーニングを最後まで行い、それが正確に何を提供するかを見ました。 20%の安定した結果は、おそらく何かを意味するためです。 結局のところ、ネットワークは過度の負担をかけない方法を見つけました。



 please, remind me tomorrow to buy stuff O
      
      





つまり、句にデータが含まれていない単語が1つだけ存在するふりをします(分類子がまだ食べていないという意味です)。 トレーニングデータを確認します。実際、約20%のフレーズはまさにそのとおりです。はい、いいえ、一部のping(つまり、すべての種類のこんにちは)と一部の承認(すべての種類の感謝)です。



スティックネットワークを車輪に配置し始めます。 yes / noの数を4倍に減らし、ping / acknowledgeを2倍にして、データを含むすべての種類の「ゴミ」を1語で追加します。 この時点で、タグに明示的なクラスバインディングをB-makiuchi-count



必要がないと判断したため、たとえばB-makiuchi-count



は単なるB-count



。 そして、新しい「ゴミ」は、 B-count



クラスの数字、予想されるB-time



タグのある「4:30」の形式の「時間」、 B-time



タグのある「今」、「今日」、「明日」のような日付の表示でしたB-when







それでも機能しません。 ネットワークはもはや「O and it's」という明確な答えを出しませんが、同時に精度は18%のレベルのままであり、答えは完全に不十分です。



 not yet expected ['O', 'O'] actual ['O', 'O', 'B-what'] what is the weather outside? expected ['O', 'O', 'O', 'O', 'O'] actual ['O', 'O', 'B-what']
      
      





これまでのところ、行き止まり。



間奏-理解



結果の欠如も結果です。 表面的にはわかりましたが、Kerasでモデルを設計するときに正確に何が起こるかを理解しています。 必要に応じて保存、読み込み、さらには終了する方法を学びました。 しかし同時に、「人間の」音声を「ボット言語」に翻訳するという、私が望んでいたものを達成できませんでした。 これ以上リードはありませんでした。



そして、記事を書き始めました。 前の記事。 最初のバージョンでは、すべてがここで終了しました-私は分類器を持っていますが、タガーは持っていません。 少し考えた後、私はこのベンチャーを放棄し、多かれ少なかれ成功した分類器についてのみ残し、タガーの問題に言及しました。



計算は正当化されました-私はRasa NLUへのリンクを得ました。 一見、非常に適切なもののように見えました。



ラサ・ヌル



数日間、私は実験に戻りませんでした。 その後、彼は座って、1時間でRasa NLUを実験スクリプトに少しねじ込みました。 これは、それが非常に難しかったということではありません。



コード
make_sample
 tag_var_re = re.compile(r'data-([az-]+)\((.*?)\)|(\S+)') def make_sample(rs, cls, *args, **kwargs): tokens = [cls] + list(args) for k, v in kwargs.items(): tokens.append(k) tokens.append(v) result = rs.reply('', ' '.join(map(str, tokens))).strip() if result == '[ERR: No Reply Matched]': raise Exception("failed to generate string for {}".format(tokens)) cmd, en, rasa_entities = cls, [], [] for tag, value, just_word in tag_var_re.findall(result): if just_word: en.append(just_word) else: _, tag = tag.split('-', maxsplit=1) words = value.split() start = len(' '.join(en)) if en: start += 1 en.extend(words) end = len(' '.join(en)) rasa_entities.append({"start": start, "end": end, "value": value, "entity": tag}) assert ' '.join(en)[start:end] == value return cmd, en, rasa_entities
      
      



この後、トレーニングデータを保存することはまったく難しくありません。
  rasa_examples = [] for e, p, r in zip(en, pa, rasa): sample = {"text": ' '.join(e), "intent": p} if r: sample["entities"] = r rasa_examples.append(sample) with open(os.path.join(data_dir, "rasa_train.js"), "w") as rf: json.dump({"rasa_nlu_data": {"common_examples": rasa_examples, "regex_features": [], "entity_synonims": []}}, rf)
      
      



モデル作成で最も難しい部分は、正しい構成です
  training_data = load_data(os.path.join(data_dir, "rasa_train.js")) config = RasaNLUConfig() config.pipeline = registry.registered_pipeline_templates["spacy_sklearn"] config.max_training_processes = 4 trainer = Trainer(config) trainer.train(training_data) model_dir = trainer.persist(os.path.join(data_dir, "rasa"))
      
      



そして、最も難しいのは彼女を見つけることです
  config = RasaNLUConfig() config.pipeline = registry.registered_pipeline_templates["spacy_sklearn"] config.max_training_processes = 4 model_dir = glob.glob(data_dir+"/rasa/default/model_*")[0] interpreter = Interpreter.load(model_dir, config)
      
      



  parsed = interpreter.parse(line) result = [parsed['intent_ranking'][0]['name']] for entity in parsed['entities']: result.append(entity['entity']+':') result.append('"'+entity['value']+'"') print(' '.join(result))
      
      



please, find me some pictures of japanese warriors

find what: "japanese warriors"

remind me to have a breakfast now, sweetie

remind action: "have a breakfast" when: "now" what: "sweetie"






...まだやるべきことがありますが。



欠点のうち、学習プロセスは完全に沈黙しています。 きっとどこかで点灯します。 ただし、すべてのトレーニングには約3分かかりました。 それでも、spacyにはソース言語のモデルが必要です。 ただし、GloVeよりもかなり軽量です。英語の場合、300メガバイト未満です。 確かに、ロシア語のモデルはまだありません。そして、私の実験の最終目標は、ロシア語で特に機能するはずです。 Rasaで利用可能な他のパイプラインを確認する必要があります。



すべてのコードはgithubで利用可能です。



All Articles