Keras神經網絡data generators解決數據內存


    在使用kears訓練model的時候,一般會將所有的訓練數據加載到內存中,然后喂給網絡,但當內存有限,且數據量過大時,此方法則不再可用。此博客,將介紹如何在多核(多線程)上實時的生成數據,並立即的送入到模型當中訓練。 本篇文章由圓柱模板博主發布。

   先看一下還未改進的版本:

   

import numpy as np
from keras.models import Sequential
#載入全部的數據!!
X, y = np.load('some_training_set_with_labels.npy')
#設計模型
model = Sequential()
[...] #網絡結構
model.compile()
# 在數據集上進行模型訓練
model.fit(x=X, y=y)

  下面的結構將改變一次性載入全部數據的情況。接下來將介紹如何一步一步的構造數據生成器,此數據生成器也可應用在你自己的項目當中;復制下來,並根據自己的需求填充空白處。

    在構建之前先定義統一幾個變量,並介紹幾個小tips,對我們處理大的數據量很重要。 
ID type為string,代表數據集中的某個樣本。 
調整以下結構,編譯處理樣本和他們的label:

    1.新建一個詞典名叫 partition :

      

partition[‘train’] 為訓練集的ID,type為list
partition[‘validation’] 為驗證集的ID,type為list

  2.新建一個詞典名叫 * labels * ,根據ID可找到數據集中的樣本,同樣可通過labels[ID]找到樣本標簽。 
舉個例子: 
假設訓練集包含三個樣本,ID分別為id-1,id-2和id-3,相應的label分別為0,1,2。驗證集包含樣本ID id-4,標簽為 1。此時兩個詞典partition和 labels分別如下:

    

partition
{'train': ['id-1', 'id-2', 'id-3'], 'validation': ['id-4']}

  

labels
{'id-1': 0, 'id-2': 1, 'id-3': 2, 'id-4': 1}

  data/ 中為數據集文件。

   

數據生成器(data generator)

接下來將介紹如何構建數據生成器 DataGenerator ,DataGenerator將實時的對訓練模型feed數據。 
接下來,將先初始化類。我們使此類繼承自keras.utils.Sequence,這樣我們可以使用多線程。

  

def __init__(self, list_IDs, labels, batch_size=32, 
             dim=(32,32,32), n_channels=1,
             n_classes=10, shuffle=True):
    'Initialization'
    self.dim = dim
    self.batch_size = batch_size
    self.labels = labels
    self.list_IDs = list_IDs
    self.n_channels = n_channels
    self.n_classes = n_classes
    self.shuffle = shuffle
    self.on_epoch_end()

  我們給了一些與數據相關的參數 dim,channels,classes,batch size ;方法 on_epoch_end 在一個epoch開始時或者結束時觸發,shuffle決定是否在數據生成時要對數據進行打亂。

      

def on_epoch_end(self):
  'Updates indexes after each epoch'
  self.indexes = np.arange(len(self.list_IDs))
  if self.shuffle == True:
      np.random.shuffle(self.indexes)

  另一個數據生成核心的方法__data_generation 是生成批數據。

   

def __data_generation(self, list_IDs_temp):
  'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
  # Initialization
  X = np.empty((self.batch_size, *self.dim, self.n_channels))
  y = np.empty((self.batch_size), dtype=int)

  # Generate data
  for i, ID in enumerate(list_IDs_temp):
      # Store sample
      X[i,] = np.load('data/' + ID + '.npy')

      # Store class
      y[i] = self.labels[ID]

  return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

  在數據生成期間,代碼讀取包含各個樣本ID的代碼ID.py.因為我們的代碼是可以應用多線程的,所以可以采用更為復雜的操作,不用擔心數據生成成為總體效率的瓶頸。 
另外,我們使用Keras的方法keras.utils.to_categorical對label進行2值化 
(比如,對6分類而言,第三個label則相應的變成 to [0 0 1 0 0 0]) 。 

    

def __len__(self):
  'Denotes the number of batches per epoch'
  return int(np.floor(len(self.list_IDs) / self.batch_size))

  現在,當相應的index的batch被選到,則生成器執行_getitem_方法來生成它。

    

def __getitem__(self, index):
  'Generate one batch of data'
  # Generate indexes of the batch
  indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

  # Find list of IDs
  list_IDs_temp = [self.list_IDs[k] for k in indexes]

  # Generate data
  X, y = self.__data_generation(list_IDs_temp)

  return X, y

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM