Как создать пользовательский слой Keras, используя функции, не включенные в бэкэнд, для выполнения выборки тензорных данных? - PullRequest
0 голосов
/ 27 февраля 2019

Я пытаюсь создать пользовательский слой в keras.Этот слой должен выполнить выборку по входному тензору (в соответствии с распределением вероятностей) и вывести тензор того же размера, только с выбранными значениями, остальные равны нулю.Однако в keras.backend, насколько мне известно, функции выборки недоступны.Обратите внимание, что этот слой не имеет обучаемых параметров, я просто хочу функцию, которая изменяет предыдущий вывод.

Сейчас я пытаюсь преобразовать входной тензор из Tensor объекта в numpy.ndarray, используя keras.backend.eval().Согласно вопросу stackoverflow # 47577060 , это кажется невозможным.Хотя было бы неплохо применить обычную функцию numpy для выборки np.random.choice.Эта функция принимает только 1-мерный массив np.array, как для ввода, так и для распределения вероятностей (нельзя использовать тензоры).Обратите внимание, что распределение вероятностей, которое я упоминаю, на самом деле является самим входным сигналом (моя цель - выборка элементов с высоким значением с более высокой вероятностью)

Пользовательский слой для выборки называется MyLayerи определяется как

def MyLayer(input_tensor): #Here we sample from the tensor directly!

# Convert to numpy array: in keras the input_tensor has shape [None,H,W,D] and is Keras.Tensor object...  
input_tensor = keras.backend.eval(input_tensor) # convert to np.array  #** THIS IS WHERE IT FAILS **#
input_tensor = input_tensor[0,:,:,:] # first dimension is None so we discard

# need to transform the np.array tensor into a matrix (custom function)
input_matrix = tensor_to_matrix(input_tensor)

# create the probability distribution that the sampling will follow
# the probability must be the matrix itself (to sample the highest elements in priority)
probability_matrix = input_matrix/np.max(input_matrix) # must be normalized to sum to 1
prob_vec = probability_matrix.flatten('F') # vectorize it, column-first

# create list of same size where each element is the value and its own position (i,j). it is necessary to create a string "value/i/j" for each element (i have no other idea)
matrix_value_position = []
for j in range(input_matrix.shape[1]):
    for i in range(input_matrix.shape[0]):
        t = str(input_matrix[i,j])+'/'+str(i)+'/'+str(j) #it will be parsed later to recover value,i,j
        matrix_value_position.append(t)
vec_value_position = np.array(matrix_value_position)

# Sample points according to a probability distribution
num_samples = 10000
sample = np.random.choice(vec_value_position, num_samples, p=prob_vec) #**THIS IS WHERE IT SAMPLES**#

# parse the strings that have been sampled, store them in a numpy array
samples_results = []
for i in range(len(sample)):
    samples_results.append(np.array(sample[i].split('/')).astype(float))
samples_results = np.array(samples_results) 

# reconstruct the matrix from the samples (the rest is zero)
reconstructed_matrix = np.zeros((input_matrix.shape[0],input_matrix.shape[1]))
for s in samples_results:
    i = int(s[1])
    j = int(s[2])
    reconstructed_matrix[x,y] = float(s[0]) #retrieve the value sampled at position [i,j]

# return a np.array tensor (custom function)
output_tensor_numpy = reverse_tensor_expand(reconstructed_matrix, input_tensor.shape)

# convert back to Keras Tensor object 
output_tensor_keras = keras.backend.variable(value=output_tensor_numpy, dtype='float32')

return output_tensor_keras

Затем я применяю слой со следующим (это второй слой):

model = keras.Sequential() 
model.add(Conv2D(filters=6, kernel_size=(7, 7), activation='relu', input_shape=(28,28,1))) 
model.add(Lambda(MyLayer, output_shape=MyLayerOutputShape)) #note: output_shape is equal to input_shape. MyLayerOutputShape is the identity
#compile
model.compile(loss='categorical_crossentropy',optimizer='rmsprop',metrics=['accuracy']) 
print(model.summary())

Возвращенная ошибка была

---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_call(self, fn, *args)
   1333     try:
-> 1334       return fn(*args)
   1335     except errors.OpError as e:

/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py in _run_fn(feed_dict, fetch_list, target_list, options, run_metadata)
   1318       return self._call_tf_sessionrun(
-> 1319           options, feed_dict, fetch_list, target_list, run_metadata)
   1320 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py in _call_tf_sessionrun(self, options, feed_dict, fetch_list, target_list, run_metadata)
   1406         self._session, options, feed_dict, fetch_list, target_list,
