ความรู้เบื้องต้นเกี่ยวกับการตัดเทนเซอร์

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดโน๊ตบุ๊ค

เมื่อทำงานกับแอปพลิเคชัน ML เช่น การตรวจจับวัตถุและ NLP บางครั้งจำเป็นต้องทำงานกับส่วนย่อย (ส่วน) ของเทนเซอร์ ตัวอย่างเช่น หากสถาปัตยกรรมแบบจำลองของคุณมีการกำหนดเส้นทาง โดยที่เลเยอร์หนึ่งอาจควบคุมว่าตัวอย่างการฝึกใดจะได้รับการกำหนดเส้นทางไปยังเลเยอร์ถัดไป ในกรณีนี้ คุณสามารถใช้ tensor slicing ops เพื่อแยกเทนเซอร์ออกและประกอบกลับเข้าที่ในลำดับที่ถูกต้อง

ในแอปพลิเคชัน NLP คุณสามารถใช้ตัวแบ่งเทนเซอร์เพื่อทำการปิดบังคำขณะฝึกได้ ตัวอย่างเช่น คุณสามารถสร้างข้อมูลการฝึกอบรมจากรายการประโยคโดยเลือกดัชนีคำที่จะมาสก์ในแต่ละประโยค นำคำออกมาเป็นป้ายกำกับ แล้วแทนที่คำที่เลือกด้วยโทเค็นการพราง

ในคู่มือนี้ คุณจะได้เรียนรู้วิธีใช้ TensorFlow API เพื่อ:

  • แยกชิ้นจากเทนเซอร์
  • แทรกข้อมูลที่ดัชนีเฉพาะในเทนเซอร์

คู่มือนี้จะถือว่าคุ้นเคยกับการจัดทำดัชนีเทนเซอร์ อ่านส่วนการจัดทำดัชนีของคู่มือ 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)

หรือคุณสามารถใช้ไวยากรณ์ Pythonic เพิ่มเติมได้ โปรดทราบว่าเทนเซอร์สไลซ์จะเว้นระยะห่างเท่าๆ กันในช่วงเริ่มต้น-หยุด

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 เพื่อแยกส่วนของเทนเซอร์โดย 'striding' เหนือมิติเทนเซอร์

ใช้ 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)
ตัวยึดตำแหน่ง21
# 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 เพื่อเลียนแบบพฤติกรรมของ sparse tensor ops

ลองพิจารณาตัวอย่างที่คุณสร้างเมตริกซ์กระจัดกระจายโดยใช้สองวิธีนี้ร่วมกัน

# 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)
ตัวยึดตำแหน่ง36

ใช้ 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)

อ่านเพิ่มเติมและทรัพยากร

ในคู่มือนี้ คุณได้เรียนรู้วิธีใช้ ops การแบ่งส่วนเทนเซอร์ที่มีอยู่ใน TensorFlow เพื่อควบคุมองค์ประกอบในเทนเซอร์ของคุณอย่างละเอียดยิ่งขึ้น