学生の備忘録なブログ

日々のことを忘れないためのブログです。

DeepLearningにおける勾配

損失関数の出力をfとすると,出力の全てのパラメータ$w_i$に関する偏微分を計算すると,偏微分を並べたベクトルを定義することができる.このベクトル

f = f d w 1 , . . . , · f W i

を勾配と呼ぶ.

f = f d w 1 , . . . , · f W i

f = f W 1 , f W i

TeXが上手に描画できないので,一旦stop

機械学習入門_第2章 途中まで

import sys
print("Python version: {}".format(sys.version))

import pandas as pd
print("pandas version: {}".format(pd.__version__))

import matplotlib
print("matplotlib version: {}".format(matplotlib.__version__))

import numpy as np
print("NumPy version: {}".format(np.__version__))

import scipy as sp
print("SciPy version: {}".format(sp.__version__))

import IPython
print("IPython version: {}".format(IPython.__version__))

import sklearn
print("scikit-learn version: {}".format(sklearn.__version__))

import mglearn
import matplotlib.pyplot as plt

Python version: 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:04:09) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)]
pandas version: 0.20.3
matplotlib version: 2.0.2
NumPy version: 1.13.1
SciPy version: 0.19.1
IPython version: 6.1.0
scikit-learn version: 0.19.0
%matplotlib inline
from preamble import *
---------------------------------------------------------------------------

ModuleNotFoundError                       Traceback (most recent call last)

<ipython-input-10-e31a7faecc4a> in <module>()
      1 get_ipython().magic('matplotlib inline')
----> 2 from preamble import *


ModuleNotFoundError: No module named 'preamble'

教師あり学習は,ある入力に対しての特定の出力を予測したい場合で,入力出力のペアのデータが入手可能な際に用いられる.

2.1 クラス分類と回帰

教師あり機械学習問題は,2つに大別することができる. * クラス分類(classification) * 2クラス分類(binary classification) * 多クラス分類(multiclass classification) * 回帰(regression)

クラス分類問題と回帰問題を区別するには,出力に何らかの連続性があるかを考えてみれば良い.出力に連続性があるなら回帰問題である.年収を予測する場合を考えてみる.40,000ドルと40,001ドルは近似できる.しかし,webサイトの言語を認識するタスク(クラス分類問題)では,量の大小は問題ではない.言語には連続性がない.英語とフランス語の中間の言語は存在しない.

汎化,過剰適合,適合不足

非常に複雑なモデルを作ることを許せば,訓練データに対してはいくらでも正確な予測を行うようにできてしまう.

[f:id:forhighlow:20171006222712p:plain]

教師あり機械学習アルゴリズム

これから,最も一般的な機械学習アルゴリズムについて,どのようにデータから学習し,どのように予想を行うん丘を見ていく.モデルの複雑さという概念が個々のモデルで果たす役割について述べ,個々のアルゴリズムがモデルを構築する方法の概念を示す.更に,それぞれのアルゴリズムの長所と短所,適しているデータの種類について述べる.重要なパラメータとオプションについても説明する.多くのアルゴリズムは,クラス分類と回帰のバリエーションがあるので両方とも説明する.

個々のアルゴリズムの説明を詳しく読む必要はないが,モデルを理解することで個々の機械学習アルゴリズムの働き方についてより良く理解することができるだろう.本章はリファレンスガイドとしても利用できる.

サンプルデータセット

合成した2クラス分類データセットの例として,forgeデータセットを見てみる.

第1特徴量をx軸に、第2特徴量はy軸にプロットしている.

# generate dataset
X, y = mglearn.datasets.make_forge()
# plot dataset
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
plt.legend(["Class 0", "Class 1"], loc=4)
plt.xlabel("First feature")
plt.ylabel("Second feature")
print("X.shape: {}".format(X.shape))
X.shape: (26, 2)

[f:id:forhighlow:20171006222715p:plain]

X.shapeからわかるようにこのデータセットは2つの特徴量を持つ26のデータポイントで構成されている.

回帰あるを紹介する際には,合成したwaveデータセットを用いる.このwaveデータセットは入力として1つの特徴量と,モデルの対象となる連続地のターゲット変数(もしくは(response))を持つ.次のグラフは特徴量をx軸に,回帰のターゲット(出力)をy軸に取る.

X, y = mglearn.datasets.make_wave(n_samples=40)
plt.plot(X, y, 'o')
plt.ylim(-3, 3)
plt.xlabel("Feature")
plt.ylabel("Target")
<matplotlib.text.Text at 0x114641160>

[f:id:forhighlow:20171006222719p:plain]

学習にこれから用いるデータセットの一つに乳がんの腫瘍を測定したデータが有る.

from sklearn.datasets import load_breast_cancer
cancer= load_breast_cancer()
print("cancer.keys(): \n{}".format(cancer.keys()))
cancer.keys(): 
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])
print("shape of cancer data: {}".format(cancer.data.shape))
shape of cancer data: (569, 30)
print("Sample counts per class:\n{}".format(
      {n: v for n, v in zip(cancer.target_names, np.bincount(cancer.target))}))
Sample counts per class:
{'malignant': 212, 'benign': 357}

212が悪性で,357が良性である.

個々の特徴量の意味を示す記述は,feature_names属性に格納されている.

print("Feature names:^n{}".format(cancer.feature_names))##特徴量名
Feature names:^n['mean radius' 'mean texture' 'mean perimeter' 'mean area'
 'mean smoothness' 'mean compactness' 'mean concavity'
 'mean concave points' 'mean symmetry' 'mean fractal dimension'
 'radius error' 'texture error' 'perimeter error' 'area error'
 'smoothness error' 'compactness error' 'concavity error'
 'concave points error' 'symmetry error' 'fractal dimension error'
 'worst radius' 'worst texture' 'worst perimeter' 'worst area'
 'worst smoothness' 'worst compactness' 'worst concavity'
 'worst concave points' 'worst symmetry' 'worst fractal dimension']
## DESCRを見れば,詳しい情報が得られる.
print("Feature names:^n{}".format(cancer.DESCR))
Feature names:^nBreast Cancer Wisconsin (Diagnostic) Database
=============================================

Notes
-----
Data Set Characteristics:
    :Number of Instances: 569

    :Number of Attributes: 30 numeric, predictive attributes and the class

    :Attribute Information:
        - radius (mean of distances from center to points on the perimeter)
        - texture (standard deviation of gray-scale values)
        - perimeter
        - area
        - smoothness (local variation in radius lengths)
        - compactness (perimeter^2 / area - 1.0)
        - concavity (severity of concave portions of the contour)
        - concave points (number of concave portions of the contour)
        - symmetry 
        - fractal dimension ("coastline approximation" - 1)

        The mean, standard error, and "worst" or largest (mean of the three
        largest values) of these features were computed for each image,
        resulting in 30 features.  For instance, field 3 is Mean Radius, field
        13 is Radius SE, field 23 is Worst Radius.

        - class:
                - WDBC-Malignant
                - WDBC-Benign

    :Summary Statistics:

    ===================================== ====== ======
                                           Min    Max
    ===================================== ====== ======
    radius (mean):                        6.981  28.11
    texture (mean):                       9.71   39.28
    perimeter (mean):                     43.79  188.5
    area (mean):                          143.5  2501.0
    smoothness (mean):                    0.053  0.163
    compactness (mean):                   0.019  0.345
    concavity (mean):                     0.0    0.427
    concave points (mean):                0.0    0.201
    symmetry (mean):                      0.106  0.304
    fractal dimension (mean):             0.05   0.097
    radius (standard error):              0.112  2.873
    texture (standard error):             0.36   4.885
    perimeter (standard error):           0.757  21.98
    area (standard error):                6.802  542.2
    smoothness (standard error):          0.002  0.031
    compactness (standard error):         0.002  0.135
    concavity (standard error):           0.0    0.396
    concave points (standard error):      0.0    0.053
    symmetry (standard error):            0.008  0.079
    fractal dimension (standard error):   0.001  0.03
    radius (worst):                       7.93   36.04
    texture (worst):                      12.02  49.54
    perimeter (worst):                    50.41  251.2
    area (worst):                         185.2  4254.0
    smoothness (worst):                   0.071  0.223
    compactness (worst):                  0.027  1.058
    concavity (worst):                    0.0    1.252
    concave points (worst):               0.0    0.291
    symmetry (worst):                     0.156  0.664
    fractal dimension (worst):            0.055  0.208
    ===================================== ====== ======

    :Missing Attribute Values: None

    :Class Distribution: 212 - Malignant, 357 - Benign

    :Creator:  Dr. William H. Wolberg, W. Nick Street, Olvi L. Mangasarian

    :Donor: Nick Street

    :Date: November, 1995

