プラットフォーム ブランディング

プラットフォーム ブランディング

プラットフォーム ブランディング

IoTの成功事例、コマツの「KOMTRAX」は何がすごいのか : 市況かぶ全力2階建を偶然読んでいた際に紹介されていたので読んでみました。ブランド戦略について体系立てて説明しており、実践における留意点も紹介されていて良書だと思いました。

プラットフォームというと仕事柄身近なのはアマゾン(AWS)やアップル(iOS)だったりするんですが、コマツのKOMTRAXも確かにプラットフォームだと思ったので、そういうプラットフォームの作り方とか仕組みが書いてあるかなと期待して読んでみました。実際にはブランド戦略が主題で、プラットフォームについてはあくまでもブランド戦略の要素として紹介していました。なお、コマツのKOMTRAXについては10行程度しか書かれてませんでしたw

あとがきにも書かれている通りもともとブランディングに関わっている現場担当者向けではなく、(ブランド戦略に理解の浅い)経営者向けに書かれているということもあり、ブランド戦略に登場する概念について基本的な定義から個々の事例の分析、実践方法から歴史まで紹介してくれていて読みやすかったです。また、それぞれのテーマについて深掘りするための書籍も紹介しており、まずはこの本を読んで全体像を掴み、その上で個別のテーマを学ぶのが効率がよさそうに思いました。

本書でも触れられていることですが、色々なものがコモディティ化する中で、ブランド戦略による差別化は必須の要素になってるんだなーと実感しました。今後、仕事において色々考える際に役に立ちそうな印象を持ちました。

ゼロから作るDeep Learning 4章 ニューラルネットワークの学習

前回はゼロから作るDeep Learning 3章 ニューラルネットワーク - n3104のブログです。

4章です。3章では学習済みのモデルを使いましたが、4章ではそのモデルの学習方法について学びます。といっても、実際にニューラルネットワークで学習する際は4章で学ぶ数値微分ではなく5章で学ぶ誤差逆伝播法を利用します。なので、モデルの学習方法というよりはモデルを学習する仕組みについて学ぶと言ったほうが適切かもです。

  • 4.1.1 データ駆動
    • 機械学習はデータが命です。”
      • ほんとその通り。
    • もちろん特徴量の抽出は考えなくて良くなるという建前だけど、元のデータが役に立つ情報を含んでいなければ当然いけないし、ネットワークの設計は残ると思うのだけど。。
      • 画像の識別なら同じネットワークが使えるのかなー。でも、画層の種類は問題によって異なるだろうし、画像の大きさとか階調でも違う気がするんだけど。。
  • 4.2 損失関数
    • 4.1.2 訓練データとテストデータでの汎化能力の説明にあるように1節で1つの概念を説明するようにする構成はとてもいいと思うんだけど、「幸せ指標」はメタファとしてはイケてない気が。。テストの点数ぐらいで良かった気がするんだけどw
  • 4.2.2 交差エントロピー誤差
    • 2 乗和誤差と比べて交差エントロピー誤差はクラスラベルの次元のみ利用するから、分類問題にしか使えないんだろうなー。その分、はっきりと結果が出るんだろうけど。
    • y = logxのグラフで 0 - 1 の区間は -inf - 0 に対応してるから -log すると 0 - inf になるって言うわけかー。
    • “中身の実装では、np.log の 計算時に、微小な値である delta を足して計算しています。これは、np.log(0) の ような計算が発生した場合、np.log(0) はマイナスの無限大を表す-inf となり、そ うなってしまうと、それ以上計算を進めることができなくなります。その防止策とし て、微小な値を追加して、マイナス無限大を発生させないようにしています。”
      • なるほどー。プログラムとして実装する上でのノウハウだなー。
      • delta = 1e-7 となってるけど e-7 が妥当というのはどこから来てるんだろう?
  • 4.2.3 ミニバッチ学習
    • “ただし、最後に N で割って正規化しています。こ の N で割ることによって、1 個あたりの「平均の損失関数」を求めることになりま す。そのように平均化すれば、訓練データの数に関係なく、いつでも統一した指標が 得られます。たとえば、訓練データが 1,000 個や 10,000 個の場合であっても、1 個 あたりの平均の損失関数を求められます。”
      • なるほど。
  • 4.2.4 [バッチ対応版]交差エントロピー誤差の実装
    • cross_entropy_error 関数は分かりやすくするためだろうが delta によるエラー回避のコードが省略されているので、実際に実行するとエラーになったw
    • ndim は配列の次元数だった。
    • reshape を使うことで配列の次元数を変換することも可能。なのでここでは入力が一次元配列の場合に二次元配列に変換している。
    • y.shape[0] はレコード数になる。
    • np.log( y[np.arange(batch_size), t] ) の所は正解ラベルが配列のインデックスと一致するラベル名だから動作するわけであって、他のラベルだと動作しないのだから紹介するのはどうなんだろう。。 ← [2017-04-20 追記] 一般的にエンコードするから問題なかった。

ndimについて

>>> np.array([1, 2]).ndim
1
>>> np.array([1, 2]).shape
(2,)
>>> np.array([[1, 2],[3,4]]).ndim
2
>>> np.array([[1, 2],[3,4]]).shape
(2, 2)
>>> np.array([[1, 2],[3,4]]).reshape(4,1)
array([[1],
       [2],
       [3],
       [4]])
>>> np.array([[1, 2],[3,4]]).reshape(1,4)
array([[1, 2, 3, 4]])
>>> np.array([[1, 2],[3,4]]).reshape(1,4).ndim
2
>>> np.array([[1, 2],[3,4]]).reshape(4,1).ndim
2
>>> np.array([[1, 2],[3,4]]).reshape(4)
array([1, 2, 3, 4])

y[np.arange(batch_size), t] について

>>> # 3行分のダミーデータを作る。
... y = softmax(np.random.rand(3, 10))
>>> y
array([[ 0.07759622,  0.08309147,  0.09904634,  0.07516991,  0.06775452,
         0.13294043,  0.11345575,  0.07123801,  0.150684  ,  0.12902336],
       [ 0.10928588,  0.09100464,  0.09566815,  0.05923705,  0.0791873 ,
         0.08125782,  0.13062538,  0.08983766,  0.14875257,  0.11514354],
       [ 0.10586304,  0.13518227,  0.1316193 ,  0.12738668,  0.06843716,
         0.05849982,  0.13193427,  0.11540083,  0.05508124,  0.07059538]])
