Tensor

12 minute read

Deep Learning


te

딥러닝을 위해 사용하는 TensorFlow에서는 데이터들을 Tensor를 이용하여 처리한다.
그렇다면 Tensor란 무엇일까 ❓







1. 텐서 소개


먼저 Tensorflow와 Numpy를 임포트 해줍니다.

import tensorflow as tf
import numpy as np

텐서는 각 항목이 같은 Datatype을 가지고 있는 다차원 배열입니다. ( 텐서를 Numpy와 같이 생각하여도 무관합니다.)

보통 int와 float를 많이 사용하지만 필요하다면 복소수나 문자열(String)도 사용가능합니다.

  • 상수 텐서 VS 변수 텐서

일반적인 텐서 즉, 상수 텐서는 항목의 값을 초기에 설정해주면 변경 및 수정이 불가능합니다.

(tf.Variable 클래스로 변수 텐서로 변경해준다면 변경, 수정, 업데이트 등의 작업이 가능합니다.)

2. 텐서 만들기


정규 텐서

  • 스칼라 ( rank-0 : 0차원) 텐서
rank_0_tensor = tf.constant(7) # tf.constat는 상수텐서를 생성하는 것입니다.
print(rank_0_tensor)
tf.Tensor(7, shape=(), dtype=int32)

스칼라 텐서는 단일 값 하나를 말합니다. 따라서 축은 없습니다.(shape을 보면 아무 값이 없습니다.)

텐서에서는 설정을 따로 해주지 않는다면 데이터타입을 int32로 사용하는 것을 확인할 수 있습니다.

  • 벡터 ( rank-1 : 1차원 ) 텐서
rank_1_tensor = tf.constant([72., 38.2, 10.10])
print(rank_1_tensor)
tf.Tensor([72.  38.2 10.1], shape=(3,), dtype=float32)

1차원 리스트와 유사하게 생각할 수 있습니다. 하나의 축이 확인 됩니다.(shape을 보시면 값이 하나, 즉 축이 하나가 있는 것이 확인 됩니다. 3은 3개의 값이 있단는 것을 보여줍니다.)

  • 행렬 ( rank-2 : 2차원) 텐서
rank_2_tensor = tf.constant([[1, 2],
                             [3, 4],
                             [5, 6]], dtype=tf.float16)
print(rank_2_tensor)
tf.Tensor(
[[1. 2.]
 [3. 4.]
 [5. 6.]], shape=(3, 2), dtype=float16)

2개의 축이 있습니다. 그리고 여기선 데이터타입을 tf.float16으로 임의로 설정해 주었습니다. (뒤에 메모리 크기를 16으로 지정해주기 위해선 tf. 을 붙여야 합니다. 그냥 float16이라는 데이터형은 파이썬에서 지원해주지 않기 때문입니다.)

  • 이미지로 확인해 보기

1

  • 3차원 이상의 다차원 텐서

3차원 텐서를 만들어 보겠습니다.

rank_3_tensor = tf.constant([
  [[0, 1, 2, 3, 4],
   [5, 6, 7, 8, 9]],
  [[10, 11, 12, 13, 14],
   [15, 16, 17, 18, 19]],
  [[20, 21, 22, 23, 24],
   [25, 26, 27, 28, 29]],])

print(rank_3_tensor)
tf.Tensor(
[[[ 0  1  2  3  4]
  [ 5  6  7  8  9]]

 [[10 11 12 13 14]
  [15 16 17 18 19]]

 [[20 21 22 23 24]
  [25 26 27 28 29]]], shape=(3, 2, 5), dtype=int32)

축이 2개 이상인 텐서를 시각화하는 방법에는 여러가지가 있습니다.

2

  • Tensor를 Numpy 또는 Array로 변환
rank_2_tensor.numpy()
array([[1., 2.],
       [3., 4.],
       [5., 6.]], dtype=float16)
np.array(rank_2_tensor)
array([[1., 2.],
       [3., 4.],
       [5., 6.]], dtype=float16)