-> 1407         run_metadata)
   1408 

InvalidArgumentError: You must feed a value for placeholder tensor 'conv2d_71_input' with dtype float and shape [?,28,28,1]
     [[{{node conv2d_71_input}} = Placeholder[dtype=DT_FLOAT, shape=[?,28,28,1], _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]
During handling of the above exception, another exception occurred:

InvalidArgumentError                      Traceback (most recent call last)
<ipython-input-316-26717973065e> in <module>()
      1 model_cust = keras.Sequential()
      2 model_cust.add(Conv2D(filters=6, kernel_size=(7, 7), activation='relu', input_shape=(28,28,1)))
----> 3 model_cust.add(Lambda(MyLayer, output_shape=QuantumSamplingLayerOutputShape))
      4 #compile
      5 model_cust.compile(loss='categorical_crossentropy',optimizer='rmsprop',metrics=['accuracy'])

/anaconda3/lib/python3.6/site-packages/keras/engine/sequential.py in add(self, layer)
    179                 self.inputs = network.get_source_inputs(self.outputs[0])
    180         elif self.outputs:
--> 181             output_tensor = layer(self.outputs[0])
    182             if isinstance(output_tensor, list):
    183                 raise TypeError('All layers in a Sequential model '

/anaconda3/lib/python3.6/site-packages/keras/engine/base_layer.py in __call__(self, inputs, **kwargs)
    455             # Actually call the layer,
    456             # collecting output(s), mask(s), and shape(s).
--> 457             output = self.call(inputs, **kwargs)
    458             output_mask = self.compute_mask(inputs, previous_mask)
    459 

/anaconda3/lib/python3.6/site-packages/keras/layers/core.py in call(self, inputs, mask)
    685         if has_arg(self.function, 'mask'):
    686             arguments['mask'] = mask
--> 687         return self.function(inputs, **arguments)
    688 
    689     def compute_mask(self, inputs, mask=None):

<ipython-input-312-a97b6c80e163> in MyLayer(input_tensor)
      2 
      3     # Convert to numpy array: in keras the input_tensor has shape [None,H,W,D] and is Keras.Tensor object...
----> 4     input_tensor = keras.backend.eval(input_tensor) # convert to np.array  #** THIS IS WHERE IT FAILS **#
      5     input_tensor = input_tensor[0,:,:,:] # first dimension is None so we discard
      6 

/anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py in eval(x)
    671     ```
    672     """
--> 673     return to_dense(x).eval(session=get_session())
    674 
    675 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/ops.py in eval(self, feed_dict, session)
    711 
    712     """
--> 713     return _eval_using_default_session(self, feed_dict, self.graph, session)
    714 
    715 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/ops.py in _eval_using_default_session(tensors, feed_dict, graph, session)
   5155                        "the tensor's graph is different from the session's "
   5156                        "graph.")
-> 5157   return session.run(tensors, feed_dict)
   5158 
   5159 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py in run(self, fetches, feed_dict, options, run_metadata)
    927     try:
    928       result = self._run(None, fetches, feed_dict, options_ptr,
--> 929                          run_metadata_ptr)
    930       if run_metadata:
    931         proto_data = tf_session.TF_GetBuffer(run_metadata_ptr)

/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py in _run(self, handle, fetches, feed_dict, options, run_metadata)
   1150     if final_fetches or final_targets or (handle and feed_dict_tensor):
   1151       results = self._do_run(handle, final_targets, final_fetches,
-> 1152                              feed_dict_tensor, options, run_metadata)
   1153     else:
   1154       results = []

/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_run(self, handle, target_list, fetch_list, feed_dict, options, run_metadata)
   1326     if handle is None:
   1327       return self._do_call(_run_fn, feeds, fetches, targets, options,
-> 1328                            run_metadata)
   1329     else:
   1330       return self._do_call(_prun_fn, handle, feeds, fetches)

/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_call(self, fn, *args)
   1346           pass
   1347       message = error_interpolation.interpolate(message, self._graph)
-> 1348       raise type(e)(node_def, op, message)
   1349 
   1350   def _extend_graph(self):

InvalidArgumentError: You must feed a value for placeholder tensor 'conv2d_71_input' with dtype float and shape [?,28,28,1]
     [[node conv2d_71_input (defined at /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517)  = Placeholder[dtype=DT_FLOAT, shape=[?,28,28,1], _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]

Если у кого-то есть идея решить эту проблему или определить другой способ выполнения этого слоя выборки и быть совместимым с Keras, я был бы очень признателен за это

Спасибо

...