chainerによるSeq2Seq

こちら
で紹介しているSeq2Seqを動く形で作成しなおしてみました。


train_pair = [
    ["初めまして。", "初めまして。よろしくお願いします。"],
    ["どこから来たんですか?", "日本から来ました。"],
    ["日本のどこに住んでるんですか?", "東京に住んでいます。"],
    ["仕事は何してますか?", "私は会社員です。"],
    ["お会いできて嬉しかったです。", "私もです!"],
    ["おはよう。", "おはようございます。"],
    ["いつも何時に起きますか?", "6時に起きます。"],
    ["朝食は何を食べますか?", "たいていトーストと卵を食べます。"],
    ["朝食は毎日食べますか?", "たまに朝食を抜くことがあります。"],
    ["野菜をたくさん取っていますか?", "毎日野菜を取るようにしています。"],
    ["週末は何をしていますか?", "友達と会っていることが多いです。"],
    ["どこに行くのが好き?", "私たちは渋谷に行くのが好きです。"]
]
test_pair = [
    ["初めまして。", "初めまして。よろしくお願いします。"],
    ["どこから来たんですか?", "米国から来ました。"],
    ["米国のどこに住んでるんですか?", "ニューヨークに住んでいます。"],
    ["おはよう。", "おはよう。"],
    ["いつも何時に起きますか?", "7時に起きます。"],
    ["夕食は何を食べますか?", "たいていトーストと卵を食べます。"],
    ["夕食は毎日食べますか?", "たまに朝食を抜くことがあります。"],
    ["肉をたくさん取っていますか?", "毎日インクを取るようにしています。"],
    ["週頭は何をしていますか?", "友達と会っていることが多いです。"],
]



# https://nojima.hatenablog.com/entry/2017/10/10/023147


import nltk
import MeCab
import chainer
from chainer.datasets import split_dataset_random , cifar
import chainer.links as L
import chainer.functions as F
import random
import numpy as np
import codecs

SIZE=10000
EOS=1
UNK=0


class EncoderDecoder(chainer.Chain):
    def __init__(self, n_vocab, n_out, n_hidden):
        super(EncoderDecoder,self).__init__()

        with self.init_scope():
            self.embed_x = L.EmbedID(n_vocab, n_hidden)
            self.embed_y = L.EmbedID(n_out,n_hidden)

            self.encoder = L.NStepLSTM(
                n_layers=1,
                in_size=n_hidden,
                out_size=n_hidden,
                dropout=0.1)
            self.decoder = L.NStepLSTM(
                n_layers=1,
                in_size=n_hidden,
                out_size=n_hidden,
                dropout=0.1)

            self.W = L.Linear(n_hidden, n_out)

    def __call__(self, xs , ys ):
        xs = [x[::-1] for x in xs]

        eos = self.xp.array([EOS], dtype=np.int32)
        ys_in = [F.concat((eos, y), axis=0) for y in ys]
        ys_out = [F.concat((y, eos), axis=0) for y in ys]

        # Both xs and ys_in are lists of arrays.
        exs = [self.embed_x(x) for x in xs]
        eys = [self.embed_y(y) for y in ys_in]

        hx, cx, _ = self.encoder(None, None, exs)
        _, _, os = self.decoder(hx, cx, eys)

        batch = len(xs)
        concat_os = F.concat(os, axis=0)
        concat_ys_out = F.concat(ys_out, axis=0)
        loss = F.sum(F.softmax_cross_entropy(self.W(concat_os), concat_ys_out, reduce='no')) / batch

        chainer.report({'loss': loss}, self)
        n_words = concat_ys_out.shape[0]
        perp = self.xp.exp(loss.array * batch / n_words)
        chainer.report({'perp': perp}, self)
        return loss

    def translate(self,xs,max_length=30):
        with chainer.no_backprop_mode(),chainer.using_config("train",False):
            xs=xs[::-1] # reverse list
            #exs = [self.embed_x(x) for x in xs]
            exs = self.embed_x(xs)
            hx, cx, _ = self.encoder(None, None, [exs])

            result=[]
            word_id=EOS
            for i in range(max_length):
                os,cs=self._translate_word(word_id,hx,cx)
                word_id=int(F.argmax(os).data)
                if word_id==EOS:break
                result.append(word_id)
            return result

    def _translate_word(self,word_id,hx,cx):
        y=np.array([word_id],dtype=np.int32)
        ey=self.embed_y(y)
        _, cs, os = self.decoder(hx, cx, [ey])
        fos=F.softmax(self.W(os[0]))
        return fos,cs

class Data(chainer.dataset.DatasetMixin):
    def __init__(self):
        mecab = MeCab.Tagger("-Owakati")

        self.vocab={"":0,"":1}
        def to_dataset(source,target,train=True):
            swords = to_number(mecab.parse(source).strip().split(" "),train)
            twords = to_number(mecab.parse(target).strip().split(" "),train)
            return (np.array(swords).astype(np.int32),np.array(twords).astype(np.int32))

        def to_number(words,train):
            ds=[]
            for w in words:
                if w not in self.vocab:
                    if train:
                        self.vocab[w]=len(self.vocab)
                    else:
                        w=""
                ds.append(self.vocab[w])
            return ds

        self.train_data=[]
        self.test_data=[]
        for source,target in train_pair:
            self.train_data.append(to_dataset(source,target))

        for source,target in test_pair:
            self.test_data.append(to_dataset(source,target,False))


        self.vocab_inv={}
        for w in self.vocab.keys():
            self.vocab_inv[self.vocab[w]]=w

def convert(batch, device):
    def to_device_batch(batch):
        return [chainer.dataset.to_device(device, x) for x in batch]

    res= {'xs': to_device_batch([x for x, _ in batch]),
            'ys': to_device_batch([y for _, y in batch])}
    return res




seed = 12345
random.seed(seed)
np.random.seed(seed)

data = Data()

batchsize=128
#train_iter = chainer.iterators.MultithreadIterator(train,batchsize,n_threads=4)
#test_iter=chainer.iterators.MultithreadIterator(test,len(test),repeat=False,shuffle=False,n_threads=4)
train_iter = chainer.iterators.SerialIterator(data.train_data,batchsize)
test_iter=chainer.iterators.SerialIterator(data.test_data,len(data.test_data))




n_vocab=len(data.vocab)
n_out=len(data.vocab)
n_hidden=300
print("n_vocab:",n_vocab)

optimizer=chainer.optimizers.Adam()

mlp=EncoderDecoder(n_vocab,n_out,n_hidden)
optimizer.setup(mlp)

updater=chainer.training.StandardUpdater(train_iter,optimizer,converter=convert,device=-1)

#train
epochs=1000
trainer=chainer.training.Trainer(updater,(epochs,"epoch"),out="dialog_result")
trainer.extend(chainer.training.extensions.LogReport())
trainer.extend(chainer.training.extensions.PrintReport(['epoch', 'main/loss', 'main/accuracy']))

trainer.run()
mlp.to_cpu()
chainer.serializers.save_npz("dialog.model",mlp)




# https://nojima.hatenablog.com/entry/2017/10/17/034840
mlp=EncoderDecoder(n_vocab,n_out,n_hidden)
chainer.serializers.load_npz("dialog.model",mlp,path="")

for source,target in data.test_data:
    predict=mlp.translate(np.array(source))
    print("source:",[data.vocab_inv[w] for w in source])
    print("predict:",[data.vocab_inv[w] for w in predict])
    print("target:",[data.vocab_inv[w] for w in target])

結果

n_vocab: 71
epoch       main/loss   main/accuracy
1           34.5502                    
2           31.7847                    
3           29.1603                    
4           26.6713                    
5           24.3079                    
6           22.0612                    
7           19.9224                    
8           17.8789                    
9           15.919                     
10          14.0387                    
11          12.2457                    
12          10.5555                    
13          8.98597                    
14          7.55335                    
15          6.26964                    
16          5.14105                    
17          4.16823                    
18          3.34746                    
19          2.67084                    
20          2.12592                    
21          1.69575                    
22          1.36043                    
23          1.10025                    
24          0.898079                   
25          0.740202                   
26          0.616168                   
27          0.518174                   
28          0.44032                    
29          0.378046                   
30          0.327818                   
31          0.286931                   
32          0.253339                   
33          0.225496                   
34          0.202227                   
35          0.18263                    
36          0.166004                   
37          0.151796                   
38          0.139575                   
39          0.128993                   
40          0.119775                   
41          0.1117                     
42          0.104586                   
43          0.09829                    
44          0.0926925                  
45          0.0876961                  
46          0.0832203                  
47          0.0791977                  
48          0.0755707                  
49          0.0722914                  
50          0.0693159                  
51          0.0666087                  
52          0.0641389                  
53          0.0618778                  
54          0.0598021                  
55          0.0578909                  
56          0.0561267                  
57          0.0544931                  
58          0.0529775                  
59          0.051567                   
60          0.0502504                  
61          0.0490188                  
62          0.0478641                  
63          0.0467791                  
64          0.0457571                  
65          0.0447925                  
66          0.0438801                  
67          0.0430147                  
68          0.0421937                  
69          0.0414122                  
70          0.0406681                  
71          0.039957                   
72          0.0392778                  
73          0.0386279                  
74          0.0380038                  
75          0.037405                   
76          0.0368287                  
77          0.0362744                  
78          0.0357389                  
79          0.0352229                  
80          0.0347236                  
81          0.0342409                  
82          0.0337726                  
83          0.0333189                  
84          0.0328779                  
85          0.0324506                  
86          0.0320346                  
87          0.0316298                  
88          0.0312351                  
89          0.0308511                  
90          0.0304759                  
91          0.0301098                  
92          0.0297521                  
93          0.0294023                  
94          0.0290616                  
source: ['初め', 'まして', '。']
predict: ['初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。', '初め', 'まして', '。']
target: ['初め', 'まして', '。', 'よろしくお願いします', '。']
source: ['どこ', 'から', '来', 'た', 'ん', 'です', 'か', '?']
predict: ['日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来', '日本', 'から', '来']
target: ['', 'から', '来', 'まし', 'た', '。']
source: ['', 'の', 'どこ', 'に', '住ん', 'でる', 'ん', 'です', 'か', '?']
predict: ['東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん', '東京', 'に', '住ん']
target: ['', 'に', '住ん', 'で', 'い', 'ます', '。']
source: ['おはよう。']
predict: ['おはよう', 'ござい', 'ます', '。']
target: ['おはよう。']
source: ['いつも', '何', '時', 'に', '起き', 'ます', 'か', '?']
predict: ['6', '時', 'に', '6', '時', 'に', '6', '時', 'に', '6', '時', 'に', '6', '時', 'に', '6', '時', 'に', '6', '時', 'に', '6', '時', 'に', '6', '時', 'に', '6', '時', 'に']
target: ['', '時', 'に', '起き', 'ます', '。']
source: ['', 'は', '何', 'を', '食べ', 'ます', 'か', '?']
predict: ['たいてい', 'トースト', 'と', '卵', 'を', '抜く', 'たいてい', 'トースト', 'と', '卵', 'を', '抜く', 'たいてい', 'トースト', 'と', '卵', 'を', '抜く', 'たいてい', 'トースト', 'と', '卵', 'を', '抜く', 'たいてい', 'トースト', 'と', '卵', 'を', '抜く']
target: ['たいてい', 'トースト', 'と', '卵', 'を', '食べ', 'ます', '。']
source: ['', 'は', '毎日', '食べ', 'ます', 'か', '?']
predict: ['たまに', '朝食', 'を', '抜く', 'たまに', '朝食', 'を', '抜く', 'たまに', '朝食', 'を', '抜く', 'たまに', '朝食', 'を', '抜く', 'たまに', '朝食', 'を', '抜く', 'たまに', '朝食', 'を', '抜く', 'たまに', '朝食', 'を', '抜く', 'たまに', '朝食']
target: ['たまに', '朝食', 'を', '抜く', 'こと', 'が', 'あり', 'ます', '。']
source: ['', 'を', 'たくさん', '取っ', 'て', 'い', 'ます', 'か', '?']
predict: ['毎日', '野菜', 'を', '取る', 'よう', 'に', '毎日', '野菜', 'を', '取る', 'よう', 'に', '毎日', '野菜', 'を', '取る', 'よう', 'に', '毎日', '野菜', 'を', '取る', 'よう', 'に', '毎日', '野菜', 'を', '取る', 'よう', 'に']
target: ['毎日', '', 'を', '取る', 'よう', 'に', 'し', 'て', 'い', 'ます', '。']
source: ['', '', 'は', '何', 'を', 'し', 'て', 'い', 'ます', 'か', '?']
predict: ['友達', 'と', '会っ', 'て', 'いる', 'と', '会っ', 'て', 'いる', 'と', '会っ', 'て', 'いる', 'と', '会っ', 'て', 'いる', 'と', '会っ', 'て', 'いる', 'と', '会っ', 'て', 'いる', 'と', '会っ', 'て', 'いる', 'と']
target: ['友達', 'と', '会っ', 'て', 'いる', 'こと', 'が', '多い', 'です', '。']
トレイニングデータは収束しているようですが,結果はまだまだダメそうですね。

