MotoJapan's Tech-Memo

技術めも

【Android】TensorFlow LiteのMobilenetサンプルコードをビルド&実機インストール・実行する方法と雑感 (Android Studio 3.0)

待ちに待っていたTensorFlow Liteが先日リリースされた。
Preview版ということでgithubに公開されていたので、触ってみた。
(そもそも本家GithubのTfLiteCameraDemo.apkというPre-build binaryのapkがエラーでインストールできない(17/11/18現在))

Nexus5実機で実行した結果はこんな感じ。
「ボールペン」と「絆創膏」のリアルタイム認識。
f:id:motojapan:20171118031641g:plain

仕組み

既存のTensorFlow学習済みを、TensorFlow Liteモデル(tflite)に変換。
この変換済みモデルをAndroid / iOSのモバイルプラットフォームに組み込み、推論が可能。
f:id:motojapan:20171118024153p:plain
(画像は、本家サイトの「TensorFlow Lite Architecture」抜粋)

今回はGitHub上で提供されるAndroid側。
Android StudioのMobilenetサンプルプロジェクトをビルドし、実機インストール、実行、デバックする。

主な手順

本家に書いてあるものは下記。

Building in Android Studio using TensorFlow Lite AAR from JCenter
The simplest way to compile the demo app, and try out changes to the project code is to use AndroidStudio.

  • Install the latest version of Android Studio 3 as specified here.
  • Make sure the Android SDK version is greater than 26 and NDK version is greater than 14 (in the Android Studio Settings).
  • Import the tensorflow/contrib/lite/java/demo directory as a new Android Studio project.
  • Click through installing all the Gradle extensions it requests.
  • Download the quantized Mobilenet TensorFlow Lite model from here
    • unzip and copy mobilenet_quant_v1_224.tflite to the assets directory: tensorflow/contrib/lite/java/demo/app/src/main/assets/
  • Build and run the demo app


https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/liteより抜粋。

かなりシンプル。
これを1つずつ追っていく。

前提環境

1. Android Studio 3 インストールする

TensorFlow Liteを使う場合、Android Studio 3が必要。
本家ここからダウンロードとインストール。
f:id:motojapan:20171118035336p:plain

2. TensorFlow Repositoryをcloneする

好きな場所にcloneする。

$ git clone https://github.com/tensorflow/tensorflow

サンプルプロジェクトは、「tensorflow/contrib/lite/java/demo」にある。

3. サンプルプロジェクトをAndroid Studio上で開く

Android Studioの「File」->「Open」で「tensorflow/contrib/lite/java/demo」を開く。
f:id:motojapan:20171118040750p:plain

上記で開いた後、足りない各種ライブラリやbuild-toolsのインストール、gradle syncを進める。
IDEが通知してくるので基本的にはぽちぽちするだけ)
f:id:motojapan:20171118041024p:plain

4. 実機インストール・実行する(モデル無し)

上記が進むと、緑三角形の「Run」が有効になり、USB接続した実機が認識されるようになる。
f:id:motojapan:20171118041331p:plain
実機が認識されたら「OK」で実行する。

まず、インストール後、起動して見事に落ちる。
f:id:motojapan:20171118041647p:plain

アプリ一覧からTfLiteCameraDemoを再度起動する。
f:id:motojapan:20171118041747p:plain

学習済みモデルがないので「Uninitialized Classifier or invalid context.」が表示される。

5. モデルをダウンロードし、プロジェクトに配置する

本家ここからzipダウンロード。

zipを解凍すると2ファイルある。

  • labels.txt : ラベル情報(文字列ベタ書き)
  • mobilenet_quant_v1_224.tflite : tensorflow lite学習済みモデル

f:id:motojapan:20171118041941p:plain

学習済みモデルファイルの配置場所は、androidプロジェクトのasset直下。(tensorflow/contrib/lite/java/demo/app/src/main/assets/mobilenet_quant_v1_224.tflite)

Android Studioのプロジェクト上にも反映されていることを確認する。
f:id:motojapan:20171118042508p:plain

6. インストール・実行を実行する(モデルあり)

5.で晴れてモデル有りで実機にインストールしてみると結果は下記のように表示される。

f:id:motojapan:20171118031922p:plain
ボールペン(ballpoint)を認識した。
万年筆(fountain pen)にも似ているらしい。

f:id:motojapan:20171118031929p:plain
絆創膏(Band Aid)も認識した。
かなりconfidenceが高い。

実機評価

処理速度

手元にあるデバイス Google Nexus5, Huawei P9 liteで確認。
入力画像サイズはMobilenetなので224 x 224、これに対する処理速度。

Google Nexus5(2013) Huawei P9 lite(2016)
CPU Qualcomm Snapdragon 800 MSM8974 2.26GHz(クアッドコア) kirin 650 (オクタコア(2.0GHz×4コア+1.7GHz×4コア))
Android version 5.0.1 6.0
RAM 2.0 [GB] 2.0 [GB]
mobilenet処理速度 (per 1 frame) 210-260 [msec] (best 140 [msec]) 150-160 [msec]

