Я пытаюсь создать пользовательский слой в 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, я был бы очень признателен за это
Спасибо