変なサービスを作るのが好き

頑張ったことを報告するブログ

機械学習分類器が載ったモバイルブラウザを作った話

はじめに

半年ほどかけてアプリのプロトタイプを製作したので、開発の動機や使用したツールなどをまとめてみる。

作ったものはページを自動分類するモバイルブラウザでWWDC2017で発表されたCore MLを使用している。

機械学習を用いたサービスを製作したのは初めてだったけれど、scikit-learn等のライブラリやgoogle custom search等のAPIが充実しているので比較的容易に開発を始めることができた。しかしパラメータの設定等まだまだ試していないことが多くあったり、教師データの質と数の問題から分類の精度は現時点であまり良いものではない。

しかし、精度を向上する仕組みなどを取り入れているので今後の改善に期待して欲しい。

 

開発の動機

友人と会った時、この漫画が面白いとか、あの映画が面白かったとかそんな話しをよくする。
後でそのコンテンツを読みたい、観たいと思ったものを忘れないように記録するようにしてから、面白いコンテンツに出会う機会が多くなったと思う。

ブックオフでバイトしている友人の勧める漫画は面白いし、映画を撮っていた友人の勧める映画は面白い。
他にもテレビや、Web、ポッドキャストなどで興味深いコンテンツを紹介される機会が多い。

そんな中で色々な方法で記録をしてきた。例えば、
自分だけのライングループに記録する。iPhoneのメモアプリに記録する、Todoアプリに記録する。Evernoteに記録する。
このような方法で記録してきたけど、レビューを見たり、ネットで注文したり、そもそも漫画だったのか、映画だったのか調べるために、Safariを開いて検索することが多かった。
なので、最初からSafariで検索してそのタブを残してメモ帳代わりにするようになった。
この方法だと、テキストに紐付いた情報が検索結果に表示されるので振り返りやすいし、レビューを読んだり注文したりその先の行動がスムーズなので気に入ってた。
しかしタブの数が増えてくると、様々なジャンルのタブで混じりあっていて振り返り辛くなっていた。
標準のブックマークはフォルダ分けが面倒で続かない。
もっとインスタントに保存と仕分けができる方法が欲しかった。

 

日頃の生活で気になったものはとにかく記録しておく。

休日の暇な時間にアプリを立ち上げ貯めておいたコンテンツを楽しむ。

自分でカテゴリごとに分類する必要はなく、勝手に整理してくれる。 そんなサービスを自分の手で作ってみたいと思った。

SwiftもPythonも初心者だったけどチャレンジしたいと思って開発を始めた。

半年間程作業してようやくプロトタイプを出すことが出来た。

 


アプリの紹介

作ったアプリは「ページを自動で分類してくれるブラウザ」 

f:id:maltz8:20180217092900p:plainf:id:maltz8:20180217092908p:plainf:id:maltz8:20180217093013p:plain

 

 

現時点では「やりたいコンテンツをメモするアプリ」というコンセプトなので、Web上のすべての記事を網羅するような種類のタグは用意されていない。これからもタグの種類は増やしていきたいが、タグが多すぎると逆に不便だと思うので慎重に追加したい。

このアプリは友達と2人で開発していて、主に僕がクライアント担当で、友達が機械学習系と、バックエンドを担当している。

その際使用したツールや、参考にした資料を以下に記載させてもらいます。

 

アプリを開発するにあたって使用したツール

Core ML

WWDC2017で発表されたCore MLの存在を知ったのも開発を始める上での大きな動機となった。
Core MLはiOS11から使用できる機械学習のライブラリで、PCで作成した機械学習の分類器をiPhone上で動く形式に変換してくれる。(iOS11がインストールされた端末でしか動作しない)例えばPCで作成した画像分類器を端末上でスタンドアローンで動かせるようになる。
本来なら、複雑な処理を書いて端末上で動かすか、サーバー上にデータを送信して分類させていたものが簡単に機械学習の機能が搭載したアプリを作成することができるようになった。
CoreMLを用いれば閲覧しているページをサーバーに送信すること無く、プライバシーも守られ、リアルタイムで分類できる。

 

Google Cloud Natural Language API

