آشنایی با برش تانسور

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

هنگام کار بر روی برنامه های ML مانند تشخیص اشیا و NLP، گاهی اوقات لازم است با بخش های فرعی (برش) تانسورها کار کنید. برای مثال، اگر معماری مدل شما شامل مسیریابی باشد، جایی که یک لایه ممکن است کنترل کند که کدام نمونه آموزشی به لایه بعدی هدایت شود. در این مورد، می‌توانید از عملیات برش تانسور برای تقسیم کردن تانسورها و قرار دادن آنها در کنار هم به ترتیب درست استفاده کنید.

در برنامه های NLP، می توانید از برش تانسور برای انجام پوشاندن کلمه در حین تمرین استفاده کنید. به عنوان مثال، می توانید با انتخاب یک فهرست کلمه برای پوشاندن در هر جمله، خارج کردن کلمه به عنوان برچسب، و سپس جایگزینی کلمه انتخابی با یک نشانه ماسک، داده های آموزشی را از لیست جملات تولید کنید.

در این راهنما، نحوه استفاده از API های TensorFlow را یاد خواهید گرفت:

  • برش ها را از یک تانسور استخراج کنید
  • درج داده ها در شاخص های خاص در یک تانسور

این راهنما آشنایی با نمایه سازی تانسور را فرض می کند. قبل از شروع کار با این راهنما، بخش های نمایه سازی راهنماهای Tensor و TensorFlow NumPy را بخوانید.

برپایی

import tensorflow as tf
import numpy as np

برش های تانسور را استخراج کنید

برش تانسور NumPy مانند را با استفاده از tf.slice انجام دهید.

t1 = tf.constant([0, 1, 2, 3, 4, 5, 6, 7])

print(tf.slice(t1,
               begin=[1],
               size=[3]))
tf.Tensor([1 2 3], shape=(3,), dtype=int32)

از طرف دیگر، می توانید از دستور زبان پایتونیک بیشتری استفاده کنید. توجه داشته باشید که برش های تانسور در یک محدوده شروع و توقف به طور مساوی فاصله دارند.

print(t1[1:4])
tf.Tensor([1 2 3], shape=(3,), dtype=int32)

print(t1[-3:])
tf.Tensor([5 6 7], shape=(3,), dtype=int32)

برای تانسورهای 2 بعدی، می توانید از چیزی مانند:

t2 = tf.constant([[0, 1, 2, 3, 4],
                  [5, 6, 7, 8, 9],
                  [10, 11, 12, 13, 14],
                  [15, 16, 17, 18, 19]])

print(t2[:-1, 1:3])
tf.Tensor(
[[ 1  2]
 [ 6  7]
 [11 12]], shape=(3, 2), dtype=int32)

می توانید از tf.slice در تانسورهای ابعاد بالاتر نیز استفاده کنید.

t3 = tf.constant([[[1, 3, 5, 7],
                   [9, 11, 13, 15]],
                  [[17, 19, 21, 23],
                   [25, 27, 29, 31]]
                  ])

print(tf.slice(t3,
               begin=[1, 1, 0],
               size=[1, 1, 2]))
tf.Tensor([[[25 27]]], shape=(1, 1, 2), dtype=int32)

همچنین می‌توانید از tf.strided_slice برای استخراج برش‌های تانسور با «گام برداشتن» بر روی ابعاد تانسور استفاده کنید.

از tf.gather برای استخراج شاخص های خاص از یک محور یک تانسور استفاده کنید.

print(tf.gather(t1,
                indices=[0, 3, 6]))

# This is similar to doing

t1[::3]
tf.Tensor([0 3 6], shape=(3,), dtype=int32)
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([0, 3, 6], dtype=int32)>

tf.gather نیازی به فاصله یکنواخت شاخص ها ندارد.

alphabet = tf.constant(list('abcdefghijklmnopqrstuvwxyz'))

print(tf.gather(alphabet,
                indices=[2, 0, 19, 18]))
tf.Tensor([b'c' b'a' b't' b's'], shape=(4,), dtype=string)

برای استخراج برش ها از چندین محور یک تانسور، از tf.gather_nd استفاده کنید. این زمانی مفید است که بخواهید عناصر یک ماتریس را بر خلاف سطرها یا ستون های آن جمع آوری کنید.

t4 = tf.constant([[0, 5],
                  [1, 6],
                  [2, 7],
                  [3, 8],
                  [4, 9]])

print(tf.gather_nd(t4,
                   indices=[[2], [3], [0]]))
tf.Tensor(
[[2 7]
 [3 8]
 [0 5]], shape=(3, 2), dtype=int32)

t5 = np.reshape(np.arange(18), [2, 3, 3])

print(tf.gather_nd(t5,
                   indices=[[0, 0, 0], [1, 2, 1]]))
tf.Tensor([ 0 16], shape=(2,), dtype=int64)
# Return a list of two matrices

print(tf.gather_nd(t5,
                   indices=[[[0, 0], [0, 2]], [[1, 0], [1, 2]]]))