Nexus5の速度が安定しない。(瞬間最大風速的に早くなる時もある)
実際OSの忙しさで待たされたりすることもあるので、ここら辺は揺らぎがあるのかなぁ。
動画でリアルタイムに見ている分には思ったよりサクサク動くし、気にならない。うまくやれば何かしら使えそう。

モデルサイズ

ここが妥当な評価になるかわからないが、TensorFlow Lite v1 model とTensorFlow Mobilenet v1 model を比較してみる。

TensorFlow Lite TensorFlow TensorFlow
mobilenet_quant_v1_224 MobileNet_v1_0.25_224 MobileNet_v1_1.0_224
バイナリサイズ 4.3 [MB] 7.6 [MB] 67.9 [MB]

サイズは小さくなっているように見える。

メモリ使用量

サンプルアプリのメモリ使用量を調べる。

$ adb shell dumpsys meminfo | grep tflitecamerademo
    91689 kB: android.example.com.tflitecamerademo (pid 22383 / activities)

カメラも動いているが、

  • 稼働時はメモリ使用量は90[MB]近い
  • 待機時は38[MB]付近。

ちなみに標準カメラ単体では、

  • 稼働時は18[MB]付近
  • 待機時は4[MB]付近。

雑感

個人的な感想として、

  • 今回程のモデルで、エンジョイユースであれば、リアルタイム性は気にならず快適。
  • モデルのフットプリントは小さくなっている模様。
    • 精度差はわからない(ちゃんと評価してないので)
  • サンプルアプリバイナリでも22.0[MB]は単純にかなり大きいアプリだなという印象。
    • モデル更新の度にアプリ更新が必要?
  • メモリもそれなりに食っている。
  • エッジとサーバーはどう協調していくかこれから大きなテーマになりそう。

近々、自作モデルをビルドしたい。

初心者が学ぶP,NP,NP困難(Hard),NP完全(Complete)とは(わかりやすく解説)

(※訂正のため更新 18/4/23)

論文を読んでいると言葉だけ出会うが、見なかったことにしている言葉なのでちゃんと知りたい。

スタート:全く意味がわかっていないレベル
ゴール:論文でその言葉の意味が掴めている状態

言葉の理解や分かりやすさを重視しており、厳密性や詳細を割愛している部分も多く、
基本的には、数ヶ月後に忘れてしまうチンパンな私の為のメモとなっています。
勘違いやミスがあればご指摘いただけると幸いです。

まず、言葉の定義を確認する(ことで絶望する)

言葉の一般的な説明

Wikipediaから抜粋してみる

P

  • 判定問題のうち、ある決定性チューリング機械によって多項式時間で解かれるものの全体をPで表す。

https://ja.wikipedia.org/wiki/P_(%E8%A8%88%E7%AE%97%E8%A4%87%E9%9B%91%E6%80%A7%E7%90%86%E8%AB%96)から抜粋。

NP

  • 非決定性チューリングマシンによって多項式時間で解くことができる問題
  • yes となる証拠が与えられたとき、その証拠が本当に正しいかどうかを多項式時間で判定できる問題

https://ja.wikipedia.org/wiki/NPから抜粋。

NP困難 (NP-Hard)

  • 問題が「NPに属する任意の問題と比べて、少なくとも同等以上に難しい」ことである
  • 正確にいうと問題 H がNP困難であるとは、「NPに属する任意の問題 Lが H へ帰着可能である」と定義される

https://ja.wikipedia.org/wiki/NP%E5%9B%B0%E9%9B%A3#cite_note-1から抜粋。

NP完全 (NP-Complete)

  • クラスNP(Non-deterministic Polynomial)に属する決定問題(言語)で、
  • かつ 任意のクラスNPに属する問題から多項式時間還元(帰着)可能なもののことである

https://ja.wikipedia.org/wiki/NP%E5%AE%8C%E5%85%A8%E5%95%8F%E9%A1%8Cから抜粋。

もうついていけない劣等感。
今回は、これらの定義や言葉がわかるようにしていく。

まず説明しやすい言葉に置き換えていく。
個人的な意見ですが、Pを理解しないとNPとかさっぱりだと思うので、根気強く読んでいけば分かるはず。

分かりやすく説明

まずはイメージを掴む。

関係図

これが頭に入っている方がイメージがつきやすい。
今現在、広く信じられている関係図は下記の通り。
細かくは後述していく。

f:id:motojapan:20171114192354p:plain

問題の難易度

P、NP、NP完全、NP困難の順で計算の複雑度が高まる。

Pの解説