とは言え文章をカテゴリごとに分類する機械学習を用いた分類器を作成するのはある程度時間がかかる。分類機能を提供するAPIがあったらまずそれで試したいと探してみると、Google Cloud Natural Language API に9月からカテゴリ分類の機能が追加されていた。
しかし日本語の文章は対応していない。swiftで簡単なブラウザアプリを作成し、evaluateJavaScriptを用いてページの本文を抽出して、翻訳APIを噛ませた上で分類APIに送信してみた。ここに記された720のカテゴリに自動で分類してくれた。しかし、価格が高く、判定までの数秒程時間がかり(翻訳APIを間にリクエストするため)、データを外部に送信するため、自前で分類機を作成することに決めた。
ただ、ページを自動でカテゴリに分類する機能の利便性について確認できたので、始めのプロトタイプとして試して良かった。

 

自動分類の精度改善の仕組み

教師データの数と質に問題があって、現時点での精度はあまり高くない。
このアプリは閲覧しているページをサーバーに送信せず端末上で分類しているので、普通のブラウザと同じように匿名性を保ったまま使用できるが、設定画面の「自動分類の精度向上に協力する」にチェックを入れると、ユーザーが手動で分類結果を修正した情報がサーバーに送信される仕組みになっている。(例えば、本と判定されたが実際は映画であり、ユーザーが映画と修正した情報。またはその逆)このデータで分類器の精度を向上させたい。
また、日本語より英語の文章の分類の方がハードルが低そうなので分類機をローカライズして配信してみたい。


特に参考になった資料

swift

Start Developing iOS Apps (Swift)
google翻訳Chrome拡張を使いながらアップルのチュートリアルをやって分からないことを下の参考書を読みながら進めるのが分かりやすかった。

詳細!Swift 3 iPhoneアプリ開発 入門ノート Swift 3+Xcode 8対応

 

WKWebviewで簡単なwebViewを作成する - Qiita

WKWebViewでブラウザを実装するのだが最初の導入で参考にした。 


mozilla-mobile/firefox-ios
WKWebViewのデリゲート内の処理の仕方等、とても参考になった。実際に運用されているプロダクトでのswiftの書き方が知れて良かった。

 

Natural Language Processing in iOS – martinmitrevski

SwiftでNLPする時のチュートリアルとして参考になった。

 

Share Extensionでデータを共有する - Qiita

Queは一応ShareExtensionに対応している。Twitter等から共有ボタンで追加できるようになっている。

 

Core ML


Core MLは画像分類の資料はたくさんあるけれど、それ以外はなかなか見つけづらいので、「core ml linear regression」等の検索ワードで出てくるチュートリアルを試すのが手軽にコツを掴めて良かった。

Machine Learning in iOS Using Core ML

GitHub - likedan/CoreML-Linear-Regression: Core ML verson of Scikit Learn Linear Regression Examples


機械学習

MeCab, gensim, scikit-learnでニュース記事の分類 - Qiita

自然言語処理における前処理の種類とその威力 - Qiita

scikit-learnとgensimでニュース記事を分類する - Qiita

とても良かった

https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5-%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-Willi-Richert/dp/4873116988
この本ではpythonのscikit-learnを使って分類器や線形回帰を作成するので、core ml toolsで変換してiosアプリにすると、swiftとpythonどっちも学べて楽しかった。

 

 

 

ザッカーバーグのハーバード卒業式スピーチが感動的だったのでアプリ作った。

 

はじまり 5月下旬

英語が話せる友達と飲み会に行く途中こんな話になった。

「どうやったら英語話せるようになる?」

「Helloは聞き取れるでしょ? でもちょっと難しい文になると途端に聞き取れなくなる」

「Helloと同じくらい自然に聞き取れる文を自分の中に増やすといいよ」

 

とても当たり前なことを言われたがその時、なるほど。と思った。

 

ハッピーアワーの時間は料金が半額なのでブリティッシュパブによく来る。

到着すると先に着いていた別の友だちが、外国の人と英語で談笑していた。

カッコイイなあと思った。

飲み会も中盤の時、彼がザッカーバーグの動画観た?面白かったよ。と話していた。

帰ってからツイッターを見てると、

ザッカーバーグのハーバード卒業式スピーチが感動的だったので日本語訳した。

の記事を見つけた。読んでいくうちに本人が喋ってる動画を見たくなりYoutubeを開いた。あんまり聞き取れなかったけれど、話してる姿を見て「この人の言ってることを英語の音声のまま理解したい」と強く感じた。

 

