2017-03-04 51 views
1

當我使用fit_generator和發電機功能嘗試從HDF5文件加載訓練數據,我得到一個ValueError是從與HDF5一個PointSelectionError結果:Keras/HDF5類型錯誤:PointSelection __getitem__只BOOL數組工作

Epoch 1/10 
Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner 
    self.run() 
    File "/usr/lib/python2.7/threading.py", line 763, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 429, in data_generator_task 
    generator_output = next(self._generator) 
    File "osr.py", line 108, in generate_training_sequences 
    X = training_save_file["X"][batch_idxs] 
    File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper (/tmp/pip-4rPeHA-build/h5py/_objects.c:2684) 
    File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper (/tmp/pip-4rPeHA-build/h5py/_objects.c:2642) 
    File "/usr/local/lib/python2.7/dist-packages/h5py/_hl/dataset.py", line 462, in __getitem__ 
    selection = sel.select(self.shape, args, dsid=self.id) 
    File "/usr/local/lib/python2.7/dist-packages/h5py/_hl/selections.py", line 72, in select 
    sel[arg] 
    File "/usr/local/lib/python2.7/dist-packages/h5py/_hl/selections.py", line 210, in __getitem__ 
    raise TypeError("PointSelection __getitem__ only works with bool arrays") 
TypeError: PointSelection __getitem__ only works with bool arrays 

Traceback (most recent call last): 
    File "osr.py", line 359, in <module> 
    osr.train_osr_model() 
    File "osr.py", line 89, in train_osr_model 
    nb_worker=1) 
    File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1532, in fit_generator 
    str(generator_output)) 
ValueError: output of generator should be a tuple (x, y, sample_weight) or (x, y). Found: None 

我研究了這個錯誤,並提到它可能是由於重複的索引,但在我的情況下似乎並不正確。這裏有被訪問的行索引:

[581 305 67 510 631 832 340 663 689 801 579 701 831 879 382 844 15 798 
342 329 118 657 503 129 602 2 528 157 341 299 731 539] 

這裏是訓練和生成功能:

def train_osr_model(self): 
     """ Train the optical speech recognizer 
     """ 
     print "\nTraining OSR" 
     validation_ratio = 0.3 
     batch_size = 32 
     with h5py.File(self.training_save_fn, "r") as training_save_file: 
      sample_count = int(training_save_file.attrs["sample_count"]) 
      sample_idxs = range(0, sample_count) 
      sample_idxs = np.random.permutation(sample_idxs) 
      training_sample_idxs = sample_idxs[0:int((1-validation_ratio)*sample_count)] 
      validation_sample_idxs = sample_idxs[int((1-validation_ratio)*sample_count):] 
      training_sequence_generator = self.generate_training_sequences(batch_size=batch_size, 
                      training_save_file=training_save_file, 
                      training_sample_idxs=training_sample_idxs) 
      validation_sequence_generator = self.generate_validation_sequences(batch_size=batch_size, 
                       training_save_file=training_save_file, 
                       validation_sample_idxs=validation_sample_idxs) 

      print "Sample Idxs: {0}\n".format(sample_idxs) # FOR DEBUG ONLY 
      print "Training Idxs: {0}\n".format(training_sample_idxs) # FOR DEBUG ONLY 
      print "Validation Idxs: {0}\n".format(validation_sample_idxs) # FOR DEBUG ONLY 

      pbi = ProgressDisplay() 
      self.osr.fit_generator(generator=training_sequence_generator, 
            validation_data=validation_sequence_generator, 
            samples_per_epoch=len(training_sample_idxs), 
            nb_val_samples=len(validation_sample_idxs), 
            nb_epoch=10, 
            max_q_size=1, 
            verbose=2, 
            callbacks=[pbi], 
            class_weight=None, 
            nb_worker=1) 

    def generate_training_sequences(self, batch_size, training_save_file, training_sample_idxs): 
     """ Generates training sequences from HDF5 file on demand 
     """ 
     while True: 
      # generate sequences for training 
      training_sample_count = len(training_sample_idxs) 
      batches = int(training_sample_count/batch_size) 
      remainder_samples = training_sample_count%batch_size 
      if remainder_samples: 
       batches = batches + 1 
      # generate batches of samples 
      for idx in xrange(0, batches): 
       if idx == batches - 1: 
        batch_idxs = training_sample_idxs[idx*batch_size:] 
       else: 
        batch_idxs = training_sample_idxs[idx*batch_size:idx*batch_size+batch_size] 

       print batch_idxs # FOR DEBUG ONLY 

       X = training_save_file["X"][batch_idxs] 
       Y = training_save_file["Y"][batch_idxs] 



       yield (np.array(X), np.array(Y)) 

    def generate_validation_sequences(self, batch_size, training_save_file, validation_sample_idxs): 
     while True: 
      # generate sequences for validation 
      validation_sample_count = len(validation_sample_idxs) 
      batches = int(validation_sample_count/batch_size) 
      remainder_samples = validation_sample_count%batch_size 
      if remainder_samples: 
       batches = batches + 1 
      # generate batches of samples 
      for idx in xrange(0, batches): 
       if idx == batches - 1: 
        batch_idxs = validation_sample_idxs[idx*batch_size:] 
       else: 
        batch_idxs = validation_sample_idxs[idx*batch_size:idx*batch_size+batch_size] 

       print batch_idxs # FOR DEBUG ONLY 

       X = training_save_file["X"][batch_idxs] 
       Y = training_save_file["Y"][batch_idxs] 

       yield (np.array(X), np.array(Y)) 