ワンライナーで拡張子を変更

Bashの変数から拡張子を除いたファイル名を取得するには

a="file.txt"
echo ${a%%.txt}  # aと表示

これをうまく利用すると一気にディレクトリ内のファイルの拡張子を変更できます。txtをjsonに変更する例はこれ。

for f in *.txt;do mv $f ${f%%.*}.json; done

pandasのseriesをintへ変換


import pandas as pd
df = pd.DataFrame({'age': [24, 42], 'state': ['NY', 'CA'], 'point': [64, 92]},index=['Alice', 'Bob'])
df
       age state  point
Alice   24    NY     64
Bob     42    CA     92

これからpointの値をとる


val=df["point"]
type(val)

Seriesとなり,Intでは所得できない

valuesをつければNumpyのarrayとして取得できる。


val.values
array([64, 92])

type(val.values)


val.values[0]
64

AWSlambdaでkerasを動かす

AWSのlambdaはサーバレスアーキテクチャで非常に扱いがいいのですが、一つ難点があって、アップロードできるファイルサイズが限られていることです。
最大50MのZIPファイルまでなのですが、裏技を使って展開時に500M以上のファイルを使うことができます。

そのカラクリは、Lambdaの/tmp以下は500Mまで使うことができます。この領域に、Lambdaが起動するときにファイルをS3から読み込めば、非常に大きなライブラリが必要なプログラムも動かすことができます。
以下は、pythonにてkeras+tensorflow+opencvを動かすサンプルです。

ライブラリ準備

python3を使用します。
ライブラリは、あらかじめ、EC2でAmazonLinuxを使って作成しておきます。

requirements.txt

keras
opencv-python
tensorflow
numpy
mkdir lib
pip3 install -U -r requirements.txt -t lib

このlib以下にライブラリがインストールされます。

find lib -name "*.pyc" -exec rm -rf {} ¥;

pycは削除しておきます。しなくてもいいですが。。。

これを全てLambdaの起動時に追加してもいいのですが、ロードが面倒になるので2つに分けます。

mv lib lib_other
mkdir lib
cd lib_other
mv cv2* ../lib
mv h5py* ../lib
mv keras* ../lib
mv tensor* ../lib
cd ..

libを固めてS3にアップ

zip -r lib.zip lib
aws s3 cp s3://bucketname/

lambdaディレクトリ

lambda用のディレクトリに、先ほど分けたlib_otherのライブラリを入れておきます。
これ全部を入れてようやく50Mぐらいまでに収まります。