tf.Tensor(
[[[ 0  1  2]
  [ 6  7  8]]

 [[ 9 10 11]
  [15 16 17]]], shape=(2, 2, 3), dtype=int64)
# Return one matrix

print(tf.gather_nd(t5,
                   indices=[[0, 0], [0, 2], [1, 0], [1, 2]]))
tf.Tensor(
[[ 0  1  2]
 [ 6  7  8]
 [ 9 10 11]
 [15 16 17]], shape=(4, 3), dtype=int64)

درج داده ها در تانسورها

از tf.scatter_nd برای درج داده ها در برش ها/شاخص های خاص یک تانسور استفاده کنید. توجه داشته باشید که تانسوری که مقادیر را در آن وارد می‌کنید، مقدار اولیه صفر است.

t6 = tf.constant([10])
indices = tf.constant([[1], [3], [5], [7], [9]])
data = tf.constant([2, 4, 6, 8, 10])

print(tf.scatter_nd(indices=indices,
                    updates=data,
                    shape=t6))
tf.Tensor([ 0  2  0  4  0  6  0  8  0 10], shape=(10,), dtype=int32)

روش هایی مانند tf.scatter_nd که به تانسورهای با مقدار اولیه صفر نیاز دارند، مشابه تانسورهای اولیه پراکنده هستند. می توانید از tf.gather_nd و tf.scatter_nd برای تقلید از رفتار تانسورهای پراکنده استفاده کنید.

مثالی را در نظر بگیرید که در آن یک تانسور پراکنده با استفاده از این دو روش به همراه یکدیگر می‌سازید.

# Gather values from one tensor by specifying indices

new_indices = tf.constant([[0, 2], [2, 1], [3, 3]])
t7 = tf.gather_nd(t2, indices=new_indices)

# Add these values into a new tensor

t8 = tf.scatter_nd(indices=new_indices, updates=t7, shape=tf.constant([4, 5]))

print(t8)
tf.Tensor(
[[ 0  0  2  0  0]
 [ 0  0  0  0  0]
 [ 0 11  0  0  0]
 [ 0  0  0 18  0]], shape=(4, 5), dtype=int32)

این شبیه به:

t9 = tf.SparseTensor(indices=[[0, 2], [2, 1], [3, 3]],
                     values=[2, 11, 18],
                     dense_shape=[4, 5])

print(t9)
SparseTensor(indices=tf.Tensor(
[[0 2]
 [2 1]
 [3 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([ 2 11 18], shape=(3,), dtype=int32), dense_shape=tf.Tensor([4 5], shape=(2,), dtype=int64))
# Convert the sparse tensor into a dense tensor

t10 = tf.sparse.to_dense(t9)

print(t10)
tf.Tensor(
[[ 0  0  2  0  0]
 [ 0  0  0  0  0]
 [ 0 11  0  0  0]
 [ 0  0  0 18  0]], shape=(4, 5), dtype=int32)

برای درج داده در یک تانسور با مقادیر از قبل موجود، از tf.tensor_scatter_nd_add استفاده کنید.

t11 = tf.constant([[2, 7, 0],
                   [9, 0, 1],
                   [0, 3, 8]])

# Convert the tensor into a magic square by inserting numbers at appropriate indices

t12 = tf.tensor_scatter_nd_add(t11,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])

print(t12)
tf.Tensor(
[[2 7 6]
 [9 5 1]
 [4 3 8]], shape=(3, 3), dtype=int32)

به طور مشابه، از tf.tensor_scatter_nd_sub برای کم کردن مقادیر از یک تانسور با مقادیر از قبل استفاده کنید.

# Convert the tensor into an identity matrix

t13 = tf.tensor_scatter_nd_sub(t11,
                               indices=[[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [2, 1], [2, 2]],
                               updates=[1, 7, 9, -1, 1, 3, 7])

print(t13)
tf.Tensor(
[[1 0 0]
 [0 1 0]
 [0 0 1]], shape=(3, 3), dtype=int32)

از tf.tensor_scatter_nd_min برای کپی کردن مقادیر حداقل عنصر از یک تانسور به دیگری استفاده کنید.

t14 = tf.constant([[-2, -7, 0],
                   [-9, 0, 1],
                   [0, -3, -8]])

t15 = tf.tensor_scatter_nd_min(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[-6, -5, -4])

print(t15)
tf.Tensor(
[[-2 -7 -6]
 [-9 -5  1]
 [-4 -3 -8]], shape=(3, 3), dtype=int32)

به طور مشابه، از tf.tensor_scatter_nd_max برای کپی کردن مقادیر حداکثر عنصر از یک تانسور به دیگری استفاده کنید.

t16 = tf.tensor_scatter_nd_max(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])

print(t16)
tf.Tensor(
[[-2 -7  6]
 [-9  5  1]
 [ 4 -3 -8]], shape=(3, 3), dtype=int32)

مطالعه بیشتر و منابع

در این راهنما، یاد گرفتید که چگونه از عملیات برش تانسور موجود با TensorFlow برای اعمال کنترل دقیق بر عناصر موجود در تانسور خود استفاده کنید.