そういえば、英語を聞き取れるようにしなければ  と思う機会がこの頃多かった。

中国から来てる研究室の美人のドクターと話した時もまじで何言っているか全然聞き取れなかったし、rebuild.fmを聞いて いつかは海外で働きたいなと思っても英語が聞き取れなからスタートからまず無理だと思った。

普段からプログラミングのドキュメントは英語で読んでいるけど、聞き取りと話すことが全くできない。なんとかしなきゃと思っていたので、丁度いいきっかけだ。

 

英語が聞き取れるようになりたい。でも参考書や普通の教材でやっても続かない。

ただ、僕はザッカーバーグの英語が聞き取れるようになりたい。そう初めは思ったので、ザッカーバーグの動画から英語を学べる環境を作ることにした。

 

制作 

その次の日から開発に取り組み1週間弱かかって完成した。

バックエンドは冒頭の英語が話せる友達に作ってもらった。センテンス解析でpython、クライアントからのリクエスト処理でRailsを使ったらしい。

僕はフロント担当で今回はreact nativeを使ってみた。作りやすくて速く書けてプロトタイピングに適していると思う。アプリの機能自体はまだまだだと思うけど、一旦リリースしてこれからもアップデートしていきたい。

作ったもの

f:id:maltz8:20170611134416p:plain

ワンタップイングリッシュ on the App Store

「Helloは聞き取れるけれど、ちょっと難しい文になると途端に聞き取れなくなる。
そんな人は、自分の中にHelloレベルに聞き取れる文を増やそう!それもかっこいいの憧れの人から!」

 

使ったツール等

react native はFacebook,Messenger,Airbnb等のモバイルアプリでも使われている、アプリを作るツールです。

```

react 16.0.0-alpha.6

react native v0.44.2

react-native-router-flux 3.38.0

react-redux 5.0.4

redux-thunk 2.2.0

axios 0.16.1

react-native-vector-icons 4.2.0

react-native-youtube 1.0.0-alpha.4

react-native-admob 1.3.0

```

これらのnode packageを使った時生じたエラーの対処法等をQiitaに書いた。

qiita.com

qiita.com

qiita.com

 

react nativeを始めてから特に参考になったページ等

Getting Started Quick StartではなくBuilding Projects with Native Codeでやる

React Native / JS.coach  ざっと見るだけでもおすすめ

【React Native】良さげなコンポーネント紹介 - Qiita これも上の記事のような

Getting Started with Redux - Course by @dan_abramov @eggheadio reduxを学ぶ時に一番分かりやすかったページ(動画で教えてくれる。英語が聞き取れなくてもコードを見れば大体分かると思う。)

GitHub - gaearon/redux-thunk: Thunk middleware for Redux 簡単なアプリなのでredux-thunkで良いと思った。

React.Component - React ライフサイクルの確認でよく見る

Using React-Native-Router-Flux with Redux – Ian Mundy – Medium わかりやすかった

ReactNativeのより良いリスト、FlatListについて。これまでのListViewとの違い。 - Qiita

http://www.gakusmemo.com/?p=794 action内でstateを確認する方法もある

 

 

素人が半年頑張ってWebサービスを作った話

半年ほどかけてWebサービスのプロトタイプを公開するところにこぎつけたのでその記録をしておこうと思います。

 

作ったもの

一言で言うと「Webブラウザで閲覧したページの履歴を共有するSNSです。

History(履歴)を流す(stream)ということでHistreamと名付けました。

Chrome拡張をインストールして、ウィンドウを選択し、オンにするとそのウィンドウで見たページ履歴を自動でアップロードします。

そしてWebサービスでアップロードされた履歴を整理された状態で確認したり、友達の履歴を読めたりします。

 

 

Chrome拡張: Histream-Extension - Chrome Web Store

Webサービス: https://histream.io

 

作ろうと思ったきっかけ

今から一年前、大学2年の冬にワンタップダイエットというアプリを作っていました。プログラミングするのはほとんど初めてで、やりたいことを実現するためにGoogleで検索しては疑問が出て、それを更に検索しての繰り返しでした。

一日中多くのページを閲覧していくと、あの情報どこでみたっけ?と言った問題や、そもそも自分と全く同じようにプログラミングについて検索し続けた人は過去にもたくさんいたはず、その人の履歴を見たいな と考えていました。なので、

  1. 自分の検索履歴をトピックごとに、重要なものだけ表示する
  2. 他の人の履歴を眺めて参考にできるWebサイトを作る

