TensorFlow는 Google이 개발한 오픈소스 머신러닝 라이브러리로, 딥러닝 모델을 효율적으로 구축하고 학습시키는 데 최적화되어 있습니다.
본 포스팅에서는 TensorFlow의 핵심 개념과 함께 간단한 예제를 통해 기본적인 사용법을 알아보겠습니다.
TensorFlow 시작하기
TensorFlow를 사용하기 위해 먼저 라이브러리를 설치하고 버전을 확인해 봅니다.
import tensorflow as tf
print(tf.__version__) # 2.18.0
저는 2.18.0 버전을 사용하고 있습니다.
텐서(Tensor)의 객체
- 타입(Type) : string, float32, float16, int32, int8 등
- 딥러닝의 경우 숫자의 경향만 표현하면 되기 때문에 계산량을 줄이고 빠르게 계산하기 위해 일반적으로 float32(더 정교하게 숫자 표현)보다 float16(덜 정교하게 숫자 표현)을 사용
- 형상(Shape) : 0, 1, 2차원 등의 데이터 차원
- 축(Rank) : 차원의 개수
텐서의 차원
텐서 객체는 constant()라는 함수로 만들 수 있고, 차원의 개수는 rank()로 확인할 수 있습니다.
a = tf.constant(2)
print(tf.rank(a)) # 0차원
print(a) # 2
b = tf.constant([2,3])
print(tf.rank(b)) # 1차원
print(b) # [2 3]
c = tf.constant([[2,3],[6,7]])
print(tf.rank(c)) # 2차원
print(c) # [[2 3] [6 7]]
텐서의 연산
당연히 사칙연산 모두 가능합니다.
먼저 텐서 객체를 만들어봅시다.
a = tf.constant(3)
b = tf.constant(2)
이제 연산을 한번 해보죠.
연산은 텐서플로우의 add, subtract, multiply, divide 함수를 사용해서 할 수 있고, 파이썬의 연산자로도 연산이 가능합니다.
print(tf.add(a,b))
print(a+b)
print(tf.subtract(a,b))
print(a-b)
print(tf.multiply(a,b))
print(a*b)
print(tf.divide(a,b))
print(a/b)
텐서 플로우 ↔ 넘파이
TensorFlow 2.x에서는 Eager Execution(즉시 실행 모드) 기능을 지원하는데, 이로써 넘파이 함수를 이용하여 텐서를 계산할 수 있게 되었습니다.
이 작업에 필수적인 2가지 함수를 확인해봅시다.
- numpy() : 넘파이 배열로 만들기
- tf.convert_to_tensor() : 텐서 형태로 만들기
먼저 넘파이 배열을 한번 만들어 봅시다.
c = (5).numpy()
print(c) # 5
print(type(c)) # <class 'numpy.int32'>
넘파이가 되었으니 여러가지 계산이 가능해졌습니다.
루트를 한번 씌워볼까요? 데이터 타입은 float32로 설정해주겠습니다.
그런 다음 다시 텐서 형태로 바꾸면 어떻게 될까요?
c_sqrt = np.sqrt(c ,dtype=np.float32)
c_tensor = tf.convert_to_tensor(c_sqrt)
print(c_tensor)
print(type(c_tensor))
넘파이 값 그대로 텐서 객체가 되었습니다.
텐서 객체를 살펴보니 EagerTensor라는 말이 붙어 있는 것도 확인해볼 수 있네요!
넘파이처럼 사용하기
그런데 애초에 텐서 객체를 넘파이처럼 사용하는 것도 가능합니다.
2차원 텐서 객체를 만들어보겠습니다.
t = tf.constant([[1.,2.,3.],[4.,5.,6.]])
print(t.shape) # (2, 3)
print(t.dtype) # <dtype: 'float32'>
넘파이에서 가능한 슬라이싱이 여기서도 바로 될까요?
행은 그대로 두고 1열을 없애보겠습니다.
print(t[:,1:])
와.. 이게 됩니다.
그럼 행렬의 모든 값에 같은 값을 더해주는 연산도 될까요?
t + 10
이게 되네요.. 굉장히 직관적인 코드이니 요긴하게 사용될 수 있을 것 같습니다.
그럼 행렬곱도 가능할까요?
간단하게 t 행렬과 t의 전치행렬을 곱해보겠습니다.
# 행렬곱
t @ tf.transpose(t)
문제없이 작동합니다. 왠만한 행렬 연산은 다 되는 것 같군요.
텐서의 타입 변환
- 텐서의 기본 dtype
- float형 텐서 : float32
- int형 텐서 : int32
- 타입 변환 시 사용하는 함수
- tf.cast()
타입변환은 왜 필요할까요?
그 이유는 텐서의 경우 연산 시 타입이 맞지 않으면 에러가 발생하기 때문입니다.
a = tf.constant(2) # dtype=int32
b = tf.constant(2.) # dtype=float32
a+b
int ↔ float 뿐만 아니라, float32 ↔ float64도 안됩니다.
tf.constant(2.) + tf.constant(2., dtype=tf.float64)
자 그럼 이제 cast() 함수를 사용해서 데이터 타입을 맞춰준 뒤 연산해봅시다.
t = tf.constant(2, ) # int32
t2 = tf.constant(2.) # float32
t3 = t + tf.cast(t2, tf.int32)
print(t3)
print(type(t3))
t = tf.constant(2.0, dtype=tf.float64) # float64
t2 = tf.constant(2.) # float32
t3 = t + tf.cast(t2, tf.float64)
print(t3)
print(type(t3))
난수 생성
텐서플로우에서는 특정 조건 내에서 랜덤한 값도 생성할 수 있습니다.
rand1 = tf.random.uniform([1], 0, 1)
print(rand1.shape) # (1,)
print(rand1) # tf.Tensor([0.45497942], shape=(1,), dtype=float32)
- [1] → 크기가 1인 텐서(1차원 배열)를 생성
- 0, 1 → 0 이상, 1 미만의 균등 분포(Uniform Distribution)에서 숫자를 랜덤하게 뽑음
rand2 = tf.random.normal(shape=(1,2), mean=0, stddev=1)
print(rand2.shape) # (1,2)
print(rand2) tf.Tensor([[ 0.43970278 -0.18841505]], shape=(1, 2), dtype=float32)
- shape=(1,2) → 크기가 (1행, 2열)인 2D 텐서(행렬) 생성
- mean=0, stddev=1 → 평균이 0, 표준편차가 1인 정규분포(가우시안 분포)에서 숫자를 랜덤하게 뽑음
rand3 = tf.random.normal([3,2], 0, 1)
print(rand3.shape) # (3, 2)
print(rand3)
이렇게 옵션 명칭을 생략하고 쓸 수도 있습니다.
간편하지만 가독성 면에서는 좋지 않으니 상황에 맞게 사용하는 것이 좋겠네요!
'Study > AI' 카테고리의 다른 글
[AI] GAN(Generative Adversarial Networks)에 대하여 (1) | 2025.02.06 |
---|---|
[AI] TensorFlow에서 Gradient Tape를 이용한 자동 미분 (0) | 2025.02.06 |
[AI] CNN(Convolutional Neural Networks)에 대하여 (0) | 2025.01.27 |
[AI] Model-Centric AI & Data-Centric AI (0) | 2024.12.05 |