Published Date : 2020年7月15日21:59

【Unity, C#, NLP, NumSharp, MeCab.DotNet】其一
【Unity, C#, NLP, NumSharp, MeCab.DotNet】Part 1


This blog has an English translation


YouTubeにアップした動画、「【Unity, C#, NLP, NumSharp, MeCab.DotNet】」の補足説明の記事です。

Here's a little more about the 「【Unity, C#, NLP, NumSharp, MeCab.DotNet】」 video I uploaded to YouTube.

Unityでやる必要があるか分からないがNumSharpとMeCab.DotNetを使った自然言語処理

Natural Language Processing in Unity with NumSharp and MeCab.DotNet

無駄な説明を省いて、忙しい時でも短時間で理解できるような動画です。

It's a video that can be understood in a short period of time even when you're busy, without any unnecessary explanation.


目次

Table of Contents




NuGetForUnityとNumSharpとMeCabDotNetのインストール
Install NuGetForUnity, NumSharp and MeCabDotNet




Download and Import NuGetForUnity

NuGetForUnityのパッケージをダウンロードする。

Download the NuGetForUnity package.

NuGetForUnity

Unityプロジェクトを立ち上げる。

Launch your Unity project.

さっきダウンロードしたパッケージをアセッツフォルダー内にインポートする。

Import the package you just downloaded into the Assets folder.

上にニューゲットタブができてるのでマネージニューゲットパッケージズをクリックする。

There's a "NeGet" tab above, so click Manage NuGet Packages.


Install NumSharp

ナムシャープと入力してサーチをクリックしてインストールする。

Type NumSharp and click Search button to install.

NumSharp

アセッツ内で右クリック、新しいC#スクリプトを作成する。

Right-click in the Assets folder to create a new C sharp script.

スクリプトをダブルクリック、Visual Studioを立ち上げて、NDArrayを作って、どんな感じか確かめる。

Double-click the script. Launch Visual Studio and create an NDArray to see how it works.


NewBehaviourScript.cs

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using NumSharp;
using MeCab;

public class NewBehaviourScript : MonoBehaviour
{

    private void Start()
    {
        var nd = np.full(5, 12);
        Debug.Log(nd);
        nd = np.zeros(12);
        Debug.Log(nd);
        nd = np.arange(12);
        Debug.Log(nd);
    }

}

ほとんどPythonのNumpyと書き方は変わらない。

It's almost the same as Numpy in Python.

スクリプトを保存したら、シーン内で右クリックしてエンプティ―オブジェクトを作成する。

After saving the script, right-click in the scene to create an empty object.

エンプティ―オブジェクトにスクリプトをアタッチする。

Attach a script to an empty object.

ゲームをプレイしてどんな感じか確かめる。

Play the game to see how it works.


Install MeCabDotNet

今度は日本語を処理してNumSharpのNDArrayに変換したいので、適当な日本語のテキストファイルを作成する。

This time We want to process Japanese and convert it to NDArray of NumSharp, So We Create an appropriate Japanese text file.


text.txt

Unityを使った自然言語処理だよ。

またマネージニューゲットパッケージズを立ち上げて、今度は日本語を品詞ごとに分割するために必要なメカブドットネットをインストールする。

We also launched Manage NuGet Packages. Now install the MeCabDotNet needed to separate Japanese into parts of speech.

MeCab.DotNet




Cシャープスクリプト
C Sharp Script



アセッツ内にテキストファイルを入れるためのリソーセズフォルダーを作成する。

Create a resources folder to contain the text file in the Assets.

テキストファイルを読み込み、表示させるスクリプトを書いてみる。

Write a script that reads and displays a text file.


NewBehaviourScript.cs

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using NumSharp;
using MeCab;

public class NewBehaviourScript : MonoBehaviour
{
    private void Start()
    {
        string sentence = (Resources.Load("text", typeof(TextAsset)) as TextAsset).text;
        Debug.Log(sentence);
    }
}

メカブドットネットをそのまま使うとエラーになるので、 メカブドットネットのパッケージ内にあるDictionaryフォルダとメタファイルを コピーして、Unityプロジェクトの一番上の階層に張り付ける。

Using MeCab.DotNet as is will result in an error. So, copy and paste the Dictionary folder and metafiles from the MeCab.DotNet package to the top level of your Unity project.

分かち書き用のスクリプトを作成して、どんな感じか確かめてみる。

Create a script for spliting the sentence and see how it works.


NewBehaviourScript.cs

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using NumSharp;
using MeCab;

public class NewBehaviourScript : MonoBehaviour
{
    private void Start()
    {
        string sentence = (Resources.Load("text", typeof(TextAsset)) as TextAsset).text;
        Debug.Log(sentence);

        var parameter = new MeCabParam();
        var tagger = MeCabTagger.Create(parameter);
        foreach (var node in tagger.ParseToNodes(sentence))
        {
            if (node.CharType > 0)
            {
                var features = node.Feature.Split(',');
                var displayFeatures = string.Join(", ", features);
                Debug.Log($"{node.Surface}\t{displayFeatures}");
            }
        }
    }
}

今度は長めのテキストを作成する。

Now create a text file with longer sentences.


text.txt

Unityを使った自然言語処理だよ。
日本語処理はMeCab.NETを使わせてもらうよ。
PythonのNumpyの代わりはNumsharpを使うよ。
楽しみだね。
でも、Unity使う必要があるのかなぁ…。

