Хорошо, поэтому в сообщениях групп Google, которые я связал, довольно хорошо объяснено, почему это не работает. AdvancedSubtensor - это самая общая форма, которая работает со всеми сумасшедшими типами индексирующих вариантов. Тогда есть AdvancedSubtensor1, который работает только для определенного типа подмножества. Существует только версия GPU для AdvancedSubtensor1, а не для AdvancedSubtensor. Я не совсем понял причину, но об этом постоянно идет дискуссия.
AdvancedSubtensor1 может использоваться, когда имеется один список индексов. Однако в моем примере это не так. Общее обходное решение, которое вы видите, также в каком-то другом примере в столбце Google Groups, заключается в том, чтобы сначала сгладить массив и рассчитать индексы для сплющенного массива.
Большинство примеров работают с каким-то nonzero()
или так, где вы также сглаживаете базовые аргументы в том же порядке, а затем получаете индексы для сплющенной версии.
Итак, вопрос в том, как применить это к моему коду?
На самом деле, есть более простое решение, в котором он будет использовать AdvancedSubtensor1, который я не понял сначала:
meminkeyP = meminkey[:, P] # (batch,n_copies,n_cells)
Однако, прежде чем я понял, что я придумал общее решение, которое также работает для других случаев. Я преобразую свои индексы tuple (batches, P_bc)
в индексы для сплющенной версии. Это делается с помощью этой функции:
def indices_in_flatten_array(ndim, shape, *args):
"""
We expect that all args can be broadcasted together.
So, if we have some array A with ndim&shape as given,
A[args] would give us a subtensor.
We return the indices so that A[args].flatten()
and A.flatten()[indices] are the same.
"""
assert ndim > 0
assert len(args) == ndim
indices_per_axis = [args[i] for i in range(ndim)]
for i in range(ndim):
for j in range(i + 1, ndim):
indices_per_axis[i] *= shape[j]
indices = indices_per_axis[0]
for i in range(1, ndim):
indices += indices_per_axis[i]
return indices
Затем я использую это так:
meminkeyP = meminkey.flatten()[indices_in_flatten_array(meminkey.ndim, meminkey.shape, batches, P_bc)]
Это похоже на работу.
И я получаю этот выход:
Using gpu device 0: GeForce GTX TITAN (CNMeM is disabled, CuDNN not available)
GpuReshape{3} [id A] '' 11
|GpuAdvancedSubtensor1 [id B] '' 10
| |GpuReshape{1} [id C] '' 2
| | |<CudaNdarrayType(float32, matrix)> [id D]
| | |TensorConstant{(1,) of -1} [id E]
| |Reshape{1} [id F] '' 9
| |Elemwise{second,no_inplace} [id G] '' 8
| | |TensorConstant{(1, 5, 10) of 0} [id H]
| | |Elemwise{Mul}[(0, 0)] [id I] '' 7
| | |InplaceDimShuffle{0,x,x} [id J] '' 6
| | | |ARange{dtype='int64'} [id K] '' 4
| | | |TensorConstant{0} [id L]
| | | |Shape_i{0} [id M] '' 0
| | | | |<CudaNdarrayType(float32, matrix)> [id D]
| | | |TensorConstant{1} [id N]
| | |InplaceDimShuffle{x,x,x} [id O] '' 5
| | |Shape_i{1} [id P] '' 1
| | |<CudaNdarrayType(float32, matrix)> [id D]
| |TensorConstant{(1,) of -1} [id E]
|MakeVector{dtype='int64'} [id Q] '' 3
|Shape_i{0} [id M] '' 0
|TensorConstant{5} [id R]
|TensorConstant{10} [id S]
Малого тест случай:
def test_indices_in_flatten_array():
n_copies, n_cells = 5, 4
n_complex_cells = n_cells/2
n_batch = 3
static_rng = numpy.random.RandomState(1234)
def make_permut():
p = numpy.zeros((n_copies, n_cells), dtype="int32")
for i in range(n_copies):
p[i, :n_complex_cells] = static_rng.permutation(n_complex_cells)
# Same permutation for imaginary part.
p[i, n_complex_cells:] = p[i, :n_complex_cells] + n_complex_cells
return T.constant(p)
P = make_permut() # (n_copies,n_cells) -> list of indices
meminkey = T.as_tensor_variable(static_rng.rand(n_batch, n_cells).astype("float32"))
i_t = T.ones((meminkey.shape[0],)) # (batch,)
n_batch = i_t.shape[0]
batches = T.arange(0, n_batch).dimshuffle(0, 'x', 'x') # (batch,n_copies,n_cells)
P_bc = P.dimshuffle('x', 0, 1) # (batch,n_copies,n_cells)
meminkeyP1 = meminkey[batches, P_bc] # (batch,n_copies,n_cells)
meminkeyP2 = meminkey.flatten()[indices_in_flatten_array(meminkey.ndim, meminkey.shape, batches, P_bc)]
numpy.testing.assert_allclose(meminkeyP1.eval(), meminkeyP2.eval())
@talonmies: Это о CUDA бэкэнде Теаны. – Albert
Действительно. Но это все еще вопрос о Теано, а не о программировании CUDA.Это не одно и то же. Если у вас есть реальный код ядра CUDA или API-интерфейсы CUDA API, с которыми вы хотели бы помочь, обязательно добавьте их в вопрос и верните его. Но я подозреваю, что вы этого не сделали, и поэтому этот вопрос не должен быть помечен тегом CUDA. – talonmies
@talonmies: Я думаю, вы правы. Я не уверен, какой тег использовать, чтобы сказать, что мой вопрос является специфическим только для CUDA-бэкэнда из Theano. gpgpu, вероятно, также не является правильным. – Albert