ジオマーリン

geomerlin.com に関することを中心に。難しいことをもっと難しく書くブログ。

動的サイト(ゲームライブラリ・D3)はハイブリッドアプリに不向きなのか?

D3.jsは可視化のためのjsライブラリだ。これを使ってモバイルアプリを出すことを考えているヒトもいるかもしれないので書いておこうと思う。なぜならD3.jsはハイブリッドアプリとして出すのには懸念事項があるからだ。

 

・ハイブリッドアプリはグラフィック描画によわい

ハイブリッドアプリとはそもそもネイティブアプリ(swift,java)とウェブアプリ(ブラウザ上でhtml/

css+js)の中間だ。

monacaの経験しかないので,monacaについてしか言及できないが、ウェブアプリを素早くモバイルアプリにするためにできている。多くのウェブサイトは静的サイトであることに注意しなければならない。ハイブリッドアプリは静的サイトのアプリ化を指向している。

 

さて動的サイトにかなり重要である要素はjavascriptそして今はsvgも加わる。

svgの描画・レンダリングはそれぞれのブラウザの仕様で行われている。たとえばchromeでは高速で動作するが、firefoxでは操作性に影響があるほど遅く動いたりする。

ハイブリッドアプリは内側に独自のブラウザが内包されているようなものだと考えて良い。

 

これらの状況から予想できることは、静的サイト向けに作られているハイブリッドアプリの描画エンジンは動的サイトのjsによる大量のDOM計算に耐えられないのでは?ということだ。

monacaで使われている描画エンジンはどう考えてもchromeほど最適化されていない。

はっきり言って遅い。

これから調べなければならないことはネイティブコードのようにうまく動くjsはどのライブラリで作れるかだ。

 

日本語の自然言語処理技術の市場規模は266億円?

日本語のNLPの市場規模はどれくらいか気になった。

 

とりあえず最もシンプルな概算を行う。

日本語NLP規模 = 世界NLP市場規模 × ネット上使用言語の日本語率

        = 76億ドル * 0.032 = 266億円

 

参考:

 世界NLP市場規模

http://researchstation.jp/report/MAM/2/Natural_Language_Processing_2021_MAM286.html

 ネット日本語率

インターネットで使われている言語の普及率をグラフ化してみる(2016年)(最新) - ガベージニュース

ニューラルネットワーク(Chainer)を使うようになって考えたこと

 機械学習をシステムに組み込みたかったけど、SVMを作るのが今まで難しすぎたということが障害だった。

SVMを組むのが難しいのは次の二点

①特徴量を設定するのが難しいこと

②教師データを集めるのが難しい

 

 そしてSVMではなくNN(ニューラルネットディープラーニング)を導入したらすんなりシステムで機械学習が作動するようになった。

 今のニューラルネットが何が素晴らしいかといえば、①特徴量云々を無視できることだ。

ニューラルネット教師データさえ揃えば何も心配はない

 

この②教師データを集めるのが難しい は何も解決していないし、問題は大きくなってすらいる。

僕はネカフェで大量にニュースにタグをつけたけど、「人工知能が人類を云々」的議論のきっかけになっている深層学習技術とこの作業のイメージギャップは確かなものだった。

 

どう考えても、(1)少ない教師データから学習する技術 (2)雑多なデータから教師データを認識する技術 がないと「全ての技術者に有益・不可欠な技術」にはならないと思う。

そしてこれは人工知能機械学習)技術者が解決するものというよりは各システム設計者・NN使用者がうまくニューラルネットを設計して始めてできるものだろうと思う。

 

このコラムの途中でPFNの代表が「これからのシステム開発はNNの設計が中心になる」と言っていたけれど、

itpro.nikkeibp.co.jp

これには僕はある程度うなずくことや理解ができる。しかしそれは、設計者が上の(1)少ない教師データから学習する技術、(2)雑多なデータから教師データを認識する技術を自力でできるAI技術の素地が整ってから始まる世界だと思う。

あるいはいくらでも教師データがそこら中に転がっているネット社会がうまれるのか?

 

MonacaのInappbrowserのエラーを遅延ロードで回避

モナカに大きなプロジェクト(長いjsファイルやエラー前提のシステム)を入れるとプラグインがうまく応答しないことがある。

 

これは憶測なので違ったら指摘して欲しいけど、プラグインが動かない原因はこれ

①仕様上devicereadyイベント発火ではじめてプラグインが使用可能

②devicereadyイベントまでに、jsファイルのロードが掛かり過ぎるORエラーが起こると、発火しないもしくは、プラグインのjsが作動しなくなる

 

というわけでバカでかいプロジェクトをそのままindex.htmlに直接書いたりロードするとうごかなくなりました。

そこで<script src="js/bakadeka.js"></script>と書いて読み込んだファイルを以下に変更

<script src="src/jquery.min.js"></script>
<script>
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
$.getScript("js/bakadeka.js")
}
<script>

何をしたかというと、ondevicereadyでプラグイン使用可能を確定したうえで、そのあとjsファイルを読み込んだ。(jqueryは各自でダウンロードしてコピペ+アップしてください)

ちなみにhtmlも遅延ロードしてみたが、うまく表示されなかったので諦めた。

geomerlin.comのシステム全体図を公開

 ちょっとエンジニア向けのページになります。

仕様を公開する意図は

①アドバイスを受けたいこと

②ユーザーを巻き込んだ開発にすること

です

f:id:geomerlin-com:20170410221117p:plain

 

よくありそうな図ですね。

クローリング→自然言語処理→DB保存→ユーザーのリクエストに対してリスポンス

 

次に細かく書きます。

①クローラ

  • 普通にurllibを使用。pyextracontent(python2)をpython3から呼び出し
  • 加えてbingNewsAPIから国ごとの情報を取得
  • RSSのデータベース(sqlite3)を元にクロール先のurlを決定