처음에 말했듯이 Tensor는 Numpy와 유사하기 때문에 Numpy 배열 또는 Array로 변환 시킬 수 있습니다.

텐서 연산

  • 덧셈
a = tf.constant([[1, 2],
                 [3, 4]])
b = tf.constant([[1, 1],
                 [1, 1]]) # tf.ones([2,2])로 만들수도 있다.
print(tf.add(a, b), "\n")
tf.Tensor(
[[2 3]
 [4 5]], shape=(2, 2), dtype=int32) 

각 항목끼리 덧셈을 한다.

  • 각 항목별 곱셈
print(tf.multiply(a, b), "\n")
tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32) 

항목 끼리 곱한다.

  • 행렬 곱셈
print(tf.matmul(a, b), "\n")
tf.Tensor(
[[3 3]
 [7 7]], shape=(2, 2), dtype=int32) 

행렬 곱셈을 수행한다.

print(a + b, "\n") # element-wise addition
print(a * b, "\n") # element-wise multiplication
print(a @ b, "\n") # matrix multiplication
tf.Tensor(
[[2 3]
 [4 5]], shape=(2, 2), dtype=int32) 

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

tf.Tensor(
[[3 3]
 [7 7]], shape=(2, 2), dtype=int32) 

연산자를 이용하여 텐서의 연산을 수행할 수도 있다.

  • 다양한 연산(ops)
c = tf.constant([[4.0, 5.0], [10.0, 1.0]])

print(tf.reduce_max(c)) # 최댓값 탐색
print(tf.argmax(c)) # 최댓값의 인덱스 
print(tf.nn.softmax(c)) # 소프트맥스 연산 
tf.Tensor(10.0, shape=(), dtype=float32)
tf.Tensor([1 0], shape=(2,), dtype=int64)
tf.Tensor(
[[2.6894143e-01 7.3105860e-01]
 [9.9987662e-01 1.2339458e-04]], shape=(2, 2), dtype=float32)

텐서를 이용한 모든 연산을 수행할 수 있다.

3. 텐서 형상 📌


텐서는 형상을 가지고 있는데 이 때 형상과 일부 용어를 살펴보겠습니다.

  • 형상 : 텐서의 각 차원의 길이(요소의 수), 즉 쉽게 모양이라고 이해할 수 있겠습니다.
  • 순위 : 텐서의 축의 수. (스칼라 : 0, 벡터 : 1, 행렬 : 2)
  • 축(차원) : 텐서의 특정 차원 (쉽게 이해 하려면 각 좌표 평면에서 축의 의미와 유사합니다.)
  • 크기 : 텐서의 총 항목 수, 곱 형상 벡터 ( 각 축을 곱하면 나온다.)

참고 : 2차원 텐서가 2차원 공간을 의미하는 것은 아닙니다.

tf.TensorShape 객체에 접근하기 쉽게 속성들이 있습니다.

rank_4_tensor = tf.zeros([3, 2, 4, 5])

3

print("Type of every element:", rank_4_tensor.dtype)
print("Number of dimensions:", rank_4_tensor.ndim)
print("Shape of tensor:", rank_4_tensor.shape)
print("Elements along axis 0 of tensor:", rank_4_tensor.shape[0])
print("Elements along the last axis of tensor:", rank_4_tensor.shape[-1])
print("Total number of elements (3*2*4*5): ", tf.size(rank_4_tensor).numpy())
Type of every element: <dtype: 'float32'>
Number of dimensions: 4
Shape of tensor: (3, 2, 4, 5)
Elements along axis 0 of tensor: 3
Elements along the last axis of tensor: 5
Total number of elements (3*2*4*5):  120

데이터타입, 차원수, 텐서의 모양, 처음 축의 수, 마지막 축의 수, 사이즈(모든 요소 수) 순서대로 확인 됩니다.

4

항상 축의 의미를 잘 파악하고 데이터를 다루어야 합니다. 보통 배치 축, 공간 차원, 특성 축 순으로 옵니다. 즉, 큰 개념에서 순차적으로 세세한 특징 축으로 옵니다. 즉, 특성 텐서는 메모리의 연속적인 영역입니다.

