본문 바로가기
COURSERA

week 3_Planar data classification with a hidden layer 실습 (Andrew Ng)

by HYUNHP 2022. 2. 10.
728x90
반응형

 


안녕하세요, HELLO

 

오늘은 DeepLearning.AI에서 진행하는 앤드류 응(Andrew Ng) 교수님의 딥러닝 전문화의 첫 번째 과정인 "Neural Networks and Deep Learning"을 정리하려고 합니다. "Neural Networks and Deep Learning"의 강의 목적은 '딥러닝의 기능, 과제 및 결과 이해'를 통해 '머신 러닝을 업무에 적용하고, 기술 수준을 높이고, AI 분야에서 단계를 밟을 수 있는 지식과 기술을 얻을 수 있는 경로'를 배우기 위함이며, 강의는 아래와 같이 구성되어 있습니다.

 

~ Introduction

~ Basics of Neural Network programming

~ One hidden layer Neural Networks

~ Deep Neural Networks

 

"Neural Networks and Deep Learning" (Andrew Ng) 3주에서 배운 내용을 바탕으로 Planar data(평면 데이터) 분류기를 1개의 hidden layer를 가진 neural network를 통해 구현하고자 합니다. 추후에 "Neural Networks and Deep Learning"을 듣게 되신다면, 정답 코드가 궁금하신 분들은 참고하시기 바랍니다.

 

1개의 은닉층(hidden layer)을 바탕으로 Planar data(평면 데이터) 분류기를 구현하는 실습을 통해 아래 내용을 배울 수 있습니다.

 

- Implement a 2-class classification neural network with a single hidden layer
- Use units with a non-linear activation function, such as tanh
- Compute the cross entropy loss
- Implement forward and backward propagation


CHAPTER 1. 'Packages'

 

CHAPTER 2. 'Load the Dataset'

 

CHAPTER 3. 'Simple Logistic Regression'

 

CHAPTER 4. 'Neural Network model'


CHAPTER 1. 'Packages'

 

실습에 앞서 필요한 라이브러리 목록입니다.

  • numpy is the fundamental package for scientific computing with Python.
  • sklearn provides simple and efficient tools for data mining and data analysis.
  • matplotlib is a library for plotting graphs in Python.
  • testCases provides some test examples to assess the correctness of your functions
  • planar_utils provide various useful functions used in this assignment

 

# Package imports
import numpy as np
import matplotlib.pyplot as plt
from testCases_v2 import *
import sklearn
import sklearn.datasets
import sklearn.linear_model
from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets

%matplotlib inline

np.random.seed(1) # set a seed so that the results are consistent

 

 

CHAPTER 2. 'Load the Dataset'

 

실습에 필요한 데이터를 불러오고, X 데이터 차원을 확인해보겠습니다.

불러온 데이터를 그래프로 살펴보면, 꽃 모양의 평면 데이터로 red (label y = 0)와 blue (label y = 1)로 이루어져 있습니다. 이번 실습은 데이터에서 red와 blue 영역을 구분하는 것이 목적입니다.

데이터 X와 Y의 차원과 입력 샘플 m의 개수를 살펴보겠습니다.

# (≈ 3 lines of code)
# shape_X = ...
# shape_Y = ...
# training set size
# m = ...
# YOUR CODE STARTS HERE
shape_X = X.shape
shape_Y = Y.shape
m = shape_X[1]
# YOUR CODE ENDS HERE

print ('The shape of X is: ' + str(shape_X))
print ('The shape of Y is: ' + str(shape_Y))
print ('I have m = %d training examples!' % (m))

#The shape of X is: (2, 400)
#The shape of Y is: (1, 400)
#I have m = 400 training examples!

 

반응형

 

CHAPTER 3. 'Simple Logistic Regression'

 

신경망을 구성하기에 앞서서 Logistic Regression을 활용해서, red와 blue 영역을 구분해보겠습니다. sklearn 라이브러리의 내장된 클래스를 사용해 보겠습니다.