下面是預處理和訓練數據保存到一個HDF5文件中的函數:

def process_training_data(self): 
    """ Preprocesses training data and saves them into an HDF5 file 
    """ 
    # load training metadata from config file 
    training_metadata = {} 
    training_classes = [] 
    with open(self.config_file) as training_config: 
     training_metadata = json.load(training_config) 
     training_classes = sorted(list(training_metadata.keys())) 

     print "".join(["\n", 
         "Found {0} training classes!\n".format(len(training_classes)), 
         "-"*40]) 
     for class_label, training_class in enumerate(training_classes): 
      print "{0:<4d} {1:<10s} {2:<30s}".format(class_label, training_class, training_metadata[training_class]) 
     print "" 

    # count number of samples 
    sample_count = 0 
    sample_count_by_class = [0]*len(training_classes) 
    for class_label, training_class in enumerate(training_classes): 
     # get training class sequeunce paths 
     training_class_data_path = training_metadata[training_class] 
     training_class_sequence_paths = [os.path.join(training_class_data_path, file_name) 
             for file_name in os.listdir(training_class_data_path) 
             if (os.path.isfile(os.path.join(training_class_data_path, file_name)) 
              and ".mov" in file_name)] 
     # update sample count 
     sample_count += len(training_class_sequence_paths) 
     sample_count_by_class[class_label] = len(training_class_sequence_paths) 

    print "".join(["\n", 
        "Found {0} training samples!\n".format(sample_count), 
        "-"*40]) 
    for class_label, training_class in enumerate(training_classes): 
     print "{0:<4d} {1:<10s} {2:<6d}".format(class_label, training_class, sample_count_by_class[class_label]) 
    print "" 

    # initialize HDF5 save file, but clear older duplicate first if it exists 
    try: 
     print "Saved file \"{0}\" already exists! Overwriting previous saved file.\n".format(self.training_save_fn) 
     os.remove(self.training_save_fn) 
    except OSError: 
     pass 

    # process and save training data into HDF5 file 
    print "Generating {0} samples from {1} samples via data augmentation\n".format(sample_count*self.samples_generated_per_sample, 
                        sample_count) 
    sample_count = sample_count*self.samples_generated_per_sample 
    with h5py.File(self.training_save_fn, "w") as training_save_file: 
     training_save_file.attrs["training_classes"] = np.string_(",".join(training_classes)) 
     training_save_file.attrs["sample_count"] = sample_count 
     x_training_dataset = training_save_file.create_dataset("X", 
                   shape=(sample_count, self.frames_per_sequence, 3, self.rows, self.columns), 
                   dtype="f") 
     y_training_dataset = training_save_file.create_dataset("Y", 
                   shape=(sample_count, len(training_classes)), 
                   dtype="i") 

     # iterate through each class data 
     sample_idx = 0 
     for class_label, training_class in enumerate(training_classes): 
      # get training class sequeunce paths 
      training_class_data_path = training_metadata[training_class] 
      training_class_sequence_paths = [os.path.join(training_class_data_path, file_name) 
              for file_name in os.listdir(training_class_data_path) 
              if (os.path.isfile(os.path.join(training_class_data_path, file_name)) 
               and ".mov" in file_name)] 
      # iterate through each sequence 
      for idx, training_class_sequence_path in enumerate(training_class_sequence_paths): 
       sys.stdout.write("Processing training data for class \"{0}\": {1}/{2} sequences\r" 
           .format(training_class, idx+1, len(training_class_sequence_paths))) 
       sys.stdout.flush() 

       # accumulate samples and labels 
       samples_batch = self.process_frames(training_class_sequence_path) 
       label = [0]*len(training_classes) 
       label[class_label] = 1 
       label = np.array(label).astype("int32") 

       for sample in samples_batch: 
        x_training_dataset[sample_idx] = sample 
        y_training_dataset[sample_idx] = label 

        # update sample index 
        sample_idx += 1 

      print "\n" 

     training_save_file.close() 

     print "Training data processed and saved to {0}".format(self.training_save_fn) 