この二つを実現するサービスを作ろうと決めました。

 

具体例

やりたいことは「Webサービスを作る」ために調べた履歴のみが欲しい ということです。ブラウザ標準の履歴から「Web」と検索しても、タイトルに「Web」というキーワードが含まれていないとヒットしません。

もし「Webサービスを作る」ために調べた履歴のみが抽出できたら、後からそれを見返して復習ができたり、学校の後輩に「僕の履歴を見たら作り方が分かるよ」と教えてあげることが出来ます。

 

まずプロトタイプを作る

前回アプリを作ったとき、コードを書く前に仕様をしっかり決めるということが一番反省すべき点でした。一つの機能を思いついて、すぐに実装を始めても後からこの機能はやっぱりいらなかったということが数多くあり、モチベーションやスピード感が落ちていきました。

 

今回、初めに行ったのはAdobe XDでコードを書かずモックを作る作業でした。それをたたき台にして、話し合いをし作るべき機能をリストアップしていきました。

実装の第一段階として、閲覧した履歴を全て公開するプロトタイプを作ってみました。Firebaseを使えばサーバーサイドのコードを記述せず端末間のデータのやり取りを用いたサービスを素早く作ることが出来ます。

友人に使ってもらい、友人がページを訪れた瞬間に自分の画面にその情報が送られてきたのを見て、とてもジワジワきたのを覚えています。これがもし、知り合い100人に使ってもらい、遠くからブラウジングの様子を見れたらとても楽しいと思いました。

 

 とは言っても履歴を公開するのはハードルが高い

プロトタイプを作って必要だと思ったことが2つあります。

ユーザーが何の履歴を公開するか選択できるようにする

最初のプロトタイプでは全ての履歴を強制的にポストしていました。人には見られたくないものはフィルターに掛ける必要があります。そこで取った手法が「ウィンドウにタグを付ける」というものです。これは「今からこのウィンドウで調べたことは全て公開するよ!」と設定出来るようにすることであり、その際「これから〜〜について調べるよ!」と同時にタグを付けることで、履歴を後から分類することもできます。

もう一つ必要だと思ったことは

個人で使っても使えるツールにする

調べ物をする際に便利な機能を用意することでまず一人のユーザーに使ってもらいます。SNSを作る際に「人が集まらないとサービスとして成り立たない」では素人が作るにはかなりハードルが高いと思いました。

Histreamには選択した文章を速攻で保存できる機能や、検索過程を要約する機能などがあります。

 

締め切り

Histreamは大学の友人と二人で作りました。最初の4ヶ月くらいはプロトタイプを作って、チームメンバーにレビューを求めると言ったことを繰り返し、作るものがようやく確定したころバックエンドの作り込みを始めました。

締切がない時期はふたりとも作業が全く進まなかったりということがありました。このような素人の学生が集団で趣味でサービスを作る際に締め切りを決めるというのが一番重要だと感じます。その締切も、人前で発表すると言った逃れられないものが効果を発揮しました。

Histreamを作る前にコンテストに出ると決めていました。むしろコンテストあり気で開発をしたと言った具合です。このコンテストは九州の学生のみが参加出来るというコンテストで半年間に渡りイベントが開催され、メンターさんにSlackで質問ができたりします。最近、福岡はこのような支援が盛んなのでとても助かります。優勝賞金が30万というのもモチベーションが上がります。

できたもの

ぼくがSwiftを始めようと思って検索した履歴がこんな感じになってます。

https://histream.io/user/maltz/hub/swift

履歴の重要度は、お気に入りをしたか、選択した文章を保存したか、何回訪れたかで判定しています。よく調べものをする人や、これから何か勉強しようと言った人に使ってもらえると嬉しいです。

 

情報発信、収集ツール界隈の位置づけとして図を作ってみました。

左下が文脈が低く(断片的な情報)プライベート。右上が文脈が高くソーシャル。と言ったプロット図です。Histreamは、ブラウザ標準の履歴に比べて圧倒的にソーシャルであり、Qiitaに投稿するほどトピックについて精査された情報ではないけど、読み手がマイニングしたら価値のあるものと言った感じです。

f:id:maltz8:20170219013500p:plain

 