This is a copy of UCI ML Breast Cancer Wisconsin (Diagnostic) datasets.
https://goo.gl/U2Uwz2

Features are computed from a digitized image of a fine needle
aspirate (FNA) of a breast mass.  They describe
characteristics of the cell nuclei present in the image.

Separating plane described above was obtained using
Multisurface Method-Tree (MSM-T) [K. P. Bennett, "Decision Tree
Construction Via Linear Programming." Proceedings of the 4th
Midwest Artificial Intelligence and Cognitive Science Society,
pp. 97-101, 1992], a classification method which uses linear
programming to construct a decision tree.  Relevant features
were selected using an exhaustive search in the space of 1-4
features and 1-3 separating planes.

The actual linear program used to obtain the separating plane
in the 3-dimensional space is that described in:
[K. P. Bennett and O. L. Mangasarian: "Robust Linear
Programming Discrimination of Two Linearly Inseparable Sets",
Optimization Methods and Software 1, 1992, 23-34].

This database is also available through the UW CS ftp server:

ftp ftp.cs.wisc.edu
cd math-prog/cpo-dataset/machine-learn/WDBC/

References
----------
   - W.N. Street, W.H. Wolberg and O.L. Mangasarian. Nuclear feature extraction 
     for breast tumor diagnosis. IS&T/SPIE 1993 International Symposium on 
     Electronic Imaging: Science and Technology, volume 1905, pages 861-870,
     San Jose, CA, 1993.
   - O.L. Mangasarian, W.N. Street and W.H. Wolberg. Breast cancer diagnosis and 
     prognosis via linear programming. Operations Research, 43(4), pages 570-577, 
     July-August 1995.
   - W.H. Wolberg, W.N. Street, and O.L. Mangasarian. Machine learning techniques
     to diagnose breast cancer from fine-needle aspirates. Cancer Letters 77 (1994) 
     163-171.
print("Feature names:^n{}".format(cancer.data))
Feature names:^n[[  1.79900000e+01   1.03800000e+01   1.22800000e+02 ...,   2.65400000e-01
    4.60100000e-01   1.18900000e-01]
 [  2.05700000e+01   1.77700000e+01   1.32900000e+02 ...,   1.86000000e-01
    2.75000000e-01   8.90200000e-02]
 [  1.96900000e+01   2.12500000e+01   1.30000000e+02 ...,   2.43000000e-01
    3.61300000e-01   8.75800000e-02]
 ..., 
 [  1.66000000e+01   2.80800000e+01   1.08300000e+02 ...,   1.41800000e-01
    2.21800000e-01   7.82000000e-02]
 [  2.06000000e+01   2.93300000e+01   1.40100000e+02 ...,   2.65000000e-01
    4.08700000e-01   1.24000000e-01]
 [  7.76000000e+00   2.45400000e+01   4.79200000e+01 ...,   0.00000000e+00
    2.87100000e-01   7.03900000e-02]]

詳しく見てもよくわからない.

ボストン住宅価格

実世界の回帰データセットとして,boston_housingデータセットを用いる.これはボストン郊外の住宅地の住宅価格の中央世知を犯罪率チャールズ川からの距離,高速道路への利便性などから予測するものだ.

13notokutyouryouwomotu 506のデータポイントが含まれる.

from sklearn.datasets import load_boston
boston = load_boston()
print("Data shape: {}".format(boston.data.shape))
Data shape: (506, 13)

このデータセットを拡張子,13の測定結果だけを特徴量とするのではなく,特徴量間の積(交互作用(interaction)と呼ぶ)も見ることにする.つまり,犯罪率と高速道路への利便性を特徴量として見るだけでなく,それらの積も特徴量として考える.このように導出された特徴量を含めることを特徴量エンジニアリング(feature engineering)と呼ぶ.

X, y = mglearn.datasets.load_extended_boston()
print("X.shape: {}".format(X.shape))
X.shape: (506, 104)

104の特徴量とは,もとの13の特徴量に,13の特徴量から2つの特徴量を選ぶ重複ありの組合せ91を足したものである.

これから,様々な機械学習アルゴリズムの特徴を説明していく.

k-最近傍法

k-NNアルゴリズムは,最も単純な学習アルゴリズムであると言われる.新しいデータポイントに対する予測を行う際には,訓練データセットのんかから一番近い点つまり最近傍点を見つける.

k-最近傍法によるクラス分類

一番簡単な倍位には,k-NNアルゴリズムは,1つの近傍点,つまり訓練データに含まれる天の中で,予測したいデータポイントに一番近いものだけみる.予測には,この点に対する出力をそのまま用いる.

mglearn.plots.plot_knn_classification(n_neighbors=1)

f:id:forhighlow:20171006222723p:plain

ここでは,星印で示される3つの新しいデータポイントを加えている.それぞれに対して訓練データのうちで,最も近いものに印を付けた.

最近傍法アルゴリズムでの予測では,近傍店のラベルが予測されたラベルになる.(星印の色で表されている).

1つ以上の近傍店を考慮にいれる場合は,投票でラベルを決める.つまり,個々のテストする点に対して,近傍点のうちいくつがクラス0に属し,いくつが暮らすに属するのかを数える.そして最も多く現れたクラスをその点に与える.言い換えればk-最近傍点の多数はのクラスを採用する.

要は多数決的に近しいものと同じになる.朱に交われば赤くなる,ということだ.

mglearn.plots.plot_knn_classification(n_neighbors=3)

png

ここでも,予測された結果は,星印の色で示されている.左上の新しいデータポイントに対する予測は,1つの最近傍点だけを使った場合とことなっている.

scikit-learnを用いてk-最近傍点アルゴリズムが適用できるか見てみたい.まず,データを訓練セットとテストセットに分割し,汎化性能を評価可能にする.

from sklearn.model_selection import train_test_split
X, y = mglearn.datasets.make_forge()
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

次にクラスをインポートして,インスタンスを作成する.この際に,近傍店の数などのパラメータを渡すことができる.ここでは3にしている.

from sklearn.neighbors import KNeighborsClassifier
clf = KNeighborsClassifier(n_neighbors=3)

次に,訓練データセットを用いてクラス分類器を訓練する. for KNeighborsClassifier this means storing the dataset, so we can compute neighbors during prediction.

clf.fit(X_train, y_train)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=3, p=2,
           weights='uniform')

finds the most common class among these

