대학원 일기

텐서 (Tensor) 본문

AI/인공지능 기초

텐서 (Tensor)

대학원생(노예) 2023. 12. 6. 10:34

2-2 텐서(Tensor)

- 데이터를 담기 위한 컨테이너(container)

- 다차원 배열 또는 리스트 형태와 유사

- 일반적으로 수치형 데이터를 저장하고, 동적 크기를 가짐

  • Rank : 축의 개수
  • shape : 형상(각 축에 따른 차원 개수)
  • type : 데이터 타입
 

0차원 텐서는 Scalar라고 불리며 축과 차원 개수가 존재하지 않는다. 1차원 텐서는 Vector라고 불리며 축이 1 차원의 개수가 3이다. 2차원 텐서는 Matrix라고 불리며 축이 행과 열에 2개 있고 9개의 데이터(shape(3,3)를 가지고 있다. 나머지는 똑같이 이런식으로 보면 된다.

 

1D Tensor(Vector)

  • 1차원 텐서는 값들을 저장한 리스트와 유사한 텐서
  • 벡터(vector)라고도 부르며, 하나의 축이 존재

2D Tensor(Matrix)

  • 2차원 텐서는 행렬과 같은 모양으로 두 개의 축이 존재
  • 일반적인 수치, 통계 데이터셋이 여기에 해당
  • 주로 샘플(samples)과 특성(features)을 가진 구조로 사용

3D Tensor

  • 3차원 텐서는 큐브(cube)와 같은 모양으로 세개의 축이 존재
  • 일반적으로 데이터가 연속된 시퀀스 데이터나 시간 축이 포함된 시계열 데이터에 해당
  • 주로 샘플(samples), 타임스텝(timesteps), 특성(features)을 가진 구조로 사용
  • 3차원 텐서를 이용하는 데 데이터로는 주식 가격 데이터셋, 시간에 따른 질병 발병 데이터 등이 존재

 

텐서 생성을 위해 TensorFlow를 임포트

import tensorflow as tf

0D Tensor(Scalar)

0차원 텐서는 하나의 숫자를 담고 있는 Tensor로, Scalar라고도 부르며, 축과 형상이 없다. tf.constant()를 사용하면 상수(constant) 텐서를 만들 수 있고, 만든 텐서에 tf.rank() 를 적용하면 축의 개수를 알 수 있다.

t0 = tf.constant(1) 
print(t0)
print(tf.rank(t0)) # 축의 개수를 반환합니다.

1D Tensor(Vector)

1차원 텐서는 값들을 저장한 리스트와 유사한 텐서이며 Vector라고도 부르며 하나의 축이 존재한다.

t1 = tf.constant([1, 2, 3]) 
print(t1)
print(tf.rank(t1))

2D Tensor(Matrix)

2차원 텐서는 행렬과 같은 모양으로 두개의 축이 존재한다. 일반적인 수치, 통계 데이터셋이 여기에 해당된다. 주로 샘플(samples)과 특성(features)을 가진 구조로 사용된다.

 

 

 

t2 = tf.constant([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])
print(t2)
print(tf.rank(t2))

 

3D Tensor

3차원 텐서는 큐브(cube)와 같은 모양으로 세개의 축이 존재하며, 일반적으로 데이터가 연속된 시퀀스 데이터나 시간 축이 포함된 시계열 데이터에 해당한다. 주로 샘플(samples), 타임스텝(timesteps), 특성(features)을 가진 구조로 사용된다. 3차원 텐서를 이용하는 데이터로는 주식 가격 데이터셋, 시간에 따른 질병 발병 데이터 등이 존재한다.

 

 

 

t3 = tf.constant([[[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]]])
print(t3)
print(tf.rank(t3))

4D Tensor

4차원 텐서는 4개의 축이 존재하며, 컬러 이미지 데이터가 대표적인 사례 (흑백 이미지 데이터는 3D Tensor로 가능)이다. 주로 샘플(samples), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용된다.

 

 

 

5D Tensor

5차원 텐서는 5개의 축이 존재하며, 비디오 데이터가 대표적인 사례이다. 주로 샘플(samples), 프레임(frames), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용된다.

 

2-3. 텐서 타입 및 변환

텐서의 타입

텐서의 기본 데이터 타입(dtype)은 정수형(int32), 실수형(float32), 문자열(string) 등이 있고, 그 외에도 여러 데이터 타입 등이 존재합니다.

 

 

텐서의 생성

# 상수 값 2인 텐서를 생성해 봅시다. 기본적으로 정수형 int32 타입을 가지는 것을 알 수 있습니다.
i = tf.constant(2)

# 상수 값 2.0으로 지정하면, 실수형 float32인 텐서를 생성합니다.
f = tf.constant(2.)

# 문자열을 값으로 가지는 텐서를 생성할 수도 있으며, 타입은 string이 됩니다.
s = tf.constant('Suan')

# 지정한 상수 값의 타입을 보고 자동으로 텐서 타입이 정해지는 것 외에도 필요한 텐서의 타입을 지정하여 생성할 수 있습니다. 
# 여기서는 tf.float16으로 16비트 실수형으로 타입을 지정하였습니다.
f16 = tf.constant(2., dtype=tf.float16)

# 그 밖에도 8비트의 정수형인 tf.int8을 지정하여 텐서를 생성할 수 있습니다.
i8 = tf.constant(2, dtype=tf.int8)

텐서 변환

# 텐서의 타입을 변환하고자 할 때는 tf.cast를 사용합니다. 
# 여기서는 16비트 실수형 tf.float16을 32비트 실수형 tf.float32로 변환하였습니다.
f32 = tf.cast(f16, tf.float32)

# 다음 예제에서는 8비트 정수형 tf.int8을 32비트 정수형인 tf.int32로 변환하고자 합니다.
# 직접 코드를 작성해 보세요.
i32 = tf.cast(i8, tf.int32)

# 텐서의 형상을 변환하는 것은 tf.reshape 함수를 통해 가능합니다.
# 이 함수는 텐서의 원소는 그대로 유지하면서 텐서의 구조를 바꿉니다.
x = tf.constant([[1], [2], [3]])
print(x) # [[1] [2] [3]]
print(x.shape) # (3, 1)

y = tf.reshape(x, [1, 3]) 
print(y) # [[1  2  3]]
print(y.shape) # (1,3)

텐서 전치

# 텐서를 전치하여 형상을 바꾸는 역할로 tf.transpose 함수를 사용할 수 있습니다.
print(y) # [[1  2  3]]
print(tf.transpose(y)) # [[1] [2] [3]]
print(y.shape) # (1, 3) <- 원래 것을 변경시키지는 않음을 확인

차원 압축

# 텐서에서 크기가 1인 차원을 제거하는 tf.squeeze 함수를 이용해 형상을 변경합니다.
print(x) # [[1] [2] [3]]

print(tf.squeeze(x)) # [1  2  3]

차원 추가

# 텐서의 차원을 추가하는 `tf.expand_dims` 함수를 이용해 형상을 변경합니다. 
# 여기서 `axis`는 차원을 확장할 텐서의 축을 지정해주는 역할을 합니다.
print(y) # [[1 2 3]]
print(tf.expand_dims(y, axis=0)) # [[[1 2 3]]]
print(tf.expand_dims(y, axis=1)) # [[[1 2 3]]]
print(tf.expand_dims(y, axis=2)) # [[[1] [2] [3]]]

텐서 분리

# tf.split 함수를 이용하여 텐서의 지정한 개수를 기준으로 여러 개의 텐서로 구분합니다. 
# 예제에서는 텐서 x를 3개로 분리한 것을 알 수 있습니다.
print(x)
print(tf.split(x, 3)) # [[1]] / [[2]] / [[3]]

텐서 연결

# tf.concat 함수는 지정한 축 axis를 기준으로 텐서들을 이어붙입니다.
print(x) # [[1] [2] [3]]
print(tf.concat([x, x], axis=0)) # [[1] [2] [3] [1] [2] [3]]
print(tf.concat([x, x], axis=1)) # [[1 1] [2 2] [3 3]]

텐서 변환 정리

 

텐서 역전

x = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=tf.int32)

