特にプログラマーでもデータサイエンティストでもないけど、Tensorflowを1ヶ月触ったので超分かりやすく解説

これ書くだけで土日２日間まるまる潰れてしまった。
学んだ内容に沿っているので、順に読み進めるに従ってコードの話になっていきます。
Tensorflow触ってみたい/みたけど、いろいろまだ理解できてない！という方向けに書きました。

**※2018年10月4日追記**
大分古い記事なのでリンク切れや公式ドキュメントが大分変更されている可能性が高いです。
この記事のTensorflowは ver0.4~0.7くらいだった気がするので ver2.0~となりそうな現在は文章の大半が何を参考にしているのか分からないかもしれません。



#1: Deep Learningってそもそも何してるの?
専門の人からはご指摘入りそうですが、要は回帰分析してくれるブラックボックスと言い切ってはどうでしょう。
"回帰"という単語が出てくるだけで `?`が出てきちゃいますよね。
求めたい"値"があってそれに限りなく近い数値を機械に計算させまくり学んでもらう。で、いいんじゃないでしょうか。
eg.適度な関数が知りたい
![Non-Linear-Regression.gif](https://qiita-image-store.s3.amazonaws.com/0/63543/70bcbddc-02e2-f091-8e21-8de0d2855e6c.gif)
eg.適度なクラスターを知りたい
![K-Means-Clustering-Gif.gif](https://qiita-image-store.s3.amazonaws.com/0/63543/5a550314-d14d-a1c0-9d9a-3de7557a04e8.gif)
eg.適度な"顔"というものをpixelの集合で知りたい
<img width="296" alt="Screen Shot 2016-03-06 at 4.44.13 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/63543/843b819e-c7f1-4bbb-17b2-e518f4c7cf5a.png">
それなら自分だって知りたいことはたくさんあるよ！という方々は多いと思います。
アイドルの動画からすげーブサイクな顔になってる時(値)だけを求めて、キャプチャしたい！とか、[Qiita: - ディープラーニングで顔写真から巨乳かどうかを判別してみる (うまくいったか微妙)](http://qiita.com/summer4an/items/db0124eee8103c1d3b85)だとか。
偉大なる先人達は常にいるようですね。
というわけでDeep Learning始めてみよう！となりました。
#2: フレームワーク選び - Tensorflowの良いところ
結論から先に言うと**情報量**
最初の方はTensorflowの中身やら関数が何やってるか分からないので、途中Theanoに乗り換えを何度も考えましたが、今のところは大抵の疑問はすでに(英語で)Stackoverflowにあったり、Githubのイシューにも色々書いてあるので、やっぱりGoogleのネーム力って凄い。 Tensorflow本体のコードも普通に関数名でgoogle検索したりすると出てくるので、使ううちにどんどん本体の理解が勝手に深まります。
そもそも触り始める前は**なにができて、なにができないのか？も分かっていない状態だった**ので、Deep Learning系フレームワークで色々な実験をされている方々のブログを読み漁りました。
ドキュメントの分かりやすさなどは `Tensorflow > Theano > Chainer`ですかね。
その他に:
 - [Caffe](http://caffe.berkeleyvision.org/)
 - 元GoogleのAndy Rubinが投資している[Nervana](http://www.nervanasys.com/)
 - GUIベースのドラッグ&ドロップで機械学習とかできちゃう[Microsoft Azure Machine Learning](https://azure.microsoft.com/en-us/services/machine-learning/)
などなど見てみました。
ただ中身の評価モデルなどを理解していない段階だとなにもできません。 なので結局情報が一番ありそうなTensorflowでスタートしました。
多分この分野に慣れてくると評価モデルの関数がたくさん用意されているとかが主な使用理由になるのではないでしょうか。
**※2016/4/26追記**
日々githubにコミットされていく内容とかを追っていると、もうTensorflow以外はしばらく様子見でいいんじゃないかなぁーと思います。
###読み漁ったブログ一覧
####-Tensorflow
[kivantium活動日記: - TensorFlowでアニメゆるゆりの制作会社を識別する](http://kivantium.hateblo.jp/entry/2015/11/18/233834)
[すぎゃーんメモ: - TensorFlowによるディープラーニングで、アイドルの顔を識別する](http://d.hatena.ne.jp/sugyan/20160112/1452558576)
####-Theano
[人工知能に関する断創録: - Theanoによる畳み込みニューラルネットワークの実装 (1)](http://aidiary.hatenablog.com/entry/20150626/1435329581)
[StatsFragments: - Theano で Deep Learning <3> : 畳み込みニューラルネットワーク](http://sinhrks.hatenablog.com/entry/2014/12/07/203048)
####-Chainer
[せかいらぼ: -LSTMで自然な受け答えができるボットをつくった](http://www.sekailab.com/wp/2015/11/02/lstm-general-responce-bot/)
[Oriental Robotics: - RNNによる学習で文豪っぽいテキストを出力させる (aka DeepDazai)](http://orientalrobotics.blogspot.jp/2015/08/rnn-aka-deepdazai.html)
[Preferred Research: - 分散深層強化学習でロボット制御](https://research.preferred.jp/2015/06/distributed-deep-reinforcement-learning/)
#3: Hello, World!的なMNIST ビギナー編
※インストール的な話は沢山出てるので飛ばします。
※※ビギナーチュートリアルを読んでからがオススメです。
ここから真面目な解説スタートです。
機械学習のベンチマーク的なものMNIST。
Tensorflowの最初のチュートリアルとして 0〜9の手書き数字画像を大量に与えて、数字を理解させる練習です。
<img src="https://qiita-image-store.s3.amazonaws.com/0/63543/79e93ee0-0b17-a398-0ab6-56c0af06ecea.png" width="200" />
[ビギナー](https://www.tensorflow.org/versions/r0.7/tutorials/mnist/beginners/index.html)も[エキスパート](https://www.tensorflow.org/versions/r0.7/tutorials/mnist/pros/index.html)もコピペすれば動くのですが... ここで学ぶべきことは直接のコードというより、Tensor, Rank, Scalar, Vector (テンソル、ランク, スカラー、ベクトル, シェイプ)などTensorflowにおける概念や処理、そして数学的な理解の再確認でした。
まずは一番重要なTensorについて。
入力となるデータなどを取り扱ってくれる頼りになる**Tensorはあくまでデータ構造で、学習処理の間でやりとりされるだけです。 Tensorはn次元の配列もしくはPython的にはlistと考えるのが良いそうな。**
学習のバッチ毎にTensorの中にデータを入れてあげる感じですね。
なので学習処理以外の時に`print hoge_Tensor`なんてしてみても中身は入ってないんです。
"重み"など学んでいく過程の値はtf.Variable変数で持ち続けます。
**そしてTensorにはRank, Shape, Typeが必ずあります。**
エラーでよく言われるので、理解してからはだいぶ楽になりました。
##Rank

`t = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]` はRank2
要はTensor自身の次元数ですね。

<table>
<tr>
<th>Rank</th>
<th>数学単位</th>
<th>Python example</th>
</tr>
<tr>
<td>0</td>
<td>Scalar (実数量のみ)</td>
<td><code>s = 483</code></td>
</tr>
<tr>
<td>1</td>
<td>Vector (量と方向)</td>
<td><code>v = [1.1, 2.2, 3.3]</code></td>
</tr>
<tr>
<td>2</td>
<td>Matrix (よくあるテーブル)</td>
<td><code>m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]</code></td>
</tr>
<tr>
<td>3</td>
<td>3-Tensor (三次元)</td>
<td><code>t = [[[2], [4], [6]], [[8], [10], [12]], [[14], [16], [18]]]</code></td>
</tr>
<tr>
<td>n</td>
<td>n-Tensor (n次元)</td>
<td><code>....</code></td>
</tr>
</table>

##Shape
先の`t = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]` Shapeは3次元x3次元なので`[3, 3]`

<table>
<thead>
<tr>
<th>Rank</th>
<th>Shape</th>
<th>Dimension number</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>[]</td>
<td>0-D</td>
<td>A 0-D tensor. A scalar.</td>
</tr>
<tr>
<td>1</td>
<td>[D0]</td>
<td>1-D</td>
<td>A 1-D tensor with shape [5].</td>
</tr>
<tr>
<td>2</td>
<td>[D0, D1]</td>
<td>2-D</td>
<td>A 2-D tensor with shape [3, 4].</td>
</tr>
<tr>
<td>3</td>
<td>[D0, D1, D2]</td>
<td>3-D</td>
<td>A 3-D tensor with shape [1, 4, 3].</td>
</tr>
<tr>
<td>n</td>
<td>[D0, D1, ... Dn-1]</td>
<td>n-D</td>
<td>A tensor with shape [D0, D1, ... Dn-1].</td>
</tr>
</tbody>
</table>

##Type
これはintやらfloatなので、あまり説明はいりません。

##MNISTでそれらTensorを見る
MNISTの例で言うと、55000枚の画像データ(images)Tensorと画像の答え(labels)Tensorがでてきます。
Images Tensorは `Shape[55000, 784]`, `Rank2`, `dtype=tf.float32`
Labels Tensorは `Shape[55000, 10]`, `Rank2`, `dtype=tf.float32`
チュートリアルでは`tf.placeholder`でまず挿入されています。(Tensor確保と言った方がわかりやすいかも)

```py:input_Tensor達
x = tf.placeholder(tf.float32, [None, 784]) #images
y_ = tf.placeholder(tf.float32, [None, 10]) #labels
#None部分にはバッチの数が入る
```

なお`tf.placeholder()`は学習実行毎に必ず`feed_dict`引数でデータを与えてもらう必要があります。
チュートリアルの場合は最後の方で学習実行開始するのですが:

```py:最後の方の学習実行開始コード
for i in range(1000):
 batch_xs, batch_ys = mnist.train.next_batch(100)
 sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
```

なので、実際にはTensor達は`x:Shape[100, 784]` `y_:Shape[100, 10]`の画像100枚ごとに処理されてますね。

####**余談: 画像の次元数について**
画像データの方はもともと28x28pixelsのグレースケール = 1 channelですが、ビギナーチュートリアルでは簡単に考えるため784次元のベクトルにフラット変換(というか既にされてます。)
28*28*1 = 784-Dimension
**- 図で見るとなんとなくわかる -**
縦横に並んでる数字を全部横にする的な。
<img width="300" alt="mnist.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/63543/0819b8b1-ff1b-f765-9edc-37c6ff636fa8.jpeg">
`00000000000000000000000000000000000000000000000000000000000000000000000000000000000000.6.7.7.50000000000.81111111.9.30000000.4.4.4.7111000000000000.1.10000000000000000000000000000000000000000000000000000000000`
<img width="300" alt="mnist1.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/63543/4b2aec34-2d8b-1c94-91f9-5240ff6048f0.jpeg">
見える人には"1"に見えるらしい。
ちなみに画像をフラット化しない`[55000, 28, 28, 1]`の場合はRank4
カラー画像の場合でも3 channelsに変わるだけなので`[55000, 28, 28, 3]` Rank4

#4: Tensorflowの処理: - ビギナーチュートリアルでしていること
さてさて、Tensorが理解できた所でやっとTensorflowの機械学習的な処理が追えるようになります。
用意したImage Tensor`x:[batch_num, 784]`ですが、784次元ベクトルから一体どうやって10通りある正解の中から正確な答えを導き出すのでしょうか？
ここで**行列演算と"重み", "バイアス", Softmax回帰** 4つの存在を理解します。

##行列演算
行列演算は簡単な話です。
`x:[batch_num, 784]`に`[784, 10]`の行列演算をすると`[batch_num, 10]`の行列が生まれるので答えが10通りになります。
wikipediaの画像を参考にすると;
`A:[4,2]`と`B:[2,3]`が`[4,3]`になっています。
![Matrix_multiplication_diagram_2.png](https://qiita-image-store.s3.amazonaws.com/0/63543/5e5e5b4c-1501-7875-de59-8873bccb8653.png)
Tensorflowでいうと

```py:行列演算matmul
tf.matmul(A,B) # A is [4,2] and B is [2,3]. output would be [4,3]

'''
x: [batch_num, 784]
W: [784, 10]
matmul: [batch_num, 10]
'''
matmul = tf.matmul(x,W)
```

このB`[2,3]`、MNISTでいうと`W:[784, 10]`が重要な**重み**となります。
##重み
重み`W:[784, 10]`が登場しました。 コードでいう部分は

```py:重みW
W = tf.Variable(tf.zeros([784, 10]))
```

`tf.Variable()`は<i>[in-memory buffers](https://www.tensorflow.org/versions/r0.7/how_tos/variables/index.html)</i>ということで、学習に使いたいパラメーターが保持されつづけるTensorを含んだ変数です。
`tf.zeros()`は中身をすべて`0`で埋めているTensorを作ります。
`0`で埋めているのは学習の過程で随時アップデートされるので、`0`スタートなだけです。ランダムな数値を入れる`tf.random_normal()`もあります。
###重みの役割
`W:[784, 10]`の中身は画像が持つ1pixel単位の数値に、0の可能性は0.XXX, 1の可能性は-0.XXX, 2の可能性は0.0XX....といった感じで数値を掛け合わせにきます。
例えば先の"1"の画像の場合、一番最初の左上のピクセルに対しては、実際の学習させた重み`W[0]`は`[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]`なことが多いです。理由は明快で0〜9の全数字でその左上ピクセルが意味をなすことがないからです。
ど真ん中あたりの重み`W[380]`を見てみると:
`[-0.23017341 0.03032022 0.02670325 -0.06415708 0.07344861 -0.05119878 0.03592584 -0.00460929 0.09520938 0.08853132]`
となっています。 0の重み`-0.23017341`がマイナスということはつまり**ど真ん中のピクセルが黒い時に”０”の可能性は低い。**ということが理解できます。
<img width="300" alt="mnist.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/63543/0819b8b1-ff1b-f765-9edc-37c6ff636fa8.jpeg">
エキスパートチュートリアルの畳み込み層などの話になるとより思うのですが、**個人的には重みというよりフィルターという言葉が一番しっくりする気がしている。**
この重みをImages Tensorに行列演算すると

```py:行列演算された後
matmul = tf.matmul(x,W)
print "matmul:", matmul[0] #最初の画像(答えは7)
matmul: [ 1.43326855 -10.14613152 2.10967159 6.07900429 -3.25419664
-1.93730605 -8.57098293 10.21759605 1.16319525 2.90590048]
```

が返ってきます。　
うーん、まだよくわかりませんね。
##バイアス
バイアスはすごい感覚で言うため不適切かもしれないですが、
`y = x(sin(2+(x^1+exp(0.01)+exp(0.5)))+x^(2+tan(10)))+x(x/2x+x^3x)+0.12`
みたいな関数があった場合の最後の`0.12`みたいなものでしょうか。
<img width="300" alt="graph.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/63543/a5db70a1-a1dc-9442-33de-791e90ae88ad.jpeg">
もっと簡単にいうと`y = xa + b`の`b`?
あっ、だからbiasなんですかね。
ただチュートリアルの場合はバイアスなしでも答えの精度はあまり変わりませんでした。
仮にバイアスの真値が`b = 1e-10`とかだとあまり意味ないのかもしれませんね。
コードでは重みと同じように作ってあげますが、画像Tensorと重みはすでに行列演算されているため、後から付け足すバイアスは`Rank1`の`Shape[10]`です。

```py:バイアス
b = tf.Variable(tf.zeros([10]))
print "b:",b #学習後のバイアス
b: [-0.98651898 0.82111627 0.23709664 -0.55601585 0.00611385 2.46202803
-0.34819031 1.39600098 -2.53770232 -0.49392569]
```

こっちもこれ単体だとよくわかりませんね。
##Softmax関数 - 答え合わせ -
元のImages Tensor `x:[batch_num, 784]`は、
`x` 重み`W:[784, 10]`と行列演算され
`=` `matmul:[batch_num, 10]`になった後、
`+` バイアス`b:[10]`を付け足されてしまいます。
しかし、それなのにいまだこれら数値が示す意味がわかりません。
そこでこれらを`tf.nn.softmax()`に渡して人でもわかるような数値にさせます。

```py:softmax
y = tf.nn.softmax(tf.matmul(x, W) + b)
print "y", y[0] #最初の画像(答えは7)
y [ 2.04339485e-05 6.08732953e-10 5.19737077e-05 2.63350527e-03
2.94665284e-07 2.85405549e-05 2.29651920e-09 9.96997833e-01
1.14465665e-05 2.55984633e-04]
```

見てみると7番目の数値が一番高いですね。どうやら`7`の確率が高そうです。
配列の中の確率というより単純に答えを合わせをしたい場合は

```py:答えちょうだいな
x_answer = tf.argmax(y,1)
y_answer = tf.argmax(y_,1)
print "x",x_answer[0:10] #Tensorflowが思う最初の10画像の答え
print "y",y_answer[0:10] #10画像の本当の答え
x [7 2 1 0 4 1 4 9 6 9]
y [7 2 1 0 4 1 4 9 5 9]
```

```py:精度が知りたいな
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print "accuracy:", accuracy
accuracy: 0.9128
```

※2016/05/19追記
Softmax関数はアービタリーな実数値のまとまりを`range(0, 1)`に押し潰してくれる関数です。
最初Softmax回帰と書いていたんですが、正確には確率に対する回帰を行うので"ロジスティック回帰"と呼ぶそうな。 Softmaxはあくまでも入力を入れると出力が帰ってくる関数なんですね。
MNISTは画像を分類する問題なので一連の処理としては、
"この画像に対する各ラベルの確率が知りたい" → "ロジスティック回帰(softmax)" → "一番確率が高いものを答えとする(argmax)"　となります。
なので実数値を求めたい回帰分析の場合はsoftmaxを多分使いません。
#5: いつ学習しているの？
TensorflowがMNISTの答えを出してくれるまでの仕組みがこれで理解できました。
でも重み`W`やバイアス`b`の学習はどうやって進んでいるの？となりますよね。
ヒントはTensorflowの学習実行が繰り返される部分にあります。

```py:最後の方の学習実行開始コード
for i in range(1000):
 batch_xs, batch_ys = mnist.train.next_batch(100)
 sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
```

この`train_step`がどうやらトレーニングしていそうです。中身は

```py:学習方法
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
'''
 y: [batch_num, 10] y is a list of processed numbers of x(images)
y_: [batch_num, 10] y_ is labels
0.01 is a learning rate
'''
```

となっていますが、もう少し噛み砕いてみましょう
`tf.log()`はわかりやすくlogを計算します。Tensor自体に変化はないので`log-y:[batch_num, 10]`です。
そして答えTensor`y_`と掛け合わせるのですが、`y_`は答え以外は全て0が入っているため掛け合わせると答え以外の`index`は値が`0`になります。
掛け合わさったTensorも`Shape`は`[batch_num, 10]`ですが、答え部分以外は`0`のため実質的な次元は`[batch_num, 1]`と考えたほうがわかりやすいかもしれません。

```py
log-y = tf.log(y)
print log-y[0]
[ -1.06416254e+01 -2.04846172e+01 -8.92418385e+00 -5.71210337e+00
 -1.47629070e+01 -1.18935766e+01 -1.92577553e+01 -3.63449310e-03
 -1.08472376e+01 -8.88469982e+00]
y_times_log-y = y_*tf.log(y)
print y_times_log-y[0] #7の値のみが残る。
[-0. -0. -0. -0. -0. -0.
-0. -0.00181153 -0. -0. ]
```

`tf.reduce_sum()`は次元間すべてでの加算を行い、第２引数と`keep_dims=True`オプションがない場合は`Rank0`のTensor（スカラー）になります。 MNISTの場合は`[batch_num]`の保有する値を全部足した数ですね。

```py:例tf.reduce_sum()
# 'x' is [[1, 1, 1]
# [1, 1, 1]]
tf.reduce_sum(x) ==> 6
tf.reduce_sum(x, 0) ==> [2, 2, 2]
tf.reduce_sum(x, 1) ==> [3, 3]
tf.reduce_sum(x, 1, keep_dims=True) ==> [[3], [3]]
tf.reduce_sum(x, [0, 1]) ==> 6
------
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
print "cross_entropy:", cross_entropy #y_*tf.log(y)の中身を全部足した数
cross_entropy 23026.0 #最初の学習後の数値
.
.
.
cross_entropy: 3089.6 #最後の学習後の数値
```

クロスエントロピーについてはこちらの記事がとても参考になります。
ニューラルネットワークと深層学習: -無料のオンライン書籍- チャプター３
http://nnadl-ja.github.io/nnadl_site_ja/chap3.html
要はどれだけ学習できているかの指標的なものですかね。
これを参考にしつつ**重み**や**バイアス**を最適化していけば学習成功のようです。
実際の最適化を行っている`tf.train.GradientDescentOptimizer()`ですが、他にも選べるチョイス`class tf.train.Optimizer`がありますので、一度見てみるのも楽しいです。
Tensorflow/api_docs - Optimizers:
https://www.tensorflow.org/versions/r0.7/api_docs/python/train.html#optimizers
追加で`.minimize()`を呼ぶとGradientの計算と`tf.Variables`への適用を一緒に行います。
逆に`.compute_gradients()`を呼ぶことで最適化の際に**重み**`W`や**バイアス**`b`をアップデートするための値、つまりは誤差値/修正値をみることができます。
実際には±大きな数値でスタートしてアッチコッチ行ったり来たりしながら収束していくみたいです。

```py:Gradient_values
#学習初期
cross_entropy 23026.0
grad W[0] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
grad W[380] [ 511.78765869 59.3368187 -34.74549103 -163.8828125 -103.32589722
 181.61528015 17.56824303 -60.38471603 -175.52197266 -232.44744873]
grad b [ 19.99900627 -135.00904846 -32.00152588 -9.99949074 18.00206184
 107.99274445 41.992836 -27.99754715 26.00336075 -8.99738121]
#学習最後
cross_entropy 2870.42
grad W[0] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
grad W[380] [ 6.80800724 1.27235568 -6.85943699 -22.70822525 -17.48428154
 13.11752224 19.7425499 -32.00106812 -41.48160553 79.59416199]
grad b [ 19.52701187 3.17797041 -20.07606125 -48.88145447 -28.05920601
 37.52313232 40.22808456 -34.04494858 -74.16973114 104.77211761]
```
重み`W`に関しては最初のピクセルは完全に無視してるみたいですね...笑
これらの数値はまぁ機械に計算を任せて、我々はゆっくりお茶でも飲んでいるのがいいのではないでしょうか。
#6: 次回はエキスパートを詳しく解説するよっ！
私自身がやりたいことは実はまだ実現できていないのですが... 機械学習は"モノづくり心"を超刺激してくれるのですっかり魅了されてしまいました。 理解が深まるほど、次は"こうしてみよう"、"あーしてみよう"とアイデアが出てきます。
うまくいかないけど楽しい。　なんだろう...この懐かしい感じ。
次はチュートリアルのMNIST エキスパート編を解説したいと思います。
畳み込み、プーリングなどがイマイチわかっていない方にはオススメの内容にしたいです。
ストック、ツイート、いいね、はてぶ、コメントなどなど、全て励みになるのでもしよければお願いします〜。
※2016.3.29追記
エキスパート編の解説書きました。
- [Tensorflowを２ヶ月触ったので"手書きひらがな"の識別95.04%で畳み込みニューラルネットワークをわかりやすく解説](http://qiita.com/tawago/items/931bea2ff6d56e32d693)
※2016.12.08追記
Advent CalenderでLSTMの解説を書きました。
[これを理解できれば自然言語処理もできちゃう？ MNISTでRNN(LSTM)を触りながら解説](http://qiita.com/tawago/items/ad4e30abba9528875908)