>>>
>>> t = np.array([2, 5, 7])
>>> batch_size = y.shape[0]
>>> # [0, 2], [1, 5], [2, 7] のデータが抽出されることが分かる。
... y[np.arange(batch_size), t]
array([ 0.09904634,  0.08125782,  0.11540083])
>>>
>>> y[0, 2]
0.099046337771526632
>>> y[1, 5]
0.081257822450627418
>>> y[2, 7]
0.11540082864090417
  • 4.2.5 なぜ損失関数を設定するのか?
    • “「認識精度」を指標にすべきではないか”
      • 実際に認識精度を指標としてパラメータのチューニングってできるんだっけ?
    • ニューラルネットワークの学習の際に、認識精度を“指標”にしてはいけない。 その理由は、認識精度を指標にすると、パラメータの微分がほとんどの場所で 0 になってしまうからである。”
      • “つまり、パラメータの少しの調整だけでは、認識 精度は改善されず一定のままなのです。もし認識精度が改善されたとしても、その値 は 32.0123…% のような連続的な変化ではなく、33% や 34% のように、不連続のと びとびの値へと変わってしまいます。一方、損失関数を指標とした場合、現在の損失 関数の値は 0.92543…のような値によって表されます。そして、パラメータの値を少 し変化させると、それに反応して損失関数も 0.93432…のように連続的に変化するの です。 ”
      • 書いてあることはその通りなんだろうけど、いまいち腑に落ちないなー。
    • “活性化関数の「ステップ関 数」にも同じ話が当てはまります。”
      • “ステップ関数は「ししおどし」のように、ある瞬間だけ変化を起こす関数でした が、一方、シグモイド関数の微分(接線)は、図4-4 に示すように、出力(縦軸の値) が連続的に変化し、さらに、曲線の傾きも連続的に変化します。つまり、シグモイド 関数の微分はどの場所であっても 0 にはならないのです。これは、ニューラルネット ワークの「学習」において重要な性質になります。この性質――傾きが 0 にはならな い――によって、ニューラルネットワークは正しい学習が行えるようになります。”
      • ここはわりと腑に落ちた。要は極端になるってことなのかなー。。
  • 4.3.1 微分
    • “ここで行っているように、微小な差分によって微分を求めることを数値微分 (numerical differentiation)と言います。一方、数式の展開によって微分を求めることは、解析的(analytic)という言葉を用いて、たとえば、「解析的に 解く」とか「解析的に微分を求める」などと言います。たとえば、y = x2 の微 分は、解析的には、dy = 2x として解くことができます。”
    • 数値微分は中心差分を使うだけでいいんだ。なんて単純なんだ。。!
    • 実際に前方差分のみと中心差分の場合とで比べてみたら、前方差分のみは 0 になってしまったw
def numerical_diff1(f, x):
    h = 10e-50
    return (f(x+h) - f(x)) / h


def numerical_diff2(f, x):
    h = 1e-4 # 0.0001
    return (f(x+h) - f(x-h)) / (2*h)


def function_1(x):
    return 0.01*x**2 + 0.1*x


print(numerical_diff1(function_1, 5))
print(numerical_diff1(function_1, 10))
print(numerical_diff2(function_1, 5))
print(numerical_diff2(function_1, 10))

出力

0.0
0.0
0.1999999999990898
0.2999999999986347
  • 4.3.2 数値微分の例
    • 4.3.1 微分 を確認する際に少し読んでいたので特に気になる点はなかった。
  • 4.3.3 偏微分
    • 説明は分かるんだけど、初めて偏微分見た人は理解が追いつくのかな。。
    • 特に説明してないけど、numerical_diff を使って偏微分を実装している。これで偏微分が出来るのは偏微分する変数以外は定数になってるからだよなー。結果的に偏微分の対象となる変数の微分、つまり微小な変化の極限が出てる。
  • 4.4 勾配
    • “すべての変数の偏微分をベクトルとしてまとめた ものを勾配(gradient)と言います。”
      • そうだったのか!
    • “ひとつ補足として述べるとすれ ば、np.zeros_like(x) は、x と同じ形状の配列で、その要素がすべて 0 の配列を 生成するということです。”
      • いや、そこよりも色々補足必要な気がするw
      • numerical_gradient で勾配が出せるのは、次元毎に中心差分を取ってるから。要は numerical_diff のロジックを再実装している。対象となる次元以外の次元は同じ値になるので結果的に相殺され、対象となる次元の微分、つまり偏微分を出せる。
      • 引数となる x に再代入しているけれど、最後に tmp_val を代入しているのでもとに戻る。とはいえ、処理中に例外発生したら呼び出し元の配列の中身が書き換わるから、この実装方法は結構微妙な気がするんだけど。。機械学習の場合は巨大な行列を扱うこともあるからメモリ節約の観点でわざわざコピーせずにやるのかなー?
    • “この勾配は何を意味しているのでしょうか? そ れを理解するために、f (x0 , x1 ) = x20 + x21 の勾配を図で表してみることにしましょ う。ただし、ここでは勾配の結果にマイナスを付けたベクトルを描画します”
      • マイナスつけてるなら納得。
    • “勾配が示す方向は、各場所において関数の値を最も減らす方向”
      • マイナス付けた場合という但し書きはあってもいい気もするが。要は傾きなので単純な勾配は減らす方向にならない。
  • 4.4.1 勾配法
    • “また、関数が複雑で歪な形をしていると、(ほとんど)平らな土地に入 り込み、「プラトー」と呼ばれる学習が進まない停滞期に陥ることがあります。”
      • なるほどー。確かにこういうケースもありそう。
    • “勾配法は、目的が最小値を探すことか、それとも最大値を探すことかによって 呼び名が変わります。正確には、最小値を探す場合を勾配降下法(gradient descent method)、最大値を探す場合を勾配上昇法(gradient ascent method)と言います。ただし、損失関数の符号を反転させれば、最小値を探す 問題と最大値を探す問題は同じことになるので、「降下」か「上昇」かの違いは 本質的には重要ではありません。一般的に、ニューラルネットワーク(ディー プラーニング)の分野では、勾配法は「勾配降下法」として登場することが多 くあります。 ”
      • 勾配上昇法というものあるんだねー。でも、上昇法だと無限を目指す必要があるから降下法を使うのかなー。 ← [2017-05-19 追記] そういう意味ではなくて上に凸なら勾配上昇法で下に凸なら勾配降下法というだけだった。そもそも、下に凸でもそこが 0 とは限らず、どこまで深いかは関数次第。
    • ニューラルネットワークの学習においては、学習率の値を変更し ながら、正しく学習できているかどうか、確認作業を行うのが一般的です。”
      • 学習率というハイパーパラメーターも残ってたか。。
      • “学習率のようなパラメータはハイパーパラメータと言います。これは、ニュー ラルネットワークのパラメータ――重みやバイアス――とは性質の異なるパラ メータです。なぜなら、ニューラルネットワークの重みパラメータは訓練デー タと学習アルゴリズムによって“自動”で獲得されるパラメータであるのに対し て、学習率のようなハイパーパラメータは人の手によって設定されるパラメー タだからです。一般的には、このハイパーパラメータをいろいろな値で試しな がら、うまく学習できるケースを探すという作業が必要になります。 ”
    • gradient_method.py はカレントディレクトリが ch04 であることを前提としていた。これをIntelliJでやる手順は以下の通り。
      • File -> Project Structure… (Cmd+;)
      • Modules -> Sources タブで ch01…ch08 を選択状態にして Sources ボタンで追加
    • “この実験の結果が示すように、学習率が大きすぎると、大きな値へと発散してしま います。逆に、学習率が小さすぎると、ほとんど更新されずに終わってしまいます。”
      • gradient_descent 関数は init_x の中身を書き換える実装になってた。なので、実際は書き換えない実装にしないと駄目な気もするけど、機械学習の界隈ではそういう割り切りなのかなー。
      • 実際にいくつか試したが、今回だと 1.0 を超えると大きすぎて発散していく。
# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
from gradient_2d import numerical_gradient


def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x
    x_history = []

    for i in range(step_num):
        x_history.append( x.copy() )

        grad = numerical_gradient(f, x)
        x -= lr * grad

    return x, np.array(x_history)


def function_2(x):
    return x[0]**2 + x[1]**2

init_x = np.array([-3.0, 4.0])    

lr = 0.1
step_num = 20
x, x_history = gradient_descent(function_2, init_x, lr=lr, step_num=step_num)

plt.plot( [-5, 5], [0,0], '--b')
plt.plot( [0,0], [-5, 5], '--b')
plt.plot(x_history[:,0], x_history[:,1], 'o')
print(init_x)

init_x = np.array([3.0, 4.0])
lr = 0.95
x, x_history = gradient_descent(function_2, init_x, lr=lr, step_num=step_num)
plt.plot(x_history[:,0], x_history[:,1], 'o')
print(init_x)

init_x = np.array([3.0, -4.0])
lr = 0.01
x, x_history = gradient_descent(function_2, init_x, lr=lr, step_num=step_num)
plt.plot(x_history[:,0], x_history[:,1], 'o')
print(init_x)

plt.xlim(-3.5, 3.5)
plt.ylim(-4.5, 4.5)
plt.xlim(-5.5, 5.5)
plt.ylim(-5.5, 5.5)
plt.xlabel("X0")
plt.ylabel("X1")
plt.show()

f:id:n-3104:20170320165206p:plain

  • 4.4.2 ニューラルネットワークに対する勾配
    • 項のタイトル通り、本当に勾配を1回出すだけで、学習しない。1項1テーマに絞ってるな、ほんと。
    • ネットワークの形は図示したほうがいい気がするけど、それは次節以降で表記してるのかなー。結局、何を求めたかイメージわかない人もいるのでは。
      • 最後まで確認したが、4章の範囲ではネットワークの形は図示しないんだなー。
    • W は np.random.randn で生成しているので、当然毎回結果が異なるwとはいえ、x と t は固定だからある程度傾向は似るんだねー。
    • 一通りコードを追いかけ直したけど、ここのサンプルソースはすごい分かりにくいのでは。。普通に f の引数 W を利用する損失関数にした方が直感出来だった気がする。
      • W に関する勾配を出すわけだから損失関数は W に関する関数である必要がある。で、loss 関数は内部で predict 関数を実行するので、結果的に loss 関数は W に関する関数であると言える。なので、勾配自体は出せる。
        • numerical_gradient 関数で勾配が出せるのは、第2引数が net.W だから。そのため、predict 関数で利用する W の参照が得られるので、numerical_gradient 関数内で前方差分と後方差分を出す際に W の参照を経由して微小量 h が増減する。。
        • “(ここで定義した f(W) という関数の引数 W は、ダミーとし て設けたものです。これは、numerical_gradient(f, x) が内部で f(x) を実行す るため、それと整合性がとれるように f(W) を定義しました)”
          • そうではなくて、ここで net.W を渡さないとそもそも W を変化させて損失関数 f を実行できないから勾配が取得できない。ここは、途中で筆者が混乱したのかなー。simpleNet のコンストラクタで W を指定するのではなくて、predict と loss 関数の引数に W があってもいい気がするんだけど。まぁ、そのなるとクラスにする意味もなくなるけどねー。。
            • ここについては、ほんとにダミーでもよかった。4.5.1 で self.params でアクセスしてた。。。
  • 4.5 学習アルゴリズムの実装
    • 学習について分かりやすくまとまっている。ただ、機械学習について初めてこの本で学ぶ人はどこまで理解できるんだろう。。
  • 4.5.1 2 層ニューラルネットワークのクラス
    • numerical_gradient を見てて思うが、こういう感じで勾配というか W と b の偏微分出せちゃうんだねー。。実際、loss 関数の中で predict 関数を呼び出していて、その中で y を出すために W と b を使って何度か計算してるけど、これを1つの数式にできちゃうもんなー。で、それぞれの偏微分ができちゃうと考えると、確かに数学そこまで分からなくてもコードレベルで理解できるというか、こう書けばいいというのはわかるなー。。
    • 今後 gradient 関数を使うし、numerical_gradient だと計算が遅いからといって、若干天下り的な感じもするねw
    • t = np.random.rand(100, 10) # ダミーの正解ラベル(100 枚分)
      • これ、正解ラベル自体が確率分布っぽくなっちゃうけど、それは問題ないんだっけ?
        • MNISTのデータは1つだけ 1 で他は 0 だった。だよねー。。
