Overfittin LSTM RNN для отладки - PullRequest
       7

Overfittin LSTM RNN для отладки

0 голосов
/ 05 декабря 2018

Я использую тензорный поток с керасами и пытаюсь построить простой двухслойный RNN с ячейками LSTM (для моделирования языка, прогнозирования следующего слова).Я использую набор данных PTB и пытаюсь реализовать сети из "Регулярной нейронной регуляризации (Embedding -> LSTM1 -> LSTM2 -> Dense). К сожалению, у меня странные результаты,первая эпоха выглядит великолепно, потери снижаются с ~ 9 до ~ 6,9 (категорическая перекрестная энтропия), но она застревает там навсегда (даже при том, что я уменьшаю свою скорость обучения). В качестве теста я хотел убедиться, что я могу превзойтималенький текст с похожей архитектурой, но я получаю те же результаты! Я использую размер пакета 20 и 20 шагов в каждом образце. Я на 100% уверен в своей функции batchGenerator ...

Можно ли переодеться? Что мне не хватает?

мой код:

tempSet = batchGenerator(text = testSet[:10000], batchSize = batchSize,timeStepsPerBatch = timeStepsPerBatch,vocabSize = vocabSize)
model = Sequential()
model.add(Embedding(vocabSize, 200, input_length=20,batch_input_shape = (20,20)))
model.add(LSTM(200,return_sequences=True,stateful = True))
model.add(LSTM(200,return_sequences=True,stateful = True))
model.add(TimeDistributed(Dense(vocabSize)))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
                           optimizer='adam', metrics=['categorical_accuracy'])
# add reset call back after each epoch, add preplixty mdss
modelHistory = model.fit_generator(tempSet.generate(),
               steps_per_epoch=tempSet.stepPerEpoch, epochs=100, verbose=1,
               callbacks=[resetStateAtEpochEndCall],
               validation_data=None, validation_steps=None)

Результаты: Epoch 1/100 24/24 [==============================] - 11 с 471 мс / шаг - потеря: 8,1857 - категориальная точность: 0,0422 эпоха 2/100 24/24 [==============================] - 4s 156 мс / шаг - потеря: 6,2512 - категориальная_точность: 0,0536 эпоха 3/100 24/24 [==============================] - 4s 155мс / шаг - потеря: 6.1297 - категориальная_точность: 0.0504 Epoch 4/100 24/24 [====================================]- 4s 154 мс / шаг - потеря: 6.0974 - категорическая точность: 0.0497 Epoch 5/100 24/24 [====================================] - 4 с 153 мс / шаг - потеря: 6,0877 - категориальная_точность: 0,0497 Эпоха 6/100 24/24 [=====================================] - 4 с 153 мс / шаг - потеря: 6,0828 - категориальная_точность: 0,0503 Epoch 7/100 24/24 [==============================] - 4 с 153 мс / шаг - потеря: 6,0800 - категориальная_точность: 0,0505 эпоха 8/100 24/24 [=====================================] - 4s 152 мс / шаг - потеря: 6,0781 - категориальная точность: 0,0505 Epoch 9/100 24/24 [===============================] - 4 с 152 мс / шаг - потеря: 6,0766 - категориальная точность: 0,0506 эпоха 10/100 24/24 [==============================] - 4 с 153 мс / шаг - потеря: 6,0755 - категориальная точность: 0,0506.,,24/24 [====================================] - 4 с 149 мс / шаг - потеря: 6.0477 - категориальная_точность: 0,0504 эпоха 98/ 100 24/24 [====================================] - 4 с 150 мс / шаг - потеря: 6,0470 - категориальная точность: 0,0501Epoch 99/100 24/24 [====================================] - 4s 150 мс / шаг - потеря: 6.0483 - категорическая точность: 0.0498 Epoch 100/100 24/24 [====================================] - 4s 149мс / шаг - потеря: 6.0471- категорическая точность: 0,0498

class batchGenerator:
  def __init__(self, text, batchSize = 20,timeStepsPerBatch = 35,vocabSize = 9999):
    self.text = text
    self.textLen = len(text)
    self.batchSize = batchSize
    self.segLen = self.textLen//self.batchSize # we'll divide the input text into segments,
                                               # each segment will be used to generate a sample inside a mini-batch
                                               # this way we can use the last hidden state of the RNN as an input to the next mini batch
    self.cursor = [ind*self.segLen for ind in range(self.batchSize)]
    self.timeStepsPerBatch = timeStepsPerBatch
    self.vocabSize = vocabSize
    self.stepPerEpoch = (self.segLen - 1)//self.timeStepsPerBatch
    print('Number of steps per epoch',self.stepPerEpoch)
    self.iterInd = 0;
    # alert for misdividing the data 
    lostDataOutOfSeg = self.textLen - self.segLen*self.batchSize
    if(lostDataOutOfSeg > 0):
      print('Amount of words lost because text didnt dived nicely to %d segments is %d Which is %.2f%% from the total data'
            %(self.batchSize,lostDataOutOfSeg,((lostDataOutOfSeg/self.textLen)*100)))

    lostDataInSeg = (self.segLen -1 - ((self.segLen - 1)//self.timeStepsPerBatch)*self.timeStepsPerBatch)*self.batchSize
    if(lostDataInSeg > 0):
      print('Amount of words lost because segment didnt dived nicely to %d time steps is: %d Which is %.2f%% from the total data'
            %(self.timeStepsPerBatch,lostDataInSeg,(lostDataInSeg/self.textLen)*100))
    if(lostDataOutOfSeg + lostDataInSeg > 0):
      print('Total lost data : %d  which is %.2f%% from the total data'
            %((lostDataOutOfSeg + lostDataInSeg),(lostDataOutOfSeg + lostDataInSeg)*100/self.textLen))

  def generate(self):
    # outputs a mini batch of data (x,y)
    # x - tensor of length batchSize. Each entrance in x is a (partial) sentence (timeStepsPerBatch words) from a segment
    # y - is the same as x, except it is shifted 1 word (targets)
    while(True): # genrator
      self.iterInd = self.iterInd + 1;
      #print(self.iterInd)
      x = np.zeros((self.batchSize,self.timeStepsPerBatch),dtype = np.int32)
      y = np.zeros((self.batchSize,self.timeStepsPerBatch,self.vocabSize),dtype = np.int32)
      # check if can take full timeStepsPerBatch at each segment
      if(self.cursor[0] + self.timeStepsPerBatch + 1> self.segLen): #TODO: double check conidtion
        # end of an epoch, reset cursors
        #print('End of epoch, cursor reset. iter num ',self.iterInd)
        self.cursor = [ind*self.segLen for ind in range(self.batchSize)]
      for i in range(self.batchSize):
        x[i,:] = self.text[self.cursor[i]:(self.cursor[i] + self.timeStepsPerBatch)]
        y_id = self.text[(self.cursor[i]+1):(self.cursor[i] + self.timeStepsPerBatch+1)]
        y[i,:,:] = tf.keras.utils.to_categorical(y_id,num_classes = self.vocabSize) # transform to 1-hot encoding
        # update cursor
        self.cursor[i] = self.cursor[i] + self.timeStepsPerBatch
      yield x,y
...