2017-03-17 113 views
1

我有一個代碼(see here),它使用slice_X()(位置:keras.engine.training)修改常見的TensorBoard後端(這將導致OOM(GPU使用)),以便在GPU使用期間使用TensorBoard。 不幸的是,自從我升級到Keras 2.0.0以後,這將導致導入錯誤,因爲keras.engine.training不再包含slice_X()。 它去了哪裏?有什麼其他解決方案可能?Keras函數`slice_X()`去哪了?

非常感謝您的幫助。

Ëd I T:

我已經更新了代碼(see here)至Keras 2.0.0和Tensorflow R1.0。

class TensorBoard(keras.callbacks.Callback): 
    ''' 
    Avoids OOM problem. 
    Adapted by: https://github.com/Vladimir-Yashin/keras/blob/13e6a1f99f33a3cc7bc0a44d285fda457cc808e4/keras/callbacks.py 
    Updated according to discussion: 
    http://stackoverflow.com/questions/42852495/where-did-keras-function-slice-x-go/42855104?noredirect=1#42855104 

Tensorboard basic visualizations. 
This callback writes a log for TensorBoard, which allows 
you to visualize dynamic graphs of your training and test 
metrics, as well as activation histograms for the different 
layers in your model. 
TensorBoard is a visualization tool provided with TensorFlow. 
If you have installed TensorFlow with pip, you should be able 
to launch TensorBoard from the command line: 
``` 
tensorboard --logdir=/full_path_to_your_logs 
``` 
You can find more information about TensorBoard 
[here](https://www.tensorflow.org/versions/master/how_tos/summaries_and_tensorboard/index.html). 
# Arguments 
    log_dir: the path of the directory where to save the log 
     files to be parsed by Tensorboard 
    histogram_freq: frequency (in epochs) at which to compute activation 
     histograms for the layers of the model. If set to 0, 
     histograms won't be computed. 
    write_graph: whether to visualize the graph in Tensorboard. 
     The log file can become quite large when 
     write_graph is set to True. 
''' 

def __init__(self, log_dir='./logs', histogram_freq=0, write_graph=True, write_images=False): 
    super(BatchedTensorBoard, self).__init__() 
    if K._BACKEND != 'tensorflow': 
     raise RuntimeError('TensorBoard callback only works ' 
          'with the TensorFlow backend.') 
    self.log_dir = log_dir 
    self.histogram_freq = histogram_freq 
    self.merged = None 
    self.write_graph = write_graph 
    self.write_images = write_images 
    #print(dir(self)) 

def set_model(self, model): 
    import tensorflow as tf 
    import keras.backend.tensorflow_backend as KTF 

    self.model = model 
    self.sess = KTF.get_session() 
    if self.histogram_freq and self.merged is None: 
     for layer in self.model.layers: 

      for weight in layer.weights: 
       tf.summary.histogram(weight.name, weight) 

       if self.write_images: 
        w_img = tf.squeeze(weight) 

        shape = w_img.get_shape() 
        if len(shape) > 1 and shape[0] > shape[1]: 
         w_img = tf.transpose(w_img) 

        if len(shape) == 1: 
         w_img = tf.expand_dims(w_img, 0) 

        w_img = tf.expand_dims(tf.expand_dims(w_img, 0), -1) 

        tf.image_summary(weight.name, w_img) 

      if hasattr(layer, 'output'): 
       tf.summary.histogram('{}_out'.format(layer.name), 
            layer.output) 
    if parse_version(tf.__version__) >= parse_version('0.12.0'): 
     self.merged = tf.summary.merge_all() 
    else: 
     self.merged = tf.merge_all_summaries() 
    if self.write_graph: 
     if parse_version(tf.__version__) >= parse_version('0.12.0'): 
      self.writer = tf.summary.FileWriter(self.log_dir, 
               self.sess.graph) 
     elif parse_version(tf.__version__) >= parse_version('0.8.0'): 
      self.writer = tf.train.SummaryWriter(self.log_dir, 
               self.sess.graph) 
     else: 
      self.writer = tf.train.SummaryWriter(self.log_dir, 
               self.sess.graph_def) 
    else: 
     if parse_version(tf.__version__) >= parse_version('0.12.0'): 
      self.writer = tf.summary.FileWriter(self.log_dir) 
     else: 
      self.writer = tf.train.SummaryWriter(self.log_dir) 

