Osomaki67のブログ

個人的な備忘録兼日記にしたいと思います。

AI 事始め16:CS231n:Module 1: Neural Networksの例題

 

 

 

 

Putting it together: Minimal Neural Network Case Study

minimal 2D toy data example : see https://cs231n.github.io/neural-networks-case-study/

自分が理解できるようにコメントを追加していきます。

In [1]:
# A bit of setup
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline
                  # magic command:To enable the inline backend for usage with the IPython Notebook:
plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots
                  #figsize : tuple of integers, optional, default: None
                  #width, height in inches. If not provided, defaults to rcParams["figure.figsize"] = [6.4, 4.8].
plt.rcParams['image.interpolation'] = 'nearest'
                  #補間の方法を指定します。
                  #   see https://matplotlib.org/gallery/images_contours_and_fields/interpolation_methods.html
                  #   see  http://cyanatlas.hatenablog.com/entry/2018/06/20/144937
plt.rcParams['image.cmap'] = 'gray'   # grayの諧調で表現する
                  #see  https://jp.mathworks.com/help/matlab/ref/colormap.html
                  #https://matplotlib.org/tutorials/colors/colormaps.html?highlight=colormap%20name
# for auto-reloading extenrnal modules
# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython
%load_ext autoreload
                  # magic command:Load an IPython extension by its module name.
%autoreload 2
                  # magic command:Reload all modules (except those excluded by %aimport) 
                  #     every time before executing the Python code typed.
 

線形に分離できない分類データセットを生成します。私たちの好きな例は、次のように生成できるスパイラルデータセットです。

玩具のスパイラルデータは、線形に分離できない3つのクラス(青、赤、黄)で構成されています。

In [2]:
np.random.seed(0)
N = 100 # number of points per class
D = 2   # dimensionality
K = 3   # number of classes
X = np.zeros((N*K,D))
y = np.zeros(N*K, dtype='uint8')
for j in xrange(K):
  ix = range(N*j,N*(j+1))   #サンプル番号 Class0:0-99, class1:100-199, class2:200-299
  r = np.linspace(0.0,1,N) # radius;numpy.linspace(start, stop, num = 50, endpoint = True, retstep = False, dtype = None)
                           # 0から1までを100個に等分した数列を作成する。
  t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 # theta
                           # Class0:0-3, class1:4-7, class2:8-11 を100個に等分し、乱数を加えた数列
  X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]   #多次元配列の結合を行うオブジェクト
  y[ix] = j                #ラベル(正解)
fig = plt.figure()         # Figureのインスタンスを生成
sc=plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)   # 散布図 (Scatter plot) を描く 
                                                                    #色はラベル(正解)の値を使用
          #    x   ,   y    ,色  ,サイズ,カラーマップ
          #                  色0:   色1:   色2: は自動的にアサインされるようだ。カラーマップを表示してみた。  
          #                  カラーマップ       
plt.xlim([-1,1])  # グラフの横軸、縦軸を調整する。
plt.ylim([-1,1])  # グラフの横軸、縦軸を調整する。
plt.colorbar(sc)             #カラーマップを表示してみた。  
#fig.savefig('spiral_raw.png')
Out[2]:
<matplotlib.colorbar.Colorbar at 0xe26c978>
 
 

Softmax線形分類器のトレーニン

次に、これは線形分類器なので、すべてのクラススコアを単一の行列乗算と非常に簡単に並列に計算できます。線形分類器のパラメータは、各クラスの重み行列W、およびバイアスベクトルbです。この例では300の2次元点があるので、この乗算の後に配列のscoresサイズは[300 x 3]になります。各行は3つのクラス(青、赤、黄)に対応するクラススコアを示します。

\( f(x_i,W,b) = Wx_i + b \) ⇒ scores = np.dot(X, W) + b

2番目に重要な要素は、損失関数です。この例ではSoftmax分類器に関連するクロスエントロピー損失を使用できます。

$$L_i=-\log\frac{\mathrm{e}^{f_{y_i}}}{\sum_{j} \mathrm{e}^{f_j}}$$