clf.predict(X_test)
array([1, 0, 1, 0, 1, 0, 0])
clf.score(X_test, y_test)
0.8571428571428571

85%の正確さである.

機械学習入門_第1章

機械学習の世界へ入門

www.oreilly.co.jp

各所でおすすめされている本.scikit-learnの作者の書いた本で,信頼がおけそう.理論的な部分より,scikit-learnの使ってできる解析としての機械学習を説明している.

データ分析の世界,というよりライブラリの進歩は著しく,基礎的説明より実践を重視する本は2,3年で通用しなくなる.(というより学習効率が下がる.)

www.oreilly.co.jp

こちらの本は2013年の本で,2017年現在はいささか古い.

この次にこの本で数式を踏まえた理論的な部分を勉強したい.

book.impress.co.jp

上記サイトに学習の手引がある.必読.

この分野では,PLMLがバイブルとして有名だが,少し見てめまいがするほど数式で埋め尽くされていた.よって,上記の2つの本で勉強していきたい.

python/numpy - 機械学習の「朱鷺の杜Wiki」

DeepLearning

www.oreilly.co.jp

ざっくりとした知識を付けた最大の要因は,KerasのMNISTチュートリアルをやってみること.怖がらずに四苦八苦しながら写経を恐れず書いてみた.わからない概念は,上記の本で分かりやすく解説されている.Kerasはラッパーとしてとても優秀なのでドキュメントをみれば,参考書内の概念が理解できる.

1.4.2

NumPy

import numpy as np
x = np.array([[1,2,3],[4,5,6]])#括弧は大外にも必要
print("x:\n{}".format(x))
x:
[[1 2 3]
 [4 5 6]]
print(x)
[[1 2 3]
 [4 5 6]]

SciPy

scikit-learnはアルゴリズムの実装をscipyの関数を用いている.scipy.sparseで疎行列を表現する.疎行列はone-hotの2次元配列を格納するのに使う.

from scipy import sparse

# 対角成分が1でそれ以外が0の2次元NumPy配列を作る
eye = np.eye(4)
print("NumPy array:\n{}".format(eye))
NumPy array:
[[ 1.  0.  0.  0.]
 [ 0.  1.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0.  1.]]
# NumPy配列をSciPyのCSR形式の疎行列に変換する
# 非ゼロ要素のみが格納される
sparse_matrix = sparse.csr_matrix(eye)
print("\nSciPy sparse CSR matrix:\n{}".format(sparse_matrix))
SciPy sparse CSR matrix:
  (0, 0)    1.0
  (1, 1)    1.0
  (2, 2)    1.0
  (3, 3)    1.0
# 疎なデータ表現を直接作る必要がある.ここでは,上のものと同じ疎行列をCOO形式で作っている.
data = np.ones(4)
row_indices = np.arange(4)
col_indices = np.arange(4)
eye_coo = sparse.coo_matrix((data, (row_indices, col_indices)))
print("COO representation:\n{}".format(eye_coo))
COO representation:
  (0, 0)    1.0
  (1, 1)    1.0
  (2, 2)    1.0
  (3, 3)    1.0
%matplotlib inline

import matplotlib.pyplot as plt
# -10から10までを100ステップに区切った列を配列として生成
# Generate a sequence numbers from -10 to 10 with 100 steps in between
x = np.linspace(-10, 10, 100)
print(x)
# create a second array using sinus
y = np.sin(x)
print(y)
# The plot function makes a line chart of one array against another
plt.plot(x, y, marker="x")

[f:id:forhighlow:20170927002441p:plain]
[-10.          -9.7979798   -9.5959596   -9.39393939  -9.19191919
  -8.98989899  -8.78787879  -8.58585859  -8.38383838  -8.18181818
  -7.97979798  -7.77777778  -7.57575758  -7.37373737  -7.17171717
  -6.96969697  -6.76767677  -6.56565657  -6.36363636  -6.16161616
  -5.95959596  -5.75757576  -5.55555556  -5.35353535  -5.15151515
  -4.94949495  -4.74747475  -4.54545455  -4.34343434  -4.14141414
  -3.93939394  -3.73737374  -3.53535354  -3.33333333  -3.13131313
  -2.92929293  -2.72727273  -2.52525253  -2.32323232  -2.12121212
  -1.91919192  -1.71717172  -1.51515152  -1.31313131  -1.11111111
  -0.90909091  -0.70707071  -0.50505051  -0.3030303   -0.1010101
   0.1010101    0.3030303    0.50505051   0.70707071   0.90909091
   1.11111111   1.31313131   1.51515152   1.71717172   1.91919192
   2.12121212   2.32323232   2.52525253   2.72727273   2.92929293
   3.13131313   3.33333333   3.53535354   3.73737374   3.93939394
   4.14141414   4.34343434   4.54545455   4.74747475   4.94949495
   5.15151515   5.35353535   5.55555556   5.75757576   5.95959596
   6.16161616   6.36363636   6.56565657   6.76767677   6.96969697
   7.17171717   7.37373737   7.57575758   7.77777778   7.97979798
   8.18181818   8.38383838   8.58585859   8.78787879   8.98989899
   9.19191919   9.39393939   9.5959596    9.7979798   10.        ]
[ 0.54402111  0.36459873  0.17034683 -0.03083368 -0.23076008 -0.42130064
 -0.59470541 -0.74392141 -0.86287948 -0.94674118 -0.99209556 -0.99709789
 -0.96154471 -0.8868821  -0.77614685 -0.63384295 -0.46575841 -0.27872982
 -0.0803643   0.12126992  0.31797166  0.50174037  0.66510151  0.80141062
  0.90512352  0.97202182  0.99938456  0.98609877  0.93270486  0.84137452
  0.7158225   0.56115544  0.38366419  0.19056796 -0.01027934 -0.21070855
 -0.40256749 -0.57805259 -0.73002623 -0.85230712 -0.93992165 -0.98930624
 -0.99845223 -0.96698762 -0.8961922  -0.78894546 -0.64960951 -0.48385164
 -0.2984138  -0.10083842  0.10083842  0.2984138   0.48385164  0.64960951
  0.78894546  0.8961922   0.96698762  0.99845223  0.98930624  0.93992165
  0.85230712  0.73002623  0.57805259  0.40256749  0.21070855  0.01027934
 -0.19056796 -0.38366419 -0.56115544 -0.7158225  -0.84137452 -0.93270486
 -0.98609877 -0.99938456 -0.97202182 -0.90512352 -0.80141062 -0.66510151
 -0.50174037 -0.31797166 -0.12126992  0.0803643   0.27872982  0.46575841
  0.63384295  0.77614685  0.8868821   0.96154471  0.99709789  0.99209556
  0.94674118  0.86287948  0.74392141  0.59470541  0.42130064  0.23076008
  0.03083368 -0.17034683 -0.36459873 -0.54402111]





[<matplotlib.lines.Line2D at 0x10d96bb38>]

png

pandas

import pandas as pd
from IPython.display import display

# create asimple dataset of people
data = {'Name': ["Jone", "Anna","Peter", "Linda"],
        'Location': ["Nes York", "Paris", "Berlin", "London"],
        'Age': [24, 13, 53, 33]
       }
data_pandas = pd.DataFrame(data)
# Ipython.displayを用いると,きれいに表示できる.
display(data_pandas)
Age Location Name
0 24 Nes York Jone
1 13 Paris Anna
2 53 Berlin Peter
3 33 London Linda
# One of many possible ways to query the table:
# selecting all rows that have an age column greate than 30
display(data_pandas[data_pandas.Age > 30])
Age Location Name
2 53 Berlin Peter
3 33 London Linda