>>> np.random.rand(3, 10)
array([[ 0.65365022,  0.63623433,  0.70117989,  0.89724433,  0.82817134,
         0.31230608,  0.34446204,  0.23931909,  0.13342318,  0.67355462],
       [ 0.85156144,  0.10901498,  0.02327781,  0.69283457,  0.13562442,
         0.09658677,  0.32591785,  0.00592776,  0.38647803,  0.91804246],
       [ 0.86498541,  0.03354259,  0.69663751,  0.01011192,  0.1069335 ,
         0.30273103,  0.8269463 ,  0.4885381 ,  0.20540422,  0.9368264 ]])
  • 4.5.2 ミニバッチ学習の実装
    • train_neuralnet.py のソースが描画するグラフは loss ではなくて訓練データとテストデータの正解率の推移だったw
      • loss を表示するようにコードを書いてみたけど、最初から loss の値は 2 ぐらいからスタートしてた。書籍中のグラフはどこから持ってきたw?
  • 4.5.3 テストデータで評価
    • “エポック(epoch)とは単位を表します。1 エポックとは学習において訓練 データをすべて使い切ったときの回数に対応します。たとえば、10,000 個の 訓練データに対して 100 個のミニバッチで学習する場合、確率的勾配降下法を 100 回繰り返したら、すべての訓練データを“見た”ことになります。この場 合、100 回= 1 エポックとなります。”
      • 分かりやすい。要は訓練データを一通り学習し終えたら1エポック。で、イテレーション数自体はエポックというか訓練データのサイズは考慮しないでバッチサイズと一緒に指定するっぽい。言われてみると、いままでもそんな感じだったかも。
    • train_neuralnet.py は 4.5.3 のソースということか。

個人的には数値微分の実装で興奮しました。こんな簡単に実装できるんですね!

次回はゼロから作るDeep Learning 5章 誤差逆伝播法 - n3104のブログです。

ゼロから作るDeep Learning 3章 ニューラルネットワーク

前回はゼロから作るDeep Learning 2章 パーセプトロン - n3104のブログです。

最近やっと5章まで読み終わりました。前回からだいぶ時間が空いてしまいましたが3章のメモをブログにしました。ついに実際に予測します。といっても学習済みのモデルを使いますけどもw

  • 3.1.3 活性化関数の登場
    • 図 3 - 4 活性化関数によるプロセスを明示的に図示する
      • すごい分かりやすい!
    • “「パーセプトロン」という言葉が指すアルゴリズムは、本書では厳密な統一がな されずに使われています。一般的に、「単純パーセプトロン」といえば、それは 単層のネットワークで、活性化関数にステップ関数(閾値を境にして出力が切り 替わる関数)を使用したモデルを指します。「多層パーセプトロン」というと、 それはニューラルネットワーク――多層で、シグモイド関数などの滑らかな活 性化関数を使用するネットワーク――を指すのが一般的です。 ”
      • なるほど。
  • 3.2 活性化関数
    • “つまり、活性化 関数の候補としてたくさんある関数の中で、パーセプトロンは「ステップ関数」を採 用しているのです。パーセプトロンでは活性化関数にステップ関数を用いているなら ば、活性化関数にステップ関数以外の関数を使ったらどうなるのでしょうか? 実は、 活性化関数をステップ関数から別の関数に変更することで、ニューラルネットワーク の世界へと進むことができるのです! ”
      • なるほど。この本は概念の説明が丁寧で分かりやすいなー。
  • 3.2.3 ステップ関数のグラフ
    • plt.ylim(-0.1, 1.1) を指定しないとy軸が0-1となり、グラフがただの直線になってしまうw なので、上下に余分に 0.1 ずつ広いy軸にしている模様。
  • 3.2.4 シグモイド関数の実装
    • “シグモイド関数の実装が NumPy 配列に対応していることは、NumPy のブロー ドキャストに秘密があります(詳しくは「1.5.5 ブロードキャスト」を参照)。ブロー ドキャストの機能により、スカラ値と NumPy 配列での演算が行われると、スカラ値 と NumPy 配列の各要素どうしで演算が行われます。”
      • NumPy便利!
  • 3.2.5 シグモイド関数とステップ関数の比較
    • こういうことを説明することにとても好感を覚える。概念を説明しようとしていることが伝わってくる。
  • 3.2.6 非線形関数
    • “活性化関数の説明では、「非線形関数」「線形関数」という用語がよく登場しま す。そもそも関数は、何かの値を入力すれば何かの値を返す「変換器」です。 この変換器に何か入力したとき、出力が入力の定数倍になるような関数を線形 関数と言います(数式で表すと h(x) = cx。c は定数)。そのため、線形関数 はまっすぐな 1 本の直線になります。一方、非線形関数は、読んで字のごとく (「線形関数に非ず」)、線形関数のように単純な 1 本の直線ではない関数を指し ます。”
      • 分かりやすい。
    • “なぜ線形関数を用いてはならないのでしょうか。それは、線形関数を用いると、 ニューラルネットワークで層を深くすることの意味がなくなってしまうからです。 ”
      • ここ、同じように非線形関数の場合で説明が欲しい。y(x) = c × c × c × x とあるが、c が異なる定数の場合はどうなる?
  • 3.3.3 ニューラルネットワーク内積
    • あくまでの出力は行ベクトルで、ノードは行列になるのか。
  • 3.4 3 層ニューラルネットワークの実装
    • ここも分かりやすいなー。各層の入力と活性化関数の分けて記述し、活性化関数の隠れ層と出力層での役割の違いについても明記していて、概念の共通点と差分が把握しやすい。
    • バイアス項ってノード毎に違うんっだっけ? ← 違う。ノード毎に学習する。
  • 3.5.1 恒等関数とソフトマックス関数
    • 恒等関数の場合はノードって1つにするのかな?複数ある場合、どれを採用すればいいかわからないよね。画像みたいにそれぞれの要素をビットマップの各インデックスや色に対応させてるなら別だけど。
  • 3.5.2 ソフトマックス関数の実装上の注意
    • なるほどなー。式変換てほんと重要だなー。
  • 3.5.3 ソフトマックス関数の特徴
    • “また、ソフトマックス関数の出力の総和は 1 になります。さて、この総和が 1 になるという性質ですが、これはソフトマックス関数の重要な性質です。この性質の おかげでソフトマックス関数の出力を「確率」として解釈することができます。”
      • 実際に確率であるわけではなくて、確率であるとみなすが正しい?
    • ニューラルネットワークのクラス分類では、一般的に、出力の一番大きいニューロ ンに相当するクラスだけを認識結果とします。そして、ソフトマックス関数を適用し ても、出力の一番大きいニューロンの場所は変わりません。そのため、ニューラル ネットワークが分類を行う際には、出力層のソフトマックス関数を省略することがで きます。実際の問題では、指数関数の計算は、それなりにコンピュータの計算が必要になるので、出力層のソフトマックス関数は省略するのが一般的です。”
      • そーなんだ!確かに分類したいだけなら数値要らないしなー。
  • 3.6.1 MNIST データセット
  • 3.6.2 ニューラルネットワークの推論処理
    • 学習済みのモデルを使うのであまり実感はわかないかも。でも、最終形を先に示すという意味ではいいのかも。
  • 3.6.3 バッチ処理
    • NumPyの素晴らしさが分かってきた。これは便利だなー。