\( \mathrm{e}^{f_{y_i}} \) ⇒ exp_scores = np.exp(scores) 

\( {\sum_{j} \mathrm{e}^{f_j}} \) ⇒ np.sum(exp_scores, axis=1, keepdims=True)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K]

\( L_i \) ⇒ corect_logprobs

Softmax分類器の完全な損失は、トレーニング例と正規化との平均クロスエントロピー損失として定義されることを想起してください。
$$L=\frac{1}{N}\sum_{j}L_i + \frac{1}{2}\lambda\sum_{k}\sum_{l}W_{k,l}^2$$   

\( \frac{1}{N}\sum_{j}L_i \) ⇒ data_loss = np.sum(corect_logprobs)/num_examples

\( \frac{1}{2}\lambda\sum_{k}\sum_{l}W_{k,l}^2 \) ⇒ reg_loss = 0.5*reg*np.sum(W*W)
loss = data_loss + reg_loss
このlossを小さくするために、先に定義したprobsを変数 \(p \) にコピーして、微分値を求める。
$$p_k = \frac{\mathrm{e}^{f_k}}{\sum_j\mathrm{e}^{f_j}} \quad\quad\quad L_i = -\log(p_{y_j})$$


probs ⇒ dscores ⇒ \( p \)     

\( \frac{\partial L_i}{\partial f_k}=p_k - 1\quad(y_i=k) \)      ⇒ dscores[range(num_examples),y] -= 1     

 

 

In [3]:
#Train a Linear Classifier

# initialize parameters randomly
W = 0.01 * np.random.randn(D,K)   # Wのサイズは、(2,3)
b = np.zeros((1,K))               # bのサイズは、(1,3)
     #  X = np.zeros((N*K,D))       Xのサイズは、(1,2)が300個
# some hyperparameters
step_size = 1e-0
reg = 1e-3 # regularization strength; In this code, the regularization strength λ is stored inside the reg. 
           # 正則化過学習を抑えるための重要な手法です。
# gradient descent loop
num_examples = X.shape[0]   # 配列の大きさ
for i in xrange(200):
  
  # evaluate class scores, [N x K] この例では300の2次元点があるので、
  #この乗算の後に配列のscoresサイズは[300 x 3]になります。
  #各行は3つのクラス(青、赤、黄)に対応するクラススコアを示します
  scores = np.dot(X, W) + b #
  
  # compute the class probabilities
  exp_scores = np.exp(scores)
  probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K]
                                         ## axis=1 Compute sum of each row;
    #keepdims=True
    #If this is set to True, the axes which are reduced are left in the result as 
    #dimensions with size one. 
    #With this option, the result will broadcast correctly against the input array.
  # compute the loss: average cross-entropy loss and regularization
  corect_logprobs = -np.log(probs[range(num_examples),y])
  data_loss = np.sum(corect_logprobs)/num_examples
  reg_loss = 0.5*reg*np.sum(W*W)
  loss = data_loss + reg_loss
  if i % 10 == 0:
    print "iteration %d: loss %f" % (i, loss)
  
  # compute the gradient on scores
  dscores = probs
  dscores[range(num_examples),y] -= 1
  dscores /= num_examples
  
  # backpropate the gradient to the parameters (W,b)
  dW = np.dot(X.T, dscores)      #転置行列は行列にTをつけるだけ
  db = np.sum(dscores, axis=0, keepdims=True)
                       # axis=0 Compute sum of each column
  dW += reg*W # regularization gradient
  
  # perform a parameter update
  W += -step_size * dW
  b += -step_size * db
 
iteration 0: loss 1.096919
iteration 10: loss 0.917310
iteration 20: loss 0.851535
iteration 30: loss 0.822352
iteration 40: loss 0.807594
iteration 50: loss 0.799452
iteration 60: loss 0.794683
iteration 70: loss 0.791765
iteration 80: loss 0.789921
iteration 90: loss 0.788726
iteration 100: loss 0.787937
iteration 110: loss 0.787408
iteration 120: loss 0.787049
iteration 130: loss 0.786803
iteration 140: loss 0.786633
iteration 150: loss 0.786514
iteration 160: loss 0.786431
iteration 170: loss 0.786373
iteration 180: loss 0.786331
iteration 190: loss 0.786302
In [4]:
W
Out[4]:
array([[ 1.03370118,  1.10345865, -2.13524878],
       [-2.32943088,  2.71627529, -0.39072902]])
