読者です 読者をやめる 読者になる 読者になる

ほろ酔い開発日誌

有意義な技術的Tipsを共有出来たら嬉しいです。Ruby、Railsが好きです。Web開発全般(Rails多め、フロント、サーバー、インフラ)、データ分析、機械学習あたりの記事が中心になる予定です。

Java 配列部分型 ( ArrayStoreException )

普段、Javaはあまり使わないほうですがJavaの型について学んだことがあったのでメモします。(触れるのはJavaですが、型の問題としては一般に関わる話です。)

BがAの部分型であるときにBの配列をAの配列の部分型にしてよいか

ということに関してです。

前提として、JavaはBがAを継承するとき、BがAの部分型といえます。 コードベースで説明します。

具体例

まず、Shape とそれを継承する Circle というclassを用意します。

public class Shape {
  public String name() { return "Shape"; }
}
public class Circle extends Shape {
  public String name() { return "Circle"; }
  public String check() { return "OK!"; }
}

このとき、 CircleShape を継承しており、 CircleShape の部分型となります。

部分型であるので以下のような代入が許容されます。

Shape s = new Circle();

Bの配列がAの配列の部分型であることを許容するとき、以下のような代入を許容するということです。

Shape[] arr_s = new Circle[1];

さて、以下のコードはその配列の部分型を許容したコードです。

public class CheckArray {

  public static void main(String[] args) {
    Shape shape = new Shape();
    Circle [] arr_circle = new Circle[1];
    Shape [] arr_shape = arr_circle;
    arr_shape[0] = shape;
    Circle circle = arr_circle[0];
    System.out.println(circle.check());
  }

}

このコードは問題が起きており、配列の部分型を許容したことで、最後の circleShapeのオブジェクトで、checkというメソッドがありません。

それにも関わらず、実際のコンパイル時にはエラーが起こりません。 代わりに実行時には ArrayStoreException というエラーが起こります。

本来であればコンパイル時でエラーを出したいところですが、Javaはこのミスに対処しておらず実行時にエラーを出すようにしたのだそうです。 ちなみに これに似たArrayList というやつはコンパイル時にちゃんとエラーを出してくれるようです。

まとめ

  • Javaコンパイル時に配列の部分型を許容してしまっているが本来はコンパイル時にエラーを出すべき。
  • Javaはその代わりに ArrayStoreException というエラーを実行時に出す。

悩ましくも面白い話だと思いました。

Google Formで回答を受けたらSlackに通知する (Google Apps Script)

やったこと

タイトル通り、Google Formで回答を受け付けたらそれをSlackに通知します。 大体の手順は以下のような感じ。

  1. Google FormでFormの用意。また、回答をSpreadSheetに出すようにしておく。
  2. Slackのincoming webhookの用意をする。
  3. Google Apps Scriptを書く。

これだけ。以下の記事を見つけたのでこの記事に沿ってやりました。基本はこれを見て下さい。スクリプトの箇所はちょっと変えたので記録しておきます。あとその他説明。

chezou.hatenablog.com

スクリプト説明

スクリプト

最初に最終型を出します。 url とかチャンネルは変えて下さい。

function sendToSlack(body, channel) {
  var url = "https://hooks.slack.com/services/hogehoge/pogepoge";
  var data = { "channel" : channel, "username" : "form-notification", "text" : body, "icon_emoji" : ":turtle:" };
  var payload = JSON.stringify(data);
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "payload" : payload
  };
  var response = UrlFetchApp.fetch(url, options);
}

function test() {
  var body = "test message by notification bot\n";
  sendToSlack(body, "#notification");
}

function onFormSubmit(e){
  var name = e.namedValues["氏名"]
  var body = name + "さんからの回答";
  sendToSlack(body, "#notification");
}

説明

はじめ紹介した記事の e.response.getItemResponses() の箇所でなぜかエラーが出てしまいました。undefined 的なことを言われました。それでデバックすると e の中に response がいないんですよね。

Documentには response があるっぽいのですけど。。

Event Objects  |  Apps Script  |  Google Developers