# Train the logistic regression classifier
clf = sklearn.linear_model.LogisticRegressionCV();
clf.fit(X.T, Y.T);

# Plot the decision boundary for logistic regression
plot_decision_boundary(lambda x: clf.predict(x), X, Y)
plt.title("Logistic Regression")

# Print accuracy
LR_predictions = clf.predict(X.T)
print ('Accuracy of logistic regression: %d ' % float((np.dot(Y,LR_predictions) + np.dot(1-Y,1-LR_predictions))/float(Y.size)*100) +
       '% ' + "(percentage of correctly labelled datapoints)")

 

sklearn의 LogisticRegressionCV 클래스를 사용해서 모델을 학습했습니다.
그리고 Logistic Regression으로 인한 Decision Boundary를 나타내면 다음과 같이 나타납니다.

dataset이 선형적으로 구분되지 않아서, logistic regression이 잘 작동하지 않습니다. (정확도 47% 달성)


CHAPTER 4. 'Neural Network model'

 

로지스틱 회귀는 'flower dataset'에서 잘 작동하지 않아서, 1개의 은닉층(hidden layer)을 가지는 신경망에서 확인하고자 합니다.

위 모델을 구현할 것이며, 아래와 같이 각 층에서 계산이 이뤄집니다. 은닉층에서 활성화 함수(activation function)는 tanh 함수를 적용하고, 출력층에서 sigmoid 함수를 적용합니다. 그리고 최종적으로 나온 확률 값이 임계점 '0.5'를 초과하면 y=1로 blue로 인지하고, 아닐 경우에는 y=0로 red로 인지합니다.

(이때 임계점(threshold)은 실습에서 임의로 0.5로 설정했습니다.)

비용 함수 J는 아래와 같이 계산됩니다.

그리고 1개의 은닉층을 가지는 신경망은 아래와 같이 진행됩니다.

 

1. Define the neural network structure ( # of input units, # of hidden units, etc)

2. 모델의 파라미터 초기화

3. 아래 과정을 반복

  • Forward propagation 수행
  • Compute loss
  • Gradients (미분 값)을 얻기 위해 Backward propagation 수행
  • Update parameteres (Gradient descent)

우리는 위 1~3단계를 각각의 함수로 정의하고, 마지막에 nn_model 함수로 합칠 예정입니다.


4.1 - Defining the neural network structure

 

네트워크 구조를 정의하기 위해서 다음과 같이 설정합니다.

- n_x : the size of the input layer

- n_h : the size of the hidden layer (set this to 4)

- n_y : the size of output layer

 

# GRADED FUNCTION: layer_sizes

def layer_sizes(X, Y):
    """
    Arguments:
    X -- input dataset of shape (input size, number of examples)
    Y -- labels of shape (output size, number of examples)
    
    Returns:
    n_x -- the size of the input layer
    n_h -- the size of the hidden layer
    n_y -- the size of the output layer
    """
    ### START CODE HERE ### (≈ 3 lines of code)
    n_x = X.shape[0] # size of input layer
    n_h = 4
    n_y = Y.shape[0] # size of output layer
    ### END CODE HERE ###
    return (n_x, n_h, n_y)

■ 4.2 - Initialize the model's parameters

 

파라미터를 초기화하는데, 신경망에서 w(가중치)는 0이 아닌 랜덤 한 값으로 초기화(Random initialization)를 해야 합니다. 그렇지 않으면, 신경망은 제대로 동작하지 않기 때문입니다. b(잔차)는 0으로 초기화해도 무관합니다.

 

다음의 numpy 함수를 사용해서 초기화(Random initialization)합니다.

W = np.random.randn(shape) * 0.01 (0.01은 임의로 설정한 값입니다.)

b = np.zeros((shape))

 

# GRADED FUNCTION: initialize_parameters

def initialize_parameters(n_x, n_h, n_y):
    """
    Argument:
    n_x -- size of the input layer
    n_h -- size of the hidden layer
    n_y -- size of the output layer
    
    Returns:
    params -- python dictionary containing your parameters:
                    W1 -- weight matrix of shape (n_h, n_x)
                    b1 -- bias vector of shape (n_h, 1)
                    W2 -- weight matrix of shape (n_y, n_h)
                    b2 -- bias vector of shape (n_y, 1)
    """
    
    np.random.seed(2) # we set up a seed so that your output matches ours although the initialization is random.
    
    ### START CODE HERE ### (≈ 4 lines of code)
    W1 = np.random.randn(n_h,n_x) * 0.01
    b1 = np.zeros((n_h,1))
    W2 = np.random.randn(n_y,n_h) * 0.01
    b2 = np.zeros((n_y,1))
    ### END CODE HERE ###
    
    assert (W1.shape == (n_h, n_x))
    assert (b1.shape == (n_h, 1))
    assert (W2.shape == (n_y, n_h))
    assert (b2.shape == (n_y, 1))
    
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}
    
    return parameters

