Mengiris tensor dengan tensor indeks dan tf.gather

Sep 27 2020

Saya mencoba memotong tensor dengan tensor indeks. Untuk tujuan ini saya coba gunakan tf.gather. Namun, saya mengalami kesulitan memahami dokumentasi dan tidak membuatnya berfungsi seperti yang saya harapkan:

Saya memiliki dua tensor. Sebuah activationstensor dengan bentuk [1,240,4]dan idstensor dengan bentuk [1,1,120]. Saya ingin mengiris dimensi kedua activationstensor dengan indeks yang disediakan di dimensi ketiga idstensor:

downsampled_activations = tf.gather(activations, ids, axis=1)

Saya telah memberikan axis=1opsi karena itu adalah sumbu pada activationstensor yang ingin saya potong.

Namun, ini tidak memberikan hasil yang diharapkan dan hanya memberi saya kesalahan berikut:

tensorflow.python.framework.errors_impl.InvalidArgumentError: indices[0,0,1] = 1 is not in [0, 1)

Saya telah mencoba berbagai kombinasi axisdan batch_dimsopsi, tetapi sejauh ini tidak berhasil dan dokumentasinya tidak benar-benar membantu saya di jalur saya. Siapapun yang ingin menjelaskan parameter secara lebih rinci atau pada contoh di atas akan sangat membantu!

Edit: ID dihitung sebelumnya sebelum runtime dan masuk melalui pipeline input seperti:

features = tf.io.parse_single_example(
            serialized_example,
            features={ 'featureIDs': tf.io.FixedLenFeature([], tf.string)}

Mereka kemudian dibentuk ulang menjadi format sebelumnya:

feature_ids_raw = tf.decode_raw(features['featureIDs'], tf.int32)
feature_ids_shape = tf.stack([batch_size, (num_neighbours * 4)])
feature_ids = tf.reshape(feature_ids_raw, feature_ids_shape)
feature_ids = tf.expand_dims(feature_ids, 0)

Setelah itu mereka memiliki bentuk yang disebutkan sebelumnya ( batch_size = 1dan num_neighbours = 30-> [1,1,120]) dan saya ingin menggunakannya untuk memotong activationstensor.

Edit2: Saya ingin keluarannya [1,120,4]. (Jadi saya ingin mengumpulkan entri di sepanjang dimensi kedua activationstensor sesuai dengan ID yang disimpan di idstensor saya .)

Jawaban

1 DaveIdito Oct 02 2020 at 02:29

tf.gatherKumpulkan irisan dari paramssumbu axismenurut indeks.

Memang dokumentasinya bukan yang paling ekspresif, dan penekanan harus ditempatkan pada irisan (karena Anda mengindeks irisan dari axiselemen dan bukan, yang menurut saya Anda keliru mengambilnya).

Mari kita ambil contoh yang jauh lebih kecil:

activations_small = tf.convert_to_tensor([[[1, 2, 3, 4], [11, 22, 33, 44]]])
print(activations_small.shape) # [1, 2, 4]

Mari kita bayangkan tensor ini:

    XX 4  XX 44 XX XX
  XX  3 XX  33 X  XX
XXX 2 XX   22XX  XX
X-----X-----+X  XX
|  1  |  11 | XX
+-----+-----+X

tf.gather(activations1, [0, 0], axis=1) akan kembali

<tf.Tensor: shape=(1, 2, 4), dtype=int32, numpy=
array([[[1, 2, 3, 4],
        [1, 2, 3, 4]]], dtype=int32)>

Apa yang tf.gatherdilakukan adalah melihat dari sumbu 1, dan mengambil indeks 0 (ofc, dua kali yaitu [0, 0]). Jika Anda lari tf.gather(activations1, [0, 0, 0, 0, 0], axis=1).shape, Anda akan mendapatkannya TensorShape([1, 5, 4]).

Kesalahan Anda Sekarang mari kita coba memicu kesalahan yang Anda dapatkan.

tf.gather(activations1, [0, 2], axis=1)

InvalidArgumentError: indeks [1] = 2 tidak dalam [0, 2) [Op: GatherV2]

Apa yang terjadi di sini adalah ketika dilihat tf.gatherdari sudut pandang sumbu 1, tidak ada item (kolom jika mau) dengan indeks = 2.

Saya rasa inilah yang diisyaratkan oleh dokumentasi

param:<indices>Tensor indeks. Harus salah satu dari jenis berikut: int32, int64. Harus dalam rentang [0, params.shape [axis]).

Solusi (potensial) Anda

Dari dimensi indices, dan hasil yang diharapkan dari pertanyaan Anda, saya tidak yakin apakah hal di atas sangat jelas bagi Anda.

tf.gather(activations, indices=[0, 1, 2, 3], axis=2)atau apapun dengan indeks dalam kisaran indeks di [0, activations.shape[2])ie [0, 4)akan bekerja. Apa pun yang lain akan memberi Anda kesalahan yang Anda dapatkan.

Ada jawaban verbatim di bawah ini jika itu hasil yang Anda harapkan.

1 TouYou Oct 02 2020 at 02:28

Kamu bisa memakai :

downsampled_activations =tf.gather(activations , tf.squeeze(ids) ,axis = 1)
downsampled_activations.shape #  [1,120,4]

Dalam kebanyakan kasus, metode tf.gather membutuhkan indeks 1d, dan itu benar dalam kasus Anda, alih-alih indeks dengan 3d (1,1,120), 1d sudah cukup (120,). Metode tf.gather akan melihat sumbu (= 1) dan mengembalikan elemen pada setiap indeks yang disediakan oleh tensor indeks.