반응형

안녕하세요.

 

오늘은 이전 포스팅 RNN 이론에 이어 LSTM 이론 및 실습을 하도록 하겠습니다.

 

실습은 "Tensorflow 2.0 beta" 버전으로 RNN을 구축하겠습니다!

 


 

먼저,

 

LSTM(Long Short-term Memory)에 대해 알아보겠습니다.

 

 

Part 1. 이론

 

LSTM은 RNN의 Gradient Vanishing 문제를 해결하기 위해 도입되었습니다.

 

LSTM 구조의 기본 원리는

신경망이 장기적인 관계를 학습을 위하여

중요한 정보를 확실하게 전송할 목적으로 설계되었다는 것입니다.

 

[RNN 과 LSTM 비교]

그림 출처: https://ratsgo.github.io

 

 

1. 유지 게이트(keep/forget gate): 얼마나 많은 양의 이전 메모리를 유지할지 결정

 

이전 시간 단계에서 메모리 상태 텐서는 정보가 풍부하지만,

 

일부 정보는 오래된 것일 수 있다.

 

 

2. 쓰기 게이트(write/input gate): 어떤 정보를 메모리 상태에 기록해야 할 것인지 결정

 

1) 어떤 정보를 쓰려는지 알아 낸다.

 

2) 계산된 텐서가 새로운 상태를 포함하길 원하는지, 이전의 값을 전달하길 원하는지 파악한다.

 

 

3. 출력 게이트(output gate): 시간 단계마다 LSTM 유닛 출력

 

1) tahnh 층은 중간 텐서를 생성한다.

 

2) 시그모이드 층은 현재 입력과 이전 출력을 사용해 비트 텐서 마스크를 생성한다.

 

3) 중간텐서는 최종 출력을 생성하기 위해 비트 텐서와 곱해진다.

 


 

Part2. 실습

 

우선 Tensorflow 2.0 버전을 설치하겠습니다.

 

!pip install -q tensorflow==2.0.0-beta1

!pip install -q tensorflow-gpu==2.0.0-beta1  # gpu 버전

 

 

두 문장이 유산한지(NLP) 예측하는 LSTM 모델을 구현하였습니다.

 

data: 캐글 대회 중 하나인 "Quora Question Pairs"

(단, 데이터 전처리는 다루지 않습니다.)

 

import tensorflow as tf
from sklearn.model_selection import train_test_split # 데이터 셋 분할
import numpy as np
import pandas as pd
import json

train_input, test_input, train_label, test_label = train_test_split(input_data, label_data, test_size=0.2, random_state=2019)

VOCAB_SIZE = input_data.max()+1
WORD_EMBEDDING_DIM = 64
BUFFER_SIZE = 10000
BATCH_SIZE = 16

train_dataset = tf.data.Dataset.from_tensor_slices((train_input, train_label))
test_dataset = tf.data.Dataset.from_tensor_slices((test_input, test_label))

train_dataset = train_dataset.shuffle(BUFFER_SIZE)
train_dataset = train_dataset.batch(BATCH_SIZE)

test_dataset = test_dataset.batch(BATCH_SIZE)

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(VOCAB_SIZE, WORD_EMBEDDING_DIM),    # 자연어 처리 핵심 함수
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64, return_sequences=True)),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dropout(rate=0.2),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])
              
# 모델 훈련
history = model.fit(train_dataset,
                    epochs=10,
#                     validation_data=test_dataset
                   )

 

[결과]

(케글에서 제공하는 test 데이터에 대한 결과는 케글에 제출하면 확인 가능합니다.)

 

[train_accuracy]
[train loss]

 

여기에서는 단층의 얕은 모델을 만들어서 유사도를 측정하였습니다.

 

추가로 더 깊은 모델을 만들어서 성능을 높여 보세요~


LSTM 이론 출처: 딥러닝의 정석

반응형
반응형

 

 

 

 

안녕하세요!

 