In [5]:
b
In [6]:
# evaluate training set accuracy
scores = np.dot(X, W) + b
predicted_class = np.argmax(scores, axis=1)
               #Returns the indices of the maximum values along an axis.
print 'training accuracy: %.2f' % (np.mean(predicted_class == y))
               #Compute the arithmetic mean along the specified axis.
 
training accuracy: 0.49
In [7]:
# plot the resulting classifier
h = 0.02
         # numpy.ndarray.min(axis = None, out = None)
         # (最小値を求めたい配列).min()の形で使います。
         #  X[:, 0]は、[(先頭から最後まで), 0]       
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
         # numpy.arange([start, ]stop, [step, ]dtype=None)
         # Return evenly spaced values within a given interval.
         # np.arange(x_min, x_max, h)→.....-1.5,-1.48,-1.46......1.46,1.48,1.5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))
         # Return coordinate matrices from coordinate vectors.
         #     
W
Out[7]:
array([[ 1.03370118,  1.10345865, -2.13524878],
       [-2.32943088,  2.71627529, -0.39072902]])
In [8]:
b
In [9]:
Z = np.dot(np.c_[xx.ravel(), yy.ravel()], W) + b  # xxもyyも描画面をすべて含む巨大な配列なので
         # 一次元のメッシュ配列に並びかえて、
         # メッシュの要素をデータとしてスコアを計算する
Z = np.argmax(Z, axis=1)  #計算したスコアで最大のものを、そのメッシュのクラスにする。
Z = Z.reshape(xx.shape)  # 配列を描画面に合わせて並び替える
fig = plt.figure()
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral, alpha=0.8) # 等高線と塗りつぶし輪郭を 描きます。
         # contour([X, Y,] Z, [levels], **kwargs)
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)# 散布図 (Scatter plot) を描く 
plt.xlim(xx.min(), xx.max())  # グラフの横軸、縦軸を調整する。
plt.ylim(yy.min(), yy.max())  # グラフの横軸、縦軸を調整する。
plt.colorbar(sc)             #カラーマップを表示してみた。  
#fig.savefig('spiral_linear.png')
Out[9]:
<matplotlib.colorbar.Colorbar at 0xe5f5b38>
 
 

ニューラルネットワークのトレーニング 

#

明らかに、線形分類器はこのデータセットには不十分であり、ニューラルネットワークを使用したいと考えています。このおもちゃのデータには、もう1つの隠れた層で十分です。隠れ層のニューロン数は100個とします。

重要なのは、非線形性を追加したことです。隠れ層のアクティベーションをゼロにする簡単なReLUです。

他のすべては同じままです。私たちは前と同じようにスコアに基づいて損失を計算し、前とdscores同じようにスコアの勾配を取得します。しかし、その勾配をモデルパラメータに逆伝播させる方法は、当然変更します。

まず、ニューラルネットワークの2番目のレイヤーをバックプロパゲーションします。これはSoftmax分類子のコードと同じですが、X(生データ)をhidden_layer変数に置き換えています。 しかし、これまでとは違って、まだ完了していません。hidden_layerは、それ自体が他のパラメータやデータの関数なのですから!この変数を使ってバックプロパゲーションを続ける必要があります。その勾配は次のように計算できます。
dhidden = np.dot(dscores, W2.T)

次に、ReLUの非線形性をバックプロパゲーションする必要があります。これは、後方伝搬中のReLUが実質的にスイッチであるため、容易であることが分かります。

\( r = max(0,x)  \)であるから、その微分は\( \quad\quad\quad \frac{dr}{dx} = 1 (x>0)  \)となります。

チェーンルールと組み合わせると、フォワードパスでのReLUユニットは、入力が0より大きい場合にはグラジエントパスを通り、変更せずに通過しますが、入力がゼロ未満の場合には出力を殺します。したがって、ReLUを単に以下のように後方伝搬することができます。
dhidden[hidden_layer <= 0] = 0  この記述がわかりません。

