이번 포스팅에서는 미래를 예측할 수 있는 네트워크인 순환 신경망(RNN, recurrent neural networks)을 알아볼 것이다.
이 신경망은 시계을 데이터를 분석해서 주식가격 같은 것을 예측해 언제 사고팔지 알려줄 수 있다. 자율주행 시스템에서는 차의 이동 경로를 예측하고 사고를 피하도록 도울 수 있다.
일반적으로 이 신경망은 고정 길이 입력이 아닌 임의 길이를 가진 시퀀스를 입력으로서 다룰 수 있다. 예를 들어, 문장, 문서, 오디오 샘플을 입력으로 받을 수 있고, 자동 번역, 스피치 투 텍스트같은 자연어 처리(NLP)에 매우 유용하다.
순환 뉴런과 순환 층
지금까지는 활성화 신호가 입력층에서 출력층 한 방향으로만 흐르는 피드포워드 신경망에 대해서 공부했었다. 순환 신경망은 피드포워드 신경망과 매우 비슷하지만 뒤쪽으로 순환하는 연결도 있다는 점이 다르다.
위의 그림은 입력을 받아 출력을 만들고 자신에게도 출력을 보내는 뉴런 하나로 구성된 가장 간단한 RNN구조이다.
하나의 뉴런으로 작동하지만 시간에 따라 입력 값과 출력 값이 다른데, 이를 시간에 따라 네트워크를 펼쳤다고 한다.
각 타임 스텝 t 마다 이 순환 뉴런은 물론 x와 이전 타임 스텝의 출력인 y(t-1) 을 입력으로 받는다.
이 과정을 통해 입력과 출력을 모두 벡터 형식으로 표현할 수 있게 된다.
(첫 번째 타임 스텝에서는 이전 출력이 없으므로 일반적으로 0으로 설정한다.
각 순환 뉴런은 두 벌의 가중치를 가진다. 하나는 입력 x를 위한 것이고 다른 하나는 이전 타임 스텝의 출력 y를 위한 것이다. 각각의 가중치 벡터를 wx, wy라고 부르겠다.
하나의 순환 뉴런이 아니라 순환 층 전체를 생각하면 가중치 벡터를 가중치 행렬 Wx와 Wy로 바꿀 수 있을 것이다. 그러면 순환 층 전체의 출력 벡터는 익숙한 형태로 변하게 되는데
이는 샘플 하나에 대한 순환 층의 출력이다.
피드포워드 신경망처럼 타임 스텝 t에서의 모든 입력을 행렬 X(t)로 만들어 미니배치 전체에 대해 순환 층의 출력을 한 번에 계산할 수도 있다.
메모리 셀
타임 스텝 t 에서 순환 뉴런의 출력은 이전 타임 스텝의 모든 입력에 대한 함수이므로 이를 일종의 메모리 형태라고 말할 수 있다. 타임 스텝에 걸쳐서 어떤 상태를 보존하는 신경망의 구성 요소를 메모리 셀이라고 한다. (혹은 셀)
일반적으로 타임 스텝 t에서의 셀의 상태 h(t) 는 그 타임 스텝의 입력과 이전 타임 스텝의 상태에 대한 함수이다. 즉, h(t) = f(h(t-1), x(t)) 이다.
입력과 출력 시퀀스
RNN은 입력 시퀀스를 받아 출력 시퀀스를 만들 수 있다. 이를 시퀀스 - 투 - 시퀀스 네트워크 라고 부른다. 이러한 모델은 주식 가격 예측과 같은 시계열 데이터를 예측하는 데 유용하다.
또는 입력 시퀀스를 네트워크에 주입하고, 마지막을 제외한 모든 출력을 무시할 수 있다. 이를 시퀀스 - 투 - 벡터 네트워크 라고 한다. 이러한 모델은 영화 리뷰에 있는 연속된 단어를 주입했을 때 감성 점수를 출력하는 예시에 유용하다.
반대로 각 타임 스텝에서 하나의 입력 벡터를 반복해서 네트워크에 주입하고, 하나의 시퀀스를 출력할 수 있다. 이를 벡터 - 투 - 시퀀스 네트워크라고 부르며 이미지를 입력하여 이미지에 대한 캡션을 출력할 수 있다.
마지막으로 인코더라고 부르는 시퀀스 - 투 - 벡터 네트워크 뒤에 디코더라고 부르는 벡터 - 투 - 시퀀스 네트워크를 연결할 수 있다. 이러한 모델은 언어의 문장을 다른 언어로 번역하는 데 사용할 수 있다. 한 언어의 문장(시퀀스)을 네트워크에 주입하면 인코더는 이 문장을 하나의 벡터 표현으로 변환하고, 그 다음에 디코더가 이 벡터를 다른 언어의 문장으로 디코딩한다. (시퀀스 - 벡터 - 시퀀스) 보통 이런 이중 단계 모델은 하나의 시퀀스-투-시퀀스 RNN보다 정확한데 그 이유는 문장의 마지막 단어가 번역의 첫 번째 단어에 영향을 줄 수 있기 때문이다.
RNN 훈련하기
기본적인 기법은 타임 스텝으로 네트워크를 펼치고 (실제로는 펼치지 않는다.) 보통의 역전파를 사용하는 것이다. (BPTT, Backpropagation through time)
BPTT 전략의 순서에 대해서 알아보자면
1) 보통의 역전파와 같이 첫 번째 정방향 패스가 펼쳐진 네트워크를 통과한다. (파선)
2) 비용 함수 C(Y(0), Y(1), ... Y(t)) 를 사용하여 출력 시퀀스가 평가된다. (일부 출력이 무시될 수 있다. Y(0), Y(1) 등,,)
3) 비용 함수의 그레이디언트는 펼쳐진 네트워크를 따라 역방향으로 전파된다. (실선)
4) 모델 파라미터는 BPTT 동안 계산된 그레이디언트를 사용하여 업데이트된다.
5) 업데이트 후 그레이디언트가 비용 함수를 사용한 모든 출력에서 역방향으로 전파된다. (Y(2),Y(3),Y(4) 를 사용하여 비용함수가 계산되었으므로 이 부분에서만)
6) 역전파가 진행되면 모든 타임 스텝에 걸쳐 합산된다. (모든 타임스텝에서는 동일한 W와 b를 사용하였으므로)
웹사이트에서 시간당 접속 사용자의 수, 도시의 날짜별 온도, 여러 지표를 사용한 기업의 분기별 재정 안정성 등을 연구한다고 가정해보자. 모두 타임 스텝마다 하나 이상의 값을 가진 시퀀스 데이터이다. 이를 시계열이라고 한다.
여기서 시간당 접속 사용자의 수, 도시의 날짜별 온도 예시는 단변량 시계열이고 (타임 스텝마다 하나의 값)
여러 지표를 사용한 기업의 분기별 재정 안정성 예시는 다변량 시계열이다. (타임 스텝마다 여러 값, 회사의 수입, 부채 등)
(보통 미래의 값을 예측하거나, 과거 누락된 값을 대체할때 시계열 데이터를 활용한다.)
이제 시계열을 만드는 함수를 한 번 살펴보자
이 함수는 batch_size 매개변수로 요청한 만큼 n_steps 길이의 여러 시계열을 만든다.
batch_size = 3 이라고 가정한 후 np.random.rand(4, batch_size, 1)을 실행하게 되면 랜덤의 넘파이 배열이 생성되고 각각의 값들을 freq1, freq2, off1, off2 에 지정한다.
np.linspace(0, 1, n_steps)를 실행하면 0~1 사이 n_steps 갯수(시계열 갯수) 만큼 나눠서 넘파이 배열로 생성해준다.
series의 벡터의 기본적인 형태를 확인해보았다.
결과적으로
series[..., np.newaxis].astype(np.float32) 를 통해 [배치 크기, n_steps, 차원 수] 크기의 넘파이 배열이 반환된다.
(위의 예시는 단변량이므로 차원 수 = 1 이다.)
각 시계열에는 타임 스텝마다 하나의 값만 있다. ( = 단변량 시계열) 각 시계열은 진폭이 같고 진동 수와 위상이 랜덤한 두 개의 사인 곡선을 더하고 약간의 잡음을 추가한다.
위의 함수를 사용하여 train, test, valid 세트를 만들었다.
보통 RNN을 시작하기 전에 기준 성능을 몇 개 준비하는 것이 좋다. 그렇지 않으면 실제 기본 모델보다 성능이 나쁠 때도 잘 작동한다고 생각할 수 있기 때문이다. 예를 들어 가장 간단한 방법은 순진한 예측이라고 불리우는, 각 시계열의 마지막 값을 그대로 예측하는 것이다.
또 다른 간단한 방법은 완전 연결 네트워크를 사용하는 것이다. 이 네트워크는 입력마다 1차원 특성 배열을 기대하기 때문에 Flatten 층을 추가해야 한다.
간단한 RNN 구현하기
이 코드가 가장 간단하게 만들 수 있는 RNN이다. 이전 모델과 달리 순환 신경망은 어떤 길이의 타임 스텝도 처리할 수 있기 때문에 입력 시퀀스의 길이를 지정할 필요가 없다. (첫 번째 차원 = None)
기본적으로 SimpleRNN 모델은 하이퍼볼릭 탄젠트 활성화 함수를 사용한다. 초기 상태를 0으로 설정하고 첫 번째 타임 스텝의 가중치 편향과 함께 순환 뉴런으로 전달되어 활성화함수를 거쳐 갱신되면 이러한 출력이 새로운 입력값이 된다.
'핸즈온머신러닝&딥러닝' 카테고리의 다른 글
RNN과 CNN을 사용해 시퀀스 처리하기 2 (0) | 2021.04.30 |
---|---|
RNN과 CNN을 사용해 시퀀스 처리하기 예시 (0) | 2021.04.29 |
합성곱 신경망을 사용한 컴퓨터 비전 4 (0) | 2021.04.20 |
합성곱 신경망을 사용한 컴퓨터 비전 3 (0) | 2021.04.15 |
합성곱 신경망을 사용한 컴퓨터 비전 2 (0) | 2021.04.14 |