오늘은 "파이썬으로 딥러닝 하기!" 중 RNN에 대해 알아보도록 하겠습니다~

 

딥러닝 알고리즘 중 CNN은 전 포스팅에서 다뤘습니다.

 

 

먼저,

 

RNN이란 Recurrent Neural Networks로 순환 신경망이라고 합니다.

 

RNN은 시퀀스 데이터, 예를 들어 음성, NLP, 동영상 등의 데이터에서 사용됩니다.

 


 

[기존 DNN과 RNN 비교]

 

 

RNN이 기존 딥러닝 알고리즘과 가장 다른 점은

 

뉴런의 상태를 저장하고 다음 스텝에서 입력으로 사용함으로

 

긴 시퀀스에 대해서도 예측할 수 있다는 것입니다.

 

 

 

<RNN, 순환 신경망 구조>

 

 

 

이미지 출처: 성킴_RNN_YouTube강의

 

 

모든 뉴런은 이전 층의 모든 뉴런에서 나오는 입력 연결과 이어지는 층으로

 

 모든 뉴런을 유도하는 출력 연결 둘 다를 가지고 있습니다.

 

 

하지만 전방향층과 달리 순환층은 순환 연결이 있으며 동일한 층의 뉴런 간에 정보를 전파합니다.

 

 

따라서 순환 신경망에서 뉴런 활성도는 신경망 인스턴스의 누적 상태를 나타냅니다.

 

 

 

 

<RNN 종류>

 

 

이미지 출처: 성킴_RNN_YouTube강의

 

 

RNN은 위와 같이 입력과 출력의 개수에 따라 다양하게 구성할 수 있습니다.

 

 

many-to-one: 마지막 출력 값이 label 값과 같아지는 것이 목표

 

many-to-many: 입력 데이터를 차례대로 입력하면 차례로 출력 데이터 출력

 

 

 

[RNN의 한계]

 

 

RNN의 Gradient Vanishing(기울기 소실) 문제

 

 

과거 여러 단계 입력들에 대해 계산할 때,

 

경사(Gradient)가 빠르게 줄어들어 (즉, 오차가 더 줄어들지 못하고 수렴하는 문제 발생)

 

장기 의존성을 학습하는 모델의 능력이 심각하게 제한됩니다.

 

 

이 문제를 해결하기 위해 LSTM 구조를 도입했습니다.

 

LSTM은 다음 포스팅에서 다루도록 하겠습니다.

 

 

※ 참고: Back-Propagation Through Time (BPTT)

 

 

RNN은 시간에 따라 펼쳐 놓으면 MLP(Multi-Layer Propagation)와 유사하기 때문에

 

Back-Propagation방법으로 Gradient를 계산할 수 있습니다.

 

 


 

오늘은 여기까지!

 

다음 포스팅으로 돌아오겠습니다~

반응형
반응형



안녕하세요 오랜만이에요~


오늘은 딥러닝의 꽃! CNN에 대해 알아보겠습니다!


CNN이란 Convolution Neural network로 합성곱 신경망이라고 부릅니다.


CNN은 이미지, 동영상 등을 분석하는데 사용됩니다.


(음성 인식, 자연어 처리와 같은 다른 작업에도 많이 사용하지만 여기서는 시각적인 부분에 초점을 맞췄습니다.)



[기존계층과 합성곱 계층 비교]


먼저, 기존 신경망과 다른 점에 대해 알아보겠습니다.



기존에 구현했던 완전 연결 계층, 즉 기존 신경망은 데이터의 형상이 무시됩니다.



따라서 글자의 크기가 달라지거나 글자가 회전되거나,


글자에 변형이 조금만 생기더라도


다른 글자로 인식하기 때문에


새로운 학습 데이터를 넣어주지 않으면


좋은 결과를 기대하기 어렵습니다.



즉, 본질적인 패턴을 읽지 못하기 때문에


인식을 위해


