: 데이터 표현과 다양한 수학식을 계산하기 위한 기본 구조로 텐서를 사용해서 표현
: 데이터를 담기위한 컨테이너(container)
다차원 배열 또는 리스트 형태와 유사
일반적으로 수치형 데이터를 저장하고, 동적 크기를 가짐
텐서는 형상이 존재하며 데이터의 표현에 따라서 사용
Rank: 축(차원)의 개수
Shape: 형상(각 축의 요소의 개수)
Type: 데이터 타입
0차원 텐서는 하나의 숫자를 담고 있는 텐서(tensor)입니다.
스칼라(scalar)라고도 부르며, 축과 형상이 없습니다.
tf.constant()를 사용하면 상수(constant) 텐서를 만들 수 있고,
만든 텐서에 tf.rank()를 적용하면 축의 개수를 알 수 있습니다.
t0 = tf.constant(1)
print(t0)
print(tf.rank(t0)) # 축의 개수를 반환합니다.
tf.Tensor(1, shape=(), dtype=int32)
tf.Tensor(0, shape=(), dtype=int32)
1차원 텐서는 값들을 저장한 리스트와 유사한 텐서입니다.
벡터(vector)라고도 부르며, 하나의 축이 존재합니다.
t1 = tf.constant([1, 2, 3])
print(t1)
print(tf.rank(t1))
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
tf.Tensor(1, shape=(), dtype=int32)
2차원 텐서는 행렬과 같은 모양으로 두개의 축이 존재합니다.
일반적인 수치, 통계 데이터셋이 여기에 해당됩니다.
주로 샘플(samples)과 특성(features)을 가진 구조로 사용됩니다.
# Q. 위 이미지와 같은 크기 (3, 3)의 2차원 텐서를 만들고, 차원을 반환해 주세요.
t2 = tf.constant([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
print(t2)
print(tf.rank(t2))
tf.Tensor(
[[1 2 3][4 5 6]
[7 8 9]], shape=(3, 3), dtype=int32)
tf.Tensor(2, shape=(), dtype=int32)
3차원 텐서는 큐브(cube)와 같은 모양으로 세개의 축이 존재하며,
일반적으로 데이터가 연속된 시퀀스 데이터나 시간 축이 포함된 시계열 데이터에 해당합니다.
주로 샘플(samples), 타임스텝(timesteps), 특성(features)을 가진 구조로 사용됩니다.
3차원 텐서를 이용하는 데이터로는 주식 가격 데이터셋, 시간에 따른 질병 발병 데이터 등이 존재합니다.
- 3D에서 흑백이미지 데이터 구현 가능
- 4D에서 컬러채널(RGB) 정보가 필요
- 5D에서 사진보다 영상이 '프레임'으로 구분이 된다.
4차원 텐서는 4개의 축이 존재하며, 컬러 이미지 데이터가 대표적인 사례 (흑백 이미지 데이터는 3D Tensor로 가능)입니다. 주로 샘플(samples), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용됩니다.
5차원 텐서는 5개의 축이 존재하며, 비디오 데이터가 대표적인 사례입니다. 주로 샘플(samples), 프레임(frames), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용됩니다.
텐서의 기본 데이터 타입(dtype)은 정수형(int32), 실수형(float32), 문자열(string) 등이 있고, 그 외에도 여러 데이터 타입 등이 존재합니다.
# tf.float16으로 16비트 실수형으로 타입을 지정
f16 = tf.constant(2., dtype=tf.float16)
print(f16)
tf.Tensor(2.0, shape=(), dtype=float16)
텐서의 타입을 변환하고자 할 때는 tf.cast를 사용합니다.
여기서는 16비트 실수형 tf.float16을 32비트 실수형 tf.float32로 변환하였습니다.
f32 = tf.cast(f16, tf.float32)
print(f32)
tf.Tensor(2.0, shape=(), dtype=float32)
텐서의 형상을 변환하는 것은 tf.reshape 함수를 통해 가능합니다.
이 함수는 텐서의 원소는 그대로 유지하면서 텐서의 구조를 바꿉니다.
x = tf.constant([[1], [2], [3]])
print(x)
print(x.shape)
y = tf.reshape(x, [1, 3])
print(y)
print(y.shape)
tf.Tensor(
[[1][2]
[3]], shape=(3, 1), dtype=int32)
(3, 1)
tf.Tensor([[1 2 3]], shape=(1, 3), dtype=int32)
(1, 3)
텐서를 전치하여 형상을 바꾸는 역할로 tf.transpose 함수를 사용할 수 있습니다.
print(y)
print(tf.transpose(y))
print(y.shape)
tf.Tensor([[1 2 3]], shape=(1, 3), dtype=int32)
tf.Tensor(
[[1][2]
[3]], shape=(3, 1), dtype=int32)
(1, 3)
텐서에서 크기가 1인 차원을 제거하는 tf.squeeze 함수를 이용해 형상을 변경합니다.
print(x)
print(tf.squeeze(x))
tf.Tensor(
[[1][2]
[3]], shape=(3, 1), dtype=int32)
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
텐서의 차원을 추가하는 tf.expand_dims 함수를 이용해 형상을 변경합니다. 여기서 axis는 차원을 확장할 텐서의 축을 지정해주는 역할을 합니다.
print(y)
print(tf.expand_dims(y, axis=0))
print(tf.expand_dims(y, axis=1))
print(tf.expand_dims(y, axis=2))
tf.Tensor([[1 2 3]], shape=(1, 3), dtype=int32)
tf.Tensor([[[1 2 3]]], shape=(1, 1, 3), dtype=int32)
tf.Tensor([[[1 2 3]]], shape=(1, 1, 3), dtype=int32)
tf.Tensor(
[[[1][2]
[3]]], shape=(1, 3, 1), dtype=int32)
tf.split 함수를 이용하여 텐서의 지정한 차원을 기준으로 여러 개의 텐서로 구분합니다. 예제에서는 텐서 x를 3개로 분리한 것을 알 수 있습니다.
print(x)
print(tf.split(x, 3))
tf.Tensor(
[[1][2]
[3]], shape=(3, 1), dtype=int32)
[<tf.Tensor: shape=(1, 1), dtype=int32, numpy=array([[1]], dtype=int32)>, <tf.Tensor: shape=(1, 1), dtype=int32, numpy=array([[2]], dtype=int32)>, <tf.Tensor: shape=(1, 1), dtype=int32, numpy=array([[3]], dtype=int32)>]
tf.concat 함수는 지정한 축 axis를 기준으로 텐서들을 이어붙입니다.
print(x)
print(tf.concat([x, x], axis=0))
print(tf.concat([x, x], axis=1))
tf.Tensor(
[[1][2]
[3]], shape=(3, 1), dtype=int32)
tf.Tensor(
[[1][2]
[3][1]
[2][3]], shape=(6, 1), dtype=int32)
tf.Tensor(
[[1 1][2 2]
[3 3]], shape=(3, 2), dtype=int32)
텐서 연산에서 주의할 점은 서로 다른 타입을 가지는 텐서는 연산이 되지 않고,
에러가 발생한다는 점입니다.
0차원의 상수값만 존재하는 텐서 계산 외에도 1차원 이상의 텐서에 대해서도 연산이 가능합니다. 다만 텐서의 모양이 직사각형이거나 연산이 가능하도록 형상을 맞춰주어야 합니다.
print(a + b) # element-wise addition print(tf.add(a, b))
print(a - b) # element-wise subtraction print(tf.subtract(a, b))
print(a * b) # element-wise multiplication print(tf.multiply(a, b))
print(a @ b) # matrix multiplication print(tf.matmul(a, b))
print(a / b) # element-wise division print(tf.divide(a, b))
reduce_max()
: 텐서 값 중에서 최대값을 계산합니다.
argmax()
: 최대값의 위치를 반환합니다.
nn.softmax()
: 텐서의 값을 0과 1 사이의 값으로 보여줍니다.