mkdir lambda_dir
cd lambda_dir
mkdir vendor
cd vendor
cp -pr ../../lib_other/* .

lambdaプログラム

lambdaのプログラムには少し工夫が必要です。
起動時に、S3から先ほどアップしたlib.zipをダウンロードし展開、ロードします。

lambda_functioy.py


import sys
import os
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), './vendor'))

import boto3
import zipfile
import importlib

def lambda_handler(event, context):
    s3 = boto3.resource("s3")

    def load_zip(file):
        print("load_zip:"+file)
        s3.Bucket(bucket_name).download_file(libfiledir+"/"+file,"/tmp/"+file)
        with zipfile.ZipFile("/tmp/"+file) as zip:
            zip.extractall("/tmp")
        os.remove("/tmp/"+file)

    if os.path.exists("/tmp/lib") is False:  # 2回目以降はスキップ
        load_zip("lib.zip")

    sys.path.append('/tmp/lib')
    importlib.import_module("numpy")
    importlib.import_module("scipy")
    importlib.import_module("six")
    importlib.import_module("yaml")
    importlib.import_module("enum")
    importlib.import_module("h5py")
    importlib.import_module("absl")
    importlib.import_module("astor")
    importlib.import_module("bleach")
    importlib.import_module("external")
    importlib.import_module("gast")
    importlib.import_module("google.protobuf")
    importlib.import_module("grpc")
    importlib.import_module("html5lib")
    importlib.import_module("markdown")
    importlib.import_module("werkzeug")
    importlib.import_module("wheel")
    importlib.import_module("cv2")
    importlib.import_module("tensorflow")
    importlib.import_module("keras")

    import cv2
    import keras
    import numpy as np

こんな感じでコードを書きます。
Lambdaは一度起動すると、しばらくはインスタンスが残っているので、2回目以降に再度S3からダウンロードするのを防ぎます。

こんな感じで、500M以上のモジュールをつかったLambdaファンクションが作ることができます。

multivariate regressionをkerasで

複数出力の回帰をKerasで行います。

通常、回帰分析は複数の説明変数に一つの目的変数なのですが、これは、複数の目的変数を取ることができます。
multivariateとmultivariableの違いはこのあたりを参照のこと。

コードはこちらを参考にこんな感じ。


import numpy as np
from keras.layers import Dense,Activation
from keras.models import Sequential
model = Sequential()
model.add(Dense(16, input_shape=(1,)))
model.add(Activation('relu'))
model.add(Dense(16, input_shape=(1,)))
model.add(Activation('relu'))
model.add(Dense(2))
model.compile(loss='mean_squared_error', optimizer='Adam')


inputs = np.zeros((10, 1), dtype=np.float32)
targets = np.zeros((10, 2), dtype=np.float32)

for i in range(10):
    inputs[i] = i / 10.0
    targets[i, 0] = 1.0-0.1 * i / 2.0
    targets[i, 1] = 0.01 * i

model.fit(inputs,targets,epochs=200,batch_size=5)

print(targets)
print(model.predict(inputs))


結果

[[1.   0.  ]
 [0.95 0.01]
 [0.9  0.02]
 [0.85 0.03]
 [0.8  0.04]
 [0.75 0.05]
 [0.7  0.06]
 [0.65 0.07]
 [0.6  0.08]
 [0.55 0.09]]
[[0.88971126 0.00797045]
 [0.9289691  0.02162787]
 [0.8843044  0.02890772]
 [0.8396398  0.03618753]
 [0.7949753  0.04346737]
 [0.7503106  0.0507472 ]
 [0.70564604 0.058027  ]
 [0.6609814  0.06530684]
 [0.61631685 0.07258669]
 [0.57165223 0.0798665 ]]

ちゃんと学習できているようです

R.3.4.3にmxnetをインストール

mxnetのインストールがエラーになるのでその対処方法

環境

mxnetを使用する際に,インストール方法が公式サイトにも書いているのですが,
その方法ではインストール時にエラーが出ます。使っている環境がMacだからなのかもしれませんが。。

  • OS:MacOS 10.13.3
  • R 3.4.3 brewでインストールしたもの

この環境で下記コマンドでインストール

> install.packages("mxnet", type = "el-capitan.binary")
Installing package into ‘/usr/local/lib/R/3.4/site-library’
(as ‘lib’ is unspecified)
Warning in install.packages :
  package ‘mxnet’ is not available (for R version 3.4.3)

どうやらVersionがあっていないようでインストールできないようです。
ググっていろいろなやり方を試したのですがダメ。

> cran <- getOption("repos")
> cran["dmlc"] <- "https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/"
> options(repos = cran)
> install.packages("mxnet")
Installing package into ‘/usr/local/lib/R/3.4/site-library’
(as ‘lib’ is unspecified)
 URL 'https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/src/contrib/mxnet_0.10.1.tar.gz' を試しています 
Warning in install.packages :
  cannot open URL 'https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/src/contrib/mxnet_0.10.1.tar.gz': HTTP status was '404 Not Found'
Error in download.file(url, destfile, method, mode = "wb", ...) : 
   URL 'https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/src/contrib/mxnet_0.10.1.tar.gz' を開けません 
Warning in install.packages :
  download of package ‘mxnet’ failed

> install.packages("mxnet", type = "mac.binary")
Installing package into ‘/usr/local/lib/R/3.4/site-library’
(as ‘lib’ is unspecified)
Warning in install.packages :
  unable to access index for repository https://cran.rstudio.com/bin/macosx/contrib/3.4:
   URL 'https://cran.rstudio.com/bin/macosx/contrib/3.4/PACKAGES' を開けません 
Warning in install.packages :
  unable to access index for repository https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/bin/macosx/contrib/3.4:
   URL 'https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/bin/macosx/contrib/3.4/PACKAGES' を開けません 

   package ‘mxnet’ is available as a source package but not as a binary

Warning in install.packages :
  package ‘mxnet’ is not available (as a binary package for R version 3.4.3)

> install.packages("mxnet", type = "el-capitan.binary")
Installing package into ‘/usr/local/lib/R/3.4/site-library’
(as ‘lib’ is unspecified)
Warning in install.packages :
  package ‘mxnet’ is not available (for R version 3.4.3)

対処方法

ここここの方法でようやくインストールできました。

opencv

まずOpenCVをインストール

brew install opencv

openblas

OpenBlasも入れます

brew install openblas

mxnet

最後にソースコードからダウンロードしてインストールします

git clone --recursive https://github.com/dmlc/mxnet
cd mxnet
cp make/osx.mk config.mk
make -j4
make rpkg

確認

これでインストールが終わっています

$ R

R version 3.4.3 (2017-11-30) -- "Kite-Eating Tree"
Copyright (C) 2017 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin17.4.0 (64-bit)

R は、自由なソフトウェアであり、「完全に無保証」です。 
一定の条件に従えば、自由にこれを再配布することができます。 
配布条件の詳細に関しては、'license()' あるいは 'licence()' と入力してください。 

R は多くの貢献者による共同プロジェクトです。 
詳しくは 'contributors()' と入力してください。 
また、R や R のパッケージを出版物で引用する際の形式については 
'citation()' と入力してください。 

'demo()' と入力すればデモをみることができます。 
'help()' とすればオンラインヘルプが出ます。 
'help.start()' で HTML ブラウザによるヘルプがみられます。 
'q()' と入力すれば R を終了します。 

> library(mxnet)
>

これで使えそうです。多分。

リモートでJupyter Notebookをつかう

大学のサーバでどうしてもJupyter Notebookが動かしたいのでメモ。

経緯

データをSQLiteで管理しており,これのサイズが10Gを超え始めた。計算などは大学のサーバで行なっているのであるが,RやJupyterなどビジュアルなツールを使いたい時にはいちいちローカルのPCへSQLiteをコピーするのが大変。

以前Xサーバを使ったリモートでの起動を試したが,どうも使いづらい。
Macからだと,XQuartzをあらかじめMacにインストールしておき,
以下のSSHコマンドで接続し,

[mac] $ ssh -Y remotehost

Jupyterを起動するだけ。

[server] $ jupyter notebook

これで,リモートサーバでFirefoxが立ち上がり,MacのXQuartzで表示される。
しかしこれがいかんせん使いづらい。遅いし,サーバ側のFirefoxなので見た目も悪く,日本語入力も一苦労。

設定

Jupyter

まずはここを参考に設定する。

$ jupyter notebook --generate-config

~/.jupyter/jupyter_notebook_config.pyを編集。ポートが8080が空いている場合には以下のように指定する。

c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8080

R

Rも使いたいので,ここを参考にRを起動してインストール。

install.packages(c('repr', 'IRdisplay', 'crayon', 'pbdZMQ', 'devtools'))

devtools::install_github('IRkernel/IRkernel')
IRkernel::installspec()  

起動

$ jupyter notebook

[I 17:43:07.065 NotebookApp] Serving notebooks from local directory: /tmp
[I 17:43:07.066 NotebookApp] 0 active kernels
[I 17:43:07.066 NotebookApp] The Jupyter Notebook is running at:
[I 17:43:07.066 NotebookApp] http://0.0.0.0:8080/?token=37e418b82da8472bf89798f70a92dda90003f61509xxxxx

起動時に現れるこれから,

http://0.0.0.0:8080/?token=37e418b82da8472bf89798f70a92dda90003f61509xxxxx

以下のようにPCのブラウザのアドレスバーに打ち込めばOK

http://server:8080/?token=37e418b82da8472bf89798f70a92dda90003f61509xxxxx

githubの仕様変更に対応する

昨日までちゃんとアクセスてきていたのですが,今日,git pushしようとするとエラーが発生。

fatal: unable to access 'http://github.com/xxxxx/yyyy.git/': error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version

ここに書いていました。SSLプロトコルはどうやら仕様から外れた模様。TLSにあげてくださいとのことです。

使っている大学のサーバのアプリケーションは古いモジュールが多く,OPENSSLもいまだに0.9.8のもの。相当古いです。。。

そこでインストールし直しますが,大学のサーバなので,ユーザ領域にインストールする必要があります。

環境

サーバcray スパコン
ユーザ領域/work/$USER

OpenSSL

wget https://www.openssl.org/source/openssl-1.0.2n.tar.gz
tar zxvfp openssl-1.0.2n.tar.gz
cd openssl-1.0.2n
./config -fPIC --prefix=/work/$USER/local shared
make
make install

ここを参考に,32bitモードでコンパイルします,これはいらないかも?

setarch i386 ./config -m32 -fPIC --prefix=/work/$USER/local shared
make clean
make
make install

curl

wget https://curl.haxx.se/download/curl-7.47.1.tar.gz
tar zxvfp curl-7.47.1.tar.gz
cd curl-7.47.1
PKG_CONFIG_PATH=/work/$USER/local/lib/pkgconfig ./configure --prefix=/work/$USER/local --enable-libcurl-option --with-ssl=/work/$USER/local  --with-includes=/work/$USER/local/include/openssl
make
make install

git

wget https://github.com/git/git/archive/v2.16.2.tar.gz
tar zxvfp v2.16.2.tar.gz
cd git-2.16.2
./configure CFLAGS='-I/work/$USER/local/include' LDFLAGS='-L/work/$USER/local/lib64' --prefix=/work/$USER/local --with-openssl=/work/$USER/local --without-tcltk
make 
make install

vimでXML整形

xmllintをインストール

sudo apt-get install libxml2-utils

.vimrcの設定

~/.vimrc

au FileType xml exe ":silent 1,$!xmllint --format --recover - 2>/dev/null"

OpenWnnの内部辞書解析

OpenWnnの内部辞書を解析したのでそのメモ

経緯

OpenWnnはオープンソースの日本語変換辞書でこの派生製品がそこそこ使われているようです。NicoWnnGというソースコードをダウンロードしていじりだしたのがきっかけ。

どうしても辞書に手を入れる必要があったので調べました。NicoWnnGだけで使うのであればJava側で辞書を持っても良かったのですが,速度や他への転用を考えて,内部辞書を解析することにしました。

オープンソースとは言いつつこの辞書に関しては,バイナリを16進数配列にしたものをソースコードにベタがきしたものしか公開されておらず,このバイナリ部分を自分で作るためのソースコードは見当たりませんでした。

10年くらい前のモバイルデバイスに使われていたらしく,その時に解析された結果がいくつかあり,このサイトを参考に,ソースとにらめっこしながらようやく解析が終了しました。

使っていないであろうコードも結構見受けられたのですがなんとか。多分100%わかっているわけではないのですが,とりあえずNicoWnnGに組み込んで動くところまでは終了しました。

仕様

ヘッダ
00000000-00000003:[NJDC]識別子
00000004-00000007:バージョン
00000008-0000000b:タイプ
0000000c-0000000f:データサイズ
00000010-00000013:extサイズ
00000014-00000017:max check用(使ってない?)
00000018-0000001b:maxlen check用(使ってない?)
0000001c-0000001f: 1c-1d:前品詞数,1e-1f:後品詞数
00000020-00000023:単語ブロックのアドレス
00000024-00000027:登録されている単語の数
00000028-0000002b:登録されている単語の数?
0000002c-0000002f:que size,データ領域の一つのブロックのバイト数
00000030-00000033:最後に編集した単語ブロックの位置, 未使用
00000034-00000037:Write Flag
00000038-0000003b:未使用
0000003C-0000003F:インデックス1のアドレス
00000040-00000043:インデックス2のアドレス

インデックス
インデックス1は読み、インデックス2は表記の昇順で、
単語ブロックの位置が2バイトずつ並んでいる
最後に2バイト00がついている

単語ブロック
00000000-00000000: 2bit fflag, 4bit mflag, 6-7bit type
00000001-00000002: 1-9bit 前品詞,10-16bit 読みバイト数
00000003-00000004: 1-9bit 後品詞,10-16bit 表記バイト数
00000005- :読み、表記が詰めて設定されている
文字コードはUNICODE

フッタ
[NJDC]識別子

変換方法

ソースコードはここに入れておきました。

writedic.cppが変換用プログラムです。
入力ファイルはタブ区切りで
よみ 表記
の順に並んでいることが必要です。

一ファイルは最大65535行まで。

作成したファイルをWnnJpnDic.hのdic_07_dataなどを作成し貼り付ける。
dic_dataにもdic_07_dataを追加。プログラムから出力されるサイズをdic_sizeの該当の場所にコピー。

コンパイル

コンパイルはAndroidStudioから行う場合には文字量によるがメモリが必要なので注意。AnroidStudioのメモリ量を増やしておく必要あり

 

こんな感じで内部辞書を新しくすることができました。