def on_epoch_end(self, epoch, logs={}): 
    import tensorflow as tf 
    from keras.engine.training import _slice_arrays #original: from keras.engine.training import slice_X 
    tf_session = K.get_session() 
    #result = [] 

    if self.validation_data and self.histogram_freq: 
     if epoch % self.histogram_freq == 0: 
      if self.model.uses_learning_phase: 
       cut_v_data = len(self.model.inputs) 
       val_data = self.validation_data[:cut_v_data] + [0] 
       tensors = self.model.inputs + [K.learning_phase()] 
      else: 
       val_data = self.validation_data 
       tensors = self.model.inputs 
      # Sample one batch of validation data to avoid OOM on GPU 
      if 'batch_size' in self.params: 
       index_array = np.arange(len(val_data[0])) 
       batch_ids = np.random.choice(index_array, self.params['batch_size']) 
       if self.model.uses_learning_phase: 
        ins_batch = _slice_arrays(val_data[:-1], batch_ids) + [val_data[-1]] #original: slice_X(val_data[:-1], batch_ids) + [val_data[-1]] 
       else: 
        ins_batch = _slice_arrays(val_data, batch_ids) #original: slice_X(val_data, batch_ids) 
      else: 
       # Generators yield one batch at a time and don't provide batch_size 
       ins_batch = val_data 
      my_feed_dict = dict(zip(tensors, ins_batch)) 

      result = tf_session.run([self.merged], feed_dict=my_feed_dict) 
      #result = self.sess.run([self.merged], feed_dict=my_feed_dict) 
      summary_str = result[0] 
      self.writer.add_summary(summary_str, epoch) 

    for name, value in logs.items(): 
     if name in ['batch', 'size']: 
      continue 
     summary = tf.Summary() 
     summary_value = summary.value.add() 
     summary_value.simple_value = value.item() 
     summary_value.tag = name 
     self.writer.add_summary(summary, epoch) 
    self.writer.flush() 

def on_train_end(self, _): 
    self.writer.close() 

回答

4

看來,slice_X()不存在了,但存在keras.engine.training的內部函數:_slice_array(),做切片的工作。請參閱code here

如果您還有其他問題,請不要猶豫。

編輯:

這裏有兩種功能。 老一:

def slice_X(X, start=None, stop=None): 
    """This takes an array-like, or a list of 
    array-likes, and outputs: 
     - X[start:stop] if X is an array-like 
     - [x[start:stop] for x in X] if X in a list 
    Can also work on list/array of indices: `slice_X(x, indices)` 
    # Arguments 
     start: can be an integer index (start index) 
      or a list/array of indices 
     stop: integer (stop index); should be None if 
      `start` was a list. 
    """ 

新一:

def _slice_arrays(arrays, start=None, stop=None): 
    """Slice an array or list of arrays. 
    This takes an array-like, or a list of 
    array-likes, and outputs: 
     - arrays[start:stop] if `arrays` is an array-like 
     - [x[start:stop] for x in arrays] if `arrays` is a list 
    Can also work on list/array of indices: `_slice_arrays(x, indices)` 
    # Arguments 
     arrays: Single array or list of arrays. 
     start: can be an integer index (start index) 
      or a list/array of indices 
     stop: integer (stop index); should be None if 
      `start` was a list. 
    # Returns 
     A slice of the array(s). 
    """ 

什麼是這裏明白的是,他們基本上只是改了名字。你只需通過_slice_arrays()用相同的參數改變slice_X()來編輯弗拉基米爾的代碼。還改變進口到

from keras.engine.training import _slice_arrays 

我希望它現在的工作。

+0

非常感謝您的親切幫助! 說實話,我不知道'slice_X()'函數做了什麼。我將包含'slice_X()'的代碼視爲一個黑盒子。 現在我感覺很不習慣用新的'_slice_array()'來模仿舊的函數,因爲舊的帽子2 params和新的3 params ... :( –

+0

也許張貼了它的代碼片段? –

+0

這是由Vladimir Yashin修改的TensorBoard回調[見這裏](https://github.com/Vladimir-Yashin/keras/blob/13e6a1f99f33a3cc7bc0a44d285fda457cc808e4/keras/callbacks.py) –