print(tf.reverse(x, axis=[0])) # [[7 8 9] [4 5 6] [1 2 3]]
print(tf.reverse(x, axis=[0,1])) # [[9 8 7] [6 5 4] [3 2 1]]

 

2-4. 텐서 연산

0차원 텐서의 연산

더하기 연산자인 +와 빼기 연산자인 -를 이용해서 텐서간의 계산이 가능하고, addsubtract 함수를 이용해서도 계산이 가능하다.

print(tf.constant(2) + tf.constant(2))
print(tf.constant(2) - tf.constant(2))
print(tf.add(tf.constant(2), tf.constant(2)))
print(tf.subtract(tf.constant(2), tf.constant(2)))

곱하기와 나누기 연산도 */ 연산자를 이용하는 방법과 multiplydivide 함수를 이용하는 방법이 있다.

print(tf.constant(2) * tf.constant(2))
print(tf.constant(2) / tf.constant(2))
print(tf.multiply(tf.constant(2), tf.constant(2)))
print(tf.divide(tf.constant(2), tf.constant(2)))

텐서 연산에서 주의할 점은 서로 다른 타입을 가지는 텐서는 연산이 되지 않고, 에러가 발생한다는 점이다.

print(tf.constant(2) + tf.constant(2.2))

다른 타입을 가지는 텐서는 연산을 위해서 타입을 변환해 주어야한다. 2-3 스텝에서 언급했던 tf.cast를 사용하여 텐서의 타입을 서로 맞춰준 후에 연산을 할 수 있다.