mglearn

import sys
print("Python version: {}".format(sys.version))

import pandas as pd
print("pandas version: {}".format(pd.__version__))

import matplotlib
print("matplotlib version: {}".format(matplotlib.__version__))

import numpy as np
print("NumPy version: {}".format(np.__version__))

import scipy as sp
print("SciPy version: {}".format(sp.__version__))

import IPython
print("IPython version: {}".format(IPython.__version__))

import sklearn
print("scikit-learn version: {}".format(sklearn.__version__))
Python version: 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:04:09) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)]
pandas version: 0.20.3
matplotlib version: 2.0.2
NumPy version: 1.13.1
SciPy version: 0.19.1
IPython version: 6.1.0
scikit-learn version: 0.19.0

A First Application: Classifying iris species¶

アイリスのクラス分析

irisデータセットはscikit-learnのload_iris関数で読み込むことができる.

from sklearn.datasets import load_iris
iris_dataset = load_iris()
# load_irisが返すirisオブジェクトは,ディクショナリによく似たBunchクラスのオブジェクトで,キーと値を持つ.
print("Keys of iris_dataset: {}".format(iris_dataset.keys()))
Keys of iris_dataset: dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])
print(iris_dataset['DESCR'][:193] + "\n...")
Iris Plants Database
====================

Notes
-----
Data Set Characteristics:
    :Number of Instances: 150 (50 in each of three classes)
    :Number of Attributes: 4 numeric, predictive att
...

キーDESCRの値は,データセットの簡単な説明である.(description)ここでは,説明の最初だけ見る.

Iris Plants Database

Notes

Data Set Characteristics:特性 :Number of Instances: 150 (50 in each of three classes)インスタンスの数:150(3クラスにそれぞれ50ずつ) :Number of Attributes: 4 numeric, predictive att属性の数:4つの数値属性,予測に利用可能 ...

キーtarget_namesに対応する値は文字列の配列で, 予測しようとしている花の種類が格納されている

print("Target names:{}".format(iris_dataset['target_names']))
Target names:['setosa' 'versicolor' 'virginica']

キーfeature_namesに対応する値は文字列のリストで.それぞれの特徴量の説明が格納されている.

print("Feature names: \n{}".format(iris_dataset['feature_names']))
Feature names: 
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

Feature names: 特徴量の名前 ガクの長さ 幅 花弁の長さ ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']花弁の幅

ダータ本題は,targetとdataフィールドに格納されている.dataには,ガクの長さ,ガクの幅などが,NumPy配列とし格納されている.

print("Type of data:{}".format(type(iris_dataset['data'])))
Type of data:<class 'numpy.ndarray'>

配列dataの行は個々の花に対応し,列は個々の花に対して行われた4つの測定に対応する.

print("Shape of data: {}".format(iris_dataset['data'].shape))
Shape of data: (150, 4)

配列には170の花の測定結果が格納されている.機械学習では個々のアイテムをサンプルといい,その特徴を特徴量と呼ぶことを思い出そう.data配列のshapeはサンプルの個数かける特徴量の数である.これはscikit-learnの慣習的表現である.

print("First five columns of data:\n{}".format(iris_dataset['data'][:5]))
First five columns of data:
[[ 5.1  3.5  1.4  0.2]
 [ 4.9  3.   1.4  0.2]
 [ 4.7  3.2  1.3  0.2]
 [ 4.6  3.1  1.5  0.2]
 [ 5.   3.6  1.4  0.2]]

このデータから,最初の5つの花は花弁の幅が全て0.2cmで,5つの中では最初の花が最も長い5.1cmのガクを持っていることがわかる.

配列targetには,測定された個々の花の種類が,やはりNumPy配列として格納されている.

print("Type of target: {}".format(type(iris_dataset['target'])))
Type of target: <class 'numpy.ndarray'>

targetは1次元の配列で,個々の花に1つのエントリが対応する.

print("Shape of target: {}".format(iris_dataset['target'].shape))
Shape of target: (150,)

種類は0から2までの整数としてエンコードされている.

print("Target:\n{}".format(iris_dataset['target']))
Target:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

これらの数値の意味は,配列iris['target_names']で与えられる.0はsetosaを1はversicolorを2はvirginicaを意味する.

データセットを並べ替えて,分割するtrain_test_splitという関数がscikit-learnには用意されている.データのテストに用いる.

1.7.2

成功度合いの測定:訓練データとテストデータ

過学習した状態を換言すると,モデルがうまく汎化(generalize)できていない状態である.

scikit-learnでは,データを大文字のXで,ラベルを小文字のyで表すのが,一般的である.これは数式のf(x)=yに習っている.さらに数学での寒冷に従い,2次元配列(行列)であるデータには,大文字のXを,1次元配列(べクトル)であるラベルには,小文字yを用いる.

https://github.com/amueller/introduction_to_ml_with_python/raw/cccbbca86d00f9d5ffb643c740de4489de80436d/images/iris_petal_sepal.png

train_test_split関数を呼び出し結果を,この命名規則に従った変数に代入しよう.

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    iris_dataset['data'],iris_dataset['target'],random_state=0)

train_test_split関数は,分割を行う前に擬似乱数を用いてデータをシャッフルする.データポイントはラベルでソートされているので,単純に最後に25%をデータセットにすると,すべてのデータポイントがラベル2になってしまう.3クラスの内,1つしか含まれていないようなデータセットでは,モデルの汎化がうまく行っているか判断できない.だから,先にデータをシャッフルし,テストデータに全てのクラスが含まれるようにする.

同じ関数を何度か呼び出した際に,確実に同じ結果が得られるよう,ramdom_stateパラメータを用いて,擬似乱数生成器に同じシードを渡している.これによって出力が決定的になり,常に同じ結果が得られるようになる.本書では,乱数を用いる際には,常にこのようにrandom_stateパラメータを固定し用いる.

関数train_test_splitの出力は,X_train,X_test,y_test,y_train,y_testとなる.これらは全てNumpy配列で,X_trainにはデータセットの75%の行が,X_testには残りの25%が含まれている.

print("X_train shape:{}".format(X_train.shape))
print("y_train shape:{}".format(y_train.shape))
X_train shape:(112, 4)
y_train shape:(112,)
print("X_train shape: {}".format(X_train.shape))
print("y_train shape: {}".format(y_train.shape))
X_train shape: (112, 4)
y_train shape: (112,)

1.7.3 最初にすべきこと:データを良く観察する

データは精査すべきである.

データを検査する最良の方法は可視化である. その1つは,散布図である. 2次元の画面で散布図を効果的にプロットするのがペアプロットである. 全ての組合せ可能な特徴量の組み合わせをプロットするものだ. 特徴量の数が少ない場合にはうまくいく.しかし相関を同時にみることができないため,この方法で可視化してもデータの興味深い側面を見ることができない場合がある.

以下のグラフを作成するには,まずnumpy配列をpandasのdataframeに変換する.pandasはscatter_matrixと呼ばれるペアプロットを作成する関数を持つ.グラフマトリックスの対角部分にはここの特徴量のヒストグラムが描画される.

# X_trainのデータからDataFrameを作る.
# iris_dataset.feature_namesの文字列を使ってカラムに名前をつける
iris_datagrame = pd.DataFrame(X_train, columns=iris_dataset.feature_names)
# データフレームからscatter matrixを作成し,y_trainに従って色をつける
pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
                           hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)
----------------------------------------------------------------------