個人的には活性化関数を明示してるのが分かりやすいなーと思いました。Python機械学習プログラミング 達人データサイエンティストによる理論と実践 impress top gearシリーズで単純パーセプトロンを読んだ際はよくわからなかったので。ただ、5章 誤差逆伝播法 まで読むとニューラルネットワークでは活性化関数は意識するの当然なんだと思ったりもしました。そもそも活性化関数レイヤとして実装するので。

次回はゼロから作るDeep Learning 4章 ニューラルネットワークの学習 - n3104のブログです。

悪いヤツほど出世する

悪いヤツほど出世する

悪いヤツほど出世する

なんとなくネットで見かけて、アマゾンの説明とレビューが良さげだったので読んでみました。レビューの通りで「なるほどねー」とか「そうだよねー」と言いたくなる感じの内容で、若干くどいというのもその通りだと思いましたが、良書だと思いました。

内容としてはリーダー神話は神話であって現実とは異なるということについてひたすらエビデンスを示しながら解説し、読者にはその前提に基づいて行動することを勧めていました。つまり、リーダー神話に存在するようなリーダーはほぼ実在せず、現実のリーダーが嘘をついてもそれほど罰せられることもないので、リーダーシップ教育産業の言葉に惑わされないように気を付けよという内容でした。

自伝とかリーダーシップ?に関する本は多少なりとも読んでいて、ほんとにそんな理想論でうまくいくのかなー?と以前から思っていたので、そういう意味ではとてもスッキリする本でした。

ゼロから作るDeep Learning 2章 パーセプトロン

最近、ゼロから作るDeep Learningを読んでます。現時点で4章まで読み終えてますが、ほんと読みやすいと思います。筆者が分かりやすく伝えようとしている熱意を感じる気がしていて、この方が他の書籍も出されたら是非読んでみたいと思ってます。

で、今回は2章 パーセプトロンです。読み終えてからエントリーを書くでもいいかなと思ってたいたのですが、手元のメモのボリュームが結構増えたこともありますし、この本の読書会もやってるのでそのメンバー向けに共有する意味でも、章ごとにエントリーを書こうかなと思いました。

ということで、以下2章に関するメモです。

  • 2.1 パーセプトロンとは
    • “本書では、0 を「信号を流さない」、1 を「信号を流す」に対応させて記述します。”
  • 2.3.3 重みとバイアスによる実装
    • “ここで −θ をバイアス b と命名しましたが”
      • (2.1) 式においてθを閾値としていたが、(2.2) 式においては 0 を敷居としており、b を右辺に移行すると -b となるので前述のように説明している模様。
  • 2.4.2 線形と非線形
    • “パーセプトロンの限界は、このように 1 本の直線で分けた領域だけしか表現できな い点にあります。図2-8 のようなクネッとした曲線をパーセプトロンでは表現できな いのです。” -> 2.5 多層パーセプトロンならできる。
    • “線形・非線形という言葉は機械学習の分野でよく 耳にしますが、イメージとしては図2-6 や図2-8 のようなものを頭に浮かべることが できます。”
      • 線形性とは違う認識でいい?線形=直線=1次関数で非線形は二次関数以上。 ← 3.2.6 非線形関数に説明があるように線形関数は直線でいい。一方で非線形関数は二次関数だけでなくシグモイド関数やステップ関数もある。
  • 2.6 NAND からコンピュータへ
    • “コンピュータの内部ではとても複雑な処理を行っているように思えますが、実は (驚くかもしれませんが)NAND ゲートの組み合わせだけで、コンピュータが行う処 理を再現することができるのです。”
    • “理論上 2 層のパーセプトロンであればコンピュータを作 ることができる、と言えます。というのも、2 層のパーセプトロン(正確には活性化 関数に非線形なシグモイド関数を用いたもの:詳細は次章を参照)を用いれば、任意 の関数を表現可能であることが証明されています。しかし、2 層のパーセプトロンの 構造で、適切な重みを設定してコンピュータを作るとなると、それはとても骨の折れ る作業になるでしょう。”
      • すげーな。。

2章に関してはあまりメモがなかったですね、そういえば。。そもそも2章は分量少ないですし、Python機械学習プログラミング 達人データサイエンティストによる理論と実践 impress top gearシリーズについても別途読書会を実施していて、そちらでパーセプトロンについては勉強してたので、別の切り口で説明していて理解が深まったという感じでした。