다양한 데이터가 많이 필요합니다.




하지만, 합성곱 계층은



원본 이미지를 가지고 여러개의 feature map (특징맵)을 만들어 분류하는


완전 연결 계층으로,



이미지의 특징을 추출하기때문에 이미지가 변형이되더라도


잘 인식할 수 있습니다.




<기존 계층>




<합성곱 계층>





합성곱 연산이란?


이미지 3차원(세로, 가로, 색상) data의 형상을 유지하면서 연산하는 작업


입력 데이터에 필터를 적용한 것을 합성곱 연산이라고 합니다.


[합성곱 연산]




<구현 예시>



# 위의 그림을 파이썬으로 출력하시오

import numpy as np

input_ = np.array([[1,2,3,0],[0,1,2,3],[3,0,1,2],[2,3,0,1]]) filter_ = np.array([[2,0,1],[0,1,2],[1,0,2]]) bias=3 a = input_.shape[0]-filter_.shape[0] + 1 b = input_.shape[1]-filter_.shape[1] + 1 result2 = []

for rn in range(a): for cn in range(b): result1 = input_[rn:rn+filter_.shape[0],cn:cn+filter_.shape[1]] * filter_ result2.append(np.sum(result1)+bias) result = np.array(result2).reshape(a,b)




패딩이란?


합성곱 연산을 수행하기 전에 데이터 주변을 특정값으로 채워 늘리는 것을 말합니다.



※ 패딩이 필요한 이유는 무엇일까요?


패딩을 하지 않을경우 data의 크기는 합성곱 계층을 지날 때마다 작아지게 되므로


가장자리 정보들이 사라지는 문제가 발생하기 때문에 패딩을 사용합니다.



<구현 예시>



# 위의 그림을 파이썬으로 출력하시오 import numpy as np input_ = np.array([[1,2,3,0],[0,1,2,3],[3,0,1,2],[2,3,0,1]]) input_pad = np.pad(input_, pad_width=1, mode='constant', constant_values=0) # padding method filter_ = np.array([[2,0,1],[0,1,2],[1,0,2]]) a = input_pad.shape[0]-filter_.shape[0] + 1 b = input_pad.shape[1]-filter_.shape[1] + 1 result2 = [] for rn in range(a): for cn in range(b): result1 = input_pad[rn:rn+filter_.shape[0],cn:cn+filter_.shape[1]] * filter_ result2.append(np.sum(result1)) result = np.array(result2).reshape(a,b)




스트라이드란?


input데이터에 filter를 적용하는 위치의 간격을 스트라이드라고 합니다.




[출력크기 공식]



(입력크기를 H(Height),W(Width), 필터크기를 FH, FW, 출력크기를 OH, OW, 패딩을 P, 스트라이드를 S라고 한다.)




3차원 합성곱 연산


이미지의 색은 보통 흑백이 아니라 RGB(Red, Green, Blue)컬러 이므로


RGB컬러에 대해서 합성곱을 해야합니다.





3차원 합성곱 구현 이론




[사진 한장을 RGB 필터로 합성곱하여 2차원 출력행렬(Feature map) 1을 출력한 그림]



위의 그림은 Feature map이 한 개가 나오는데


실제로는 사진 한 장에 대해서 여러개의 Feature map이 필요합니다.






Filter의 갯수를 늘리면 여러개의 Feature map을 출력할 수 있습니다.


하나의 Filter에 하나의 Feature map을 출력할 수 있습니다.





이미지를 한 장씩 학습시키는 것은 학습속도가 느립니다.


따라서 100장의 이미지를 묶음으로 나눠서 한번에 학습시킵니다.


이를 mini batch라고 합니다.


+ 합성곱 연산에 편향(bias)을 더해줍니다.




하지만 합성곱 계층을 미니 배치로 구현할 때 4차원 행렬의 연산이 됩니다.


따라서 연산의 속도가 느려지므로


