서론
딥러닝이 발전을 하면서 알파고와 같은 딥러닝과 강화학습이 결합된 형태가 생겨났기에 딥러닝의 간단한 개념에 대해 공부한 다음에 결합된 형태에 대해 알아보자.
Artificial Neuron
뉴런은 인간 두뇌의 기본 계산 단위이다. 뉴런은 수상돌기라고 하는 가지 모양의 구조를 통해 외부 환경, 감각 기관 또는 다른 뉴런으로부터 입력을 받는다. 이러한 입력은 강화되거나 약화된다. 즉, 중요도에 따라 가중치가 부여된 다음 체세포(soma, 세포체)에서 함께 합산된다. 그런 다음 세포체에서 이러한 합산된 입력이 처리되어 축삭을 통해 이동하고 다른 뉴런으로 전송된다.
인공뉴런은 입력으로 외부, 센서 혹은 다른 뉴런에서 들어오며 weights를 곱하고 모든 입력의 합한 뒤 bias를 더해준다. 만약 입력이 하나라면 y=ax+b로 표현이 가능하다. 만약 bias가 없다면, y = ax, 와 같은 일직선 형태가 된다. 즉, 원점을 지나가게 된다는 제약조건이 생기게 된다. 그렇기에 bias가 존재해야 모든 직선 조합을 표현할 수 있다. 위의 z방정식을 보면 선형 회귀(linear regression) 방정식 혹은 직선의 방정식(𝑧 = 𝑚x + 𝑏)처럼 보인다. 즉, 수많은 데이터를 입력한들 한 직선으로 보여주기에 많은 데이터 생략이 되기에 정확한 근사를 하지 못한다. 이를 해결하기 위해 활성화(activation function) 또는 전달 함수(transfer function)라고 하는 함수 𝑓()를 적용하여 결과 𝑧에 비선형성(non linealrity)을 도입한다.
Artificial Neural Networks (ANNs)
단일 뉴런은 복잡한 작업을 수행할 수 없다. 그렇기에 우리 뇌는 네트워크를 형성하는 레이어로 구성된 수십억 개의 뉴런을 갖는 이유이다. 유사하게, 인공 뉴런은 층으로 배열된다. 각 레이어는 정보가 한 레이어에서 다른 레이어로 전달되는 방식으로 연결된다. 일반적인 ANN은 다음 계층(입력층(Input layer), 은닉층(Hidden layer), 출력층(Output layer))으로 구성된다. 각 레이어에는 뉴런 모음이 있으며 한 레이어의 뉴런은 다른 레이어의 모든 뉴런과 상호 작용한다. 그러나 같은 레이어의 뉴런은 서로 상호 작용하지 않는다.
입력층(Input layer)
입력층은 네트워크에 입력을 제공하는 곳이다. 입력층의 뉴런 수는 네트워크에 공급하는 입력 수이다. 각 입력에 가중치(weight)가 곱해지고 바이어스(bias)가 추가되어 다음 레이어로 전달된다.
은닉층(Hidden layer)
입력층과 출력층 사이의 모든 레이어를 은닉층이라고 한다. 은닉층은 입력과 출력 간의 복잡한 관계를 유도하는 역할을 한다. 즉, 은닉층은 데이터셋의 패턴을 식별한다. 은닉층은 개수의 제약은 없지만, 문제에 따라 더 효율적인 수의 은닉층을 선택해야 한다. 아주 간단한 문제의 경우 하나의 은닉층만 사용하면 되지만 이미지 인식과 같은 복잡한 작업을 수행하는 동안에는 각 계층이 이미지의 중요한 특징을 추출하는 역할을 하는 많은 은닉층을 사용하여 이미지를 쉽게 인식할 수 있다.
출력층(Output layer)
입력을 처리한 후 은닉층의 결과를 출력층으로 보낸다. 출력층은 출력을 내보낸다. 출력층의 뉴런 수는 네트워크가 해결하려는 문제 유형과 관련이 있다. 이진 분류(binary classification)의 경우 출력층의 뉴런 수는 입력이 속한 클래스를 알려준다. 5개의 클래스가 있는 다중 클래스 분류(multi-class classification)인 경우 각 클래스가 출력이 될 확률을 얻기 위해 출력층의 뉴런 수는 5개이다. 회귀(regression) 문제인 경우 출력 레이어에 하나의 뉴런이 있다.
Activation Functions
활성 함수는 신경망에서 비선형성을 도입하는 데 사용된다.
Sigmoid functions
시그모이드 함수(Sigmoid functions)는 가장 많이 사용되는 활성화 함수 중 하나이다. 0과 1 사이의 값을 조정한다. 로지스틱 함수(logistic function)라고도 한다.
Hyperbolic tangent function
시그모이드 함수(Sigmoid functions)와 달리 하이퍼볼릭 탄젠트 함수(Hyperbolic tangent function)는 -1과 +1 사이의 값을 스케일링한다.
ReLU function
ReLU는 정류된 선형 단위(rectified linear unit)라고도 한다. 가장 널리 사용되는 활성화 기능 중 하나이다. 언제 미분하면 1 혹은 0이 나온다.
Softmax function
일반적으로 네트워크의 마지막 계층과 다중 클래스 분류 작업을 수행에 적용된다. 각 클래스가 출력이 될 확률을 제공하므로 softmax 값의 합은 항상 1이다.
Deep diving into ANN
Fully connected layer
두 개의 입력 𝑥1, 𝑥2 및 하나의 출력 𝑦이 있는 2 계층 신경망을 고려해 보자. 입력이 2개이므로 입력층의 뉴런 수는 2개이다. 이제 이러한 입력에 가중치를 곱한 다음 바이어스를 추가하고 결과 값을 활성화 함수가 적용될 은닉층으로 전파한다. 가중치와 바이어스 값을 무작위로 초기화한다.
입력층 사이에 흐르는 가중치와 편향을 다음과 같이 나타낼 수 있다. 은닉층을 각각 𝑤𝑥ℎ 및 𝑏ℎ로 지정한다.
가중치 행렬의 차원은 다음과 같아야 한다.
입력층에서 출력층까지의 전체 프로세스를 순방향 전파(forward propagation)라고 한다.
ANN에서 생성된 출력이 올바른지 어떻게 알 수 있을까? 손실 함수(loss function)라고도 하는 비용 함수 𝐽라는 새로운 함수를 정의해야 한다. 이 함수는 ANN이 얼마나 잘 수행되고 있는지 알려준다.
평균 제곱 오차(Mean squared error)란 실제값(𝑦)과 예측값(𝑦^)의 제곱차 평균이다. 우리의 목표는 ANN 예측이 더 나아지도록 비용 함수를 최소화하는 것이다. 가중치와 편향의 일부 값을 변경하여 비용 함수를 최소화할 수 있다. 가중치 행렬과 편향을 무작위로 초기화했기 때문에 완벽하지는 않다. 이제 이러한 가중치 행렬과 편향을 조정하여 비용 함수를 최소화한다.
Gradient Descent
정방향 전파(forward propagation)의 결과 출력층에 있다. 이제 출력층에서 입력층으로 네트워크를 역전파(backpropagate)하고 가중치에 대한 비용 함수의 기울기를 계산하여 가중치를 업데이트하여 오류를 최소화한다. 이해하기 쉽게 우리가 언덕 꼭대기에 있고 언덕의 가장 낮은 지점에 도달하고 싶다고 상상해 보자.
가장 낮은 지점으로 연결되는 언덕에서 한 걸음 아래로 내려가야 한다. 언덕에서 가장 낮은 지점처럼 보이는 많은 지역이 있을 수 있지만 우리는 전체 최저 지점(global lowest point)에 도달해야 한다. 즉, 로컬 최저점(local lowest point)에에 갇히지 않아야 한다.
유사하게 비용 함수를 다음과 같이 나타낼 수 있다. 아래 그림은 가중치에 대한 비용 플롯이다. 비용이 최소가 되는 가장 낮은 지점에 도달해야 한다. 초기 가중점을 아래로 이동시키면 오차가 가장 적은 비용함수에서 가장 낮은 지점에 도달할 수 있다.
어떻게 하강하여 가장 낮은 지점에 도달할까? 해당 점에 대한 비용 함수의 기울기를 계산하여 이 점을 이동할 수 있다. 그래디언트(Gradients)는 실제로 위 다이어그램에 표시된 접선의 기울기인 도함수이다. 따라서 기울기를 계산하여 하강(아래로 이동)하고 가장 낮은 지점에 도달한다. 그래디언트를 계산한 후 가중치 업데이트 규칙에 따라 이전 가중치를 업데이트한다.
이때 𝛼란 학습 속도(학습률)를 의미한다. 학습률이 작으면 약간 아래로 내려가서 경사하강법이 느려질 수 있다. 그렇다고 학습률이 크면 큰 걸음을 내딛고 경사하강법은 빨라지지만 전역 최솟값에 도달하지 못할 수 있다. 따라서 학습률을 적절하게 선택해야 한다.(하이퍼파라미터 값)
Backpropagation
두 개의 가중치 𝑤𝑥ℎ 및 𝑤ℎ𝑦가 있고 이 가중치를 업데이트해야 한다고 가정하자. 먼저 가중치에 대한 비용 함수의 미분을 계산해야 한다. 출력층에서 입력층으로 역전파하기 때문에 첫 번째 가중치는 𝑤ℎ𝑦가 된다.
1. 𝑤ℎ𝑦에 대한 𝐽의 도함수 계산
2. Recall the cost function: 𝐽
현재 𝐽은 𝑤ℎ𝑦가 함수 내에 없기 때문에 𝑤ℎ𝑦에 대한 𝐽의 도함수를 계산할 수 없다.
3. Recall forward propagation
4. 연쇄법칙(chain rule)으로 먼저 𝑦^에 대한 편미분을 계산한 다음 𝑦^에서 𝑧2에 대한 편미분을 계산한 다음 𝑧2에서 미분 𝑤ℎ𝑦를 계산할 수 있다.
따라서 우리의 방정식은 아래와 같이 나온다.
이제 𝑤𝑥ℎ에 대한 𝐽의 도함수를 계산해야 한다. 유사하게 연쇄 법칙을 다시 사용해야 한다.
이 역전파의 전체 코드는 다음과 같다.
Terminology
- 포워드 패스(Forward pass): 순방향 패스는 입력층에서 출력층으로 가는 순방향 전파를 의미한다.
- 백워드 패스(Backward pass): 역방향 패스는 출력층에서 입력층으로 가는 역방향 전파를 의미한다.
- 에포크(Epoch): 신경망이 전체 교육 데이터를 보는 횟수를 지정한다. 따라서 하나의 에포크는 모든 훈련 샘플에 대해 하나의 순방향 패스와 하나의 역방향 패스와 같다고 말할 수 있다.
- 배치 크기(Batch size): 하나의 순방향 패스와 하나의 역방향 패스에서 사용하는 훈련 샘플의 수를 지정한다.
- 반복 횟수(No. of iterations): one passs = one forward pass + one backward pass
훈련 샘플이 12,000개이고 배치 크기가 6,000이라고 가정하자. 하나의 에포크를 완성하려면 두 번의 반복이 필요하다. 첫 번째 반복에서 처음 6,000개의 샘플을 전달하고 정방향 전달과 역방향 전달을 수행한다. 두 번째 반복에서는 다음 6,000개의 샘플을 전달하고 정방향 전달과 역방향 전달을 수행한다. 두 번의 반복 후, 우리의 신경망은 전체 12,000개의 훈련 샘플을 보게 될 것이다.
NN in Tensorflow
MNIST Problem using Fully Connected Layer
학습을 위해 레이블이 지정된 손글씨 이미지 컬렉션이 있는 인기 있는 MNIST 데이터 세트를 사용할 것이다. 1개의 입력층, 300개의 뉴런이 있는 은닉층 1개, 손으로 쓴 숫자를 예측하는 출력층 1개로 구성된 2 계층 신경망을 구축한다. 은닉층의 경우 ReLU 활성화 기능을 사용한다. 출력 층의 경우 softmax 활성화 기능을 사용한다. 비용 함수를 교차 엔트로피 손실로 정의한다. 교차 엔트로피 손실은 로그 손실이라고도 하며 다음과 같이 정의할 수 있다.
아래 코드를 실행하기 위해 tensorflow를 설치해야 한다. 현재 자신이 사용하고 있는 파이썬 버전이 3.5 이상이어야 하고 터미러에 "pip3 install tensorflow"를 입력하자.
import tensorflow as tf
import numpy as np
from tensorflow.keras import datasets, layers, model, optimalzers
import matplotlib.pyplot as plt
# datasets의 데이터 불러오기
(train_images, train_label), (test_images, test_labels)= datasets.fashion_mnist.load_data()
# 픽셀 값을 0~1 사이로 정규화
train_images, test_images = train_images / 255.0, test_images / 255.0
#하이퍼파라미터값 정의
leanring_rate = 0.1
epochs = 10
batch_size = 100
print("No of images in training set {}".format(train_images.shape))
print("No of labels in training set {}".format(train_labels.shape))
print("No of images in test set {}".format(test_images.shape))
print("No of labels in test set {}".format(test_labels.shape))
img1 = train_images[41].reshape(28,28)
plt.imshow(img1, cmap='Greys')
train_images = np.reshape(train_images, (60000, -1))
test_images = np.reshape(train_images, (10000, -1))
# 학습 모델 정의
model = models.Sequential()
model.add(layers.Dense(300, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
sgd = optimizers.SGD(lr=learning_rate)
model.compile(optimizer=sgd, loss='sparse_cateforical_crossentropy',metrics=['accuracy'],)
# 학습 시키기
model.fit(train_images, train_labels, epochs=epochs, batch_size=batch_size)
# 평가
modle.evalute(test_image, test_labels, verbose=2)
# 결과
plt.imshow(test_images[1].reshape(28,28), cmap='Greys')
np.argmax(model.predict(test_images[1].reshape(1,784)))
Convolutional Neural Network (CNN)
CNN은 이미지를 인식하기 위해 공간 정보를 사용한다. 특히, 컴퓨터 비전 분야에서 광범위하게 사용된다. 활용 예시로 자율 주행 자동차의 시야 확보부터 Facebook 사진에 친구를 자동으로 태그 하는 것까지 다양하다.
Image Classification
3D의 현실을 사진 혹은 영상을 통해 2D작업을 거친 결과물들을 인식하기 위해 즉 아날로그적인 표현을 디지털로 표현에 가로, 세로, 그리고 색상(RGB)이 필요하다. 그렇기에 일반적으로 이미지는 [0, 255] 사이의 큰 숫자 그리드를 가진다.
Challenges of Image Classification
다음은 컴퓨터가 이미지 분류에 있어 어려움을 겪는 문제들이다.
- Viewpoint variation(시점 차이): 같은 조각상이어도 다른 각도에서 찍은 조각상을 다른 조각상으로 분류함
- Scale variation(척도 차이): 같은 크기에 노드북이라도 아기가 들고 있는 노트북과 성인이 들고 있는 노트북의 크기가 다르다고 인식
- Deformation(변형): 여러 자세의 고양이를 모두 고양이로 인식하지 못 함
- Occlusion(폐색): 고양이의 일부분만 보일 때, 고양이라 인식을 못 함
- Illumination conditions(조명): 조명에 의해 부각되지 않는 부분을 인식하지 못 함
- Background clutter(배경 혼란): 보호색을 지닌 동물과 배경과 구분을 하지 못 함
- Intra-class variation(클래스 내 변형): 같은 의자라 할지라도 다양한 모양의 의자가 있으며, 이 모두를 같은 카테고리로 묶지 못 함
이를 해결하는 간단한 방법은 많은 데이터를 다양하게 입력하는 것이다
CNN Architecture
좌측 그림은 일반적인 풀커넥팅 딥러닝 구조이고, 우측 그림이 CNN 구조이다.
Layers Used to Build CNN
- 입력(INPUT): 원시 픽셀 값 e.g. [32x32x3]
- CONV 계층(CONV layer): 입력에서 로컬 영역에 연결된 뉴런의 출력을 계산한다.
- RELU 계층(RELU layer): 요소별 활성화 함수(activation function) 적용
- POOL 계층(POOL layer): 공간 차원(너비, 높이)에 따라 다운샘플링 작업을 수행한다.
- FC (fully-connected): 분류 점수 계산
CNN Process
처음 들어오는 입력은 (가로, 세로, 색상)(width * hight * depth) 3차원으로 들어온다. 그리고 필터를 통해 해당 그림을 인식한다. 필터의 크기는 사용자가 정하는 하이퍼파라미터 값이지만, depth는 동일하게 해주어야 한다. 해당 필터가 첫 번째 칸에서 인식이 완료되면 다음 칸으로 넘어가는 것을 'Stride'라 한다. 이를 통해 이미지를 인식을 하면 아래와 같이 원래 이미지 크기보다 작은 값이 나오게 된다. 이 때 필터 인식할 때 모두 같은 weight를 적용한다.
사이즈를 작게 하는 것은 필터의 역할이 아니기에 이를 해결하고자. zero pad라는 개념이 도입된다. zero pad는 사이즈가 줄어드는 것을 방지하기 위해 이미지 테두리에 0을 추가하는 방법이다. 0을 추가하는 것은 이미지에 아무런 영향이 미치지 않기에 큰 문제가 되지 않는다.
이런 과정을 여러 번 실행을 하여 이미지 인식을 하는 것이 CNN이다. 여기서 같은 크기에 필터로 다른 weight로 적용하여 여러 층을 쌓는다. 아래 그림은 zero padding을 하지 않은 예이다. 아래 예시에 대해 설명하자면, 32 * 32 * 3 이미지를 5 * 5 * 3 필터를 통한 작업을 6번 하여 28 * 28 * 6의 데이터를 얻고 다시 이 데이터로 5 * 5* 6 필터를 통한 10번의 작업을 표현한 것이다. 더 나아가 다음 필터의 크기는 본인이 정하기에 알 수 없지만 앞의 depth가 10이기에 다음 필터의 depth는 10이다. 이렇게 여러 번 실행하는 이유는 많이 인식할 수록 더 다양하게 구분을 가능하기 때문이다.
추가적으로 pool층에서 다운샘플링을 진행한다. Pooling에는 여러 방법이 있지만, Max Pooling을 자주 사용한다. 우측 하단의 그림은 Max Pooling의 이해를 돕기 위한 그림이다. 정보를 겹치게 하기 때문에 필터가 겹치지 않도록 stride를 한다.
추가적으로 필터도 5 * 5 필터 보다 3 * 3의 필터를 자주 사용한다.
Classifying fashion products using CNN
CNN의 대표적인 예 Classifying fashion products이다. "Classifying fashion products"는 의류, 액세서리, 신발 등 다양한 유형의 패션 제품을 분류하는 작업이다. 이러한 제품들은 다양한 특성과 속성을 가지고 있으며, 분류는 이러한 특성과 속성을 기반으로 CNN과정을 보여준다.
import tensorflow as tf
import numpy as np
from tensorflow.keras import datasets, layers, models, optimizers
import matplotlib.pyplot as plt
# datasets의 데이터 불러오기
(train_images, train_label), (test_images, test_labels)= datasets.fashion_mnist.load_data()
# 픽셀 값을 0~1 사이로 정규화
train_images, test_images = train_images / 255.0, test_images / 255.0
print("No of images in training set {}".format(train_images.shape))
print("No of labels in training set {}".format(train_labels.shape))
print("No of images in test set {}".format(test_images.shape))
print("No of labels in test set {}".format(test_labels.shape))
# 분류할 클래스 정의
labels = {
0: 'T-shirt/top',
1: 'Trouser',
2: 'Pullover',
3: 'Dress',
4: 'Coat',
5: 'Sandal',
6: 'Shirt',
7: 'Bag',
9: 'Ankle boot'
}
test_images = train_images.reshape((60000,28,28,1))
test_images = test_images.reshape((10000,28,28,1))
img1 = train_images.reshape(28,28)
print(labels[train_labels[41]])
plt.imshow(img1, cmap='Greys')
# 학습 모델 정의
model = models.Sequenmtial()
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(28,28,1)))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64,activation='relu'))
model.add(layers.Dense(10,activation='softmax'))
model.summary()
# 학습 시작
model.compile(optimizer='adam',loss='spares_categorical_crossentropy',metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=10)
# 정확도 측정
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
# 결과
plt.imshow(test_images[0].reshape(28,28),cmap='Greys')
labels[np.argmax(model.predict(test_images[0].reshape(-1,28,28,1)))]
Loss가 높으면 오버피팅이 일어났다고 판단이 되면 필터의 복잡도를 줄이거나 데이터를 직접 구축하여 이슈를 해결한다. Accuracy는 해당 CNN의 정확도를 말한다.
Code
해당 코드 중 아래 과정이 어떻게 작동되는지 생각해보자.
처음 입력 값으로 (28,28,1)의 그림이 들어 왔고, (3,3)필터를 32번 반복하여 (26,26,32)라는 결과가 나왔다. 이때 파라미터는 (필터) * (입력 값) * (출력 값) + bias 의 결과이다.((3*3)*1*32+32) 이후 (2,2) maxplooling 결과 (26,26,32)에서 (13,13,32)로 pooling하였고, 다시 이 값을 다음 conv에 넣어 (3,3)필터를 64번 반복하여 (26,26,64)라는 결과가 나왔다. 여기서 또한 파라미터는 (3 * 3) * 32 * 64 + 64 = 18496 을 얻게 된다. 아래 과정은 위 과정을 반복하여 얻게 되었고, 전체 파라미터는 위에서 계산된 파라미터를 모두 더한 값이다.
주섬주섬
딥러닝에 CNN, RNN 등이 있지만, 다음 강화학습과 딥러닝이 결합된 DQN을 이해하기 위해 CNN만 알고 있으면 이해하는 데 도움이 될 것이다. CNN에 대해 알고 싶다면 추후에 자세히 적은 블로그를 작성하겠다.
참고
'컴퓨터공학 > AI' 카테고리의 다른 글
강화 학습 8. The Asynchronous Advantage Actor Critic(A3C) Network (5) | 2023.05.23 |
---|---|
강화 학습 7. Deep Q Network(DQN) (1) | 2023.05.16 |
강화 학습 5.Multi-Armed Bandit (MAB)Problem (0) | 2023.04.25 |
강화 학습 4.Temporal Difference(TD) Learning (0) | 2023.04.18 |
강화 학습 3.Monte Carlo(MC) Methods (0) | 2023.04.04 |
댓글