■ 4.3 - The Loop

 

경사 하강법(Gradient Descent)을 반복적으로 수행하는데, forward propagation / cost function / backward propagation를 각각의 함수로 구현해보겠습니다.

 

▲ forward_propagation()

은닉층(hidden layer)에서는 activation 함수로 tanh 함수를 사용하고, 출력층(output layer)에서 sigmoid 함수를 activation function으로 사용합니다. 출력층에서 sigmoid 함수를 사용하는 이유는 이진 분류의 출력 함수에 있어 sigmoid 함수가 tanh 함수보다 계산에 효율적이기 때문입니다. 그리고 캐시(cache)에 각 층의 파라미터와 출력 값을 저장했습니다.

 

# GRADED FUNCTION: forward_propagation

def forward_propagation(X, parameters):
    """
    Argument:
    X -- input data of size (n_x, m)
    parameters -- python dictionary containing your parameters (output of initialization function)
    
    Returns:
    A2 -- The sigmoid output of the second activation
    cache -- a dictionary containing "Z1", "A1", "Z2" and "A2"
    """
    # Retrieve each parameter from the dictionary "parameters"
    ### START CODE HERE ### (≈ 4 lines of code)
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
    ### END CODE HERE ###
    
    # Implement Forward Propagation to calculate A2 (probabilities)
    ### START CODE HERE ### (≈ 4 lines of code)
    Z1 = np.dot(W1,X) + b1
    A1 = np.tanh(Z1)
    Z2 = np.dot(W2,A1) + b2
    A2 = sigmoid(Z2)
    ### END CODE HERE ###
    
    assert(A2.shape == (1, X.shape[1]))
    
    # Values needed in the backpropagation are stored in "cache". This will be given as an input to the backpropagation
    cache = {"Z1": Z1,
             "A1": A1,
             "Z2": Z2,
             "A2": A2}
    
    return A2, cache

 

▲ compute_cost()

 

비용 함수는 아래와 같이 구할 수 있습니다.

 

# GRADED FUNCTION: compute_cost

def compute_cost(A2, Y, parameters):
    """
    Computes the cross-entropy cost given in equation (13)
    
    Arguments:
    A2 -- The sigmoid output of the second activation, of shape (1, number of examples)
    Y -- "true" labels vector of shape (1, number of examples)
    parameters -- python dictionary containing your parameters W1, b1, W2 and b2
    [Note that the parameters argument is not used in this function, 
    but the auto-grader currently expects this parameter.
    Future version of this notebook will fix both the notebook 
    and the auto-grader so that `parameters` is not needed.
    For now, please include `parameters` in the function signature,
    and also when invoking this function.]
    
    Returns:
    cost -- cross-entropy cost given equation (13)
    
    """
    
    m = Y.shape[1] # number of example

    # Compute the cross-entropy cost
    ### START CODE HERE ### (≈ 2 lines of code)
    logprobs = logprobs = np.multiply(Y ,np.log(A2)) + np.multiply((1-Y), np.log(1-A2))
    cost = (-1/m) * np.sum(logprobs)
    ### END CODE HERE ###
    
    cost = float(np.squeeze(cost))  # makes sure cost is the dimension we expect. 
                                    # E.g., turns [[17]] into 17 
    assert(isinstance(cost, float))
    
    return cost

 