NameError                            Traceback (most recent call last)

<ipython-input-31-f2a828888675> in <module>()
      3 iris_datagrame = pd.DataFrame(X_train, columns=iris_dataset.feature_names)
      4 # データフレームからscatter matrixを作成し,y_trainに従って色をつける
----> 5 pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
      6                            hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)


NameError: name 'iris_dataframe' is not defined
# create dataframe from data in X_train
# label the columns using the strings in iris_dataset.feature_names
iris_dataframe = pd.DataFrame(X_train, columns=iris_dataset.feature_names)
# create a scatter matrix from the dataframe, color by y_train
grr = pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
                           hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)
----------------------------------------------------------------------

NameError                            Traceback (most recent call last)

<ipython-input-32-5c8cdb97d244> in <module>()
      4 # create a scatter matrix from the dataframe, color by y_train
      5 grr = pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
----> 6                            hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)


NameError: name 'mglearn' is not defined
# create dataframe from data in X_train
# label the columns using the strings in iris_dataset.feature_names
iris_dataframe = pd.DataFrame(X_train, columns=iris_dataset.feature_names)
# create a scatter matrix from the dataframe, color by y_train
pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
                           hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)
----------------------------------------------------------------------

NameError                            Traceback (most recent call last)

<ipython-input-33-0c4391853194> in <module>()
      4 # create a scatter matrix from the dataframe, color by y_train
      5 pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
----> 6                            hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)


NameError: name 'mglearn' is not defined
# create dataframe from data in X_train
# label the columns using the strings in iris_dataset.feature_names
iris_dataframe = pd.DataFrame(X_train, columns=iris_dataset.feature_names)
# create a scatter matrix from the dataframe, color by y_train
pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
                           hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)
----------------------------------------------------------------------

NameError                            Traceback (most recent call last)

<ipython-input-34-0c4391853194> in <module>()
      4 # create a scatter matrix from the dataframe, color by y_train
      5 pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(15, 15), marker='o',
----> 6                            hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)


NameError: name 'mglearn' is not defined

1.7.4 最初のモデル:k-最近傍法

scikit-learnにはさまざまなクラス分類アルゴリズムが用意されている.ここでは,わかりやすい,k-最近傍法(k-Nearest Neighbors)によるクラス分類を用いる.このモデルを構築するには,単に訓練セットを格納するだけでよい.

このアルゴリズムは,新しいデータポイントに対して予測する際に,新しい点に最も近い点を訓練セットから探し,新しい点に最も近かった点のラベルを新しいデータポイントに与える.

k-最近傍法のkは,新しい点に最も近い1点だけを用いたりするのではなく,訓練セットの中の固定されたk個の近傍点(例えば3,5)を用いることができることを意味する.予測には,これらの近傍店の中の多数を占めるクラスを採用する.今回は,1つの近傍点しか使わない.

すべてのscikit-learnの機械学習モデルには,Estimatorと総称される個別のクラスに実装される.k-最近傍法クラス分類アルゴリズムはneighborsモジュールのKNeiborsClassifierクラスに実装されている.モデルを使う前に,クラスのインスタンスを生成してオブジェクトを作らなけれあならない.この際にパラメータを渡すことができる.KNeighborsClassfierの最も重要なパラメータは近傍点の数だが,ここでは1つとする.

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=1)

knnオブジェクトは,訓練データからモデルを構築する際に用いられるアルゴリズムと新しいデータポイントに対して予測するためのアルゴリズムとをカプセル化している.さらに,訓練データからアルゴリズムがが抽出した情報も保持する.KNeighborsClassifierの場合には,単純に訓練データその斧を保持している.

訓練セットからモデルを構築するにはknnオブのfitメソッドを呼び出す.このメソッドはは,訓練データを含むNumpy配列X_trainとそれに対応する訓練ラベルを含むNumpu配列y_trainを引数に取る.

knn.fit(X_train, y_train)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=1, p=2,
           weights='uniform')

このfitメソッドはknnオブエクとそのものを返す(同時にknnを書き換える)ので,出力にこのクラス分類オブジェクトの文字列表現が表示されている.この文字列表現から,モデルを構築する際に用いられたパラメータが分かる.ほとんどのパラメータがデフォルトだが,n_neighbors=1だけは,我々が与えたものだ.scigit-learnのモデルの多くは多数のパラメータがあるが,ほとんどは速度の最適化のためや,まれにしか使われないものだ.

1.7.5 予測を行う.

さて,ラベルが分かっていない新しいデータに対して予測をしてみよう.野生のアイリスを見つけたとして,ガク長5cm,ガク幅2.9,花弁の長さが1cm花弁の幅が0.2cm,である.このアイリスの品種はなんだろうか.このデータをnumpy配列に格納し,さの形を計算してみる

X_new = np.array([[5,2.9,1,0.2]])
print("X_new.shape:{}".format(X_new.shape))
X_new.shape:(1, 4)

ここで,1つの花の測定結果を2次元のnumpy配列にしていることに注意しよう.これは,scikit-learnが常に入力が2次元numpy配列であることを前提にするためだ. 予測を行うにはknnオブジェクトのpredickメソッドを呼ぶ.

prediction = knn.predict(X_new)
print("Prediction: {}".format(prediction))
print("Predicted target name: {}".format(
       iris_dataset['target_names'][prediction]))
Prediction: [0]
Predicted target name: ['setosa']

我々のモデルは,新しいアイリスをクラス0すなわち,setosaだと判断した.

しかし,これは正しいかどうかわからない.

1.7.6 モデルの評価

ここで先程作ったテストセットを用いる.モデルがどれくらい上手く機能していかどうか.精度(accuracy)を計算して測定できる. 精度は正しく品種を予測できたアイリスの割合である.

y_pred = knn.predict(X_test)
print("Test set predictions:\n {}".format(y_pred))
Test set predictions:
 [2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0
 2]
print("Test set score: {:.2f}".format(np.mean(y_pred == y_test)))
Test set score: 0.97

knnオブジェクトのscoreメソッドを用いても良い.このメソッドはテストセットに対応する精度を計算してくれる.

print("Test set score: {:.2f}".format(knn.score(X_test,y_test)))
Test set score: 0.97

このモデルでは,97%の精度で予測できた.

1.8 まとめと今後の展望

クラス分類問題では,分類結果となる品種はクラスと呼ばれ,個々のアイリスの品種はラベルと呼ばれる.

今回はk-最近傍法クラス分類アルゴリズムを用いた.これは,新しいデータポイントのラベルをそれと最も近い訓練データによって予測するアルゴリズムだ.このクラスはKNeighborsClassifierッックラスに実装される.

以下必要最小限の実装

X_train, X_test, y_train, y_test = train_test_split(
    iris_dataset['data'], iris_dataset['target'], random_state=0)

knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(X_train, y_train)

print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))
Test set score: 0.97

fit,predict,scoreメソッドは教師あり学習モデルに共通のインターフェースである.

SNSを解析

気になる本の1つ

みんな嘘つき - 検索データの新科学 - 未翻訳ブックレビュー

ソーシャルメディアの解析

twitterfacebookの解析は,人類の性質を如実に表す.最初に手を出すのは,どこから行けばよいのか.qiitaのようなサイトからか,オライリ本か,はたまたオンライン学習コンテンツか.選択肢が豊かなのは喜ぶべきことなのだが,片っ端から試してみるという気概がない.いささか無精者すぎる.

gakuseibiz.com

このような人は尊敬する.

ruby on rails 環境設定

ruby on rails

webアプリケーションを作るので,必要になった.

