Keras LSTM 이해


311

나는 LSTM에 대한 나의 이해를 조정하려고 노력하고 있으며 Keras에서 구현 한 Christopher Olah 의이 게시물 에서 지적했습니다 . Keras 튜토리얼을 위해 Jason Brownlee이 작성한 블로그를 따르고 있습니다. 내가 주로 혼동하는 것은

  1. 데이터 계열을 [samples, time steps, features]
  2. 스테이트 풀 LSTM

아래에 붙여 넣은 코드를 참조하여 위의 두 가지 질문에 집중하십시오.

# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)

# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
    model.fit(trainX, trainY, nb_epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
    model.reset_states()

참고 : create_dataset은 길이 N의 시퀀스를 취하고 N-look_back각 요소가 look_back길이 시퀀스 인 배열을 반환합니다 .

시간 단계 및 기능이란 무엇입니까?

알 수 있듯이 TrainX는 Time_steps 및 Feature가 각각 마지막 2 차원 (이 특정 코드에서 3 및 1) 인 3 차원 배열입니다. 아래 이미지와 관련하여 many to one분홍색 상자의 수가 3 인 경우를 고려하고 있습니까? 또는 문자 그대로 체인 길이가 3 (즉, 3 개의 녹색 상자 만 고려 됨)을 의미합니까?여기에 이미지 설명을 입력하십시오

다변량 계열을 고려할 때 기능 인수가 관련성이 있습니까? 예를 들어 두 개의 금융 주식을 동시에 모델링 하는가?

상태 저장 LSTM

상태 저장 LSTM은 배치 실행간에 셀 메모리 값을 저장한다는 의미입니까? 이 경우, batch_size하나이고, 훈련 실행 사이에 메모리가 재설정되므로 상태가 좋았다는 것이 중요합니다. 나는 이것이 훈련 데이터가 섞여 있지 않다는 사실과 관련이 있다고 생각하지만 어떻게 해야할지 모르겠습니다.

이견있는 사람? 이미지 참조 : http://karpathy.github.io/2015/05/21/rnn-effectiveness/

편집 1 :

빨간색과 초록색 상자가 동일하다는 @van의 의견에 대해 약간 혼란 스럽습니다. 확인하기 위해 다음 API 호출이 롤링되지 않은 다이어그램에 해당합니까? 특히 두 번째 다이어그램에 주목하십시오 ( batch_size임의로 선택되었습니다). 여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오

편집 2 :

Udacity의 딥 러닝 과정을 수행했지만 time_step 인수에 대해 여전히 혼란스러워하는 사람들은 다음 토론을 참조하십시오 . https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169

최신 정보:

그것은 밝혀 model.add(TimeDistributed(Dense(vocab_len)))내가 무엇을 찾고 있었다되었다. 예를 들면 다음과 같습니다. https://github.com/sachinruk/ShakespeareBot

업데이트 2 :

https://www.youtube.com/watch?v=ywinX5wgdEU 에서 LSTM에 대한 나의 이해를 요약했습니다.


7
첫 번째 사진은 (batch_size, 5, 1)이어야합니다. 두 번째 사진은 (batch_size, 4, 3)이어야합니다 (다음 시퀀스가없는 경우). 출력이 여전히 "X"인 이유는 무엇입니까? "Y"여야합니까?
Van

1
여기서 X_1, X_2 ... X_6은 단일 숫자라고 가정합니다. 그리고 세 개의 숫자 (X_1, X_2, X_3)는 모양 (3,)의 벡터를 만듭니다. 하나의 숫자 (X_1)는 모양 (1,)의 벡터를 만듭니다.
Van

2
@ 반, 당신의 가정은 정확합니다. 흥미 롭기 때문에 기본적으로 모델은 time_steps 이상의 패턴을 학습하지 않습니다. 따라서 시계열 길이가 1000이고 100 일마다 시각적으로 패턴을 볼 수 있다면 time_steps 매개 변수를 최소 100 이상으로 만들어야합니다. 이것이 올바른 관찰입니까?
sachinruk

3
예. 하루에 3 개의 관련 기능을 수집 할 수 있다면 두 번째 사진에서와 같이 기능 크기를 3으로 설정할 수 있습니다. 이 상황에서 입력 모양은 (batch_size, 100, 3)입니다.
Van

1
첫 번째 질문에 답하기 위해서는 단일 시계열을 사용했기 때문입니다. 예를 들어, 주가와 같은 관계로 X와 Y는 같은 시리즈입니다.
sachinruk

답변:


173

우선, 시작하기 위해 훌륭한 자습서 ( 1 , 2 )를 선택하십시오 .

시간 단계의 의미 : Time-steps==3X.shape (데이터 모양 설명)에서 세 개의 분홍색 상자가 있음을 의미합니다. Keras에서 각 단계에는 입력이 필요하므로 녹색 상자 수는 일반적으로 빨간색 상자 수와 같아야합니다. 구조를 해킹하지 않는 한

하나에 많은 많은 대 많은 : keras에서는이 return_sequences당신의 초기화 매개 변수 LSTMGRU또는 SimpleRNN. 때 return_sequences입니다 False(기본적으로), 다음은 한 많은 그림과 같이. 반환 모양은 (batch_size, hidden_unit_length)마지막 상태를 나타내는입니다. 때 return_sequences입니다 True, 다음은 많은 많은 . 반환 형태는(batch_size, time_step, hidden_unit_length)

기능 인수가 관련이 있습니까? 기능 인수는 "빨간색 상자의 크기" 또는 각 단계의 입력 차원을 의미합니다. 예를 들어 8 가지 종류의 시장 정보를 예측하려면을 사용하여 데이터를 생성 할 수 있습니다 feature==8.

Stateful : 소스 코드를 찾을 수 있습니다 . 상태를 초기화 할 때이면 stateful==True마지막 훈련의 상태가 초기 상태로 사용되며, 그렇지 않으면 새 상태가 생성됩니다. stateful아직 켜지지 않았습니다. 그러나 batch_size1 만 할 수 있다는 데 동의하지 않습니다 stateful==True.

현재 수집 된 데이터로 데이터를 생성합니다. 모든 순차적 정보를 수집하기 위해 하루를 기다리지 않고 재고 정보가 스트림으로 제공되는 이미지를 작성하십시오 . 네트워크를 통한 교육 / 예측 동안 온라인으로 입력 데이터를 생성하려고 합니다. 동일한 네트워크를 공유하는 400 개의 주식이있는 경우을 설정할 수 있습니다 batch_size==400.


빨간색과 초록색 상자가 동일한 이유에 대해 약간 혼란 스러웠습니다. 내가 편집 한 내용 (주로 새 사진)을보고 댓글을 달 수 있습니까?
sachinruk

1
과연. 문서를 확인하십시오 :stateful: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
Van

1
@Van 다변량 시계열이있는 경우에도 계속 사용해야 lookback = 1합니까?
innm

1
출력 공간 (32)의 LSTM 차원이 뉴런 (LSTM 셀)의 수와 다른 이유는 무엇입니까?
Sticky

1
추가 stateful=True: 배치 크기는 원하는 것이 될 수 있지만 충실해야합니다. 당신은 모든 5의 배치 크기 모델을 구축 할 경우 fit(), predict()및 관련 방법이 상태로 저장되지 않습니다 그러나 것을 5 주의 배치가 필요합니다 model.save()바람직하지 보일 수 있습니다. 그러나 필요한 경우 hdf5 파일에 상태를 수동으로 추가 할 수 있습니다. 그러나 실제로는 모델을 저장하고 다시로드하여 배치 크기를 변경할 수 있습니다.
jlh

191

허용 된 답변을 보완하는이 답변은 각성 행동과 각 그림을 달성하는 방법을 보여줍니다.

일반적인 케 라스 행동

표준 케 라스 내부 처리는 다음 그림과 같이 항상 많거나 많습니다 ( features=2예 : 압력 및 온도를 사용한 경우).

ManyToMany

이 이미지에서는 다른 차원과의 혼동을 피하기 위해 단계 수를 5로 늘 렸습니다.

이 예의 경우 :

  • 우리는 N 오일 탱크가 있습니다
  • 우리는 5 시간 동안 시간 단위로 조치를 취했습니다 (시간 단계).
  • 우리는 두 가지 특징을 측정했습니다 :
    • 압력 P
    • 온도 T

입력 배열은 다음과 같은 모양이어야합니다 (N,5,2).

        [     Step1      Step2      Step3      Step4      Step5
Tank A:    [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B:    [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
  ....
Tank N:    [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
        ]

슬라이딩 윈도우 용 입력

LSTM 레이어는 종종 전체 시퀀스를 처리해야합니다. 창문을 나누는 것이 가장 좋은 아이디어는 아닙니다. 레이어는 시퀀스가 ​​진행되면서 어떻게 진화하고 있는지에 대한 내부 상태를 가지고 있습니다. Windows는 긴 시퀀스를 학습 할 가능성을 없애 모든 시퀀스를 윈도우 크기로 제한합니다.

창에서 각 창은 긴 원본 시퀀스의 일부이지만 Keras에서는 각각 독립적 인 시퀀스로 표시됩니다.

        [     Step1    Step2    Step3    Step4    Step5
Window  A:  [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window  B:  [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window  C:  [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
  ....
        ]

이 경우 처음에는 하나의 시퀀스 만 있지만 창을 만들기 위해 여러 시퀀스로 나눕니다.

"시퀀스 란 무엇인가"라는 개념은 추상적입니다. 중요한 부분은 다음과 같습니다.

  • 많은 개별 시퀀스로 일괄 처리 할 수 ​​있습니다
  • 시퀀스를 시퀀스로 만드는 것은 단계 (일반적으로 시간 단계)로 진화한다는 것입니다.

"단일 레이어"로 각 경우 달성

다 대다 표준 달성 :

StandardManyToMany

다음을 사용하여 간단한 LSTM 계층으로 다대 다를 달성 할 수 있습니다 return_sequences=True.

outputs = LSTM(units, return_sequences=True)(inputs)

#output_shape -> (batch_size, steps, units)

다 대일 달성 :

똑같은 레이어를 사용하면 keras는 똑같은 내부 전처리를 수행하지만, return_sequences=False이 인수 를 사용 하거나 무시하면 keras는 자동으로 이전 단계를 무시합니다.

ManyToOne

outputs = LSTM(units)(inputs)

#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned

일대 다 달성

이제는 keras LSTM 레이어만으로는 지원되지 않습니다. 단계를 곱하려면 자신 만의 전략을 만들어야합니다. 두 가지 좋은 접근 방식이 있습니다.

  • 텐서를 반복하여 일정한 다단계 입력 생성
  • a stateful=True를 사용하여 한 단계의 출력을 반복적으로 가져 와서 다음 단계의 입력으로 사용합니다 (필요 output_features == input_features)

반복 벡터가있는 일대 다

keras 표준 동작에 맞추려면 단계적으로 입력이 필요하므로 원하는 길이만큼 입력을 반복하면됩니다.

OneToManyRepeat

outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)

#output_shape -> (batch_size, steps, units)

상태 저장 이해 = True

stateful=True한 번에 컴퓨터의 메모리에 맞지 않는 데이터를로드하지 않는 것 외에도 사용 가능한 방법 중 하나가 제공됩니다.

상태 저장을 통해 시퀀스의 "부분"을 단계적으로 입력 할 수 있습니다. 차이점은 다음과 같습니다.

  • 이어 stateful=False, 두 번째 배치의 첫 번째 배치로부터 독립적 새로운 시퀀스를 포함
  • 이어 stateful=True, 두 번째 배치를 동일한 서열을 연장 제 배치를 계속한다.

창에서 시퀀스를 나누는 것과 마찬가지로 두 가지 주요 차이점이 있습니다.

  • 이 창문은 중첩되지 않습니다 !!
  • stateful=True 이 창들은 하나의 긴 시퀀스로 연결되어 있습니다.

에서은 stateful=True, 모든 새로운 배치는 이전 배치 (당신이 호출 할 때까지 계속하는 것으로 해석됩니다 model.reset_states()).

  • 배치 2의 순서 1은 배치 1의 순서 1을 계속합니다.
  • 배치 2의 시퀀스 2는 배치 1의 시퀀스 2를 계속합니다.
  • 배치 2의 시퀀스 n은 배치 1의 시퀀스 n을 계속합니다.

입력 예, 배치 1에는 1 단계와 2 단계가 있고 배치 2에는 3 ~ 5 단계가 있습니다.

                   BATCH 1                           BATCH 2
        [     Step1      Step2        |    [    Step3      Step4      Step5
Tank A:    [[Pa1,Ta1], [Pa2,Ta2],     |       [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B:    [[Pb1,Tb1], [Pb2,Tb2],     |       [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
  ....                                |
Tank N:    [[Pn1,Tn1], [Pn2,Tn2],     |       [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
        ]                                  ]

배치 1과 배치 2에서 탱크 정렬을 확인하십시오! 그것이 우리가 필요한 이유 shuffle=False입니다 (물론 하나의 시퀀스 만 사용하지 않는 한).

당신은 배치를 무제한으로 가질 수 있습니다. (일괄 처리마다 가변 길이를 사용하려면을 사용하십시오 input_shape=(None,features).

stateful = True 인 일대 다

여기서는 하나의 출력 단계를 가져 와서 입력하기 때문에 배치 당 1 단계 만 사용하려고합니다.

그림의 동작이 "원인"이 아님을 유의하십시오 stateful=True. 아래의 수동 루프에서 해당 동작을 강제합니다. 이 예에서는 stateful=True시퀀스를 중지하고 원하는 것을 조작하며 중지 한 부분부터 계속할 수 있습니다.

OneToManyStateful

솔직히 말해서,이 경우에는 반복 접근법이 더 나은 선택 일 것입니다. 그러나 우리가 조사하고 있기 때문에 stateful=True이것은 좋은 예입니다. 이것을 사용하는 가장 좋은 방법은 다음 "다 대다"사례입니다.

층:

outputs = LSTM(units=features, 
               stateful=True, 
               return_sequences=True, #just to keep a nice output shape even with length 1
               input_shape=(None,features))(inputs) 
    #units = features because we want to use the outputs as inputs
    #None because we want variable length

#output_shape -> (batch_size, steps, units) 

이제 예측을위한 수동 루프가 필요합니다.

input_data = someDataWithShape((batch, 1, features))

#important, we're starting new sequences, not continuing old ones:
model.reset_states()

output_sequence = []
last_step = input_data
for i in steps_to_predict:

    new_step = model.predict(last_step)
    output_sequence.append(new_step)
    last_step = new_step

 #end of the sequences
 model.reset_states()

stateful = True 인 다 대다

이제 우리는 매우 멋진 응용 프로그램을 얻습니다. 입력 시퀀스가 ​​주어지면 미래의 알려지지 않은 단계를 예측하십시오.

위의 "일대 다"와 동일한 방법을 사용하고 있지만 다음과 같은 차이점이 있습니다.

  • 한 단계 앞선 시퀀스 자체를 대상 데이터로 사용합니다.
  • 시퀀스의 일부를 알고 있으므로 결과의이 부분을 버립니다.

ManyToManyStateful

레이어 (위와 동일) :

outputs = LSTM(units=features, 
               stateful=True, 
               return_sequences=True, 
               input_shape=(None,features))(inputs) 
    #units = features because we want to use the outputs as inputs
    #None because we want variable length

#output_shape -> (batch_size, steps, units) 

훈련:

시퀀스의 다음 단계를 예측하기 위해 모델을 훈련시킬 것입니다.

totalSequences = someSequencesShaped((batch, steps, features))
    #batch size is usually 1 in these cases (often you have only one Tank in the example)

X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X

#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
    model.reset_states()
    model.train_on_batch(X,Y)

예측 :

예측의 첫 단계는 "상태 조정"과 관련이 있습니다. 이것이 우리가 이미이 부분을 알고 있더라도 전체 시퀀스를 다시 예측하는 이유입니다.

model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step

이제 우리는 일대 다 사례 에서처럼 루프로갑니다. 그러나 여기서 상태를 재설정하지 마십시오! . 우리는 모델이 시퀀스의 어느 단계에 있는지 알기를 원합니다 (그리고 우리가 위에서 만든 예측 때문에 첫 번째 새로운 단계에 있음을 알고 있습니다)

output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:

    new_step = model.predict(last_step)
    output_sequence.append(new_step)
    last_step = new_step

 #end of the sequences
 model.reset_states()

이 접근법은 다음 답변과 파일에서 사용되었습니다.

복잡한 구성 달성

위의 모든 예제에서 "하나의 레이어"의 동작을 보여주었습니다.

물론, 반드시 동일한 패턴을 따르지 않고 여러 레이어를 서로 겹쳐 쌓고 자신 만의 모델을 만들 수 있습니다.

흥미로운 하나의 예는 "다 대일 인코더"와 "일대 다"디코더가있는 "자동 인코더"입니다.

인코더 :

inputs = Input((steps,features))

#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)    

#many to one layer:
outputs = LSTM(hidden3)(outputs)

encoder = Model(inputs,outputs)

디코더 :

"반복"방법 사용

inputs = Input((hidden3,))

#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)

#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)

#last layer
outputs = LSTM(features,return_sequences=True)(outputs)

decoder = Model(inputs,outputs)

오토 인코더 :

inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)

autoencoder = Model(inputs,outputs)

와 훈련 fit(X,X)

추가 설명

LSTM에서 단계가 계산되는 방법 또는 stateful=True위 의 경우 에 대한 세부 사항을 원하는 경우이 답변에서 자세한 내용을 읽을 수 있습니다 .`Keras LSTM 이해 '


1
출력을 입력으로 사용하여 상태 저장을 매우 흥미롭게 사용합니다. 추가 메모와 마찬가지로이 작업을 수행하는 또 다른 방법은 기능적인 Keras API를 사용하는 것입니다 (순서 하나를 사용할 수 있다고 생각하지만 여기에서 한 것처럼) 매 단계마다 동일한 LSTM 셀을 재사용하는 것입니다 결과 상태와 셀에서 출력을 모두 전달합니다. 즉 my_cell = LSTM(num_output_features_per_timestep, return_state=True), 다음 루프가 이어집니다a, _, c = my_cell(output_of_previous_time_step, initial_states=[a, c])
Jacob R

1
셀과 길이는 완전히 독립적 인 값입니다. 그림 중 어느 것도 "셀"의 수를 나타내지 않습니다. 그들은 모두 "길이"입니다.
Daniel Möller

1
@ DanielMöller 나는 조금 늦었지만 당신의 대답은 실제로 내 관심을 끌었습니다. LSTM의 배치가 무엇인지에 대한 나의 이해에 관한 모든 것이 산산조각났습니다. N 탱크, 5 단계 및 2 가지 기능의 예를 제공합니다. 배치가 예를 들어 2 인 경우, 2 개의 샘플 (5 단계 2 피처가있는 탱크)이 네트워크에 공급되고 그 후에 가중치가 적용된다는 것을 의미했습니다. 그러나 내가 올바르게 이해하면 배치 2는 샘플의 타임 스텝이 2로 나뉘고 모든 샘플의 절반이 LSTM-> 가중치 업데이트로 공급되고 두 번째보다 빠르다는 것을 의미합니다.
viceriel

1
예. 상태 저장 = True, 배치 1 = 샘플 그룹에서 업데이트. 그런 다음 배치 2 = 동일한 샘플 그룹에 대해 더 많은 단계를 업데이트하십시오.
Daniel Möller

2
나는 이것을 100 번 공표 할 수 있기를 바랍니다. 매우 유용한 답변.
adamconkey 2016 년

4

RNN의 마지막 계층에 return_sequences가 있으면 간단한 Dense 계층을 사용할 수 없으며 대신 TimeDistributed를 사용하십시오.

다음은 다른 사람들을 도울 수있는 예제 코드입니다.

단어 = keras.layers.Input (batch_shape = (없음, self.maxSequenceLength), 이름 = "입력")

    # Build a matrix of size vocabularySize x EmbeddingDimension 
    # where each row corresponds to a "word embedding" vector.
    # This layer will convert replace each word-id with a word-vector of size Embedding Dimension.
    embeddings = keras.layers.embeddings.Embedding(self.vocabularySize, self.EmbeddingDimension,
        name = "embeddings")(words)
    # Pass the word-vectors to the LSTM layer.
    # We are setting the hidden-state size to 512.
    # The output will be batchSize x maxSequenceLength x hiddenStateSize
    hiddenStates = keras.layers.GRU(512, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength,
                                        self.EmbeddingDimension),
                                        name = "rnn")(embeddings)
    hiddenStates2 = keras.layers.GRU(128, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength, self.EmbeddingDimension),
                                        name = "rnn2")(hiddenStates)

    denseOutput = TimeDistributed(keras.layers.Dense(self.vocabularySize), 
        name = "linear")(hiddenStates2)
    predictions = TimeDistributed(keras.layers.Activation("softmax"), 
        name = "softmax")(denseOutput)  

    # Build the computational graph by specifying the input, and output of the network.
    model = keras.models.Model(input = words, output = predictions)
    # model.compile(loss='kullback_leibler_divergence', \
    model.compile(loss='sparse_categorical_crossentropy', \
        optimizer = keras.optimizers.Adam(lr=0.009, \
            beta_1=0.9,\
            beta_2=0.999, \
            epsilon=None, \
            decay=0.01, \
            amsgrad=False))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.