ディープラーニングで形態素解析器を10分で作る!

#初めに

今回はLSTMを使って何かしようと思っていたので、形態素解析器を作りたいと思います。
今回はとにかく実行して動くことを目的としたので色々と手抜きです。
**重要なことなのでもう一度言います。信じられないほどの手抜きです。**

#modelを考える

文字列を1文字ずつone-hotにしてLSTMに食わして区切る場所を出力させます。

```text:例
今日寝ます->[[1,0],[0,1],[0,0],[0,0]]->LSTM->[2,0,0,0]->今日 寝ます
```

※0はデータ長を合わせるためです。

#ソースコードを書く

モデルを考えたので早速ソースコードを書きたいと思います。
学習データは分かち書き済みのテキストファイルです。

```python3:main.py
import sys
import math
import numpy as np
import pickle
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.layers.recurrent import LSTM
from keras.optimizers import Adam

args=sys.argv


class Bow_class:
      def __init__(self):
         self.ID_data={}
         self.ID_data['<EOF>']=0
         
      
      
      def set(self,a):
            temp=list(a)
            for e2 in temp:
                if e2 not in self.ID_data:
                    self.ID_data[e2]=len(self.ID_data)
            
      
      def size(self):
             return len(self.ID_data)

      def char_to_vec(self,a):
         
         A=np.zeros(len(self.ID_data))
         if a in self.ID_data:
            A[self.ID_data[a]]=1
         else:
            pass

                  
         return A


MN=50
time_step_N=20

def Make_data(data,ID_data):
       
       
       x=[]
       y=[]
       
       for e in data:
            ty=[]
            tx=[]
            for i,e2 in enumerate(list(e)):
                 if e2==' ':
                        ty.append(i+1)
                 else:
                        #tx.append(ID_data.char_to_vec(e2))
                        tx.append(ID_data.char_to_vec(e2))
            x.append(tx+[np.zeros(ID_data.size()) for i in range(MN-len(tx))])
            y.append(ty+[0 for i in range(time_step_N-len(ty))])
       
       print(x)
       print(y)
       
       return np.array(x),np.array(y)


def lmain():
      
      ID_data=Bow_class()
      
      data=[]
      
      with open(args[2],"r") as f:
             data=[e.replace("\n", "") for e in f.readlines()]
      
      for e in data:
           ID_data.set(e)
      
      print("ID_class set End")
      

      model = Sequential()
      
      model.add(LSTM(512,batch_input_shape=(None, MN, ID_data.size()), return_sequences=False))
      
      model.add(Dense(512))
      
      model.add(Dense(time_step_N))
      
      model.compile(loss="mse", optimizer=Adam())
      
      x,y=Make_data(data,ID_data)      
     
      model.fit(x,y,epochs=100)
     
      model.save_weights('model.bin')
      with open("ID_data.bin","wb") as f:
          pickle.dump(ID_data,f)

def main():

      ID_data=None
      with open("ID_data.bin","rb") as f:
          ID_data=pickle.load(f)

      model = Sequential()
      
      model.add(LSTM(512,batch_input_shape=(None, MN, ID_data.size()), return_sequences=False))
      
      model.add(Dense(512))
      
      model.add(Dense(time_step_N))

      model.load_weights('model.bin')

      
      while True:
            in_data=input(">")
            in_data2,_=Make_data([in_data],ID_data)
            out_data=[int(round(e)) for e in model.predict(in_data2)[0]]
            print(out_data)
            out_data2=list(in_data)
            for e in out_data:
                  if e<=0:break
                  out_data2=out_data2[:e]+[' ']+out_data2[e:]
            print("".join(out_data2))

      
if args[1]=='l':
     lmain()
      
if args[1]=='r':
     main()
```

やはり、kerasは短くシンプルに書けますね。
因みに、デフォルトだと50文字以上又は20単語以上の文は学習できません。
長い文を学習させたい場合、MN(文字数),time_step_N(単語数)の値を変更してください。

#実行

下記のデータを使って学習させます。

```text:data.txt
今日 は 晴れ です ね
今日 は 雨 です ね
昨日 は 晴れ です ね
```
学習を開始します。

```bash
python3 main.py l data.txt 
```

未学習のデータでテストしてみたいと思います。

```bash
$ python3 main.py r
>昨日は雨ですね
デバッグ用のnp.arrayデータ...
昨日は 雨 です ね 
>
```

ちゃんと、分かち書き出来ました。

#このモデルの欠点

問題点を探せば沢山あるのですが、例えば

- 未知の文字にエラーを吐く
- one-hotを使っているためメモリーの使用量が大きく、大きな学習データで試せない(致命的)
- 大きな学習で試せないので実績がない

等々

#最後に

問題点や課題は多々あるとは言え、10分で形態素解析器(もどき)を作ることは可能でした。