---
# System prepended metadata

title: はじめてのディープラーニング（分類）
tags: [' numpy', general]

---

---
tags: general, numpy
---

# はじめてのディープラーニング（分類）


numpyを使った簡単な分類モデルになります。$-1 \leqq x \leqq 1$ 領域で$y(-1 \leqq y \leqq 1)$の値が$\sin{x \pi}$より大きいか小さいかを分類するモデルを構築します。


---

### 0.1 ライブラリ
```
import numpy as np
import matplotlib.pyplot as plt
```

### モデル
- 入力：　($x$, $y$)
- 出力：　$p = (p_{correct}, p_{wrong})$

入力は、$-1 \leqq x \leqq 1$、$y(-1 \leqq y \leqq 1)$を0.1ずつ取った点の2次元$(x, y)$をランダムに入力しています。中間層は１層でノードは６つとします。活性化関数はsigmoid関数を使っています。出力層では、正解・不正解の確率を求めるために活性化関数にsoftmax関数を適用します。
また、損失関数は交差エントロピー関数、最適化アルゴリズムには確率的勾配降下法です。

### 0.1 ハイパラメータ
- $w$(重み)：0.01
- $\eta$(学習率)：　0.1
- $epoch$: 100
- $interval$: 10

```
wb_width = 0.01
eta = 0.1
epoch = 101
interval = 10
```

### 0.2 入力データと正解データの準備

```:qiita.rb
X = np.arange(-1.0, 1.1, 0.1)
Y = np.arange(-1.0, 1.1, 0.1)

input_data = []
correct_data = []

for x in X:
    for y in Y:
        input_data.append([x, y])
        if y < np.sin(np.pi * x):
            correct_data.append([0, 1])
        else:
            correct_data.append([1, 0])

n_data = len(correct_data)

input_data = np.array(input_data)
correct_data = np.array(correct_data)
```

## 1.1 中間層の構築

```
class MiddleLayer:
    def __init__(self, n_upper, n):
        self.w = wb_width * np.random.rand(n_upper, n)
        self.b = wb_width * np.random.rand(n)
    
    def forward(self, x):
        self.x = x
        u = np.dot(x, self.w) + self.b
        self.y = 1 / (1 + np.exp(-u))
    
    def backward(self, grad_y):
        delta = grad_y * (1 - self.y)*self.y
        
        self.grad_w = np.dot(self.x.T, delta)
        self.grad_b = np.sum(delta, axis=0)
        
    def update(self, eta):
        self.w -= eta * self.grad_w
        self.b -= eta * self.grad_b
```

### 1.2 出力層の構築

```
class OutputLayer:
    def __init__(self, n_upper, n):
        self.w = wb_width * np.random.randn(n_upper, n)
        self.b = wb_width * np.random.rand(n)
        
    def forward(self, x):
        self.x = x
        u = np.dot(x, self.w) + self.b
        self.y = np.exp(u) / np.sum(np.exp(u), axis=1, keepdims=True)
        
    def backward(self, t):
        delta = self.y - t
        
        self.grad_w = np.dot(self.x.T, delta)
        self.grad_b = np.sum(delta, axis=0)
        
        self.grad_x = np.dot(delta, self.w.T)
        
    def update(self, eta):
        self.w -= eta * self.grad_w
        self.b -= eta * self.grad_b
```

### 1.3 モデルの宣言

```classify.ipynb
n_in = 2
n_mid = 6
n_out = 2

middle_layer = MiddleLayer(n_in, n_mid)
output_layer = OutputLayer(n_mid, n_out)
```

## 2.1 実装

```classify.ipynb
sin_data = np.sin(np.pi * X)
for i in range(epoch):
    index_random = np.arange(n_data)
    np.random.shuffle(index_random)
    
    total_error = 0
    x_1, y_1, x_2, y_2 = [], [], [], []
    
    for idx in index_random:
        x = input_data[idx]
        t = correct_data[idx]
        
        middle_layer.forward(x.reshape(1, 2))
        output_layer.forward(middle_layer.y)
        
        output_layer.backward(t.reshape(1, 2))
        middle_layer.backward(output_layer.grad_x)
        
        middle_layer.update(eta)
        output_layer.update(eta)
        
        if i%interval == 0:
            y = output_layer.y.reshape(-1)
            
            total_error += - np.sum(t * np.log(y + 1e-7) )
            
            if y [0] > y[1]:
                x_1.append(x[0])
                y_1.append(x[1])
            else:
                x_2.append(x[0])
                y_2.append(x[1])
                
    if i%interval == 0:
        plt.plot(X, sin_data, linestyle="dashed")
        plt.scatter(x_1, y_1, marker='+')
        plt.scatter(x_2, y_2, marker='x')
        plt.show()

        print(f"Epoch: {i} / {epoch}, Error: {total_error/n_data}")
```

https://github.com/jsakaguc/NCCEPOC/blob/main/general/classify.ipynb

のclassify.ipynbで公開しています。