次回はゼロから作るDeep Learning 3章 ニューラルネットワーク - n3104のブログです。

2016年振り返り

2016年について振り返ってみたいと思います。ちなみに、去年は2015年振り返り - n3104のブログでした。

マネージャー職になった

2015年からビッグデータチームの立ち上げやデータ分析チームの立ち上げなどチームのリーダーという役職はやっていたのですが、2015年の5月からメンバーズという自社サービスを開発していくチームのマネージャーになりました*1。また、10月からの3ヶ月間だけでしたがアーキテクトグループというグループのマネージャも兼務していました。

リーダーやマネージャーという名前は会社によって意味は違うでしょうが、今までよりもチームの育成みたいなことについて取り組めたのはいい経験になっているかと思います。自分の中でこうやれば上手くいくだろうという仮説があっても、実際にその立場になって実践してみないことには上手くいくかどうかは確認できないので。チームの目的の共有や3ヶ月毎の振り返り、発生した課題に対応するという後手の状態から未然に防ぐ先手を打つような取り組み方についてメンバーに共有することが出来たと思うので、これから半年、1年後の結果がどうなるか楽しみです。

後はマネージャー職ということで評価もやるようになるのですが、評価する経験は今までになかったので怖さもありますが勉強できるという意味では楽しみだったりもします。評価ってほんと難しいと思っていて、評価は何を頑張って欲しいかというメッセージになるという認識でいます。そのため、間違えた評価制度や評価方法を採ると、本来の意図とは間違った方向にみんなが頑張ることになるので、全体のパフォーマンスを上げるような評価ってとても難しいと考えています。同時に、給与の原資は限られているので、全員が満足するような評価ができることはほぼないとも思っていて、だからこそ難しい評価というものをする側の経験をできるのは楽しみであると同時に怖さも感じています。まぁ、やってみないことには課題には気づけないでしょうから、まずは経験して少しずつ上手く出来るようになりたいと考えています。

それと、マネージャー職は打ち合わせだらけというのはよく聞く話だったのですが、ほんとに打ち合わせだらけになりましたね。アーキテクトグループマネージャーと兼務していた10月以降は月の7割以上が打ち合わせやトラブル対応になっていて、自分自身が担当している業務もあったりしたので、打ち合わせの合間の1時間で調査したり、コード書いたりするみたいな感じで、結果としてまったくブログが書けませんでした。。今年からはサービス開発グループのマネージャーのみになったので、自由に使える時間が増える分、(会社)ブログは再開したいと思ってます。

Hadoop

自社サービスのチームに移るタイミングで既存のHadoopを利用した集計バッチのリプレースを実施し、以降は保守/運用もやっています。前職から2年ぶりぐらいに日常的にHadoopに触れるようになりました。といっても、リプレースの時期は毎日のように触っていましたがリリース後は安定稼働しているのでたまにサービスメニューの追加に合わせた改修作業をする以外はほとんど触らないですがw

前職ではジョブフローの制御にBashを使っていたのですが、例外処理等が面倒だったので今回はPythonを使ってみました。結果的には成功だったと思います。AWS APIの呼び出しもBoto3経由で出来るのでBash+AWS CLIよりはかなり楽に実装できたと思いますし、保守も楽になったと思います。

他にもEMRの導入コンサル案件やAWSサポート業務の一環としてEMR関連のサポート案件を何件かやりました。Sparkについても調査用にSpark Shellは日常的に使うようになりました。

今年は集計バッチをHiveベースからSparkベースに移行するのはやってもいいかなと思ってます。処理の性質的にSparkの方が向いてそうなのと保守性も良くなりそうな印象があるので。処理時間も短縮できるしAWS利用費も下げられると予想してます。後はSparkのランタイム周りは結構謎なので、調査しても面白いかなと思ってます。何冊か書籍も読んだんですが、アプリケーションフレームワークとしてのSparkについて書かれている本はあっても、象本みたいにランタイム周りについて書いてある本がなかったので(実際に運用まですれば分かることなのかもですが)。

機械学習

本格的に取り組みはじめて1年半ほど経ち、去年と比べてもかなり理解が進んだと思っています。そこに知能があったりするわけではなくて、単に計算してるだけだと言うのが分かりました。あと数学、具体的には線形代数微積分を理解しないとどうにもならないことも良くわかりました。社内の読書会を継続しているおかげで最近だと正則化が何をしているとか線形分離できない問題を非線形変換して線形分離するという考え方もイメージとして理解できるようなり、とても楽しいです。

機械学習関連だと以下を読みました。

今後も機械学習の勉強は単純に面白いので継続するつもりです。あと今年は ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 も読むつもりなので、DNNでどうやってネットワークを設計するのか学んで以下みたいなことをやってみたいと思ってますw

後は機械学習を勉強していて思うのは、最近の機械学習関連や分散処理のブレイクスルーは結局ハードウェアの進化に起因してるんだなーと思うようになりました。元々Hadoopを学んでいた頃から漠然と思っていたことではあるんですが、読書会に80年代ぐらいに大学で機械学習を勉強していた方が参加してくれていて、実感を持つようになりました。具体的にはなんでこんな単純な理論でやってるのかみたいな話になることがよくあって、それは当時のハードウェアが貧弱すぎてそうせざるを得なかったみたいな話になります。結局ソフトウェア関連の理論自体は80年代ぐらいまでに出ていても、当時のハードウェアのスペックが貧弱すぎて検証できなかったわけで、それが最近の進化でやっと検証できるようになり、検証できるようになったので実用化されるようになったのだと。なので、今後も実用化される技術を調べたければ80年代ぐらいの論文を漁ったりすると面白いんだろうなーと思ってます。

SICP

まったく偶然ですが社内でSICPの読書会も始めました。隔週で毎回1時間でやっていて、2016年の間に19回やって2.2.3 公認インターフェースとしての並びまで来ました。問題も基本的に全て解いていて、恐らく読み終わるのにあと1年以上掛かると思いますw