In [15]:
# initialize parameters randomly
h = 100 # size of hidden layer   # 隠れ層のニューロン数は100個とします。
W = 0.01 * np.random.randn(D,h)  # サイズがニューロンの数(最終クラスの数ではない)
b = np.zeros((1,h))
W2 = 0.01 * np.random.randn(h,K) # 入力はニューロンの数で、出力サイズが最終クラスの数
b2 = np.zeros((1,K))

# some hyperparameters
step_size = 1e-0
reg = 1e-3 # regularization strength

# gradient descent loop
num_examples = X.shape[0]
for i in xrange(10000):        # 繰り返し数がけた違いに大きいです。
  
  # evaluate class scores, [N x K]
  hidden_layer = np.maximum(0, np.dot(X, W) + b) # note, ReLU activation
  scores = np.dot(hidden_layer, W2) + b2
  
  # compute the class probabilities
  exp_scores = np.exp(scores)
  probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K]
  
  # compute the loss: average cross-entropy loss and regularization
  corect_logprobs = -np.log(probs[range(num_examples),y])
  data_loss = np.sum(corect_logprobs)/num_examples
  reg_loss = 0.5*reg*np.sum(W*W) + 0.5*reg*np.sum(W2*W2)  # W2の項を追加します。
  loss = data_loss + reg_loss
  if i % 1000 == 0:
    print "iteration %d: loss %f" % (i, loss)
  
  # compute the gradient on scores
  dscores = probs
  dscores[range(num_examples),y] -= 1
  dscores /= num_examples
  
  # backpropate the gradient to the parameters
  # first backprop into parameters W2 and b2
  dW2 = np.dot(hidden_layer.T, dscores)
  db2 = np.sum(dscores, axis=0, keepdims=True)
  # しかし、これまでとは違って、まだ完了していない。
  # hidden_layerは、それ自体が他のパラメータやデータの関数なのですから!
  # この変数を使ってバックプロパゲーションを続ける必要があります。
  # next backprop into hidden layer
  dhidden = np.dot(dscores, W2.T)   #compute the gradient on dscores
  # 次に、ReLUの非線形性をバックプロパゲーションする必要があります。
  # これは、逆方向パス中のReLUが実質的にスイッチであるため、容易であることが分かる。  
  # backprop the ReLU non-linearity
  dhidden[hidden_layer <= 0] = 0
  # finally into W,b
  dW = np.dot(X.T, dhidden)
  db = np.sum(dhidden, axis=0, keepdims=True)
  
  # add regularization gradient contribution
  dW2 += reg * W2
  dW += reg * W
  
  # perform a parameter update
  W += -step_size * dW
  b += -step_size * db
  W2 += -step_size * dW2
  b2 += -step_size * db2
# dscores = probs
# dhidden
#hidden_layer
hidden_layer.shape
 
iteration 0: loss 1.098513
iteration 1000: loss 0.303631
iteration 2000: loss 0.266166
iteration 3000: loss 0.262572
iteration 4000: loss 0.251706
iteration 5000: loss 0.257814
iteration 6000: loss 1.925122
iteration 7000: loss 0.250567
iteration 8000: loss 0.250313
iteration 9000: loss 0.250620
Out[15]:
(300L, 100L)
In [11]:
# evaluate training set accuracy
hidden_layer = np.maximum(0, np.dot(X, W) + b)
scores = np.dot(hidden_layer, W2) + b2
predicted_class = np.argmax(scores, axis=1)
print 'training accuracy: %.2f' % (np.mean(predicted_class == y))
 
training accuracy: 0.98
In [12]:
# plot the resulting classifier
h = 0.02
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))
Z = np.dot(np.maximum(0, np.dot(np.c_[xx.ravel(), yy.ravel()], W) + b), W2) + b2
Z = np.argmax(Z, axis=1)
Z = Z.reshape(xx.shape)
fig = plt.figure()
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.colorbar() 
#fig.savefig('spiral_net.png')
Out[12]:
<matplotlib.colorbar.Colorbar at 0xe3c6ac8>
 