Pとは、多項式(Polynomial) を指す。
ざっくりしたイメージだと、Pは「現実的に(効率的に)解ける問題クラス」。
イメージは、「何もなくても多項式で余裕で解けるよ」
そして、「アルゴリズムで解ける各種問題において多項式時間で解決可能な問題はむしろだよ」

定義では、「判定問題のうち、ある決定性チューリング機械によって多項式時間で解かれるものの全体をPで表す。」とあるが、特に青文字の言葉の意味に詰まって理解が進まない。
1つずつ説明してく。

判定問題とは

「0 / 1」、「yes / no」等を出力する二値分類問題
「判別問題ではない」問題は、例えば、「スタート地点から目的地までの所要時間や最短ルート」を求める問題だったりする。

決定性チューリングマシン(機械)とは

計算機を数学的に議論するための単純化・理想化された仮想機械。
データxに対して決まった(同じ)yが一意付けられて出力される。
厳密性を除き、突き詰めて考えると、現在の一般コンピュータもこれに相当するとされている。

多項式とは

多項式とは、定数と変数の積和から成り立つ式。(中学数学の復習)
例:

  • f(n)=an+c
  • f(n)=an^2+bn+c
  • f(m,n)=mn+c

多項式以外で言えば、「指数関数」。
指数関数とは、底に対して、指数部に変数を持つものを式。
例:

  • f(n)=a^n

多項式時間で解ける」とは

多項式時間で解けるとは、多項式を解ける時間(と同等の時間)を指す。
説明には整数倍を無視した表現:オーダー(O)を使う。(詳細は割愛)

O(n) ← これは多項式オーダーで解ける時間を指す
例えば、ダイクストラ法。
駅数nと路線本数mにおける最適な径路を求めるのはO(mn)となり、多項式時間で解ける

O(2^n) ← これは指数オーダーで解ける問題を指す
これは次に説明するNPに属する(困難か完全かは言ってない)

ちなみに
多項式に関しては、nは整数レベルであればそのorderで解ける。
一方で、
指数関数に関しては、

  • nが小さければ、多項式時間より早く解ける場合がある
  • nが大きければ、計算時間は発散していく

P読み直し

ここまで来て定義を読み直してみる。
「0/1で解ける問題の内、解が一意付けされた数学的に理想的なマシンによって、多項式を解ける相当の時間で解かれる集合」となる。

なので0/1で解ける判定問題以外はPではないし、指数オーダーで解ける問題はPではない。
やっとNPを説明できる下準備が終わった。

NPの解説

NPとは、非決定性多項式時間(Non-deterministic Polynomial time)であり、Not Pではない

定義は、「非決定性チューリングマシンによって多項式時間で解くことができる問題」かつ、「yes となる証拠が与えられたとき、その証拠が本当に正しいかどうかを多項式時間で判定できる問題」。
上述したPの説明までで上はかなり読めるようになっているはず。
初出の非決定性チューリングマシンについて説明を書く。

非決定性チューリングマシンとは

データxに対して決まった(同じ)yが一意付けられておらず、状態が確定しないことを指す。
現在の状態から次の状態への遷移選択において、解に近づく選択肢を選べる(解を求めるのに効率的な選択が毎回可能な)マシンである。
具体的には、量子コンピュータ、並列処理できる強力なコンピュータ、普通のコンピュータ。
量子コンピュータは、指数時間で解く問題を多項式時間で解けるようになったりすると言われている。
普通のコンピュータも非決定性チューリングマシンに属しているが、突き詰めると決定性チューリングマシンでもあるらしい。

「その証拠が本当に正しいかどうかを多項式時間で判定できる」とは

ざっくりとしたイメージは、
証拠が与えられた時に、それを確かめる時間は多項式で調べられるよ
「でも何も証拠ないと計算時間はよくわからないよ」。
一般的に、何も無い所から解を導くより、証拠の検証の方が解くことが容易と言われている。

NP読み直し

ということで読み直すと、
量子コンピュータや並列処理可能なコンピュータなど、解を求めるのに効率的に状態遷移していくマシンで、多項式(で解ける相当)時間で解ける集合」であり、「証拠yes(1)が与えられた時、その検証が多項式時間で判定できる問題」となる。

ちなみに後述するが、NPがPを含むことは自明。
なので、0/1が解にならない問題(判定以外の問題)はNPではないし、多項式時間で解けなればNPではない。

NP困難 (NP-Hard)の解説

NP困難とは、NPに属しているかはわからないが、少なくともNP以上に複雑ということ。
復習になるが、「問題がNPに属しているかは不明」ということなので、例えば、その問題が判別問題であってもいいし、そうで無くてもよい。

定義の言葉を砕いていく。
まず、「問題が「NPに属する任意の問題と比べて、少なくとも同等以上に難しい」ことである」について。
NP困難な問題は、少なくともNP以上に複雑な計算であることを指す。