4. 인덱싱

단일 축 인덱싱


텐서에서 인덱싱은 Python의 List 또는 문자열 인덱싱과 같은 표준 파이썬 인덱싱 규칙과 numpy 인덱싱의 기본 규칙을 따릅니다.

  • 인덱스는 0부터 시작
  • 음수로 하면 거꾸로 끝에서부터 계산
  • 콜론(:)은 start:stop:step 에 사용
rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])
print(rank_1_tensor.numpy())
[ 0  1  1  2  3  5  8 13 21 34]

위의 텐서로 인덱싱해보겠습니다.

print("First:", rank_1_tensor[0].numpy())
print("Second:", rank_1_tensor[1].numpy())
print("Last:", rank_1_tensor[-1].numpy())
First: 0
Second: 1
Last: 34

스칼라를 이용하여 즉, 그 인덱스 값에 해당하는 값 만을 뽑아내므로 축이 사라졌습니다. 결과도 단일 값(스칼라)가 나왔습니다.

print("Everything:", rank_1_tensor[:].numpy())
print("Before 4:", rank_1_tensor[:4].numpy())
print("From 4 to the end:", rank_1_tensor[4:].numpy())
print("From 2, before 7:", rank_1_tensor[2:7].numpy())
print("Every other item:", rank_1_tensor[::2].numpy())
print("Reversed:", rank_1_tensor[::-1].numpy())
Everything: [ 0  1  1  2  3  5  8 13 21 34]
Before 4: [0 1 1 2]
From 4 to the end: [ 3  5  8 13 21 34]
From 2, before 7: [1 2 3 5 8]
Every other item: [ 0  1  3  8 21]
Reversed: [34 21 13  8  5  3  2  1  1  0]

콜론(:)을 이용하여 인덱싱을 하니 축이 유지 되는 것이 보입니다.

다축 인덱싱


더 높은 차원(축)의 텐서에서는 그에 해당하는 더 많은 인덱스 정보를 주어서 인덱싱을 합니다. 단일 축에서의 규칙이 각 축에 독립적으로 각각 적용됩니다.

print(rank_2_tensor.numpy())
[[1. 2.]
 [3. 4.]
 [5. 6.]]

위의 텐서를 이용해보겠습니다.

print(rank_2_tensor[1, 1].numpy())
4.0

마찬가지로 정수(단일값)를 이용한 인덱싱을 하였습니다. (좌표를 입력하는 것과 유사함) 그 결과 또한 스칼라 값이 나왔습니다.

print("Second row:", rank_2_tensor[1, :].numpy())
print("Second column:", rank_2_tensor[:, 1].numpy())
print("Last row:", rank_2_tensor[-1, :].numpy())
print("First item in last column:", rank_2_tensor[0, -1].numpy())
print("Skip the first row:")
print(rank_2_tensor[1:, :].numpy(), "\n")
Second row: [3. 4.]
Second column: [2. 4. 6.]
Last row: [5. 6.]
First item in last column: 2.0
Skip the first row:
[[3. 4.]
 [5. 6.]] 

정수와 슬라이스(콜론 이용)을 조합하여 인덱싱에 사용할 수 있습니다.

2차원 텐서의 세로축(column)과 가로축(row)을 확인해 보았습니다.

print(rank_3_tensor[:, :, 4])
tf.Tensor(
[[ 4  9]
 [14 19]
 [24 29]], shape=(3, 2), dtype=int32)

3차원 텐서에서도 해보았습니다. 그림에서 인덱싱한 부분을 시각적으로 확인할 수 있습니다.

5

5. 형상 조작 🔧


텐서의 형상을 바꾸는 것은 데이터 복제가 필요 없으므로 재구성이 빠르고 매우 유용합니다.

var_x = tf.Variable(tf.constant([[1], [2], [3]]))
print(var_x.shape)
(3, 1)