本当にやりたかったこと

僕たちが開発を始めた根本的なきっかけは「ソーシャル・ネットワーク」の世界観に憧れを抱いたからです。夜な夜なファミレスに集まり、タスクやプライバシーポリシーを決めたりするのが楽しかったし、コンテスト前の緊張で徹夜でプレゼン資料を作ったり、無駄にインフラを整えたりそんなことを真剣にするのがやりたかった という感じです。

ですがせっかく頑張って作ったので、少しでも多くの人に使ってもらえるように開発を続けていきたいです。

 

Chrome拡張: Histream-Extension - Chrome Web Store

Webサービス: https://histream.io

 

以下、無駄に整えたインフラや、開発に用いたツールなどをまとめておきたいと思います。

 

開発に用いたもの

コードを描かずモックを作る

画面遷移を作るAdobe XDと、グラフィックをデザインするSketchを使用しました。

  1. コードを書いてプロトタイプを作っても大幅な変更をする際に、腰を上げづらい
  2. コードでやりづらい表現も画像なら直ぐやれる

Githubの環境を整える

todoやマイルストーンの管理、機能の議論、後からメンバーが増えた時のためにGithubを使ったissueベースの開発にしました。

モバイル向けのCode Hubとデスクトップ向けのJasperを使用しました。

Chrome拡張を作る

https://github.com/yeoman/generator-chrome-extension

これを用いてchrome拡張の雛形を作成しました。ライブリロードやminiy、uglifyもやってくれます。ES6の文法も同梱されているESLintで学ぶことが出来ました。gulpの使い方も参考になります。

バックエンドはまずはBaaS

いきなりバックエンドのコードを書かず、以下の理由で最初はFirebase用いてAPIを作成しました。

  1. 大幅な変更をする際に、腰を上げづらい
  2. リアルタイム通信が簡単にできる
  3. バックエンドのデプロイ等必要なくスピードが速い

バックエンドを作る

Firebaseでサービスの全体が決まったら、バックエンドを自前で開発します。Chrome拡張はjavascriptで開発します。バックエンドも同じ言語でやりたかったので、Node.jsで開発しました。

http://blog.slatepeak.com/creating-a-real-time-chat-api-with-node-express-socket-io-and-mongodb/

https://yoshiokatsuneo.gitbooks.io/meanstack3/content/chapter1.html

が最初の取っ掛かりに参考になりました。

バックエンドをデプロイする

当初はEC2で環境を構築していましたが諸々面倒に感じ、周辺環境が整っていて扱いやすいHerokuにデプロイしました。mongoDBやSocketのアドオンも揃っています。そして、標準でhttpsなので対応の必要もありませんでした。

Webサイトを作る

今回のサービスは、 Chrome拡張 ↔ Node.js ↔ Webフロントという構成です。フロントはバックエンドと分離し、Angular.jsで作成しました。APIを叩いて表示するだけのサービスでしたら速攻でつくれます。ですが、HashbangなどSPAのデメリットも痛感しました

https://github.com/yeoman/generator-angular

Chrome拡張と同じようにyeomanのgeneratorでひな形を作成します。

この本でAngularを知って以来、ずっと使っています。

CSSフレームワークにAngular materialを用いたので簡単にいい感じの要素が作れます。

Webサイトをデプロイする

APIと完全分離したので、静的なファイルをホスティングするだけで済みます。S3とCloud Frontを用いて配信しました。Cloud Frontの設定でhttpsの対応も無料で可能です。

ドメインを取る

S3などAWSを使っているのでroute53で取得しました。

histream.ioで年間4000円です。

Rollbarの導入

クラスの友達に使ってもらった結果、様々なバグでサーバーが落ちました。ログを取って自動でGithubにIssueを立ててくれるRollbarを導入しました。Rollbarは無料でプライベートレポジトリを登録できます。

CIツールの導入

werkerを導入しました。こちらも無料でプライベートレポジトリを登録できます。

プルリクエストを送ったら、マージする前にwerkerでテストを行い、通ったらマージ出来るように、そしてMasterにマージしたら自動でデプロイするようにしました。

werkerはChrome拡張、Node API、Webフロントの三つのレポジトリで活用しています。

メールサーバー

無料で独自ドメインに対応したメールサーバーを借りれるサービスとしてZohoを使用しました。無料で25アカウント管理できます。