[CNN] Simple Convolution Network function

Simple Convolution Network 나머지 함수들

전체 코드

def predict(self, x):
    for layer in self.layers.values():
        x = layer.forward(x)

    return x

def loss(self, x, t):
    """손실 함수를 구한다.

    Parameters
    ----------
    x : 입력 데이터
    t : 정답 레이블
    """
    y = self.predict(x)
    return self.last_layer.forward(y, t)

def accuracy(self, x, t, batch_size=100):
    if t.ndim != 1 : t = np.argmax(t, axis=1)

    acc = 0.0

    for i in range(int(x.shape[0] / batch_size)):
        tx = x[i*batch_size:(i+1)*batch_size]
        tt = t[i*batch_size:(i+1)*batch_size]
        y = self.predict(tx)
        y = np.argmax(y, axis=1)
        acc += np.sum(y == tt) 

    return acc / x.shape[0]

def numerical_gradient(self, x, t):
    """기울기를 구한다(수치미분).

    Parameters
    ----------
    x : 입력 데이터
    t : 정답 레이블

    Returns
    -------
    각 층의 기울기를 담은 사전(dictionary) 변수
        grads['W1']、grads['W2']、... 각 층의 가중치
        grads['b1']、grads['b2']、... 각 층의 편향
    """
    loss_w = lambda w: self.loss(x, t)

    grads = {}
    for idx in (1, 2, 3):
        grads['W' + str(idx)] = numerical_gradient(loss_w, self.params['W' + str(idx)])
        grads['b' + str(idx)] = numerical_gradient(loss_w, self.params['b' + str(idx)])

    return grads

def gradient(self, x, t):
    """기울기를 구한다(오차역전파법).

    Parameters
    ----------
    x : 입력 데이터
    t : 정답 레이블

    Returns
    -------
    각 층의 기울기를 담은 사전(dictionary) 변수
        grads['W1']、grads['W2']、... 각 층의 가중치
        grads['b1']、grads['b2']、... 각 층의 편향
    """
    # forward
    self.loss(x, t)

    # backward
    dout = 1
    dout = self.last_layer.backward(dout)

    layers = list(self.layers.values())
    layers.reverse()
    for layer in layers:
        dout = layer.backward(dout)

    # 결과 저장
    grads = {}
    grads['W1'], grads['b1'] = self.layers['Conv1'].dW, self.layers['Conv1'].db
    grads['W2'], grads['b2'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
    grads['W3'], grads['b3'] = self.layers['Affine2'].dW, self.layers['Affine2'].db

    return grads

def save_params(self, file_name="params.pkl"):
    params = {}
    for key, val in self.params.items():
        params[key] = val
    with open(file_name, 'wb') as f:
        pickle.dump(params, f)

def load_params(self, file_name="params.pkl"):
    with open(file_name, 'rb') as f:
        params = pickle.load(f)
    for key, val in params.items():
        self.params[key] = val

    for i, key in enumerate(['Conv1', 'Affine1', 'Affine2']):
        self.layers[key].W = self.params['W' + str(i+1)]
        self.layers[key].b = self.params['b' + str(i+1)]

1. predict

입력값에 대한 예측값을 리턴해주는 함수이다.
Conv -> Relu -> Pooling -> Affine -> Relu -> Affine -> Softmax

def predict(self, x):
    for layer in self.layers.values():
        x = layer.forward(x)

    return x

각각 레이어의 정의되어있는 forward 함수는 다음과 비슷하다.

class Relu:

    def forward(self, x):
        self.mask = (x <= 0)
        out = x.copy()
        out[self.mask] = 0

        return out

class Sigmoid:

    def forward(self, x):
        out = sigmoid(x)
        self.out = out
        return out

class Affine:

    def forward(self, x):
        # 텐서 대응
        self.original_x_shape = x.shape
        x = x.reshape(x.shape[0], -1)
        self.x = x

        out = np.dot(self.x, self.W) + self.b

        return out

2. loss

입력값 x 에 대한 결과 y를 저장하고 desire value t와 비교하여 loss를 구한다. loss로는 cross-entropy, mean-sqaured error 등이 있다.

def loss(self, x, t):

    y = self.predict(x)
    return self.last_layer.forward(y, t)
class SoftmaxWithLoss:

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)

        return self.loss

3. accuracy

np.argmax()는 배열 내 가장 큰 원소의 인덱스를 반환하는 형식이다.
axis = 0: 세로축끼리 원소를 비교한다.
axis = 1: 가로축끼리 원소를 비교한다.

a = [10, 3, 13, 11]
np.argmax(a) # 2출력

t 정답레이블 배열의 차원이 1이 아니라면 t에 np.argmax(t, axis=1)을 저장하여 가로축끼리 비교한 뒤 인덱스를 저장한다 -> 한차원 축소