AI 事始め15:Neural Networks の基礎知識ー1

the Stanford CS class CS231n: Convolutional Neural Networks for Visual Recognition. を読もうとしたが、Googleの翻訳も、内容も小生には難解で理解が進まない。元々基礎知識が無いので、無謀な企ては止めにして、先人の知恵におすがりし、その足跡を追いながら、少しでも習得できたら良いな。

線形識別モデルの基本

サポートベクターマシン(support vector machine:SVM)の基礎

カーネル法

フィードフォワードニューラルネットワークの基本

上記の記事を勉強させて頂きながら、自分なりに要点をまとめてMEMOしてみた。(間違った引用があるかも知れないし、Memoの内容が正しいとは限らないけど、しかたない。数式の書き方も勉強できたし、成果はゼロではないと思う。)

 

1.線形識別モデルの例

K個の異なるカテゴリ(j=1,K)を示す画像(サイズはD=23×32×3=3072ピクセル)を分類する場合。スコアベクトル\(f\)を下記のように定義する。

$$f(x_i,W,b)=Wx_i+b$$

 \(x_i\)は\(i\)番目の入力ベクトルで、サイズはD[3072 x 1]。

N個の入力ベクトル(学習用・テスト用サンプル画像)があると仮定する。\((i=1,N)\)

 \(x_i\)が学習用の時は、正解ラベル\(y_i\)(サイズは[K x 1])を用意する。

\(W\)は重み行列でサイズは [K x D]。

\(b\)はバイアスベクトルでサイズは [K x 1]

結果的にスコアベクトル\(f\)のサイズは [K x 1]となる。