テキストを分かち書きして、NDArrayに変換する処理を別のスクリプトファイルに分ける。

Separate the conversion process of breaking a sentence into parts of speech, converting each into a number, and then converting it to NDArray into separate CS files.

前処理をするクラスメソッドを作成して、メカブを使って分かち書き、IDからワード、ワードからID用の辞書を作成する。

Create a class method to preprocess. Use "MeCab" to divide a sentence into parts of speech and create a dictionary from ID to word and from word to ID.

分かち書きされた日本語のIDだけを抜き出したコーパスを作成して、 結果としてその三つの変数を外に返してあげる。

Creates a corpus of Japanese IDs converted to NDArray. Finally, the three variables are returned as the result of the method.


Helper.cs

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using NumSharp;
using MeCab;


namespace Helper
{
    public class Util
    {
        public static (NDArray, Dictionary<string, int>, Dictionary<int, string>) preprocess(string text)
        {
            var words = new List<string>();
            var idToWord = new Dictionary<int, string>();
            var wordToID = new Dictionary<string, int>();
            var parameter = new MeCabParam();
            var tagger = MeCabTagger.Create(parameter);

            foreach (var node in tagger.ParseToNodes(text))
            {
                if (node.CharType > 0)
                {
                    var features = node.Feature.Split(',');
                    var displayFeatures = string.Join(", ", features);
                    words.Add(node.Surface);

                }
            }

            foreach (var word in words)
            {
                if (!(wordToID.ContainsKey(word)))
                {
                    var newId = wordToID.Count();
                    wordToID[word] = newId;
                    idToWord[newId] = word;
                }
            }

            var corpus = new List<int>();
            foreach (var word in words)
            {
                corpus.Add(wordToID[word]);

            }

            var ndArrayCorpus = np.array(corpus);

            return (ndArrayCorpus, wordToID, idToWord);
        }
    }
}

複数の型を取り扱うので、トゥープルを返すメソッドを作る必要があります。下記のサイトを参考にさせて頂きました。とても読みやすいです。

Since we are dealing with multiple types, we need to create a method that returns a tuple. I referred to the following site. It's very easy to read.

タプルを返すメソッドの実装方法

public static (NDArray, Dictionary<string, int>, Dictionary<int, string>) preprocess(string text)

そして、以下のスクリプトでIDと単語の辞書を作ります。最初は空の辞書なのでカウントは0。それがそのままその単語のIDになります。単語が重複していれば同じIDとして扱われます。

The following script creates a dictionary of IDs and words. The count is 0 because it is initially an empty dictionary. That is the ID of the word. Duplicate words are treated as the same ID.


foreach (var word in words)
{
    if (!(wordToID.ContainsKey(word)))
    {
        var newId = wordToID.Count();
        wordToID[word] = newId;
        idToWord[newId] = word;
    }
}

最初に作ったスクリプトファイルでその結果を確かめる。

Use the first script file you created to see the results.


NewBehaviourScript.cs

using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using NumSharp;
using MeCab;

using Helper;


public class NewBehaviourScript : MonoBehaviour
{

    private void Start()
    {
        string sentence = (Resources.Load("text", typeof(TextAsset)) as TextAsset).text;
        Debug.Log(sentence);

        (var ndArrayCorpus, var wordToID, var idToWord) = Util.preprocess(sentence);

        var wti = "";
        var itw = "";
        var corpus = "";

        foreach (KeyValuePair<string, int> kvp in wordToID)
        {
            wti = wti + "{ key=" + kvp.Key + ",val=" + kvp.Value.ToString() + " } ";
            itw = itw + "{ key=" + wordToID[kvp.Key].ToString() + ",val=" + kvp.Key + " } ";
            corpus = corpus + wordToID[kvp.Key].ToString() + ", ";
        }
        Debug.Log("word to id -> " + wti);
        Debug.Log("id to word -> " + itw);
        Debug.Log("corpus -> " + corpus);
        Debug.Log("ndarray corpus: ");
        Debug.Log(ndArrayCorpus);

    }

}

リストや辞書の結果を一行で表示できるように、無駄な作業ですが一つずつ文字列として連結させていきます。確認のための作業なので確認が終わったらコメントアウトでもしといてください。

To display the results of a list or dictionary in a single line, we concatenate them one by one as strings. It's for checking, so please comment out after checking.

var wti = "";
var itw = "";
var corpus = "";

foreach (KeyValuePair<string, int> kvp in wordToID)
{
    wti = wti + "{ key=" + kvp.Key + ",val=" + kvp.Value.ToString() + " } ";
    itw = itw + "{ key=" + wordToID[kvp.Key].ToString() + ",val=" + kvp.Key + " } ";
    corpus = corpus + wordToID[kvp.Key].ToString() + ", ";
}

プレイボタンを押して、期待した結果になっているか確かめてみる。

Press the play button to see if it works as expected.

これで準備完了です。

We're all set.

次回はより発展させて行きたいと思います。

I would like to develop it further next time.



以上です。お疲れ様です。

That's all. Thank you for your hard work.

漫才をPythonで自動生成する試みも過去にやってます。興味があったらどうぞ。

I have also tried to automatically generate manzai in Python in the past. If you're interested, go ahead.

Manzai





See You Next Page!