shape 함수를 통해 행, 렬을 알 수 있다.

b = np.array([[4, 3, 2], [8, 5, 9]]) # 2 * 3 matrix
b.shape # (2,3)

입력 데이터에서 batch size만큼 뽑아내어 predict하고 argmax로 뽑은 값이 정답 데이터에서 뽑은 값과 같다면 정확도를 카운트하고 전체에서 카운트를 나눈값을 리턴한다.

def accuracy(self, x, t, batch_size=100):
    if t.ndim != 1 : t = np.argmax(t, axis=1)

    acc = 0.0

    for i in range(int(x.shape[0] / batch_size)):
        tx = x[i*batch_size : (i+1)*batch_size]
        tt = t[i*batch_size : (i+1)*batch_size]
        y = self.predict(tx)
        y = np.argmax(y, axis=1)
        acc += np.sum(y == tt) 

    return acc / x.shape[0]

4. numerical_gradient

grads라는 빅 딕셔너리 타입의 변수를 만들고 W1, W2, W3, b1, b2, b3를 순회하며 loss를 저장하여 리턴한다.

lambda 식이 이해가 안됬는데 간단한 예제를 만들어봤다.
lambda 매개변수 : 함수(매개변수)

def add(a, b):
    return a+b

x = lambda x, k : add(x, k)
x(10,2)
 def numerical_gradient(self, x, t):

    loss_w = lambda w: self.loss(x, t)

    grads = {}
    for idx in (1, 2, 3):
        grads['W' + str(idx)] = numerical_gradient(loss_w, self.params['W' + str(idx)])
        grads['b' + str(idx)] = numerical_gradient(loss_w, self.params['b' + str(idx)])

    return grads

5. gradient

Backpropagation 학습에 대한 함수이다.

self.loss 함수를 거치면 SoftmaxWithLoss 클래스의 forward 함수가 실행되고 loss값이 나온다(forward).

backward에 관해서는 추후 정리해보려고 한다.

  def gradient(self, x, t): 
    # forward
    self.loss(x, t)

    # backward
    dout = 1
    dout = self.last_layer.backward(dout)

    layers = list(self.layers.values())
    layers.reverse()
    for layer in layers:
        dout = layer.backward(dout)

    # 결과 저장
    grads = {}
    grads['W1'], grads['b1'] = self.layers['Conv1'].dW, self.layers['Conv1'].db
    grads['W2'], grads['b2'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
    grads['W3'], grads['b3'] = self.layers['Affine2'].dW, self.layers['Affine2'].db

    return grads

6. save, load params

init 했을때의 딕셔너리 타입의 params 변수를 생성했고 key, value 쌍을 items()로 불러와 파일에 저장한다.

 def save_params(self, file_name="params.pkl"):
    params = {}
    for key, val in self.params.items():
        params[key] = val
    with open(file_name, 'wb') as f:
        pickle.dump(params, f)

파일을 로드해서 layer의 Weight, bias에 값을 저장한다.

def load_params(self, file_name="params.pkl"):
    with open(file_name, 'rb') as f:
        params = pickle.load(f)
    for key, val in params.items():
        self.params[key] = val

    for i, key in enumerate(['Conv1', 'Affine1', 'Affine2']):
        self.layers[key].W = self.params['W' + str(i+1)]
        self.layers[key].b = self.params['b' + str(i+1)]

참고자료

https://amber-chaeeunk.tistory.com/22

 

딥러닝) 신경망 학습 전체 알고리즘 (코드)

1. 신경망 구축에 필요한 Layers import numpy as np from common.functions import * class Relu: def __init__(self): self.mask = None def forward(self, x): self.mask = (x lambda 변수: return 식 grads = {} grads['W1'] = numerical_gradient(loss_W, se

amber-chaeeunk.tistory.com

 

https://jimmy-ai.tistory.com/72

 

[Numpy] 파이썬 최대값, 최소값 위치 반환 np.argmax, np.argmin

파이썬 넘파이 argmax, argmin 함수 안녕하세요. 이번 포스팅에서는 파이썬 넘파이 라이브러리에서 제공하는 최대값, 최소값의 위치 인덱스를 반환하는 함수인 np.argmax와 np.argmin 함수에 대해서 간략

jimmy-ai.tistory.com

 

https://wikidocs.net/22804

 

4) 람다함수(익명함수)

파이썬에서는 람다함수를 통해 이름이 없는 함수를 만들 수 있습니다. 람다함수의 장점은 코드의 간결함 메모리의 절약이라고 생각할 수 있습니다. `def`키워드를 통해서 함수를 …

wikidocs.net

 

'📦 개발 > AI' 카테고리의 다른 글

[CNN] Simple Convolution Network  (0) 2023.01.30
[CNN] 용어 정리  (0) 2023.01.26