print(tf.cast(tf.constant(2), tf.float32) + tf.constant(2.2))

 

1차원 이상의 텐서 연산

0차원의 상수값만 존재하는 텐서 계산 외에도 1차원 이상의 텐서에 대해서도 연산이 가능하다. 다만 텐서의 모양이 직사각형이거나 연산이 가능하도록 형상을 맞춰주어야 한다.

1차원 텐서의 연산

# Q. 1차원 텐서 2개를 생성해 보세요. 
tensor1 = tf.constant([1, 2, 3], dtype=tf.float32)
tensor2 = tf.constant([4, 5, 6], dtype=tf.float32)

print(tensor1)
print(tensor2)

생성된 2개의 텐서에 사칙연산을 해본다.

# Q. 사칙연산(더하기, 빼기, 곱하기, 나누기)을 해보세요. 
# 1차원 텐서 생성
tensor1 = tf.constant([1, 2, 3], dtype=tf.float32)
tensor2 = tf.constant([4, 5, 6], dtype=tf.float32)

# 더하기
add_result = tf.add(tensor1, tensor2)

# 빼기
subtract_result = tf.subtract(tensor1, tensor2)

# 곱하기
multiply_result = tf.multiply(tensor1, tensor2)

# 나누기
divide_result = tf.divide(tensor1, tensor2)

print("덧셈 결과:")
print(add_result)

print("\n뺄셈 결과:")
print(subtract_result)

print("\n곱셈 결과:")
print(multiply_result)

print("\n나눗셈 결과:")
print(divide_result)

2차원 텐서의 연산

2차원 텐서를 생성한 후 연산을 해본다.

# Q. 크기 (2,2)인 2차원 텐서 2개를 생성해 보세요. 
a = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
b = tf.constant([[5, 6], [7, 8]], dtype=tf.float32)

print("첫 번째 2차원 텐서:")
print(tensor1)
print("\n두 번째 2차원 텐서:")
print(tensor2)

텐서를 계산하기 위한 여러 연산자들을 제공하고 있으며, +, -, *, / 연산자는 요소별(element-wise) 연산을 수행하고, @ 연산자의 경우에는 행렬 곱 연산을 수행한다.

print(a + b) # element-wise addition
print(a - b) # element-wise subtraction
print(a * b) # element-wise multiplication
print(a @ b) # matrix multiplication
print(a / b) # element-wise division

텐서 연산은 연산자를 통해서도 가능하지만, 제공되는 함수를 통해서도 연산이 가능하다.

print(tf.add(a, b))
print(tf.subtract(a, b))
print(tf.multiply(a, b))
print(tf.matmul(a, b))
print(tf.divide(a, b))

그 밖에도 유용한 여러 함수들이 존재한다.

  • reduce_max() : 텐서 값 중에서 최대값을 계산한다.
  • argmax() : 최대값의 위치를 반환한다. 예제에서는 [4.0, 5.0, 6.0] 보다 [10.0, 9.0, 8.0]이 다 크기 때문에 [0 0 0]이 아니라 [1 1 1]의 결과를 보여준다.
  • nn.softmax() : 텐서의 값을 0과 1 사이의 값으로 보여준다. 예제에서는 [4.0, 5.0, 6.0] 값이 [0.09003057 0.24472848 0.66524094]으로 변환되었고, [10.0, 9.0, 8.0]이 [0.66524094 0.24472848 0.09003057]로 변환되었다.
c = tf.constant([[4.0, 5.0, 6.0], 
                 [10.0, 9.0, 8.0]])

print(tf.reduce_max(c))
print(tf.argmax(c))
print(tf.nn.softmax(c))

텐서의 연산 정리

 

 

2-5 마무리하며

아래 텐서를 각각 (2,2,2)의 형태를 가진 3차원 텐서로 만들고 행렬곱 연산을 해보세요.

a = tf.constant([1, 2, 3, 4, 5, 6, 7, 8], dtype=tf.float32)
b = tf.constant([[1., 2., 3., 4., 5., 6., 7., 8.]])

# a를 (2, 2, 2)의 형태로 변환
a_reshaped = tf.reshape(a, (2, 2, 2))

# b를 (2, 2, 2)의 형태로 변환
b_reshaped = tf.reshape(b, (2, 2, 2))

# 행렬곱 연산
result = tf.matmul(a_reshaped, b_reshaped)

print("변환된 a:")
print(a_reshaped)
print("\n변환된 b:")
print(b_reshaped)
print("\n행렬곱 연산 결과:")
print(result)

'AI > 인공지능 기초' 카테고리의 다른 글

딥러닝 모델 학습  (0) 2023.12.06
딥러닝 구조와 모델  (0) 2023.12.06
인공신경망과 딥러닝  (0) 2023.12.04
Deep Learning Layer: Convolution Layer  (0) 2023.11.20
Deep Learning Layer: Linear Layer  (1) 2023.11.20
Comments