特徴は下記。

  1. K個のカテゴリー分類を並列に扱うことが、単一行列乗算で可能。
  2. \(x_i\)を与えた時、\(f\)が\(y_i\)に近づくようにWとbを学習する。
  3. 学習が完了したらWとbが固定され、新しいテスト画像を分類するには、行列の乗算と加算を1回行うだけでよい。これは、テスト画像とすべてのトレーニング画像を比較するよりもはるかに高速です。
  4. 特定のカテゴリー jのスコアを\(f_j\)で表すと、\(f_j>=0\)で、カテゴリjと判定し、\(f_j<0\)でj以外のカテゴリーと判定するように、Wとbを決めた場合は、上式は識別をする上での境界を作り、このとき境界上の点xは\(f(x)=0\)となる。式を変形していくと下記のこともわかる。
  • 重みベクトルWは、境界に対していつでも直交(内積が0である)している。
  • 数式によれば何次元になろうとも、Wが決定面の向きを決め(Wに直行した決定面になる)、bが原点との位置を定めているということが分かる。(この時の原点のイメージの理解が難しい。)
  • 次は空間上の任意の点\(x\)を考え、この任意の点\(x\)を決定面上に直交射影したときの点を\(x'\)と表現しておけば、空間上の任意の点\(x\)は、W方向の単位ベクトルを用いて、下式で示される。$$x=x'+r\frac{W}{\|W\|}$$
  • さらに式を変形していくと、任意の点\(x\)との直交距離\(r\)が下記の式で表される。この直交距離\(r\)を最大化するように、wを決定すれば、識別が有利になる。$$r=\frac{f(x_i,W,b)}{\|W\|}$$
  • データ点が直線では分離できないような場合には、データ点を変換してしまい、変換後の空間で直線を引く。元の空間に戻ってきたら曲線になっているので、結果だけ見れば、もとのデータ点にたいして曲線により回帰・分類を行ったことになる。

2.Neural Networks Part 1: Setting up the Architecture

 

線形分類器としての単一ニューロン

フィードフォワードニューラルネットワークの数学的形式は、あなたに馴染みのあるように見えるかもしれません。線形分類器で見たように、単一ニューロンは、その入力空間にある特定の線形領域を「好き」(1に近い活性化)、または「嫌い」(0に近い活性化)する能力を有する。したがって、ニューロンの出力における適切な損失関数を用いることにより、単一ニューロンを線形分類器とみなすことができます。

 

疲れた、ここら辺で一度中断して、不足分は、その都度追加して行こう。高度なAPIを使用するので、あまり細かいことは知らなくても良いかも。

AI 事始め14:Get Started with TensorFlow : PythonとNumpyのお勉強

Python Numpyチュートリアル を読むことから始めました。とても素晴らしい資料です。PythonとNumpyに関しても、聞きかじりで、部分的にしか知らない自分が、全体を斜め読みできたことは、勉強になりました。「Tuples」、「Broadcasting」など初めて聞く用語もありました。視覚認識のための畳み込みニューラルネットワークの報告書を読むために大いに役立つ予感がします。IPythonノートブック(最近のJupyterノートブック)のチュートリアルもありました。

AI 事始め13:Get Started with TensorFlow : Classic & Fashion MNIST

Why we made Fashion-MNISTという記事を読みました。

Classic MNISTのデータセットでは進歩が望めない程に機械学習の技術が進展しまったというようなことが書いてありました。

 Fashion-MNISTのデータセットを用いた機械学習は、現在でも、多くの機関でBenchmarkされている。Tensorflow's docが報告しているのは、Classifierが2 Conv+poolingで、Fashion test accuracyが0.916でした。もっと高いaccuracyを報告している他の機関も多くありました。

Tensorflow's docには、Classic MNISTのデータセット使う例ですが、Build a Convolutional Neural Network using Estimatorsとして、基本、仕組みが詳細に記述されています。Note: For a more comprehensive walkthrough of CNN architecture, see Stanford University's Convolutional Neural Networks for Visual Recognition course materials.

この辺は、じっくりと時間をかけて理解したいですが、理解できるかな? Google翻訳も昔と比べると、格段の進歩をしているので、Chromeブラウザで「日本語に翻訳」を駆使すればなんとかなるかな? せめて、用語ぐらいは覚えよう。先に進むことも並行してやってみたいしな。

AI 事始め12:Get Started with TensorFlow : Keras (κέρας)

Keras: The Python Deep Learning library によると、Keras (κέρας) means horn in Greek. だそうです。脇道に逸れないで、本題に入ると、Keras is a high-level neural networks API, written in Python and capable of running on top of TensorFlow, CNTK, or Theano.だそうです。しかし、TensorFlow Keras guideによれば、tf.keras is TensorFlow's implementation of the Keras API specification. なので、


tf.keras can run any Keras-compatible code, but keep in mind:

   ・The tf.keras version in the latest TensorFlow release might not be the same as the latest keras version from PyPI. Check tf.keras.version.
   ・When saving a model's weights, tf.keras defaults to the checkpoint format. Pass save_format='h5' to use HDF5.

です。つまり、

model = keras.Sequential([ という表記より、TensorFlow を使う限りは、

model = tf.keras.models.Sequential([ という表記を使った方が安全ということですか。

次に、下記のようなコードを読み解くには、それぞれのリンクを辿るしかありません。

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)

])

 

model.compile(optimizer='adam',

                        loss='sparse_categorical_crossentropy',
                        metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=5)
model.evaluate(test_images, test_labels)

理解できるかどうかは、努力次第とは思いますが、どこまで理解しないといけないかが不明なので、斜め読みして、先に進みます。

Get Started with TensorFlow では、ここまでに二つのモデルが例示されていて、違いは

    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dropout(0.2),

の部分のみです。neural networkのoutput arrays of shape が(*, 128)のモデルと(*, 512)のモデルが例示されています。また、Dropoutのあるモデルと無いモデルがあります。Dropoutとは、

Dropout consists in randomly setting a fraction rate of input units to 0 at each update during training time, which helps prevent overfitting.

と書かれていますが、知識ゼロでは、overfittingを抑制するために、input units?を操作するくらいしか理解できませんので、飛ばします。

計算時間の速いモデルを、tf.kerasで書き換えて実行してみました。ReStartしてRunさせる毎に結果が微妙に変わっているのは、多分、学習に使うデータをランダムに選んでいるためかな。とにかく、仕組みがわかりません。

In [1]:
# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras  # 最新のtensorflowにはkerasが同梱されているのかな?

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)
 
1.11.0
In [2]:
fashion_mnist = keras.datasets.fashion_mnist

(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
In [3]:
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
In [4]:
train_images.shape
Out[4]:
(60000, 28, 28)
In [5]:
len(train_labels)
Out[5]:
60000
In [6]:
train_labels
Out[6]:
array([9, 0, 0, ..., 3, 0, 5], dtype=uint8)
In [7]:
test_images.shape
Out[7]:
(10000, 28, 28)
In [8]:
len(test_labels)
Out[8]:
10000
In [9]:
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
 
In [10]:
train_images = train_images / 255.0

test_images = test_images / 255.0
In [11]:
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
 
In [12]:
# tf.keras.で書き換え
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128, activation=tf.nn.relu),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
In [13]:
model.compile(optimizer='adam', 
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
In [14]:
model.fit(train_images, train_labels, epochs=5)
test_loss, test_acc = model.evaluate(test_images, test_labels)

print('Test accuracy:', test_acc)
 
Epoch 1/5
60000/60000 [==============================] - 4s 58us/step - loss: 0.5057 - acc: 0.8219
Epoch 2/5
60000/60000 [==============================] - 3s 52us/step - loss: 0.3768 - acc: 0.8636
Epoch 3/5
60000/60000 [==============================] - 3s 51us/step - loss: 0.3408 - acc: 0.8760
Epoch 4/5
60000/60000 [==============================] - 3s 52us/step - loss: 0.3149 - acc: 0.8849
Epoch 5/5
60000/60000 [==============================] - 3s 50us/step - loss: 0.2961 - acc: 0.8904
10000/10000 [==============================] - 0s 24us/step
Test accuracy: 0.869
In [15]:
predictions = model.predict(test_images)
In [16]:
predictions[0]
Out[16]:
array([5.0372423e-06, 8.1114271e-09, 8.7406681e-07, 2.6778051e-09,
       4.5041918e-07, 3.0179184e-03, 1.2975282e-06, 2.3487598e-02,
       7.7159930e-06, 9.7347915e-01], dtype=float32)
In [17]:
np.argmax(predictions[0])
Out[17]:
9
In [18]:
test_labels[0]
Out[18]:
9
In [19]:
def plot_image(i, predictions_array, true_label, img):
  predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
  plt.grid(False)
  plt.xticks([])
  plt.yticks([])
  
  plt.imshow(img, cmap=plt.cm.binary)

  predicted_label = np.argmax(predictions_array)
  if predicted_label == true_label:
    color = 'blue'
  else:
    color = 'red'
  
  plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                100*np.max(predictions_array),
                                class_names[true_label]),
                                color=color)