▲ backward_propagation()

 

역전파(backward propagation)는 순전파(forward propagation)의 결괏값과 활성화 함수를 활용하여, 미분한 결과를 활용하여 계산됩니다. 아래 그림에서 왼쪽은 수식을 나타낸 것이고, 오른쪽은 코드로 구현한 모습니다.

 

# GRADED FUNCTION: backward_propagation

def backward_propagation(parameters, cache, X, Y):
    """
    Implement the backward propagation using the instructions above.
    
    Arguments:
    parameters -- python dictionary containing our parameters 
    cache -- a dictionary containing "Z1", "A1", "Z2" and "A2".
    X -- input data of shape (2, number of examples)
    Y -- "true" labels vector of shape (1, number of examples)
    
    Returns:
    grads -- python dictionary containing your gradients with respect to different parameters
    """
    m = X.shape[1]
    
    # First, retrieve W1 and W2 from the dictionary "parameters".
    ### START CODE HERE ### (≈ 2 lines of code)
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
    ### END CODE HERE ###
        
    # Retrieve also A1 and A2 from dictionary "cache".
    ### START CODE HERE ### (≈ 2 lines of code)
    A1 = cache["A1"]
    A2 = cache["A2"]
    Z1 = cache["Z1"]
    Z2 = cache["Z2"]
    ### END CODE HERE ###
    
    # Backward propagation: calculate dW1, db1, dW2, db2. 
    ### START CODE HERE ### (≈ 6 lines of code, corresponding to 6 equations on slide above)
    dZ2 = A2 - Y
    dW2 = (1/m) * np.dot(dZ2,A1.T)
    db2 = (1/m) *(np.sum(dZ2,axis=1,keepdims=True))
    dZ1 = np.dot(W2.T,dZ2) * (1 - np.power(A1,2))
    dW1 = (1/m) *(np.dot(dZ1,X.T))
    db1 = (1/m) *(np.sum(dZ1, axis=1, keepdims=True))
    ### END CODE HERE ###
    
    grads = {"dW1": dW1,
             "db1": db1,
             "dW2": dW2,
             "db2": db2}
    
    return grads

 

역전파(backward propagation)를 진행하고 미분 값을 구했으면, 파라미터를 업데이트합니다.

새로운 θ로 파라미터를 업데이트하며, 이때 는 학습률(learning rate)입니다. 만약 learning rate가 적절하다면, 알고리즘은 잘 동작하고 cost를 최소화하는 파라미터를 찾지만, learning rate가 너무 크면 제대로 동작하지 않을 것입니다.

 

# GRADED FUNCTION: update_parameters

def update_parameters(parameters, grads, learning_rate):
    """
    Updates parameters using the gradient descent update rule given above
    
    Arguments:
    parameters -- python dictionary containing your parameters 
    grads -- python dictionary containing your gradients 
    
    Returns:
    parameters -- python dictionary containing your updated parameters 
    """
    # Retrieve each parameter from the dictionary "parameters"
    ### START CODE HERE ### (≈ 4 lines of code)
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
    ### END CODE HERE ###
    
    # Retrieve each gradient from the dictionary "grads"
    ### START CODE HERE ### (≈ 4 lines of code)
    dW1 = grads["dW1"]
    db1 = grads["db1"]
    dW2 = grads["dW2"]
    db2 = grads["db2"]
    ## END CODE HERE ###
    
    # Update rule for each parameter
    ### START CODE HERE ### (≈ 4 lines of code)
    W1 = W1 - learning_rate * dW1
    b1 = b1 - learning_rate * db1
    W2 = W2 - learning_rate * dW2
    b2 = b2 - learning_rate * db2
    ### END CODE HERE ###
    
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}
    
    return parameters