そして詰まった.

nokogiriができないエラー

Mac OS X Mavericksで”gem i nokogiri”失敗の解決方法 - Qiita

基本的流れ

プロジェクトごとの手順を示してくれている.

[Rails 5] rbenvでRubyをインストールして新規Rails開発環境を準備する

Rails開発環境の構築(rbenvでRuby導入からBundler、Rails導入まで)(Macport編) - Qiita

bundle execが必要なくなる

$ bundle install --path=vendor/bundle --binstubs=bundle_bin

Ruby の gem をプロジェクト毎に Bundler で管理する - fugafuga.write

【翻訳+解説】binstubをしっかり理解する: RubyGems、rbenv、bundlerの挙動

railsを学ぶ為にやるサイト

railsチュートリアル

Ruby on Rails チュートリアル:実例を使って Rails を学ぼう

railsgirls

Rails Girls - Japanese

AIによる感情推定システムの確立

Silver Logic Labs(SLL)は、映像解析により人が何を感じているかを把握するAIを開発した。

要旨

記事によれば,動画から,89%の確率で人の感情を特定することができるようになったそうだ.これはすなわち,皆がメンタリストの得るということであり,感情を偽れなくなるということだ.

所感

これは,人間に不可逆な変化を与える.圧倒的インパクトを持つ記事に思える.

 人間は社会的生物として嘘を巧みに使い,高度なコミュニケーションを取ることで現代社会の秩序を維持している.

 これがすべて嘘がわかるとしたらどうだろう.誰かに対して,お世辞を言うことはできなくなる. 常識ある社会人として,否定するべき非社会的でショッキングな映像(etc…喧嘩の映像など)を見て,否定的コメントをしたとき,幸福,楽しい,等の感情を読み取られてしまったら,どうすれば良いのか.

 Happiness,Neutral,Contempt,Sadness,Surprise,Anger,Fear,などかなり細かく感情を分類することができる.これではもう数種の映像に対する反応で,その人の性格,嗜好は確実に分析することができるだろう.

参考

https://www.fashionsnap.com/the-posts/2017-08-24/sll/

私的!最速!CNNによるMNIST分類問題!

私的!最速!CNNによるMNIST分類問題!

 三層CNNによりMNIST分類問題を最短距離で実装します.

注意

必要最小限の説明のみをしているため,誤差逆伝播法などの部分の説明を省いています.

実験内容

実験

 本稿ではKeras用いて,手書き数字(以降MNIST)の画像を分類(以降MNIST分類)し,次に学習結果の向上の考察をする.

 まずはじめに,畳み込みニューラルネットワーク(以降CNN)ではない実装の1つ,結合を全結合で行うレイヤ(以降Affineレイヤ)によるMNISTの実装を行う.次に,CNNを用いた,MNIST分類を行う.

CNNを用いないMNIST分類の実装

データの確認

MNISTのデータをニューラルネットワーク(以降NN)に入力したい.

%matplotlib inline
import keras
from keras.datasets import mnist
import matplotlib.pyplot as plt

#Kerasの関数でデータの読み込み。データをシャッフルして学習データと訓練データに分割している.
(x_train, y_train), (x_test, y_test) = mnist.load_data()

#MNISTデータの表示
fig = plt.figure(figsize=(9, 9))
fig.subplots_adjust(left=0, right=1, bottom=0, top=0.5, hspace=0.05, wspace=0.05)
for i in range(81):
    ax = fig.add_subplot(9, 9, i + 1, xticks=[], yticks=[])
    ax.imshow(x_train[i].reshape((28, 28)), cmap='gray')

pngf:id:forhighlow:20170814154824p:plain

60,000枚の28x28,10個の数字の白黒画像と10,000枚のテスト用画像データセット

num_classes = 10 # 出力層(output layer)のニューロンは10個 分類したい数に対応している.
x_train = x_train.reshape(60000, 784) #  reshapeは28×28画素の画像を784×1のデータに変換している.
x_test = x_test.reshape(10000, 784)
#各データを扱いにくいので、RGBの値(白なら255、黒なら0)を利用して0から1までの間に正規化.
x_train = x_train.astype('float32') 
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test =  keras.utils.np_utils.to_categorical(y_test, num_classes)

print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
60000 train samples
10000 test samples
#to_categorical()は,num_classの数の要素を持つ前からy_trainがonehotのリストを作る.
#0#[1,0,0,0,0,0,0,0,0,0]
#1#[0,1,0,0,0,0,0,0,0,0]

3層ニューラルネットワーク

 MNISTのデータを受け取り,学習する3層ニューラルネットワーク

 Affine->relu->Affine->relu->softmax の順でデータを渡す,線形スタックである.

Affineレイヤとは

 Affineレイヤは,ニューロン同士が全結合のニューラルネットワークレイヤを指す.

CNNにおけるAffineレイヤ

 CNNはAffineレイヤに加え,畳み込みレイヤ(Convolution)とプーリングレイヤ(Pooling)を用いる.

softmaxレイヤとは

 入力されたデータを足した値が1になるように出力する層.各要素の大小関係は変わらない.NNにおいて往々にして出力層はsoftmaxレイヤである.この特性から,a%で結果A,b%で結果B,c%で結果Cという確率的な答えが求められる場合がある.しかし,今回のようなクラス分類問題では,出力の一番大きいニューロンに相当するものみが選ばれるため,その役割は満たせない.

ReLUレイヤとは

 活性化関数として使われる.回路におけるスイッチの様に機能する.

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.optimizers import RMSprop

##add()でレイヤーを重ねる.
##Affine->relu->Affine->relu->softmax の3層NNの線形スタック
##dropout()で過学習を抑制.
##512はニューロンの数
##activationで活性化関数をreluに指定.
##最後の出力層にはsoftmaxを指定.

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,))) ## 入力のshapeは(512,784,)になる.
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu')) ## 2度目以降は入力のshapeをkerasが推定.
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))## softmaxは今回は分類問題なので,必要性は低い.

##訓練プロセスの設定
##RMSprop()は学習係数を過去の勾配を徐々に忘れる,"指数移動平均"を使う.
model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(),
              metrics=['accuracy'])

バッチ処理

 バッチ処理によって,実行時間を短縮することができる. imageのサイズ/バッチのサイズ ->1epochでの計算回数

batch_size = 128
epochs = 20 ##学習の回数
##historyにfittingの課程を保存.
history = model.fit(x_train, y_train,
                    batch_size=batch_size, epochs=epochs,
                    verbose=1, validation_data=(x_test, y_test))