自然言語処理

③サーバーサイド(AWS

④クライアントサイド

  • 可視化(特に地球儀・エフェクト)をD3で処理。
  • リクエストはAjax
  • いくつかUIをbootstrap
  • タップイベントとかはjquery
  • スマホアプリはMonaca+Inappbrowserプラグイン

python3からpython2呼び出しを最速で

人それぞれの事情でpython3からどうしてもpython2のプログラムを実行したい時、するべきことを簡単に書く

 

やることは

python2コード(p2.py)を書く

→②python3コードの中でsubprocessを書く

以上

 

では具体的に以上の2つを実践する

python2コード(p2.py)を書く

import sys

#最初にpython3から標準でテキストを受け取る
got_line = sys.stdin.readline()
got_line = got_line.strip()

#ここでやりたい処理を行う(出力は文字列)
result = doingSomething(got_line)

sys.stdout.write(result.encode("utf-8")

python3コードの中でsubprocessを書く

def inputSomethingToPython2(input_text):

p = subprocess.Popen("python p2.py", shell=True,stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

#ここでpyton2に文字列を渡す
stdout_data, stderr_data = p.communicate(input_text.encode("utf-8"),timeout=20)
return stdout_data.decode("utf-8")

 

 

 

 

chainerで文書分類(ニュースをカテゴリ分け) 訓練後を中心

chainerはディープラーニングもできるNNライブラリ

ディープラーニングということは入力と出力のサンプル(教師データ)を用意すれば分類問題は絶対自動化できる。

ただ、入力と出力の型が違うとコードも違ってくるから、「でぃーぷらーにんぐをやれ!」と一言では済ませられない。

 

chainerはトレーニング→実用なのだが、実用の部分がドキュメント・ブログともに少ないので、訓練後を丁寧にやっていきたい。トレーニングまでは

Chainerでフィードフォワードニューラルネットワークを実装して文書分類する - Qiita

を参照してほしい。

まず最低限のchainer用語を紹介

l1,l2,l3 →入力から第一層目に変換、一層目から二層目、二層目から三層目へ変換する関数

・optimizer →最適化のためのクラス

・model→学習済みニューラルネットワーク

 

ここでこの記事の結論を先に言うことにする

l3の出力をnp.argmaxすれば分類を出力できます。

 

では前述のありがたい記事にしたがって書いていく。

想定する教師データ: [[文字リスト],番号] ×n行 :[[[この、学校、バカ、ばっかり],0],[[けど、俺、は、すごい],1]] 

 

【Chainer】畳み込みニューラルネットワークによる文書分類 - Qiita をコピペして動かしますが、2点を変更

①インポートライブラリとload_data

# coding: utf-8
import numpy as np
from sklearn.cross_validation import train_test_split
from collections import defaultdict
import six
import sys
import json
import chainer
import chainer.links as L
from chainer import optimizers, cuda, serializers
import chainer.functions as F
import argparse
from gensim import corpora, matutils
import pickle


def load_data():

source = []
target = []

document_list = [] #各行に一文書. 文書内の要素は単語
with open("teacher.json", "r") as fi:
dataset = json.load(fi)

for l in dataset:
#ラベルと単語列を分ける

label = int(l[1]) #ラベル
target.append(label)
document_list.append(l[0]) #単語分割して文書リストに追加

#単語辞書を作成
for document in document_list:
tmp = dictionary.doc2bow(document) #文書をBoW表現
vec = list(matutils.corpus2dense([tmp], num_terms=len(dictionary)).T[0])
source.append(vec)

dataset = {}
dataset['target'] = np.array(target)
dataset['source'] = np.array(source)
print("vocab size:", len(dictionary.items()))
return dataset, dictionary

load_dataを少々変更。

この関数は教師データをchainerにぶち込める形に変換する。

 

②データ保存コードを変更。pickleのほうが何かと便利で使いやすい

#modelとoptimizerを保存
print('save the model')
#serializers.save_npz('pn_classifier_ffnn.model', model)
#print('save the optimizer')
#serializers.save_npz('pn_classifier_ffnn.state', optimizer)

with open('classifier_ffnn3.pickle',"wb") as fi:
pickle.dump(model,fi)
with open('dictionary3.pickle',"wb") as fi:
pickle.dump(dictionary,fi)

 

ではトレーニングを終えた後のことについて

別ファイルで次のコードを書きます。

import chainer
import chainer.functions as F
from gensim import corpora, matutils
import pickle

####################
#ファイル読み込み
####################
with open("classifier_ffnn3.pickle", "rb") as fi:
Model = pickle.load(fi)

with open("dictionary3.pickle","rb") as fi:
Dictionary = pickle.load(fi)


#NNによる分類関数
def fwd(model,dictionary,x):
x = dictionary.doc2bow(x) #文書をBoW表現
vec = list(matutils.corpus2dense([x], num_terms=len(dictionary)).T[0])
x = np.array([vec]).astype(np.float32)
x =chainer.Variable(x)
h1 = F.sigmoid(model.l1(x))
h2 = model.l2(h1)
h3 = model.l3(h2)
return np.argmax(h3.data)#F.softmax(h2)

####################
#関数用意
####################
def label_news(word_list):
return fwd(Model,Dictionary,word_list)

pickleで保存したNNとディクショナリを復活。

fwd関数で文字リストx(["ムズい","試験","タルい"]など)を最後の引数で受け取り、教師と同じように分類して返す。ラッパーがlabel_news関数になっている。

結論はl3の出力をnp.argmaxすれば分類できます。

 

このコードは http://geomerlin.com のニュース分類に使っています。

//訓練データ作るのにネカフェで修行僧になってました:D