次に、「正確にいうと問題 H がNP困難であるとは、「NPに属する任意の問題 Lが H へ帰着可能である」と定義される」について。
これですが、定義なので「そうですか」という感想です。
つまり「どんなNPな問題も、NP困難な問題Hに帰着できる」それがNP困難だ、ということ。

他にも「NP困難問題を解ける多項式時間の機械がもしあれば、それを利用してNPに属するどの問題も多項式時間で解くことができる。」という主張などがあります。

NP完全 (NP-Complete)の解説

NP完全とは、NPかつNP困難。
NPの中では最も難しい問題である。

定義は「クラスNP(Non-deterministic Polynomial)に属する決定問題(言語)で、
かつ 任意のクラスNPに属する問題から多項式時間還元(帰着)可能なもののことである」。

大体理解できる言葉が並んでいるが、初出で「多項式時間還元」を知る。

多項式時間還元(polynomial-time reduction)とは

分かりやすく定理を説明したものをhttp://www.cs.tsukuba.ac.jp/~takahito/gcourse/part2.pdfより抜粋。

問題 A を1回の基本演算と同じ時間で解くアル ゴリズム α があれば,α をサブルーチンとして用いることで問題 B を多項式時間で解くことが できるとき,B は A に多項式時間還元可能であるという.

なので、このサブルーチンを探し当てることが重要とされている。