Train on 60000 samples, validate on 10000 samples
Epoch 1/20
60000/60000 [==============================] - 15s - loss: 0.2501 - acc: 0.9226 - val_loss: 0.1096 - val_acc: 0.9650
Epoch 2/20
60000/60000 [==============================] - 13s - loss: 0.1025 - acc: 0.9682 - val_loss: 0.1021 - val_acc: 0.9685
Epoch 3/20
60000/60000 [==============================] - 14s - loss: 0.0776 - acc: 0.9764 - val_loss: 0.0755 - val_acc: 0.9778
Epoch 4/20
60000/60000 [==============================] - 13s - loss: 0.0615 - acc: 0.9818 - val_loss: 0.0894 - val_acc: 0.9746
Epoch 5/20
60000/60000 [==============================] - 13s - loss: 0.0506 - acc: 0.9846 - val_loss: 0.0784 - val_acc: 0.9794
Epoch 6/20
60000/60000 [==============================] - 13s - loss: 0.0451 - acc: 0.9872 - val_loss: 0.0778 - val_acc: 0.9806
Epoch 7/20
60000/60000 [==============================] - 13s - loss: 0.0398 - acc: 0.9886 - val_loss: 0.0697 - val_acc: 0.9831
Epoch 8/20
60000/60000 [==============================] - 13s - loss: 0.0366 - acc: 0.9893 - val_loss: 0.1008 - val_acc: 0.9812
Epoch 9/20
60000/60000 [==============================] - 13s - loss: 0.0322 - acc: 0.9907 - val_loss: 0.0854 - val_acc: 0.9831
Epoch 10/20
60000/60000 [==============================] - 13s - loss: 0.0284 - acc: 0.9918 - val_loss: 0.0904 - val_acc: 0.9817
Epoch 11/20
60000/60000 [==============================] - 13s - loss: 0.0268 - acc: 0.9918 - val_loss: 0.0958 - val_acc: 0.9820
Epoch 12/20
60000/60000 [==============================] - 13s - loss: 0.0262 - acc: 0.9930 - val_loss: 0.1001 - val_acc: 0.9797
Epoch 13/20
60000/60000 [==============================] - 12s - loss: 0.0238 - acc: 0.9930 - val_loss: 0.0951 - val_acc: 0.9834
Epoch 14/20
60000/60000 [==============================] - 12s - loss: 0.0228 - acc: 0.9937 - val_loss: 0.0975 - val_acc: 0.9847
Epoch 15/20
60000/60000 [==============================] - 14s - loss: 0.0214 - acc: 0.9942 - val_loss: 0.0984 - val_acc: 0.9831
Epoch 16/20
60000/60000 [==============================] - 13s - loss: 0.0191 - acc: 0.9946 - val_loss: 0.0994 - val_acc: 0.9842
Epoch 17/20
60000/60000 [==============================] - 13s - loss: 0.0192 - acc: 0.9948 - val_loss: 0.1141 - val_acc: 0.9834
Epoch 18/20
60000/60000 [==============================] - 13s - loss: 0.0191 - acc: 0.9948 - val_loss: 0.1025 - val_acc: 0.9846
Epoch 19/20
60000/60000 [==============================] - 13s - loss: 0.0182 - acc: 0.9950 - val_loss: 0.1054 - val_acc: 0.9834
Epoch 20/20
60000/60000 [==============================] - 13s - loss: 0.0171 - acc: 0.9958 - val_loss: 0.1104 - val_acc: 0.9834
#正答率
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
#loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

png f:id:forhighlow:20170814154827p:plain

png f:id:forhighlow:20170814154831p:plain

考察

 上記出力結果のmodel lossが,学習が進むに連れて悪くなっていった.これは過学習をしかけていると考えられる.

考察を踏まえた改善

Dropout関数

 過学習を防ぐ手法にDropoutがある.ランダムにニューロンを削除することにより,過学習を防いでいる.

最適化関数

RMSpropsから,Adadeltaへ変更した.これらは最適化関数Adagradは急速に学習率が低下するという問題点から,過去の勾配を利用するという共通点がある.

Adadelta

過去の勾配による影響を減衰させる.

\begin{align} r &\leftarrow \gamma r + (1 - \gamma) g\vec{w}^{2} \ v &\equiv \frac{\sqrt{s + \epsilon}}{\sqrt{r + \epsilon}} g\vec{w} \ w &\leftarrow w - \alpha v \ s &\leftarrow \gamma s + (1 - \gamma) v^{2} \end{align}

RMSprop

学習率は、勾配の二乗の指数関数的減衰平均の除算. 過去の勾配による影響を減衰させる.

\begin{align} r &\leftarrow \gamma r + (1 - \gamma) g\vec{w}^{2} \ w &\leftarrow w - \frac{\alpha}{\sqrt{r} + \epsilon} g\vec{w} \end{align}

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.optimizers import Adadelta


model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,))) 
model.add(Dropout(0.2))## dropout()で過学習を抑制.
model.add(Dense(512, activation='relu')) 
model.add(Dropout(0.2))## dropout()で過学習を抑制.
model.add(Dense(10, activation='softmax'))


model.compile(loss='categorical_crossentropy',
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])
batch_size = 128
epochs = 20
history = model.fit(x_train, y_train,
                    batch_size=batch_size, epochs=epochs,
                    verbose=1, validation_data=(x_test, y_test))
Train on 60000 samples, validate on 10000 samples
Epoch 1/20
60000/60000 [==============================] - 21s - loss: 0.3602 - acc: 0.8959 - val_loss: 0.1609 - val_acc: 0.9517
Epoch 2/20
60000/60000 [==============================] - 18s - loss: 0.1556 - acc: 0.9540 - val_loss: 0.1114 - val_acc: 0.9667
Epoch 3/20
60000/60000 [==============================] - 15s - loss: 0.1121 - acc: 0.9658 - val_loss: 0.0936 - val_acc: 0.9712
Epoch 4/20
60000/60000 [==============================] - 14s - loss: 0.0885 - acc: 0.9726 - val_loss: 0.0741 - val_acc: 0.9781
Epoch 5/20
60000/60000 [==============================] - 12s - loss: 0.0734 - acc: 0.9782 - val_loss: 0.0719 - val_acc: 0.9779
Epoch 6/20
60000/60000 [==============================] - 12s - loss: 0.0607 - acc: 0.9816 - val_loss: 0.0654 - val_acc: 0.9791
Epoch 7/20
60000/60000 [==============================] - 13s - loss: 0.0518 - acc: 0.9840 - val_loss: 0.0669 - val_acc: 0.9796
Epoch 8/20
60000/60000 [==============================] - 13s - loss: 0.0454 - acc: 0.9858 - val_loss: 0.0629 - val_acc: 0.9806
Epoch 9/20
60000/60000 [==============================] - 13s - loss: 0.0391 - acc: 0.9882 - val_loss: 0.0614 - val_acc: 0.9810
Epoch 10/20
60000/60000 [==============================] - 13s - loss: 0.0354 - acc: 0.9891 - val_loss: 0.0614 - val_acc: 0.9816
Epoch 11/20
60000/60000 [==============================] - 15s - loss: 0.0310 - acc: 0.9903 - val_loss: 0.0576 - val_acc: 0.9833
Epoch 12/20
60000/60000 [==============================] - 15s - loss: 0.0286 - acc: 0.9911 - val_loss: 0.0573 - val_acc: 0.9831
Epoch 13/20
60000/60000 [==============================] - 15s - loss: 0.0262 - acc: 0.9922 - val_loss: 0.0585 - val_acc: 0.9831
Epoch 14/20
60000/60000 [==============================] - 16s - loss: 0.0221 - acc: 0.9929 - val_loss: 0.0561 - val_acc: 0.9845
Epoch 15/20
60000/60000 [==============================] - 15s - loss: 0.0196 - acc: 0.9940 - val_loss: 0.0567 - val_acc: 0.9835
Epoch 16/20
60000/60000 [==============================] - 14s - loss: 0.0184 - acc: 0.9943 - val_loss: 0.0575 - val_acc: 0.9830
Epoch 17/20
60000/60000 [==============================] - 13s - loss: 0.0164 - acc: 0.9953 - val_loss: 0.0572 - val_acc: 0.9837
Epoch 18/20
60000/60000 [==============================] - 13s - loss: 0.0153 - acc: 0.9953 - val_loss: 0.0626 - val_acc: 0.9828
Epoch 19/20
60000/60000 [==============================] - 15s - loss: 0.0142 - acc: 0.9956 - val_loss: 0.0630 - val_acc: 0.9820
Epoch 20/20
60000/60000 [==============================] - 16s - loss: 0.0133 - acc: 0.9959 - val_loss: 0.0615 - val_acc: 0.9831