shape은 텐서의 각 축의 크기를 알려 줍니다. (0번 축 : 3, 1번 축 : 1)

print(var_x.shape.as_list())
[3, 1]

다음과 같이 텐서를 Python의 리스트로 바꿀 수 있습니다.

reshaped = tf.reshape(var_x, [1, 3])

텐서를 새로운 형상으로 바꾸어 보았습니다. 여기서 원하는 형상을 리스트를 입력해 주었다는 것을 주의해야합니다.

print(var_x.shape)
print(reshaped.shape)
(3, 1)
(1, 3)

원하는 형상으로 바꾸었습니다.

새로운 형상을 만들 때는 그 형상에 맞는 새로운 텐서를 만들고 기억하고 있는 원래의 텐서에서 제일 오른쪽 인덱스를 하나씩 올려가며 새로운 형상의 텐서를 채워가는 방법으로 만들어집니다.

print(rank_3_tensor)
tf.Tensor(
[[[ 0  1  2  3  4]
  [ 5  6  7  8  9]]

 [[10 11 12 13 14]
  [15 16 17 18 19]]

 [[20 21 22 23 24]
  [25 26 27 28 29]]], shape=(3, 2, 5), dtype=int32)

위의 텐서를 사용해보겠습니다.

print(tf.reshape(rank_3_tensor, [-1])) #여기서 -1은 어떻게든 맞추라는 것입니다.
tf.Tensor(
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 24 25 26 27 28 29], shape=(30,), dtype=int32)

텐서를 평평하게 만들어 보았습니다. 어떤 식으로 텐서를 변환하는지 알 수 있습니다. 앞의 축에서부터 각 축의 낮은 인덱스 순으로 쭉 붙였습니다.

tf.reshape은 인접한 축을 붙이거나 분할할 때 사용하는 것이 합리적입니다.(또는 1을 추가하거나 빼거나) 앞의 두 축을 곱하거나 뒤의 두축을 곱하거나 이러한 방법이 가장 합리적입니다.

print(tf.reshape(rank_3_tensor, [3*2, 5]), "\n")
print(tf.reshape(rank_3_tensor, [3, -1]))
tf.Tensor(
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]
 [25 26 27 28 29]], shape=(6, 5), dtype=int32) 

tf.Tensor(
[[ 0  1  2  3  4  5  6  7  8  9]
 [10 11 12 13 14 15 16 17 18 19]
 [20 21 22 23 24 25 26 27 28 29]], shape=(3, 10), dtype=int32)

이러한 방법으로 할 수 있습니다.

6

형상 변화는 같은 데이터 요소를 사용하는 새로운 형상의 텐서를 의미하지만, 축의 수를 고려하지 않는다면 무쓸모합니다.

축 교환을 하려면 tf.transpose를 이용해야 합니다.

# 나쁜 예제

# 축을 다시 지정해 줄 수 없습니다. ( 의도하지 않은 텐서가 나올 것임 )
print(tf.reshape(rank_3_tensor, [2, 3, 5]), "\n") 

# 한 덩어리입니다.
print(tf.reshape(rank_3_tensor, [5, 6]), "\n")

# 전혀 작동하지 않습니다.
try:
  tf.reshape(rank_3_tensor, [7, -1])
except Exception as e:
  print(f"{type(e).__name__}: {e}")
tf.Tensor(
[[[ 0  1  2  3  4]
  [ 5  6  7  8  9]
  [10 11 12 13 14]]

 [[15 16 17 18 19]
  [20 21 22 23 24]
  [25 26 27 28 29]]], shape=(2, 3, 5), dtype=int32) 

tf.Tensor(
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]
 [24 25 26 27 28 29]], shape=(5, 6), dtype=int32) 

InvalidArgumentError: Input to reshape is a tensor with 30 values, but the requested shape requires a multiple of 7 [Op:Reshape]

7

none 형상으로도 작동합니다. (축이든 전체이든)

6. DTypes에 대한 추가 정보 📝


텐서의 데이터정보를 확인하려면 Tensor.dtype 속성을 사용합니다.