そもそもNP完全かどうかは証明が必要
1971年にCookが、「充足可能性問題はNP完全」と証明済み
これが多項式で解ければ、すべてのNP完全問題多項式で解けることになる(が、現実はまだ解けていない

決定性、非決定性チューリングマシンの違い

  • 決定性チューリングマシンとは、
    • データxに対して決まった(同じ)yが一意付けられて出力される。
  • 非決定性チューリングマシンとは、
    • データxに対して決まった(同じ)yが一意付けられておらず、状態が確定しない。
    • 状態は、問題が効率的に解けるように毎回選択されていく。

なので非決定性チューリングマシンで解くとは、効率的な状態遷移性のあるアルゴリズムで解くことを意味する。

例えば、現在の状態Sから次の状態へN個の分岐(選択肢)があり、分岐の深さをHとする。

つまりこの場合、非決定性チューリングマシン多項式時間で解けるということを意味する。

P, NPの違い

ある視点で見てみると、
どっちのクラスも多項式時間で解けるが、「何を使って多項式時間で解けるか」が違う。

別の視点「何を多項式時間で解くか」で見てみると、

  • NPは、「与えられた証拠多項式時間で検証できる問題クラス」とある。
  • Pは、「解を求めること自体までもが多項式時間で解ける問題クラス」である。

NP困難, NP完全の違い

表現を変えて、おさらい。
解きたい問題がAの場合、

  • NP完全とは、
    • 問題AがNPで,全てのNP問題がAへ多項式時間還元可能なとき,AはNP完全であるという.
  • NP困難とは、
    • 問題AがNPで,全てのNP問題がAへ多項式時間還元可能なとき,AはNP困難であるという.

つまり、問題AがNPに限ったものがNP完全で、NPに限らないがNP困難(限らないとは例えば、判定問題でも判定問題以外でも良い)。

P、NP、NP完全、NP困難と具体的例題

P ダイクストラ
NP(完全) 部分和、ハミルトン閉路問題(全ての交差点を通過する経路があるか否かを解く問題、組み合わせ最適化問題)、充足性問題、3充足性、頂点被覆、ぷよぷよテトリス
NP困難 巡回セールスマン問題(都市間移動における総移動コストの最小化問題、問題の大きさは都市数)、ナップサック問題(部分和の一般化)

「P≠NP予想」とは

一般に「P≠NP」信じられている。
NPはPを自明に含む。しかし、PはNPと等しくないと予想されている。
一方で、NP完全問題が一つでも多項式時間で解けることが証明ができると、これは棄却され、多項式時間還元の定理より、「P=NP」となる。
「P=NP」となれば、ハミルトン閉路問題 やナップサックもPとなり、多項式時間で解が得られるようになる。
ただ、「P≠NP」も「P=NP」も証明に成功した者は今のところいない。

「総当りすればNPってPじゃないのか?」という疑問

「総当たりしたら各々は全て多項式時間で解けるからNPじゃなくてPじゃ無いか?」という疑問
実際、問題の複雑度次第。
それぞれの問題を多項式時間で解けたとしても、その候補数の増え方が多項式とは限らない。(「解ける」とは、「検証出来る」ということ)

終わりに

んー大枠はわかった。
しっくり来てないとこもあるが、一旦ここまで。
あとは3ヶ月後も思い出せることを祈る。

【神価格】ビックカメラでMacbook Air 13 inch 新品を39,800円という激安で買った話と一週間使ってみて

([10/30 午後更新] 本記事ですが想像以上に反響があり、格安な物やサービス、ライフハックな情報を探したりすることが趣味なので、twitterフォローしてもらえればライフハック情報とかバーゲン、格安速報とかします。(twitterも使い道に困っていたので) そんなレベルでもよければ、是非フォローしてやってください、お願いします。細かい情報更新も通知できると思うので。そして、あまり期待せずお待ちください。)

(もう少し細かく自由に書ける専用のライフハックブログを建てようかなとも考え中ですが、決まったらtwitterで報告します。(スマホを安く買った話とか、沖繩旅行を無料で行った話とか書こうかな))


箸休め投稿です。
(今月一度も投稿しなのもあれなので)

事の経緯

土曜の午後3時。
先週雨が強く3時間くらい時間を持て余したので、ふらっとビックカメラに入った。
「いつでもいいけど、そのうちMacbook 1台くらい欲しいなー」とAppleコーナーをふらついていた。
展示品で処理速度を確認してみたくてスクリプトを書いていたらおっちゃん店員さんが「活きがいいの入っているよ」と言ってきた。(怪しい)
「いくら?」と聞いたら「サンキュッパ」と言ってきた。(怪しすぎる、ドルじゃ無いよね、円だよね)
「え?どこにもそんな広告ないけど」と言ったら「たった今から10台限定だよ」と言ってきた(ますます怪しすぎる、絶対変なオプション契約させられる)

私の疑心暗鬼ボルテージはMaxを超えていた。

だが、嘘でもこんな面白そうな話はなかなか無いと思ったので乗ってみた。


限定10台とゴリ押しされたのはこれ↓
MacBookAir 13インチ [Core i5(1.6GHz)/8GB/SSD:256GB/USキーボード] (Early 2015) MMGG2JA/A
https://www.biccamera.com/bc/item/3752858/
(うん、ビックカメラさん、11万超えてるね)

Apple MacBook Air (13.3/1.6GHz Dual Core i5/8GB/256GB/802.11ac/USB3/Thunderbolt2) MMGG2J/A

Apple MacBook Air (13.3/1.6GHz Dual Core i5/8GB/256GB/802.11ac/USB3/Thunderbolt2) MMGG2J/A

(うん、amazonさんでも11万超えてるね)

国内販売でギャップがあるのは、USキーボードってことぐらい。
ただ別に日本語が打てない訳でもないし、慣れれば特に不便は無い。


会計結果↓
最後まで疑心暗鬼でレジに並んだが、ノーオプションで、本当に 78,829円 値引きだと。。
f:id:motojapan:20171029144254j:plain
(ありがとうビックカメラ様)

という事で、戦績は税別39,800円 + ビックポイントとなった。

ちなみに、レジのお兄さんにはタイムセールの話が言ってなかったらしく「聞いてないんですけど〜」とダチョウ倶楽部バリの困り顔。めちゃめちゃ揉めてた。結局レジは、おっちゃん店員さんにチェンジして丸く収まった。

※よくよく後から話を聞くと、量販店は在庫処分したいMacbookを常に一定数抱えていて、売り上げが悪い日の悪い時間帯に一斉放出を不定期にやっているとの事。今回は台風の午後3時という絶妙なタイミングでやって来た私に白羽の矢が立ったのだ(私としてはUSキーボードはなんの問題でも無くサンキューの一言だ)

開封と1週間使用レビュー

初期不良対応期間の1週間使い倒すまでがMacbook遠足。

外観

普通。
PowerSupportのエアジャケットもすんなり入った。
f:id:motojapan:20171029145743j:plain
開けても普通。
f:id:motojapan:20171029145858j:plain

キーボード

日本語キーボードと特に違うのはスペース両サイドにある「英数」「かな」が無く、いきなり「command」があるという点。
f:id:motojapan:20171029145946j:plain
入力切り替えは、「control + space」で可能だが、日本語キーボード並みに快適にする方法があるので次に書く。

1週間でやった事

次の事をやったが全て問題なくできた
そもそものスペック問題かもしれないが、動きが悪いものは (x)で記載

  • 起動、システム終了
  • システムアップデート(High Sierra 10.13へ)
  • カメラ起動、撮影(カメラデバイス確認)
  • Siri(マイク、スピーカーデバイス確認)
  • youtube再生 (プログレッシブダウンロード、リアルタイム性、デコーダ周り確認)
    • (x) 4K再生(たまにカクツク。2Kなら問題無い)
  • Xcodeアプリ開発(アプリ系の開発環境確認)
  • Tensorflowで深層学習(学習系の開発環境確認)
  • 入力切り替えアプリをインストール
    • ⌘英かな」という神アプリにより、左Command単押しを「英数」、右Command単押しを「かな」にバインドできた。これで日本語キーボードと似た入力切り替えが可能。
  • その他色々アプリインストール

結論

うん、「なんの変哲も無いMacbook Airだね。

まとめ

  • 雨の日は家電量販店にいってみる
  • スクリプトを書いてみる
  • 怪しい話に便乗してみる
  • そうすると稀にいいことがあるようだ
  • そして至って普通のMacbookだった

暇で気が狂いそうな雨の日は量販店へ!

【Raspberry Pi 3】sambaサーバーが接続できないときのハマリポイントまとめチェック

久しぶりにsambaを入れたらうまく動かないとか、ubuntu16.04ではsambaサーバーが動いていたのに、raspberry pi 3ではうまくいかないときのためのチェック項目

基本手順

インストール

$ sudo apt-get install samba

設定変更

$ sudo vim /etc/samba/smb.conf 
 
[global]
interfaces = 127.0.0.0/8 eth0
[homes]
browseable = yes
public = yes
read only = no
create mask = 0775    #Sambaにより作成されるファイルに許容される最大アクセス権 (権限は各自のレベルで設定) 
directory mask = 0775 #Sambaにより作成されるディレクトリに許容される最大アクセス権 (権限は各自のレベルで設定)

sambaを再起動

sambaを起動する

$ sudo service samba restart
//もしくは
$ sudo /etc/init.d/samba restart

【チェック1】sambaが起動しているか確認する

下記コマンドでステータス[OK]をチェックする

$ sudo /etc/init.d/samba restart
[ ok ] Restarting nmbd (via systemctl): nmbd.service.
[ ok ] Restarting smbd (via systemctl): smbd.service.
[ ok ] Restarting samba-ad-dc (via systemctl): samba-ad-dc.service.

【チェック2】ファイアーウォールを切断してみる

network問題を切り分ける

$ sudo apt-get install ufw
$ sudo ufw allow 137/udp
$ sudo ufw allow 138/udp
$ sudo ufw allow 139/tcp
$ sudo ufw allow 445/tcp
$ sudo ufw reload

【チェック3】interfacesを明示的に指定してみる

自分の環境は、192.168.0.xなのでこれを設定してみる

$ sudo vim /etc/samba/smb.conf 
 
[global]
interfaces = 192.168.1. 127.0.0.0/8 eth0

【チェック4】パスワードを設定したか確認する

接続したいユーザのパスワードをチェックする
なければ登録が必要

//確認方法
pdbedit -L
//ユーザ名、uid、フルネームの順で表示される

//無ければ登録 (ユーザー : pi)
sudo smbpasswd -a pi

【エラー】samba再起動で「Failed to restart samba.service: Unit samba.service is masked.」と出る場合

下記実行時に、「Failed to restart samba.service: Unit samba.service is masked.」が出る

$ sudo service samba restart

この場合次で置き換え可能

//こっち
$ sudo service nmbd restart
$ sudo service smbd restart
$ sudo service samba-ad-dc restart

//もしくは既出だが
$ sudo /etc/init.d/samba restart
[ ok ] Restarting nmbd (via systemctl): nmbd.service.
[ ok ] Restarting smbd (via systemctl): smbd.service.
[ ok ] Restarting samba-ad-dc (via systemctl): samba-ad-dc.service.

【iOS11 / CoreML】自作した回帰予測モデル(.mlmodel)の結果を得る実装方法 (Regression, VNCoreMLRequest)

iOS11がリリースされて3日経過したが、本家が提供するモデルはMobileNet、SqueezeNet、Places205-GoogLeNet、ResNet50、Inception v3と分類モデルが多く、サンプルコードも分類しか見つけられない。
なので、今回は回帰予測モデル(具体的には、1次元配列 : 3次元ベクトル回帰)について説明。(世間で回帰関連の記事もないので)

説明すること:回帰の場合の実装方法(比較として分類の場合も記載)
説明しないこと:CoreMLの基本的な使い方、実行方法(巷に溢れているので割愛)

参考資料

本家で提供される学習済みモデル一覧
Machine Learning - Apple Developer

CoreMLの分類サンプルコード
Classifying Images with Vision and Core ML | Apple Developer Documentation

回帰モデルの説明

自作したモデルは、1次元配列(3次元ベクトル)を求めるようなモデル。
(まぁ多次元配列でもスカラーでも、話は同じだったので割愛)
Kerasで学習させた回帰モデルをCoreMLToolsを用いて変換する。

変換イメージ

  • Keras model (.h5) → [CoreMLTools] → CoreML model (.mlmodel)

生成されたモデル (例えば、MyRegression.mlmodel) はXcodeでプロジェクトにドラック&ドロップすることで見える。

モデルの確認方法

  • プロジェクト上にドラック&ドロップした自作モデルをクリック -> [Model Evaluation Parameters] -> [outputs]

モデル情報は次の通り。

Name Type Description
output1 MultiArray<Double, 3> (未記入)

MultiArrayとして、3要素のDouble型1次元配列を回帰するモデルとなっていると確認できる。

[分類/回帰]モデルをロード

なんてことはない、分類も回帰も同じ手順

//学習済みmodelをロード (分類)
let model = try! VNCoreMLModel(for: MyClassification().model) # 提供される学習済みであればMobileNet()とか

//学習済みmodelをロード (回帰)
let model = try! VNCoreMLModel(for: MyRegression().model)

[分類/回帰]モデルと結果を受け取るコールバックを設定

ここも特に差はない、分類も回帰も同じ手順

//分類
let coremlRequest = VNCoreMLRequest(model: model, completionHandler: { (request, error) in
self?.processClassification(for: request, error: error)
})

//回帰
let coremlRequest = VNCoreMLRequest(model: model, completionHandler: { (request, error) in
self?.processRegression(for: request, error: error)
})

[分類/回帰]コールバック関数 / 結果の読み取り【最重要】

ポイントは下記で、分類と回帰でクラスを使い分ける

分類の場合 回帰の場合
VNClassificationObservation VNCoreMLFeatureValueObservation
//分類(VNClassificationObservation)
func processClassification(for request: VNRequest, error: Error?) {
    guard let observations = request.results as? [VNClassificationObservation] else { fatalError() }
    guard let best = observations.first else { fatalError() }
  //best.identifier : best時のクラス情報
    //best.confidence : best時の信頼度
}

//回帰(VNCoreMLFeatureValueObservation)
func processClassification(for request: VNRequest, error: Error?) {
    guard let observations = request.results as? [VNCoreMLFeatureValueObservation] else { fatalError() }
    guard let values = observations[0].featureValue.multiArrayValue!
    //valuesはここでArrayになっているので
    //あとはランダムアクセスすればスカラー値が取得できる
    //values[0], values[1], values[2]
}

ちなみに、回帰でbservations[0]の0は、学習時のバッチサイズの問題だと思っている。(確か)

感想

  • 単純な回帰だけでなく生成モデルとかやる場合は使いそう。
  • 17/09/23時点では、 Webで調べても全く記事が無く、世間はあまり回帰に興味が無いのか?
  • もっといい方法があれば教えてください。

Linuxのジョブ/プロセス(jobs/process)関連のコマンドまとめ (起動、中断、終了、検索、ジョブ強制終了、ログアウト継続実行)

ubuntu/raspberry piでの開発で重宝しているコマンドを覚書
今回は、hoge.pyというスクリプトを例にとる

プロセスを起動する方法

$ python hoge.py   #フォアグラウンド
$ python hoge.py & #バックグランド
[1] 20664          # [ジョブID]プロセスID

特定のプロセスを検索する方法

hoge.pyを検索する場合

$ ps aux | grep hoge.py
pi       20664  100  0.5   8992  4992 pts/0    R    15:44   4:01 python hoge.py
pi       20744  100  0.5   8992  4916 pts/0    R    15:46   2:30 python hoge.py
pi       20745  3.1  0.5   8992  4928 pts/0    T    15:46   0:04 python hoge.py
pi       20903  0.0  0.1   4272  1844 pts/0    S+   15:48   0:00 grep --color=auto hoge.py

3回実行しているとこんな感じ

フォアグラウンドのプロセスを終了する方法

python hoge.pyを実行中に下記コマンド

ctrl+c 強制終了 ジョブにから消える
ctrl+z 中断 ジョブに残る(Stopped)

バックグランドのプロセスを終了する方法

方法1. python hoge.py &を実行すると、実行直後のログに" [ジョブID]プロセスID "が出力されるのでそれをメモしてkill
方法2. プロセスを検索してkill

プロセスを検索する

$ ps aux | grep hoge.py

ここで見つかるプロセスIDをメモ

プロセスkill

$ sudo kill プロセスID

ジョブを確認する方法

現在のジョブを確認するコマンドは下記

$ jobs
[1]   Running                 python hoge.py &
[2]-  Running                 python hoge.py &
[3]+  Stopped                 python hoge.py

Ctrl+Zで終わるとstatusが[Stopped]になっている
これを再起動したり、強制終了させる方法は下記

中断したジョブをフォアグラウンド/バックグラウンドで再開する方法

フォアグラウンドで再開する場合

$ fg %ジョブ番号

バックグラウンドで再開する場合

$ bg %ジョブ番号

ジョブの切り替えは下記
Stoppedのジョブをバックグランドで再開し、フォアグラウンドに切り替える場合

$ bg %ジョブ番号 # バックグランドで再開
$ fg %ジョブ番号 # バックグランドからフォアグラウンドに切り替え

中断したジョブを強制終了する方法

中断した場合はstatusがstoppedになるので、ジョブを終了する

$ sudo kill %ジョブ番号

※実際に即ジョブが強制終了されるわけではないので、少し待つ

ログアウト後もコマンドを実行する方法

sshで繋いでいると切りたくなることがある
(私の場合、特に機械学習とか)
下記コマンドで可能

sudo nohup python hoge.py &

ログアウト後も実行しているコマンドを終了する方法

バックグランドのプロセスを終了する方法と同じ

【お家IT#1】 googleスプレッドシートで管理した賞味期限リストをGASでメールで定期通知してみた

GAS(Google Apps Script)という、Google製サービス上で動くJavascript互換のスクリプトを初めて触ってみた。

家の課題を解決するために。

課題:家の調味料や保存食の賞味期限がいつの間に切れていく

こんなことありますよね。(え、ないですか?)
私と妻で掃除してみたところ65品目ありましたが、この期限を全て把握することは記憶力が鶏レベルの私には無謀です。

調味料だけでもよくわからないほどあった。

写真は調味料棚の一部
f:id:motojapan:20170918224818p:plain
実際棚はこの9倍くらいの容積があるので覚えられるわけがない。

これに対して、賞味期限を定期通知することで、家の中の賞味期限食品を管理し、ゴミを減らし、地球温暖を防ぎ、さらに世界の家庭で蔓延しているらしい「夕食何にする?」という問いを「今晩あれを使って何か作ろう」という積極的な思考へ変換することで、世の中全ての家庭が円満になることを妄想して作ってみた。

概略図
f:id:motojapan:20170919232912p:plain

やったこ

0.夫婦共有のスプレットシートを作る

夫婦共有のGoogle Driveフォルダにスプレットシートを作る。

1.スプレットシートに賞味期限を書く

大掃除がてらキッチン周りの掃除と一緒にやる。
15分程度で書き込み終わり。

こんな感じ。
f:id:motojapan:20170919222810p:plain

最低限、B列とC列があればOK。

説明
A列 今日の日付(A1セル)
B列 品目名
C列 賞味期限
D列 残り日数

今回はスクリプトで完結するので使わないが
A1セルは、[=TODAY]で今日の日付を取得。
D2セルは、[=C2-$A$1]で残り日数を取得。

2.スプレットシートの情報をemailで送るスクリプトを書く

スプレットシートの[ツール]->[スクリプトエディタ]を選択。

ここで空プロジェクトができるので下記を記載。
ソース自体は30行くらいでできた。

ソースコード全体は下にあるが重要なところだけ先んじて覚書。

getRangeについて
  var MAX_LINES = 200
  //シート情報を取得
  var sheet = SpreadsheetApp.getActiveSheet();  
  //B,C列の情報を、配列で取得
  var lines = sheet.getRange(2, 2, MAX_LINES, 2).getValues();  

getRangeでシート情報を配列として取得できるが、多重定義されてるのでいろいろなデータの取り方がある。
本家API referenceを参考にする。

今回の場合下図の対応。
getRange(row, column, numRows, numColumns)

f:id:motojapan:20170919235816p:plain


ここ以外特にハマったとこはなく終わった。

ソースコード全体

下記の通り。

function myFunction() {
  var MAX_LINES = 200
  var today = new Date();

  var sheet = SpreadsheetApp.getActiveSheet();  
  var lines = sheet.getRange(2, 2, MAX_LINES, 2).getValues();  
  var text = ""
  var flag = true
  
  for (var idx in lines) {
      var date      = lines[idx][1]
      var item_name = lines[idx][0]
      if(date == null || date == "") {
        continue;
      }    
      if(item_name == null || item_name == "") {
        continue;
      }
      
      if(flag && date > today) {
        today_info = Utilities.formatDate(today, 'Asia/Tokyo', 'yyyy年M月d日')
        text +=  "------- today : " + today_info + " ------- \n"
        flag = false
      }

      var dt = date.getTime() - today.getTime();
      var diff_day = dt / (1000 * 60 * 60 * 24) + 1;
      
      day_info = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy年M月d日')
      text +=  day_info + "(" + Math.floor(diff_day) + ") \t" + item_name + "\n"
  }
  
  GmailApp.sendEmail("xxxxxx@gmail.com", "notify", text);  // 私のアドレス
  GmailApp.sendEmail("yyyyyy@gmail.com", "notify", text);  // 妻のアドレス
}

3.定期配信のためのスケジュール設定する

[スクリプトエディタ] → 時計マークの[現在のプロジェクトのトリガー]を選択
月曜の夜と金曜の夜に計画的な買い出しをするため、月曜と木曜に定期配信設定。
f:id:motojapan:20170919224700p:plain

結果

通知されたメールはこんな感じ(やったぜ)。
f:id:motojapan:20170919225936p:plain

雑感

  • GASはかなり簡単にかけた、必要な部分だけで済むので実装が楽
  • デバックやログも簡単に出力可能
  • 翌日だったが、apps-scripts-notifications@google.com からエラーレポートが届くので監視が楽 (下図参考)

f:id:motojapan:20170919225532p:plain


そのうち画像認識と文字認識を組み合わせて、賞味期限リストへの登録を半自動化したいと思う。
それ以外であっても業務効率化で使えそう。

では、はっぴー食べ物らいふを!(今晩はマグロの漬け丼になりました)