よくわからないですけど e の中にいないものはしょうがないです。 e をデバックしたら中身に namedValues というのがいたのでこれを使いました。カラム名をキーにすると値がとれます。

実行エラー等は「表示」->「実行トランスクリプト」で見れました。 あとは Logger.log('test 内容'); とかを使って、「表示」->「ログ」でデバック出来ました。

ちなみに、最初に紹介した記事でやっていることは response オブジェクトを利用して値を取り出しているのですが、以下で説明がありました。

Class FormResponse  |  Apps Script  |  Google Developers

form全体のオブジェクトをループさせるのはいいのですが、1行に対応するオブジェクトをループさせるのはちょっと気持ちわるい感がありました。

ひとまず namedValues で短く書けるし結果オーライでした。

おわりに

他の記事もあたりましたが、 e.response.getItemResponses() のエラーの記事はちょくちょくありました。 namedValues で出来たという備忘録として残します。

Tensorflow run() vs eval() と InteractiveSession() vs Session()

はじめに

Tensorflowを使う際にコードによって若干の違いが見られたのでその点を理解しておきたいと思います。

  • run() と eval()
  • InteractiveSession() と Session()

この2点に違いについて説明します。

run() vs eval()

例えば、以下のような簡単なMLPの実装の一部を見て下さい。

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=t, logits=h_fc))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cost)
correct_prediction = tf.equal(tf.argmax(h_fc, 1), tf.argmax(t, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

sess = tf.InteractiveSession()
init = tf.global_variables_initializer()
sess.run(init)

n_epochs = 10
batch_size = 100
n_batches = train_X.shape[0] // batch_size
train_X, train_y = shuffle(train_X, train_y)

for epoch in range(n_epochs):
    for i in range(n_batches):
        start = i * batch_size
        end = start + batch_size
        train_step.run(feed_dict={x: train_X[start:end], t: train_y[start:end]})
    train_accuracy = accuracy.eval(feed_dict={x: valid_X, t: valid_y})
    print("EPOCH::%i, training_accuracy %g" % (epoch+1, train_accuracy))

print("test accuracy %g" % accuracy.eval(feed_dict={x: mnist.test.images, t: mnist.test.labels}))
sess.close()

上のコードの中で、例えば、

train_step.run(feed_dict={x: train_X[start:end], t: train_y[start:end]})

の部分では run が使われているのに

accuracy.eval(feed_dict={x: valid_X, t: valid_y})

の部分では eval が使われているじゃないですか。 evalrun って何が違うのでしょうか?

stackoverflow.com

上記のAnswerとして以下のようにあります。

op.run() is a shortcut for calling tf.get_default_session().run(op)
t.eval() is a shortcut for calling tf.get_default_session().run(t)

ここでいう tf.get_default_session().run()

sess = tf.Session()
sess.run()

の sess = tf.get_default_session と考えれば分かりやすいと思います。 じゃ、「結局どっちも同じじゃん」って感じですけど、run は Operation クラスで evalTensor クラスに属するのでオブジェクトに応じてメソッドを変える必要があるということです。これが結論です。

ここで、「あれれ、じゃあ sess.run ってどういうやつだっけ?」ともなっているかもしれません。次で説明します。

InteractiveSession() vs Session()

Session management  |  TensorFlow

InteractiveSession() がTensorflowの公式に載っていました。Session()に対してInteractiveSession() は何が違うのでしょうか?

A TensorFlow Session for use in interactive contexts, such as a shell.

The only difference with a regular Session is that an InteractiveSession installs itself as the default session on construction. The methods Tensor.eval() and Operation.run() will use that session to run ops.

This is convenient in interactive shells and IPython notebooks, as it avoids having to pass an explicit Session object to run ops.

つまり、 InteractiveSessonを使うとsess = Session() のようにして指定したsessを明示的に指定しなくてもよくなるよ、ということです。IPython notebookで使うときとかに便利だということですね。

Frequently Asked Questions  |  TensorFlow

以下は上記リンク先のコード例です。わざわざ sess.run() のような記述はいらなくなります。

sess = tf.InteractiveSession()
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
# We can just use 'c.eval()' without passing 'sess'
print(c.eval())
sess.close()

ちなみに with 公文を使えば、tf.Session() を使っても同様の記述が出来るようです。こちらも上記リンク先のコードです。

a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
with tf.Session():
  # We can also use 'c.eval()' here.
  print(c.eval())

sess.run を使って書いてみます。

a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
sess = tf.Session()
sess.run(c)
sess.close()

以上で違いが理解出来たのではないでしょうか?

おわりに

IPython notebookを使うときはInteractiveSession が便利のような気もしますが(ちょっと楽)、Sessionrun のメソッドで(eval とごちゃごちゃにならず)統一的に書けるので良いなと思ったりもしました。

RNNやWord2Vec関連のリンクの備忘録

RNN概要

LSTMについての説明が中心。 RNNのRがrecurrentの頭文字であることからも表されるように、RNNは同じネットワークを繰り返して前のネットワークで学習した結果の一部を後続のネットワークに渡すようなことをしています。それは前のネットワークの情報も現在のネットワークで使えるからいいよねって話なのですが、場合によっては直前の情報だけじゃなくて結構前のネットワークの情報も使いたいわけです。それをいい感じにやってくれるのがLSTMというわけです。以下の記事がこのあたりの説明をもっとちゃんと、詳しくしてくれてる記事です。 最近のアテンションというやつについても機会があればまとめたいところです。

Tensorflow tutorialにgreat articleとして紹介されてた記事。

Understanding LSTM Networks -- colah's blog

(日本語翻訳) qiita.com

かなり詳しくて分かりやすい qiita.com

Tensorflowのチュートリアル

Recurrent Neural Networks  |  TensorFlow

Sequence-to-Sequence Models  |  TensorFlow

Word2Vec

word2vecを使えば文章から単語のベクトル表現が出来て、単語の特徴が分かるよという認識です。 その中のアルゴリズムとしてcbowとskip-gramがあるよという感じです。 (word to vec ですもんね。文字をベクトルにってことですね)

word2vec、cbow、skip-gramが簡潔に説明されていてよい。 resola.ai

skip-gramについて詳しめに丁寧な説明。 qiita.com

【Swift3】ニュースアプリ風の横スクロールメニューバーライブラリ3つの検討

ニュースアプリのメニューバーを実装したくなったので、ライブラリを検討してみました。 イメージとしては以下のGunosyのメニューのようにスライドしてジャンルを切り替えるようなものです。

f:id:seishin55:20170131112756p:plain:w300

調べた結果良さそうだと感じたものは下記です。

  • PageMenu
  • PagingMenuController
  • TabPageViewController

PageMenu

github.com

READMEにあるデモを見るとわかるのですが、見た目がクールでなかなかよさそうだという印象を最初に持ちました。

ただし最終コミットが執筆時点で18 Aug 2016 でSwift3に対応されていません。

以下、上記のレポジトリをフォークしてSwift3に対応しています。 こちらを使えば大丈夫です。

github.com

これはこのQiitaの記事に載っていて、このサンプルアプリを作ってみましたがなかなかよい感じでした。(このデモだと初期のメニュー下のアンダーバーがおかしいので少し手は加えましたが。)

qiita.com

開発がアクティブでないので不安定感はありますが、動作自体はいい感じなので、細かいことを気にしなければこれで十分だと思いました。

PagingMenuController

github.com

This library is inspired by PageMenu とあるようにPageMenu にインスパイアされたらしい。メルカリの人が作っているみたいです。 今月中にもコミット&リリースがなされていて、活発に開発されているみたいです。比較的新しいライブラリでSwift3にも完全対応されています。

ひとつ残念だったのはメニューをスワイプさせるとページが変わってしまうということです。一気に一番右のスライドに移動が出来なかったです。

github.com

issueが立っているのでアップデートを期待です。 これがあればこれに即採用だったのですが、現段階ではPageMenuのほうを採用したいかなという感じです。

TabPageViewController

github.com

VASILYの方が作成したライブラリです。 ブログにも載っています。

tech.vasily.jp

以下を参考にサンプルを作ってみましたが、第一印象は「最高」って感じでした。

hchckeeer.hatenadiary.jp

しかし、一点重大な問題があって選択されているタブを画面外にはずして、他のタブをクリックするとフォーカスされたタブが2つになってしまうのです。

追記 2017.02.13

TabPageViewControllerで問題になっていた箇所を解消して頂きました! ver 0.2.3のアップデートからタブが二重にフォーカスされるバグが消えました。

なので、2017.02.13現在で最もおすすめなのは TabPageViewController ということになりました。

終わりに

以上から結局、PageMenuを採択しようと思います。

以下の記事を参考にして作業を進めたいと思います。

qiita.com

x1.inkenkun.com

PagingMenuController、TabPageViewControllerのアップデートがあればそちらのほうを使いたいところです。

群知能(Swarm Intelligence)の実装 (Java) - PSO・ABC-

大学の課題で群知能(Swarm Intelligence)の実装が課題に出て、PSO(Particle Swarm Intelligence) と ABC(Artificial Bee Colony) のアルゴリズムを実装することになりました。

そこで、コードの紹介(github)と参考になったものを載せておきます。

群知能(ぐんちのう、むれちのう、Swarm Intelligence, SI)は、分権化し自己組織化されたシステムの集合的ふるまいの研究に基づいた人工知能技術である。( 群知能 -Wikipedia- )

群知能はたくさんのエージェントを用意してそれぞれが各々相互作用を起こしながら最適解を探し出す人工知能技術です。それぞれのエージェントを中央管理するわけではなく、それぞれが自発的に行動し、結果的に全体としての創発をもたらすところが特徴にあります。

群知能のアルゴリズムは自然界からヒントを得たものが多く、PSOは動物の群れをヒントにしたアルゴリズムですし、ABCは蜂の採餌行動をヒントにしたアルゴリズムになります。

アルゴリズム

まず実装したコードは以下です。PSOとABCの2つを実装してあります。

github.com

以下の関数の最小化問題を解けるようになっています。 (もちろん、自分で定義すれば他の関数でも可)

  • shpere関数 定義域 [-5.0, 5.0]
  • rastrigin関数 定義域 [-5.0, 5.0]
  • rosenbrock関数 定義域 [-5.0, 5.0]
  • griewank関数 定義域 [-600.0, 600.0]
  • alpine関数 定義域 [-10.0, 10.0]
  • 2n-minima関数 定義域 [-5.0, 5.0]

Javaの実装になっています。本当はPythonでやりたかったのですが(それがダメでもRubyがいい)、JavaC言語C++のどれかの制限があったので、Javaにしました。C言語はあまりちゃんとしたコードは書いてこなかったのでやめました。(勉強しておきます。)

PSO

粒子群最適化(りゅうしぐんさいてきか、Particle Swarm Optimization、PSO)とは、群知能の一種。 昆虫の大群や魚群において、一匹がよさそうな経路を発見すると(すなわち、食料を発見したとか安全であるという場合)、群れの残りはどこにいても素早くそれに倣うことができる。( 粒子群最適化 -Wikipedia- )

まず、アルゴリズムなのですがWikipediaで十分わかりました。

粒子群最適化 - Wikipedia

具体的なコードとしてPythonで実装してある下記もわかりやすく参考になりました。Wikipeiaのアルゴリズムを見たあとにこちらを見るとすっきりします。

qiita.com

下記はN-Queens問題をPSOで解いたコードです。アルゴリズム自体は上記の2つを参考にしたのですが、Javaの書き方として参考になりました。

github.com

ABC

In computer science and operations research, the artificial bee colony algorithm (ABC) is an optimization algorithm based on the intelligent foraging behaviour of honey bee swarm, proposed by Karaboga in 2005. ( Artificial bee colony algorithm -Wikipedia- )

↑ ABCアルゴリズムは蜂の採餌行為をもとにした最適化アルゴリズムです、ということですね。(英語版しかなかった)

アルゴリズムはまずWikipediaを参考にしました。

Artificial bee colony algorithm - Wikipedia

Wikipediaだけではちょっと分かりづらかったのですが下記の2つが分かりやすかったです。

Step by Step Procedure of ABC

研究/2012-03-09 - Kondo's Page

下記はN-Queens問題をABCで解いたコードです。Javaの書き方も参考になりましたし、アルゴリズムも分かりやすかったです。

github.com

終わりに

他の講義の課題でカッコウアルゴリズムやホタルアルゴリズムなども調べたのですが、たくさんのアルゴリズムがあるのですね。自然界から発想を得てアルゴリズムにおこすところはディープラーニングも同じで面白さを感じます。 アルゴリズムの発想が詰まったら生命に戻って考える必要があると教授がおっしゃっていたのを思い出しました。

MacでディープラーニングのためにGPUを使いたかった話

ディープラーニングをするときは処理速度を上げるためにGPUを使いたいです。GPUを使わないとなれば、大きなデータセットは扱いたくはないです。この前、CPUでやろうとして3日くらいかかった(途中で諦めた笑)やつもGPUだったらどれだけ楽になったことか。

ところで最近、新しいMacbook Pro(2016 late, 13 inch)を買いました。こいつにはGPUがあるとのことで使う気満々でした。

よし、使ってみよう

ひとまず、Tensorflowでやろうと思って調べたら以下のような感じで記事が出てきて、やっぱり出来るんだと嬉しくなりました。

qiita.com

qiita.com

さて、Tensorflowのドキュメントにもご丁寧にMacGPUのセットアップ方法が書いてあったので指示通りにやりました。ほんとにちゃんとやりました。

出来ない。なんかエラーが出てうまくいかないのです。

 CUDA Device Query (Runtime API) version (CUDART static linking)

cudaGetDeviceCount returned 35
-> CUDA driver version is insufficient for CUDA runtime version
Result = FAIL

こんな感じのエラーが出てきます。何度もやり直してもうまくいかなかったです。

Macbook ProなのにGPUを利用出来ない??

それで、重要なことに気づいたのですが、そもそも勘違いもしていました。

Macbook Pro (2016 late, 13 inch) のGPUは NVIDIA製じゃない。
だからそもそもまだTensorflowにサポートされていない。

この記事を読んでわかりました。

stackoverflow.com

以前のMacbook ProのモデルのGPUNVIDIA製でした。しかし、現在はAMD製です。なので、Tensorflowにサポートされていないんです。issueはあるみたいなので頑張って欲しいです。

github.com

GPUの話

そもそもGPUディープラーニングで使うために最低限のことをざっくり書いておきます。(厳密じゃないかもです、ただ僕と同じ現象にぶつかった人が腑に落ちるように)

GPUは一般的には画像処理のための演算装置です。単純な計算にはめっぽう強いみたいです。CPUがボスキャラ1体、GPUが雑魚キャラ1000体みたいなものだと思ってます。GPUは単純なことならたくさんの処理を効率よく行ってくれます。

それで、画像処理だけじゃなくても使えるんじゃない?といった感じで他の分野にも使うことになりました。GPGPU(General-purpose GPU)ってやつです。

このGPGPUを使う環境を整えてくれているのがNVIDA社のCUDAという環境です。なのでNVIDA社のGPUを使うときはこの環境を使えるので幸せになれるというわけです。

さて、じゃあそれを使えばいいじゃないという話になるんですが、このCUDAというやつは標準化されてなくてNVIDA製のGPUじゃないとダメみたいなんです。

じゃあGPUが使える標準規格は何かというとOpenCLというやつになります。ただこいつはGPGPUに特化していないです。そういうわけで、ディープラーニングのライブラリ的にはサポートしづらいのではないでしょうか。

そうなると、なんでわざわざAMD製にしたんだという感じですが、既にNVIDIA製に向けて進んでいるみたいです。

www.universityherald.com

ホットな分野はGPGPUが求められますし、割りと大事だと思うんですよね。 次のモデルではNVIDIA製に戻るのではないでしょうか。

そうなると、今回のモデルでたまたまNVIDIA製じゃなかったということで少しだけ残念な気もします。

ただ、外付けのGPUの開発も進んでいるようで期待したいところですね。

www.gizmodo.jp

こちら参考にしました。

qiita.com