def process_frames(self, video_file_path): 
    """ Preprocesses sequence frames 
    """ 
    # haar cascades for localizing oral region 
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') 
    mouth_cascade = cv2.CascadeClassifier('haarcascade_mcs_mouth.xml') 

    video = cv2.VideoCapture(video_file_path) 
    success, frame = video.read() 

    frames = [] 
    success = True 

    # convert to grayscale, localize oral region, equalize frame dimensions, and accumulate valid frames 
    while success: 
     success, frame = video.read() 
     if success: 
     # convert to grayscale 
     frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 

     # localize single facial region 
     faces_coords = face_cascade.detectMultiScale(frame, 1.3, 5) 
     if len(faces_coords) == 1: 
      face_x, face_y, face_w, face_h = faces_coords[0] 
      frame = frame[face_y:face_y + face_h, face_x:face_x + face_w] 

      # localize oral region 
      mouth_coords = mouth_cascade.detectMultiScale(frame, 1.3, 5) 
      threshold = 0 
      for (mouth_x, mouth_y, mouth_w, mouth_h) in mouth_coords: 
      if (mouth_y > threshold): 
       threshold = mouth_y 
       valid_mouth_coords = (mouth_x, mouth_y, mouth_w, mouth_h) 
      else: 
       pass 
      mouth_x, mouth_y, mouth_w, mouth_h = valid_mouth_coords 
      frame = frame[mouth_y:mouth_y + mouth_h, mouth_x:mouth_x + mouth_w] 

      # equalize frame dimensions 
      frame = cv2.resize(frame, (self.columns, self.rows)).astype('float32') 

      # accumulate frames 
      frames.append(frame) 

     # ignore multiple facial region detections 
     else: 
      pass 

    # equalize sequence lengths 
    if len(frames) < self.frames_per_sequence: 
     frames = [frames[0]]*(self.frames_per_sequence - len(frames)) + frames 
    frames = np.array(frames[-self.frames_per_sequence:]) 

    # function to normalize and add channel dimension to each frame 
    proc_frame = lambda frame: np.array([frame/255.0]*3) 

    samples_batch = [np.array(map(proc_frame, frames))] 
    # random transformations for data augmentation 
    for _ in xrange(0, self.samples_generated_per_sample-1): 
     rotated_frames = random_rotation(frames, rg=4.5) 
     shifted_frames = random_shift(rotated_frames, wrg=0.05, hrg=0.05) 
     sheared_frames = random_shear(shifted_frames, intensity=0.08) 
     zoomed_frames = random_zoom(sheared_frames, zoom_range=(1.05, 1.05)) 
     samples_batch.append(np.array(map(proc_frame, zoomed_frames))) 

    return samples_batch 

回答

1

這個錯誤來自兩兩件事:

  • 您正在閱讀的內容來自batch_idxs是一個數組,而不是一個列表。 h5py對象接受帶有列表的索引。但即使你改變了

    X = training_save_file["X"][list(batch_idxs)] 
    

    你仍然會得到一個錯誤。這來自對列表索引的一些限制。這使我們想到了第二點。

  • 如果你讀了doc you sent me,這寫的是:

    The following restrictions exist:

    • List selections may not be empty
    • Selection coordinates must be given in increasing order
    • Duplicate selections are ignored
    • Very long lists (> 1000 elements) may produce poor performance

    第二子彈是我們的問題:你的隨機洗牌時產生training_sample_idxs使索引順序隨機數據集期待他們ecreasing順序。這是一個限制,你將不得不處理,但它不是太約束,因爲批次中的訂單無關緊要,無論如何,該模型將在整個批次中進行優化。

這有幫助嗎?

+0

你好Nassim謝謝你的迴應。 「X」和「Y」是數據集,而不是組,並且我相信訪問數據集「X」的正確方法是,例如,X = training_save_file [「X」] [batch_idxs]',如文檔所示: http://docs.h5py.org/en/latest/high/dataset.html#fancy-indexing –

+0

我仍然認爲錯誤來自這一行。爲了幫助我們解決問題,您可以發佈最初創建HDF5文件的方式嗎? –

+0

你好Nassim我已經用預處理和保存訓練數據到HDF5文件的函數更新了這個問題。 –

相關問題