4.4 Integrate 4.1, 4.2, 4.3 in nn_model()

 

4.1 ~ 4.3을 통해 정리된 함수들을 하나의 함수로 정리해보겠습니다. 파라미터를 초기화하고, 매 실행 횟수(iteration)마다 세 가지 함수 forwad_propagation, compute_cost, backward_propagation을 실행하고, 구한 Gradient값으로 파라미터를 업데이트해주는 함수입니다.

 

# NN_model
def nn_model(X, Y, n_h, learning_rate, num_iterations = 10000, print_cost=False):
    n_x = layer_sizes(X, Y)[0]
    n_y = layer_sizes(X, Y)[2]
    
    # Initialize parameters
    parameters = initialize_parameters(n_x, n_h, n_y)
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
    
    # Loop (gradient descent)
    for i in range(0, num_iterations):
        # Forward propagation. Inputs: "X, parameters". Outputs: "A2, cache"
        A2, cache = forward_propagation(X, parameters)
        # Cost function. Inputs: "A2, Y, parameters". Outputs: "cost"
        cost = compute_cost(A2, Y, parameters)
        # Backpropagation. Inputs: "parameters, cache, X, Y". Outputs: "grads"
        grads = backward_propagation(parameters, cache, X, Y)
        # Update rule for each parameter
        parameters = update_parameters(parameters, grads, learning_rate)
        # If print_cost=True, Print the cost every 1000 iterations
        if print_cost and i % 1000 == 0:
            print ("Cost after iteration %i: %f" %(i, cost))
    # Returns parameters learnt by the model. They can then be used to predict output
    return parameters

Predictions

 

신경망 학습을 통해 결괏값을 예측합니다. 설정한 임계값(thershold) 0.5보다 크면 blue (y=1), 0.5보다 작거나 같으면 red (y=0)으로 분류합니다.

# GRADED FUNCTION: predict

def predict(parameters, X):
    """
    Using the learned parameters, predicts a class for each example in X
    
    Arguments:
    parameters -- python dictionary containing your parameters 
    X -- input data of size (n_x, m)
    
    Returns
    predictions -- vector of predictions of our model (red: 0 / blue: 1)
    """
    
    # Computes probabilities using forward propagation, and classifies to 0/1 using 0.5 as the threshold.
    ### START CODE HERE ### (≈ 2 lines of code)
    A2, cache = forward_propagation(X, parameters)
    predictions = (A2 > 0.5)
    ### END CODE HERE ###
    
    return predictions

 

이렇게 구현한 nn_model로 X, Y 데이터와 hidden layer의 size를 4로 설정해서 학습하게 되면 아래와 같은 결과를 얻을 수 있습니다.

 

# Build a model with a n_h-dimensional hidden layer
parameters = nn_model(X, Y, 4, 1.2 , num_iterations = 10000, print_cost=True)

# Plot the decision boundary
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
plt.title("Decision Boundary for hidden layer size " + str(4))

 

이렇게 훈련된 신경망은 정확도 90%가 나옵니다.

 

# Print accuracy
predictions = predict(parameters, X)
print ('Accuracy: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')
# Accuracy: 90%

■ 마무리

 

"Neural Networks and Deep Learning" (Andrew Ng) 3주차에서 배운 내용을 바탕으로 Planar data(평면 데이터) 분류기를 1개의 hidden layer를 가진 neural network를 만드는 코드에 대해서 정리해봤습니다.

 

그럼 오늘 하루도 즐거운 나날 되길 기도하겠습니다

좋아요와 댓글 부탁드립니다 :)

 

감사합니다.

 

반응형

댓글