私はLISPで書くのがどうしても馴染めず、途中からPythonで問題を解いてるんですが、cons/car/cdr/list/map/filterなどの標準関数もPythonで再実装することになり、おかげで言語仕様の違いとかも分かって勉強になりました。2016年に今更SICPを勉強することに意味があるかは正直わかりませんが*2、楽しいので続けるつもりです。現時点での成果は以下ぐらいですがw

  • LISPのリストは一方向リンクリストしかない。他言語の配列やリストはなんて便利なんだろう。。!
  • 再帰的な構造について意識するようになったというか、再帰の問題しかないw
  • LISPのコードでもPythonで書き直せば理解できるという安心感を得た
  • LISPのコードは宣言的でSQLみたい。まぁ、LISP式なので当たり前なのだけど
  • デバッグ辛すぎる。手続き的アプローチと宣言的アプローチは適材適所で使い分けしよう!

Python

もともと機械学習Pythonがよく使われているので勉強したいと思っていたら、ちょうど集計バッチのリプレースがあったので未経験だったのですがPython使ってみました。その後、SICPでもPython使うようになり、とりあえずコード書くだけならさくっと書けるようになりました。いやー、Pythonいいですね。とても言語仕様がシンプルで書きやすいし、標準ライブラリも充実していて大抵のことは出来るので。

新しい言語を学ぶと比較軸を増やせて、結果として言語そのものやプログラミングへの理解が深まるので、今年も1つぐらい学べるといいなと思ってます。

その他

一時期忙しすぎてSAN値が下がったので8月ぐらいから1年ぶりぐらいにラノベ読んだり、10年ぶりぐらいにゲーム機でロープレやったりしてたら、最後はアマゾンプライムでアニメ観まくるようになりましたw ただ、QOLは急上昇したので、今年はうまくバランスを取りながら付き合っていくつもりです。Kindleも試しに買ってみたら思ったよりも読みやすくて技術書以外はKindleでもいいかなと思うようになりました。

プライムはほんとひどくて、SAOを12月から観はじめて、そのままデュラララを年末までに観終わり、最後にシュタインズ・ゲートは正月休み中に観終わっていて、3作で1ヶ月ぐらいしかかかっていないのがなんとも。。そして1/9時点で化物語の10話まで観終わっているという。。。

まとめ

振り返ってみると、2016年も変化の大きくて密度の高い1年だったと思います。後半は打ち合わせばかりしてて、自分がプレイヤーとして担当している仕事をあまり進められませんでしたが、そちらも今年は改善すると思うので上手くバランスを取って進めたいと思います。あと、読書会に3つ参加していましたが、勉強するリズムを維持できるので今後も続けたいと思っています。

ちなみに、2016年の振り返りをするためにクラスメソッドに入社してから更新していなかった職務経歴書を3年分更新したら案件数が 20 -> 65 に増えてました。。w*3

  • 入社前:20案件(約12年)
  • 入社後:45案件(約3年)

おかげで並行で案件を回したり、新規のお客様と話すのはかなり慣れたと思います。今後は自社サービスの開発チームが主体なので社外のお客様向けの仕事をする機会は減ると思いますが、勘が鈍るのである程度は定期的に社外の案件もやっておければと思ってます。

*1:正確には5月時点ではそういうチームができてリーダーになりました。そのチームがそのまま2017年1月にグループとして独立してマネージャーになり、やってることは大差ないのでマネージャーと書いています

*2:バークレイのカリキュラムもLISPからPythonに変わってるみたいですし。。 CS 61A Fall 2016

*3:この更新作業で年末休みを使い切り、振り返りが年明けになりましたw

ITエンジニアのための機械学習理論入門

ITエンジニアのための機械学習理論入門

ITエンジニアのための機械学習理論入門

社内の読書会が終わりました。毎週1時間で全18回でした。5ヶ月弱です。一言で言うと非常に読みやすかったです。今まで何冊か機械学習の入門書を読んでいましたが、理論的なアプローチについて体系立てて、かつ、分かりやすく書かれていたと思います。同じテーマについて複数の手法を適用し、その差についても説明されているので、全体像も把握できるのがよかったです。数式も数学徒の小部屋というコラムで導出過程について説明されており、同僚の助けもあって何とか読める感じでした。以下、メモです。

  • 統計学のための数学入門30講 (科学のことばとしての数学)を読んでいたおかげで数式は読めた。微積線形代数と統計の基本的な知識(正規分布など)は知らないと読んでも面白く無いと思う。
  • 話のわかりやすさを優先して、一部定義が曖昧だったり省略されていると感じる部分はあった。そういう箇所は気にせず読み飛ばして、筆者が全体として言いたいことだけ読み取るで良いと思った。何度か遭遇し、読書会のメンバーで悩んでも結論が出なかったのでw
  • 改めてモデルを理解することは重要だと感じた。仕組みがわかれば向き/不向きも分かるので、とりあえずデータ集めて適当なモデルにぶち込んでとやっても精度出るわけないよなーと再認識した。既にみんなが取り組んでいるタスクでセオリーも存在し、素性と利用するモデルも分かっている場合はいいだろうけど。
  • 読書会として読んでよかった。一人で読むと数式で心が挫けたり、読みやすいのでなんとなく理解した気になって読み飛ばしていたところがかなりありそうな感じだった。
  • 数式はノートに写しながら導出過程を理解するのがいいかと考えていたけれど、同僚から計算結果だけを見て利用するスタンスでもいいのではと言われたのは結構衝撃だった。実際に深層学習 (機械学習プロフェッショナルシリーズ)を少しだけ読んだら計算の流れは似ていて、導出過程が分からなくとも結果となる数式の意味が分かればそれなりに読める感じだった。
  • ソースコードがついているので実際に試せるのもよかった。ただ、ソースはあまり読みやすい感じではない気もした。

ということで、来週からはPython機械学習プログラミング 達人データサイエンティストによる理論と実践 (impress top gear)に取り組みます。Pythonでさくっと機械学習スクリプトを書けるようになるといいなと思ってます。