def plot_value_array(i, predictions_array, true_label):
  predictions_array, true_label = predictions_array[i], true_label[i]
  plt.grid(False)
  plt.xticks([])
  plt.yticks([])
  thisplot = plt.bar(range(10), predictions_array, color="#777777")
  plt.ylim([0, 1]) 
  predicted_label = np.argmax(predictions_array)
 
  thisplot[predicted_label].set_color('red')
  thisplot[true_label].set_color('blue')
In [20]:
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions,  test_labels)
 
In [21]:
i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions,  test_labels)
 
In [22]:
# Plot the first X test images, their predicted label, and the true label
# Color correct predictions in blue, incorrect predictions in red
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
  plt.subplot(num_rows, 2*num_cols, 2*i+1)
  plot_image(i, predictions, test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions, test_labels)
 
In [23]:
# Grab an image from the test dataset
img = test_images[0]

print(img.shape)
 
(28, 28)
In [24]:
# Add the image to a batch where it's the only member.
img = (np.expand_dims(img,0))

print(img.shape)
 
(1, 28, 28)
In [26]:
plot_value_array(0, predictions_single, test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
 
In [27]:
np.argmax(predictions_single[0])
Out[27]:
9
In [28]:
#@title MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

AI 事始め11:Get Started with TensorFlow :classic MNIST

Get Started with TensorFlowの冒頭のコードに記述されているtf.keras.datasets.mnistは、classic MNISTのデータセットであることが判明したので、そのJyupiter Notebookを下記のように作成してみた。

 

 

In [1]:
# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras  # 最新のtensorflowにはkerasが同梱されているのかな?

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)
 