행렬 연산을 빠르게 하기 위해 4차원이 아닌 2차원으로 차원을 축소해야할 필요가 있습니다.



※ 이때 im2col함수를 이용합니다.




원리: 각 4차원 블럭을 R,G,B로 각각 나누어 2차원으로 변환 후 합쳐줍니다.


※ 배치를 사용할 때 위의 방법을 여러번 하여 나온 결과인 2차원 행렬을 합쳐줍니다.



[im2col 함수]

def im2col(input_data, filter_h, filter_w, stride=1, pad=0): """다수의 이미지를 입력받아 2차원 배열로 변환한다(평탄화). Parameters ---------- input_data : 4차원 배열 형태의 입력 데이터(이미지 수, 채널 수, 높이, 너비) filter_h : 필터의 높이 filter_w : 필터의 너비 stride : 스트라이드 pad : 패딩 Returns ------- col : 2차원 배열 """

N, C, H, W = input_data.shape out_h = (H + 2 * pad - filter_h) // stride + 1 # 위의 출력크기 공식을 이용하여 구현 out_w = (W + 2 * pad - filter_w) // stride + 1 img = np.pad(input_data, [(0, 0), (0, 0), (pad, pad), (pad, pad)], 'constant') col = np.zeros((N, C, filter_h, filter_w, out_h, out_w)) for y in range(filter_h): y_max = y + stride * out_h for x in range(filter_w): x_max = x + stride * out_w col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride] col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N * out_h * out_w, -1)

return col



※ 2차원으로 변경해야할 행렬 2가지



1. 원본이미지를 필터 사이즈에 맞게 2차원으로 변경한 행렬


-> im2col 함수 이용



2. 4차원 필터 행렬을 2차원으로 변경


-> reshape 함수를 이용 (FN, -1)



[CNN 구현하기]



"Convolution 계층에서 일어나는 일"


1. 원본이미지를 im2col을 사용하여 2차원 행렬로 변경한다.


2. filter를 reshape을 사용하여 2차원 행렬으로 변경한다.


3. 2차원 행렬로 변환한 두 행렬을 내적한다.


4. 내적한 결과인 2차원 행렬을 다시 4차원으로 변환한다.



CNN층 구조


" conv  ->  pooling  -> fully connected "



- conv: 이미지 특징(feature map)을 추출하는 층


- pooling: 추출한 feature map을 선명하게 하는 층




pooling 계층의 역활


출력 값에서 일부만 취하여 사이즈가 작은 이미지를 만든다.


마치 사진을 축소하면 해상도가 좋아지는 듯한 효과와 비슷하다.




※ 풀링 종류 3가지


1. 최대 풀링


: 컨볼루션 데이터에서 가장 큰 값을 대표값으로 선정



2. 평균 풀링


: 컨볼루션 데이터에서 평균값을 대표값으로 선정



3. 확률적 풀링


: 컨볼루션 데이터에서 임의 확률로 한 개를 선정




※ 그림출처: '밑바닥부터 시작하는 딥러닝'



생각보다 내용이 길어져서


파이썬으로 Convolution 계층 구현하는 것은


다음 포스팅에서 하겠습니다!



궁금하신 부분은 댓글 남겨주세요!!

반응형
반응형



안녕하세요~ 오늘은 드디어! 신경망에 대해 살짝 맛보도록 하겠습니다!



우선, 퍼셉트론과 신경망의 차이부터 알아봅시다!


퍼셉트론을 모른다면 "퍼셉트론(Perceptron)이란?" 을 참고하세요!



1. 퍼셉트론은 원하는 결과를 출력하도록 사람이 직접 가중치를 정해줘야 합니다!


AND, OR, NAND 게이트를 만들때 가중치를 채워 넣는 문제를 냈습니다!


어떻게 찾으셨나요? 저는 직접 숫자를 대입해보며 찾았답니다!


 혹시 더 쉽게 찾는 방법을 아시나요? 아신다면 댓글로 공유해주세요!