텐서를 만들 때 데이터 유형을 선택해 줄 수 있습니다. 이 때 float64나 32와 같이 크기를 정해 줄 때에는 tf.float64 혹은 tf.float32를 사용해야 함을 주의 해야합니다.

따로 설정해 주지 않는다면 Python 정수를 tf.int32, Python 부동소수점을 tf.float32로 설정합니다. 또는 Numpy에서 설정한 것을 그대로 이어 받습니다.

the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64)
the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16)

the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)
print(the_u8_tensor)
print(the_f64_tensor)
print(the_f16_tensor)
tf.Tensor([2 3 4], shape=(3,), dtype=uint8)
tf.Tensor([2.2 3.3 4.4], shape=(3,), dtype=float64)
tf.Tensor([2.2 3.3 4.4], shape=(3,), dtype=float16)

각각이 데이터 유형을 설정한 대로 나오는 것을 확인할 수 있습니다.

7. 브로드캐스팅 💨


특정 조건에서 결합된 연산을 수행할 때 작은 텐서를 더 큰 텐서로 자동 확장하는 기능

x = tf.constant([1, 2, 3])

y = tf.constant(2)
z = tf.constant([2, 2, 2])

print(tf.multiply(x, 2)) # tf.multiply함수 이용
print(x * y) # 연산자 사용 스칼라와 텐서 곱
print(x * z) # 같은 모양의 텐서 곱
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
tf.Tensor([2 4 6], shape=(3,), dtype=int32)

결과가 모두 같음을 확인할 수 있습니다.

스칼라와 텐서를 곱하는 경우입니다. 스칼라가 자동으로 다른 텐서에 맞춰 브로드캐스트 되었습니다.

x = tf.reshape(x,[3,1])
y = tf.range(1, 5)
print(x, "\n")
print(y, "\n")
print(tf.multiply(x, y))
tf.Tensor(
[[1]
 [2]
 [3]], shape=(3, 1), dtype=int32) 

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

tf.Tensor(
[[ 1  2  3  4]
 [ 2  4  6  8]
 [ 3  6  9 12]], shape=(3, 4), dtype=int32)

크기가 1인 축은 다른 인수와 일치 시켜서 확장 시킬 수 있습니다. y의 축은 1개 입니다. 따라서 곱해주는 x의 모양에 맞추어 3x4 행렬이 만들어졌습니다.

8

x_stretch = tf.constant([[1, 1, 1, 1],
                         [2, 2, 2, 2],
                         [3, 3, 3, 3]])

y_stretch = tf.constant([[1, 2, 3, 4],
                         [1, 2, 3, 4],
                         [1, 2, 3, 4]])

print(x_stretch * y_stretch)  # Again, operator overloading
tf.Tensor(
[[ 1  2  3  4]
 [ 2  4  6  8]
 [ 3  6  9 12]], shape=(3, 4), dtype=int32)

브로드캐스팅이 없는 연산 입니다. 위의 방법과 비교해 볼 수 있습니다.

브로드캐스트는 확장된 텐서를 구체화해서 메모리에 가지고 있는 것이 아니라서 효율적입니다. 또한 메모리 절약을 위해 특별한 연산을 수행하지 않습니다.

print(tf.broadcast_to(tf.constant([1, 2, 3]), [3, 3]))
tf.Tensor(
[[1 2 3]
 [1 2 3]
 [1 2 3]], shape=(3, 3), dtype=int32)

tf.broadcast_to 를 이용해서 브로드캐스트 된 텐서의 모습을 확인해 볼 수 있습니다.

8. tf.convert_to_tensor 🔨


대부분의 ops는 텐서를 인수로 사용합니다. 위에서 봤듯이 텐서 형상의 Python 객체가 수용될 수 있음을 확인 하였습니다.

ops 대부분은 텐서가 아닌 인수에 대해 convert_to_tensor를 호출하여 텐서로 변환하여 수용할 수 있는 기능이 있습니다.

9. 다양한 텐서 🙌