1.11.0
In [2]:
classic_mnist = tf.keras.datasets.mnist

(train_images, train_labels), (test_images, test_labels) = classic_mnist.load_data()
In [3]:
class_names = ['zero', 'one', 'two', 'three', 'four', 
               'five', 'six', 'seven', 'eight', 'nine']
In [4]:
train_images.shape
Out[4]:
(60000, 28, 28)
In [5]:
len(train_labels)
Out[5]:
60000
In [6]:
train_labels
Out[6]:
array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)
In [7]:
test_images.shape
Out[7]:
(10000, 28, 28)
In [8]:
len(test_labels)
Out[8]:
10000
In [9]:
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
 
In [10]:
train_images = train_images / 255.0

test_images = test_images / 255.0
In [11]:
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
 
In [12]:
# MODELを変えてみました。
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
# ここの記述を変えてみました。
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=5)
model.evaluate(test_images, test_labels)
 
Epoch 1/5
60000/60000 [==============================] - 14s 237us/step - loss: 0.2000 - acc: 0.9412
Epoch 2/5
60000/60000 [==============================] - 14s 227us/step - loss: 0.0802 - acc: 0.9754
Epoch 3/5
60000/60000 [==============================] - 13s 224us/step - loss: 0.0537 - acc: 0.9830
Epoch 4/5
60000/60000 [==============================] - 14s 225us/step - loss: 0.0366 - acc: 0.9884
Epoch 5/5
60000/60000 [==============================] - 13s 224us/step - loss: 0.0265 - acc: 0.9916
10000/10000 [==============================] - 0s 40us/step
Out[12]:
[0.07169422345789499, 0.9801]
In [13]:
predictions = model.predict(test_images)
In [14]:
predictions[0]
Out[14]:
array([4.8529500e-11, 4.6674481e-10, 3.1813300e-08, 1.2909177e-06,
       9.0128634e-15, 2.9170492e-11, 2.8064065e-15, 9.9999869e-01,
       6.5376677e-09, 7.0768231e-09], dtype=float32)
In [15]:
np.argmax(predictions[0])
Out[15]:
7
In [16]:
test_labels[0]
Out[16]:
7
In [17]:
def plot_image(i, predictions_array, true_label, img):
  predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
  plt.grid(False)
  plt.xticks([])
  plt.yticks([])
  
  plt.imshow(img, cmap=plt.cm.binary)

  predicted_label = np.argmax(predictions_array)
  if predicted_label == true_label:
    color = 'blue'
  else:
    color = 'red'
  
  plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                100*np.max(predictions_array),
                                class_names[true_label]),
                                color=color)

def plot_value_array(i, predictions_array, true_label):
  predictions_array, true_label = predictions_array[i], true_label[i]
  plt.grid(False)
  plt.xticks([])
  plt.yticks([])
  thisplot = plt.bar(range(10), predictions_array, color="#777777")
  plt.ylim([0, 1]) 
  predicted_label = np.argmax(predictions_array)
 
  thisplot[predicted_label].set_color('red')
  thisplot[true_label].set_color('blue')
In [18]:
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions,  test_labels)
 
In [19]:
i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions,  test_labels)
 
In [20]:
# Plot the first X test images, their predicted label, and the true label
# Color correct predictions in blue, incorrect predictions in red
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
  plt.subplot(num_rows, 2*num_cols, 2*i+1)
  plot_image(i, predictions, test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions, test_labels)
 
In [21]:
# Grab an image from the test dataset
img = test_images[0]

print(img.shape)
 
(28, 28)
In [22]:
# Add the image to a batch where it's the only member.
img = (np.expand_dims(img,0))

print(img.shape)
 
(1, 28, 28)
In [24]:
plot_value_array(0, predictions_single, test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
 
In [25]:
np.argmax(predictions_single[0])
Out[25]:
7
In [26]:
#@title MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.