あと、参考までに読書会のメモについて以下に貼っておきます。ノートにとっていた数式のメモは貼るのが大変なので割愛します。あと、記号は意味がわかればいいと割り切りそれっぽくメモしたのでその辺りはご了承下さい。

  • 主な数学記号と基本公式
  • 2.1.4
    • E(RMS)とあるが、数式でEのrmsと書いてるからか
  • 2.1.5
  • 2.2.4
    • M=9でもいいのでは?
      • 精度が変わらないならパラメータは小さい方がよいという基準があるのでは。赤池情報量規準
      • おそらく、M=40とかになると過学習になるのでは
      • M=9でもM=3とほぼおなじ値になってM4以降の係数は小さくなるはず。実際、M=9のグラフがぐにゃぐにゃしていない
  • 3.1.3
    • 最小二乗法は最尤推定法の中でも、正規分布の誤差を仮定した特別な場合に対応するとみなせる
    • 03-maximum_likelihood.py ではWの値はコンソールに出力されないが、02-square_error.pyに記述されている print df_ws.transpose() を追記すれば出力される
  • 3.2.2
  • 3.2.3
    • 一致性はデータ数を大きくすると真の値に近づいていくこと
    • 不偏性は何度も推定を繰り返した際に、推定値の平均が真の母数に近づいていく。不偏性がある場合は、データ数が少ない場合に真の母数からはずれる可能性があるが、大きい方にはずれる場合と小さい方にはずれる場合が均等にある。
  • 3.3.2
    • 標本分散がずれるのは、「NS2n/σ2が自由度N-1のx2分布に従う」という事実に関係する。そもそも、標本分散S2nは正の値しか取らないため、散らばり具合が対称な形にならない
    • 不偏分散はN/(N-1)倍したものなので、データの散らばり具合は対象な形にならない
    • 不偏推定量というのは、あくまでも「多数の推定を繰り返した際の平均値」についての性質であって、1回の観測に基づく推定値の正確性を示すものではない
  • 4.1
  • 4.1.1
    • (4.2)は普段見ている一次関数。f(x,y)=1 とかだと、それは切片(w0)
    • 直線上は不正解としている?
      • そもそも直線上を正解にできない手法。そうしないとその後の計算を透過的に扱えない。
  • 4.1.2
    • Σは判定に失敗したものだけなので、式に補足があってもいい気がする。
  • 4.1.3
  • 4.2.1
    • 4.30 式
      • もっと効率のよい方法はあるのか?
        • xとyのデータの分布に依存する?
        • 正規化すれば問題ない?
      • xとyのオーダーが異なる場合はどうなる?
        • xとyにはバイアス項のようなものはつけられない。xとyは移動する距離が決まっている。一方cは任意なので計算する意味がありそう。
    • w0は増え続けたりしない?
      • tが + / - 両方あるので大丈夫。
    • 局所解に陥ることはある?
      • 収束したかどうかの判定条件に1つもエラーがないことがあるので、大域解に至るといえるのでは。
  • 4.2.3
  • 5.1.1
  • 5.1.3
    • 計算コストで比較するとどうなのか?
    • 現実的にあえてパーセプトロンを使うケースはあるのか?
      • 次元が多くなると逆行列あるし、大変なのでは。
    • 収束速度に差はあるのは?
    • 必ず 1 や 0 になる?そもそもロジスティック関数は距離が離れていれば 0 や 1 になるだろうが、近ければ 0.4 や 0.6 になるのでは?
  • 5.2.3
    • 下回るなら反転すればいいから、実際は学習してるはずw
    • 階段みたいな線になったら、それはデータを増やせば直線になるはず。
    • 最初下回って、途中から上回るみたいなのがあれば、そこで線を引いて反転させれば応用としては使えそう。
  • 5.3
  • 6.1
  • 6.2
    • k近傍法も使える場面あるのでは。
  • 7.1.1
    • なぜこれで上手くいくのかという説明を構築するモデルが必要
  • 7.1.2
    • あくまで1ピクセルごとが独立しいて、それぞれのピクセルが一致する確率を出しているだけ。なので掛け算。
    • 画像として考えるから分かりにくいが、画像同士が一致しているというよりは順序が固定されたトレーニングセットを前提として最尤推定している。なので、画像を横に並べた1つの大きな画像と一致する確率と捉えても問題ない。
  • 7.2.1
  • 7.2.2
    • 7.14 画層生成器毎の確率Pνk(X)にπを掛けているから。
  • 8
  • 8.1.2
    • 図8.4の偽陽性の箱が小さすぎる。
    • ベイズ定理のメリットって?
      • ひっくり返せるのがメリット。(8.10)とか(8.15)
  • 8.1.3
    • (8.25)は確率。正規分布がある前提でのtとなる確率
    • 分散はどうやってでる?
      • 8.1.4ででるのでは?- 8.1.3
    • p221"観測するデータ数Nが十分に大きくなると、事前分布の影響はなくなって、μNはμNbarに一致する。言い換えると、トレーニングセットのデータが十分に得られるなら、事前分布は多少適当に設定しても構わない"
      • 事前分布の分散は適当でも大丈夫。
      • 十分なデータ数はどの程度?サンプルではN=100でも十分な感じ。
  • 8.1.4
    • (8.50)で分かっている前提の分散に収束するというのが書いてあるので、あくまで分散は分かっている前提だった模様。
      • ベイズ推定の雰囲気を理解するのが趣旨なので、分散については分かっている前提で書いてあるのかも。
    • 08-bayes_normal.py
      • あくまでデータ件数が少ないと事前分布に引きづられると言いたいだけで、分散を出せると言いたいわけではない。
      • 実際 33 行目で真の分散を計算式に代入している。
        • mu_N = (beta_true * mu_ML + beta_0 * mu_0 / n) / (beta_true + beta_0 / n)
  • 8.2.1
    • (8.65) は右辺がない場合は最小二乗法とおなじになる。そして右辺がある場合は最小化するために左辺のf(Xn)の中のWも含めて小さくなるという意味。要はαの大きさでWの大きさを調整できるということが言いたい。
  • 8.2.2
    • (8.69)はどうやって出す?
  • 8.2.3
    • 図 8.9
      • オーバーフィッティングはM=9、α-1=10000でも図3.5のM=9のようになっていないという意味。
      • 観測点から離れるほど分散が大きくなっていることが分かる。
    • 図 8.10
      • Wを4つ適当に選出しても、データ数が多くなれば分散が小さくなるので問題ない事がわかる。
      • 8.9 はあくまでも観測データの話。