2. 신경망은 가중치 매개변수의 적절한 값을 기계가 데이터로부터 학습해서 자동으로 알아냅니다!





" 신경망 학습하기 "




이전 포스팅에서 신경망에 들어가는 함수


계단함수, 시그모이드 함수, 렐루 함수에 대해 알아보았습니다!



좀더 자세히 말하자면 위의 3가지 함수는


은닉층에 들어가는 함수 중 3가지를 의미합니다.




그렇다면 마지막 출력층에 들어가는 함수는 어떻게 될까요?


출력층 함수란,


그동안 흘러온 확률의 숫자를 취합해 결론을 내는 함수입니다.



신경망으로 구현하고자 하는 문제에 따라 사용하는 출력층 함수가 다릅니다.



1. 회귀(Regression)의 경우, 항등함수를 사용합니다.


항등함수란, 어떤 변수도 자기 자신을 함수값으로 하는 함수입니다.


[파이썬코드]

def identity(x): return x

간단하죠?




2. 분류(Classfication) 의 경우, 두 가지로 나뉘는데요.


2-1) 시그모이드(Sigmoid) 함수 : 2클래스 분류에서 사용합니다. ( ex, 개 vs 고양이 분류)


2-2) 소프트맥스(Softmax) 함수 : 다중 클래스 분류 (ex, 정상 폐사진 vs 폐결절, 폐혈증... 등 분류)



시그모이드는 은닉층의 활성화 함수에서 알아봤으니,



새로운 함수인, 소프트맥스 함수에 대해 더 자세히 알아보겠습니다.


소프트 맥스(Softmax) 함수란?


0과 1사이의 숫자를 출력하는 함수로, 출력하는 값은 확률입니다.


[파이썬 코드]


def softmax(a): C = np.max(a) exp_a = np.exp(a-C) sum_a = np.sum(exp_a) return exp_a / sum_a


[소프트 맥스 함수식]


e%203.10.png



소프트 맥스 함수식과 위의 파이썬 코드가 조금 다르죠?


그 이유는, overflow때문입니다!



우선, 소프트 맥스 함수는 지수함수를 사용하는데 이 지수함수라는 것은 아주 쉽게 아주 큰 값을 내뱉습니다.



예를 들어


exp == e (무리수: 자연상수)


e ^10 > 20000: 자연상수의 10승은 20000보다 크고


e ^1000 == inf : 자연상수의 1000승은 무한대(inf)를 나타냅니다.



따라서 표현할 수 없는 큰 값을 해결하기위해 아래와 같은 식으로 변형을 해서 사용합니다.




지수함수와 로그함수를 잘 모르겠다면 "여기"를 참고하세요!






" 이제, 아래의 신경망을 직접 구현해보도록 하겠습니다!"





import numpy as np # 신경망 함수 def sigmoid(x): return 1 / (1 + np.exp(-x)) def identity(x): return x def init_network(): network = {} network['W1'] = np.array([[1,3,5],[2, 4, 6]]) # weight 은 관습적으로 W라고 합니다. network['W2'] = np.array([[1,2],[3,4],[5,6]]) network['W3'] = np.array([[1,2],[3,4]]) return network

# 신경망 구현 def forward(network, x): W1, W2, W3 = network['W1'], network['W2'], network['W3'] y = np.dot(x, W1) y_hat = sigmoid(y) k = np.dot(y_hat, W2) k_hat = sigmoid(k) j = np.dot(k_hat, W3) j_hat = identity(j) # identity 대신 softmax함수를 사용할 수 있습니다. return j_hat network = init_network() x = np.array([1,2]) # 입력 y = forward(network, x) # 출력 print(y)





오늘은 여기까지!


신경망 학습 방법은 다음 포스팅에서 더 자세히 다루겠습니다!


좋은 하루 보내세요! 

반응형

+ Recent posts