改善の結果

 Dropoutを用いた結果,過学習を防ぐことができた.

#正答率
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
#loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

png f:id:forhighlow:20170814154834p:plain

png f:id:forhighlow:20170814154838p:plain

CNNによるMNIST分類の実装

異なる点

 CNNを用いない上記の実装では,28ピクセル×28ピクセルのデータを1次元のベクトルに変換して入力していた.CNNは行列で入力するため,次元数を落とすことによるデータの形状の情報の欠損がない.

import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 12

img_rows, img_cols = 28, 28 ##画像のピクセル数

(x_train, y_train), (x_test, y_test) = mnist.load_data()

#Kerasのバックエンドで動くTensorFlowとTheanoでは入力チャンネルの順番が違うので場合分けして書いています
if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

Using TensorFlow backend.
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test =  keras.utils.np_utils.to_categorical(y_test, num_classes)
60000 train samples
10000 test samples

CNNによる3層ニューラルネットワーク

 Convolution->relu->Convolution->relu->softmaxの線形スタック.

Convolutionレイヤ

畳み込み層.形状を維持する.

画像の場合,入力データを3次元のデータとして受け取り,同じく3次元のデータとして,次の層にデータを出力する.

畳み込み演算

フィルター演算とも言う.

入力データをフィルターの一定のウィンドウの要素との乗算をし,その和を求める.積和演算とも言う.

Poolingレイヤ

縦,横方向の空間を小さくする演算を行う.

Flatten関数

入力を平滑化する.バッチサイズの影響を受けない.コード中では,1次元配列へ変換している.

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))#行列で入力
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2))) #Poolingレイヤ
model.add(Dropout(0.25))#dropout
model.add(Flatten())#1次元配列へ変換
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])
history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
          verbose=1, validation_data=(x_test, y_test))
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
60000/60000 [==============================] - 254s - loss: 0.3201 - acc: 0.9028 - val_loss: 0.0764 - val_acc: 0.9761
Epoch 2/12
60000/60000 [==============================] - 247s - loss: 0.1121 - acc: 0.9668 - val_loss: 0.0531 - val_acc: 0.9824
Epoch 3/12
60000/60000 [==============================] - 226s - loss: 0.0859 - acc: 0.9750 - val_loss: 0.0436 - val_acc: 0.9861
Epoch 4/12
60000/60000 [==============================] - 224s - loss: 0.0725 - acc: 0.9785 - val_loss: 0.0394 - val_acc: 0.9874
Epoch 5/12
60000/60000 [==============================] - 249s - loss: 0.0618 - acc: 0.9814 - val_loss: 0.0354 - val_acc: 0.9885
Epoch 6/12
60000/60000 [==============================] - 217s - loss: 0.0556 - acc: 0.9832 - val_loss: 0.0354 - val_acc: 0.9876
Epoch 7/12
60000/60000 [==============================] - 223s - loss: 0.0503 - acc: 0.9846 - val_loss: 0.0331 - val_acc: 0.9893
Epoch 8/12
60000/60000 [==============================] - 215s - loss: 0.0472 - acc: 0.9860 - val_loss: 0.0314 - val_acc: 0.9883
Epoch 9/12
60000/60000 [==============================] - 232s - loss: 0.0445 - acc: 0.9871 - val_loss: 0.0291 - val_acc: 0.9898
Epoch 10/12
60000/60000 [==============================] - 200s - loss: 0.0427 - acc: 0.9874 - val_loss: 0.0280 - val_acc: 0.9909
Epoch 11/12
60000/60000 [==============================] - 219s - loss: 0.0396 - acc: 0.9884 - val_loss: 0.0286 - val_acc: 0.9897
Epoch 12/12
60000/60000 [==============================] - 205s - loss: 0.0379 - acc: 0.9884 - val_loss: 0.0281 - val_acc: 0.9902

実行結果

import matplotlib.pyplot as plt
#正答率
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
#loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

png f:id:forhighlow:20170814154841p:plain

png f:id:forhighlow:20170814154846p:plain

実行結果の比較

CNNではない実装

Epoch 12/20
60000/60000 [==============================] - 15s - loss: 0.0286 - acc: 0.9911 - val_loss: 0.0573 - val_acc: 0.9831
Epoch 20/20
60000/60000 [==============================] - 16s - loss: 0.0133 - acc: 0.9959 - val_loss: 0.0615 - val_acc: 0.9831

CNNによる実装

Epoch 5/12
60000/60000 [==============================] - 249s - loss: 0.0618 - acc: 0.9814 - val_loss: 0.0354 - val_acc: 0.9885
Epoch 6/12
60000/60000 [==============================] - 217s - loss: 0.0556 - acc: 0.9832 - val_loss: 0.0354 - val_acc: 0.9876
Epoch 12/12
60000/60000 [==============================] - 205s - loss: 0.0379 - acc: 0.9884 - val_loss: 0.0281 - val_acc: 0.9902

正答率

 どちらも,98.8%以上の確率で文字を認識している.しかし,CNNを用いた実装のほうが,収束が遅い.

 原因は二つ考えられる.

1つは一番の違いである,ニューラルネットワーク層の構造が複雑になったことから,12というephoch数では,足りなかったと考えられる.

2つ目は,原因はなく,この差はただの誤差であると考えることだ.ニューラルネットワークの実装の課程で,ランダムにニューロンを削除するdropoutや,正答かどうかを判断するための教師データを元データからランダムに選び出したりなど,ランダムに選ぶことがよくある.この為にたまたま収束が遅い事があり得ると考えられる.

今後の課題

 本稿では,MNIST分類問題をテーマに,畳み込みニューラルネットワーク(CNN)とそれ以前のニューラルネットワークを比較して実装し,CNNの特徴について学んだ.

 本稿ではMNIST分類をテーマとして選択したが,CNNの特徴であるデータの形状が持つ情報を活かせる複雑なテーマではなかったことがCNNとそうでない実装の実験結果の比較からも分かる.次はこれらの違いが如実に出るような,複雑な分類問題に取り組みたい.

引用元

https://keras.io/ja/

本稿を参照したい場合

本稿を参照したい場合 https://github.com/psato/Keras-MNIST

参考

  • 今回も大変役立った参考書 こちらを見れば,基本的構造はすべてわかると言って過言でない.ただ,コードを実際に引用してもあまり旨味はない.Kerasを用いていないため理論的理解は進む.

O'Reilly Japan - ゼロから作るDeep Learning

  • Kerasが公開しているMNISTの例

keras/mnist_cnn.py at master · fchollet/keras · GitHub

  • 画像の確認や,基本的構造を解説しているわかりやすいサイト

KerasでDeep Learning:KerasでMNISTデータを扱ってみる - データサイエンティスト(仮)

  • Keras

日本語ドキュメント

最適化 - Keras Documentation

分からないモジュールの引用を,ここで検索すると,機能がわかる.簡潔で分かりやすい!

  • 次はこれにチャレンジ

Deep Learning はじめました【CIFAR-10の識別】 - sonickun.log

CIFAR-10 and CIFAR-100 datasets

  • ipython からスライド作成

iPython でスライド作り - Qiita

Converting notebooks to other formats — IPython 3.2.1 documentation

Jupyter nbconvert(ファイル変換)メモ - はしくれエンジニアもどきのメモ

  • エラーの対処 パッケージのインストールで済むことが多い.