tf.Tensor 클래스에서 만드는 텐서는 직사각형 즉, 각 축에 따라 모든 요소의 크기가 같아야 합니다. 그러나 필요에 따라 모양이 다양한 텐서를 사용할 수 있습니다.

비정형 텐서 (RaggedTensor)


축에 따라 다양한 요소를 가진 텐서

비정형 데이터는 tf.ragged.RaggedTensor 를 이용해서만 텐서로 다룰 수 있습니다.

9

ragged_list = [
    [0, 1, 2, 3],
    [4, 5],
    [6, 7, 8],
    [9]]

이러한 비정형 데이터를 텐서로 만들기 위해 앞에서 했듯이 정규텐서로 시도해보겠습니다.

try:
  tensor = tf.constant(ragged_list)
except Exception as e:
  print(f"{type(e).__name__}: {e}")
ValueError: Can't convert non-rectangular Python sequence to Tensor.

예외가 발생한다면 그 문구가 출력되도록 하여 어떤 오류가 발생한지 확인 해보았습니다.

사각형모양이 아닌(non-rentangular) 이유로 텐서로 바꿀수 없다고 합니다.

이번에는 tf.ragged.constant를 이용하여 tf.RaggedTensor를 만들어 보겠습니다.

ragged_tensor = tf.ragged.constant(ragged_list)
print(ragged_tensor)
<tf.RaggedTensor [[0, 1, 2, 3], [4, 5], [6, 7, 8], [9]]>

축에 따라 요소의 수가 다양한 텐서가 확인됩니다.

print(ragged_tensor.shape)
(4, None)

두 번째 축의 요소의 갯수가 각각 다르기에 None이라는 값이 보입니다.

문자열 텐서(String Tensor)


문자열을 항목으로 가진 텐서

데이터 타입이 tf.string (가변 길이의 바이트 배열 가능 ) 입니다. 단, 문자열은 하나의 요소(원자)로 취급하므로 문자열의 길이가 축에 해당하지 않습니다. 그냥 하나의 요소로 보고 있습니다. 따라서 파이썬에서와 같이 인덱싱할 수 없습니다.

문자열을 조작하기 위해 tf.strings함수를 이용할 수 있습니다

  • 스칼라 문자열 텐서
scalar_string_tensor = tf.constant("Lionel Messi")
print(scalar_string_tensor)
tf.Tensor(b'Lionel Messi', shape=(), dtype=string)

축이 없다는 것이 확인 됩니다.

  • 벡터 문자열 텐서

10

tensor_of_strings = tf.constant(["Gray wolf",
                                 "Quick brown fox",
                                 "Lazy dog"])
print(tensor_of_strings)
tf.Tensor([b'Gray wolf' b'Quick brown fox' b'Lazy dog'], shape=(3,), dtype=string)

서로 다른 길이의 문자열도 가능하다는 것이 확인됩니다. 그리고 shape의 3을 확인하면 문자열의 길이가 축에 포함되지 않는다는 것이 확인됩니다. 즉 각각의 문자열을 하나의 항목으로 인식합니다.

출력에 보면 각 항목 앞에 b라는 것이 접두사로 보입니다. 이것은 문자열 데이터타입이 유니코드가 아닌 바이트 문자열임을 말합니다.

참고 : 유니코드는 UTF-8로 인코딩하여 처리합니다.

tf.constant("🥳👍")
<tf.Tensor: shape=(), dtype=string, numpy=b'\xf0\x9f\xa5\xb3\xf0\x9f\x91\x8d'>

tf.strings


함수를 이용한 문자열 조작

  • tf.strings.split
print(tf.strings.split(scalar_string_tensor, sep=" "))
tf.Tensor([b'Lionel' b'Messi'], shape=(2,), dtype=string)

공백을 기준으로 문자열을 쪼개는 함수입니다.

두 개의 요소로 바뀌면서 축이 1개 생겼습니다. (shape 참고)

