텐서 슬라이싱 소개

TensorFlow.org에서 보기 Google Colab에서 실행 GitHub에서 소스 보기 노트북 다운로드

객체 감지 및 NLP와 같은 ML 애플리케이션에서 작업할 때 텐서의 하위 섹션(슬라이스)으로 작업해야 하는 경우가 있습니다. 예를 들어, 모델 아키텍처에 라우팅이 포함된 경우 한 계층이 다음 계층으로 라우팅되는 교육 예제를 제어할 수 있습니다. 이 경우 텐서 슬라이싱 작업을 사용하여 텐서를 분할하고 올바른 순서로 다시 결합할 수 있습니다.

NLP 애플리케이션에서 텐서 슬라이싱을 사용하여 훈련하는 동안 워드 마스킹을 수행할 수 있습니다. 예를 들어 각 문장에서 마스킹할 단어 인덱스를 선택하고 해당 단어를 레이블로 선택한 다음 선택한 단어를 마스크 토큰으로 교체하여 문장 목록에서 훈련 데이터를 생성할 수 있습니다.

이 가이드에서는 TensorFlow API를 사용하여 다음을 수행하는 방법을 배웁니다.

  • 텐서에서 조각 추출
  • 텐서의 특정 인덱스에 데이터 삽입

이 가이드는 텐서 인덱싱에 익숙하다고 가정합니다. 이 가이드를 시작하기 전에 TensorTensorFlow NumPy 가이드의 인덱싱 섹션을 읽으십시오.

설정

import tensorflow as tf
import numpy as np
2022-12-14 21:53:15.775691: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory
2022-12-14 21:53:15.775783: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory
2022-12-14 21:53:15.775793: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.

텐서 조각 추출

tf.slice 사용하여 NumPy와 같은 텐서 슬라이싱을 수행합니다.

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 '하여 텐서 조각을 추출할 수도 있습니다.

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 를 사용하여 텐서의 특정 슬라이스/인덱스에 데이터를 삽입합니다. 값을 삽입하는 텐서는 0으로 초기화됩니다.

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)

0으로 초기화된 텐서를 필요로 하는 tf.scatter_nd 와 같은 메서드는 희소 텐서 이니셜라이저와 유사합니다. tf.gather_ndtf.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에서 사용할 수 있는 텐서 슬라이싱 작업을 사용하여 텐서의 요소를 더 세밀하게 제어하는 방법을 배웠습니다.