Deep Learning from scratch vol.1

# Deep Learningについて
**Deep Learning**(深層学習)とは, "AI"の要素技術の1つである[^DL].
時系列順に"AI"に関する技術発展を図式化すると, 以下のような図で表される[^ai]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/c0be618d-ff4e-fea6-9ed4-806fbd2ad0ab.png "Time scale of relationship with AI.")
[^DL]: [LeapMind ディープラーニング(Deep Learning)とは【入門編】](https://leapmind.io/blog/2017/06/16/%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%EF%BC%88deep-learning%EF%BC%89%E3%81%A8%E3%81%AF%EF%BC%9F%E3%80%90%E5%85%A5%E9%96%80%E7%B7%A8%E3%80%91/)
[^ai]: [What’s the Difference Between Artificial Intelligence, Machine Learning and Deep Learning?](https://blogs.nvidia.com/blog/2016/07/29/whats-difference-artificial-intelligence-machine-learning-deep-learning-ai/)

ここで, "AI"とは"何か"は論ぜず, 要素技術であるMachine Learning(機械学習), Deep Learning(深層学習)の概要についてのみ言及する.

## Machine Learning
"AI"を実現するためのアプローチとして考えられた学習手法[^ai]であり, 特定の事象に対してデータを解析して, その結果を基に判断や予測をおこなうアルゴリズムである.
Machine Learningの手法は以下のようなものがある[^DL].

* 教師あり学習：正解付きのデータを機械に学習させる手法
    * 回帰：データを入力すると, 出力として数値を返す(予測).
    * 分類：データを入力すると, 出力としてデータの属性や種類を返す(ラベリング).
* 教師なし学習：正解を必要とせず、膨大なデータから自動的に算出した特徴量から構造や傾向、法則などを導くことで機械に学習させる手法. 
    * クラスタリング：データを入力すると, 出力としてデータのグルーピング結果を返す.
* 強化学習：自ら試行錯誤して最適な行動を見つける学習で、直近の目標を達成し、報酬を与えることで上達していく手法.

## Deep Learning
十分なデータ量があれば, 自動的にデータから特徴を抽出するニューラルネットワーク(Neural Network, NN)を用いた手法のこと.
Deep Learningのアルゴリズムには主に以下のような種類がある.

* Deep Neural Network(DNN)
    * 人間や動物の脳神経回路をモデルとしたアルゴリズムを多層構造化したもの.
* Convolutional Neural Network(CNN)
    * 畳み込みニューラルネットワーク
    * 局所的な情報の抽象化, 及び位置普遍性をもたせた順伝播型NNを利用したアルゴリズム.
    * 画像認識等に使われる.
* Recurrent Neural Network(RNN)
    * 再帰型ニューラルネットワーク
    * 音声、動画データのような可変長のデータを扱えるようにするために, 中間層に再帰的な構造をもたせた双方向に信号が伝播するNNを利用したアルゴリズム.
    * 音声認識, 動画認識, 自然言語処理等に使われる.

# Python入門
参考書[^reference]で特に理解しておくべき項目についてまとめる.
[^reference]: O'REILLY&reg;「ゼロから作るDeep Learning ~Pythonで学ぶディープラーニングの理論と実装~」 https://www.oreilly.co.jp/books/9784873117584/

## class
初めからPythonに組み込まれたデータ型以外に, `class`というキーワードを使って独自のデータ型を作成することが出来る.

```python
class name:
    def __init__(self, val_1, ...): # constructor
        ...
    def method_1(self, val_1, ...): # method 1
        ...
    def method_2(self, val_1, ...): # method 2
        ...
```
`def __init__(self, val_1, ...):`は**コンストラクタ**(constructor)と呼ばれる初期化用のメソッドである.インスタンスを生成する際に, 一度だけ呼ばれる.

## Numpy
Numpyをimportすることで, 配列計算が簡単にできる[^list].

[^list]: importする前の配列同士で計算させると, 配列同士の連結になってしまう. 配列の要素同士を計算させたい場合には, forを使って各要素に対して演算処理を記述する必要がある.

### 配列の生成
```python
import numpy as np

x = np.array([1, 2.0, 3.2, 4.39])
print(x)
>>> [1.   2.   3.2  4.39]
```
### 算術計算
Numpy配列は要素数が同じであれば, 各要素に対して算術計算をおこなうことが可能.
また, 配列とスカラ値の組み合わせでの計算も可能[^broadcast].

[^broadcast]: 形状の異なる配列の演算をおこなう機能を**ブロードキャスト**(Broadcast)と呼ぶ.

:::note info
要素ごと -> element-wise
:::


```python
# before
x = [1, 2.0, 3.2, 4.39]
y = [2.0, 4.0, 6.0, 8.0]
print(x + y)
>>> [1, 2.0, 3.2, 4.39, 2.0, 4.0, 6.0, 8.0]

# after
x = np.array([1, 2.0, 3.2, 4.39])
y = np.array([2.0, 4.0, 6.0, 8.0])
print(x + y)
>>> [ 3.    6.    9.2  12.39]
print(x - y)
>>> [-1.   -2.   -2.8  -3.61]
print(x * y) # element-wise product
>>> [ 2.    8.   19.2  35.12]
print(x / y) 
>>> [0.5        0.5        0.53333333 0.54875   ]
print(x / 2.0) # broadcast
>>> [0.5   1.    1.6   2.195]
```

### N次元配列
1次元配列と同様, 多次元配列[^tensor]を作成可能で, 算術計算は各要素でおこなわれる.

[^tensor]: 1次元配列を**ベクトル**(vector), 一般化されたベクトルや多次元配列を**テンソル**(tensor)と呼ぶ.

```python
A = np.array([[1.0, 2.2], [3.2, 4.0]])
print(A)
>>> [[1.  2.2]
     [3.2 4. ]]
print(A.shape)
>>> (2, 2)
A.dtype
>>> dtype('float64')
B = np.array([[3, 0], [0, 6]])
B.dtype
>>> dtype('int64')
print(A + B)
>>> [[ 4.   2.2]
     [ 3.2 10. ]]
print(A * B)
>>> [[ 3.  0.]
     [ 0. 24.]]
print(A * 10)
>>> [[10. 22.]
     [32. 40.]]
```

### 要素へのアクセス
```python
X = np.array([[51, 55], [14, 19], [0, 4]])
print(X)
>>> [[51 55]
     [14 19]
     [ 0  4]]
print(X[0])
>>> [51 55]
print(X[0][1])
>>> 55
for row in X:
  print(row)
>>> [51 55]
    [14 19]
    [0 4]
Y = X.flatten() # 3*2 -> vector
print(Y)
>>> [51 55 14 19  0  4]
print(Y[np.array([0, 2, 4])])
>>> [51 14  0]
print(X > 15)
>>> [[ True  True]
     [False  True]
     [False False]]
print(Y > 15)
>>> [ True  True False  True False False]
print(Y[Y > 15])
>>> [51 55 19]
print(Y[[False, False, True, False, True, True]])
>>> [14  0  4]
```
:::note info
ブーリアンインデックスの考え方を用いて, Trueの要素だけを取り出す.
:::