print(tf.strings.split(tensor_of_strings))
<tf.RaggedTensor [[b'Gray', b'wolf'], [b'Quick', b'brown', b'fox'], [b'Lazy', b'dog']]>

이번에는 쪼개니 각각의 문자열이 다른 숫자로 나누어져서 비정형텐서(RaggedTensor)로 바뀐것이 확인됩니다.

11

  • tf.strings.to_number
text = tf.constant("1 10 100")
print(tf.strings.to_number(tf.strings.split(text, " ")))
tf.Tensor([  1.  10. 100.], shape=(3,), dtype=float32)

문자열의 숫자들을 쪼갠 뒤 각각 float형으로 하나의 요소로 만들어 주었습니다. 요소가 3개가 된것이 확인됩니다.

  • tf.cast

문자열을 바로 숫자로 바꿀 수는 없지만 바이트로 바꾼 후 숫자로 바꿀 수는 있습니다.

byte_strings = tf.strings.bytes_split(tf.constant("Duck"))
byte_ints = tf.io.decode_raw(tf.constant("Duck"), tf.uint8)
print("Byte strings:", byte_strings)
print("Bytes:", byte_ints)
Byte strings: tf.Tensor([b'D' b'u' b'c' b'k'], shape=(4,), dtype=string)
Bytes: tf.Tensor([ 68 117  99 107], shape=(4,), dtype=uint8)

각각의 스펠링을 쪼개서 바이트로 바꾼 후 마지막에 숫자로 바꾸었습니다. 항목이 4개가 되었습니다.

unicode_bytes = tf.constant("アヒル 🦆")
unicode_char_bytes = tf.strings.unicode_split(unicode_bytes, "UTF-8")
unicode_values = tf.strings.unicode_decode(unicode_bytes, "UTF-8")

print("\nUnicode bytes:", unicode_bytes)
print("\nUnicode chars:", unicode_char_bytes)
print("\nUnicode values:", unicode_values)
Unicode bytes: tf.Tensor(b'\xe3\x82\xa2\xe3\x83\x92\xe3\x83\xab \xf0\x9f\xa6\x86', shape=(), dtype=string)

Unicode chars: tf.Tensor([b'\xe3\x82\xa2' b'\xe3\x83\x92' b'\xe3\x83\xab' b' ' b'\xf0\x9f\xa6\x86'], shape=(5,), dtype=string)

Unicode values: tf.Tensor([ 12450  12498  12523     32 129414], shape=(5,), dtype=int32)

유니코드로 쪼갠 후에도 가능합니다.

TensorFlow 에서 바이트 데이터를 다룰 때 tf.string 데이터 타입을 사용합니다. 텐서플로우에서 데이터를 다루기 위해 사용하는 모듈에서는 데이터를 바이트로 혹은 바이트의 데이터를 변환하는 함수들을 제공합니다.

희소 텐서(SparseTensor)


실제 데이터에 비해 빈 공간이 많은 텐서

12

메모리의 효율적인 사용을 위해 실제 데이터에 비해 빈 공간이 많을 때 사용하는 텐서 입니다.

sparse_tensor = tf.sparse.SparseTensor(indices=[[0, 0], [1, 2]],
                                       values=[1, 2],
                                       dense_shape=[3, 4])
print(sparse_tensor)


SparseTensor(indices=tf.Tensor(
[[0 0]
 [1 2]], shape=(2, 2), dtype=int64), values=tf.Tensor([1 2], shape=(2,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))

데이터를 저장하는 방식이 다릅니다. indices는 실제 데이터가 존재하는 좌표를 말합니다. 그리고 values는 각각의 해당하는 값을 말합니다. 즉 존재하는 데이터의 좌표와 값을 기억함으로써 모든 텐서의 값을 기억할 필요가 없습니다.

print(tf.sparse.to_dense(sparse_tensor))
tf.Tensor(
[[1 0 0 0]
 [0 0 2 0]
 [0 0 0 0]], shape=(3, 4), dtype=int32)

tf.sparse.to_dense 함수를 통해 모든 텐서도 확인할 수 있습니다.

Updated: