티스토리 뷰

 

TensorFlow Implementation - Inference in Code

 

TensorFlow는 딥러닝 구현에 널리 사용되는 강력한 프레임워크로, 신경망 추론을 쉽게 구현할 수 있다.

(물론, PyTorch도 유용한 프레임워크이다)

 

TensorFlow를 사용하여 추론 코드를 구현하는 방법에 대해 알아보자.

신경망의 뛰어난 점은 같은 알고리즘을 다양한 응용 프로그램에 적용할 수 있다는 것이다. 이를 위해 coffee roasting 최적화의 예시를 사용해 보겠다.

 

커피 로스팅에서 제어할 수 있는 두 가지 주요 변수는 온도시간이다. 이를 통해 머신 러닝 모델이 좋은 커피를 예측할 수 있다. 예를 들어, 특정 온도와 시간 조합이 주어졌을 때, 그 결과물이 맛있는 커피가 될지 예측할 수 있다. (보라색 삼각형 안의 데이터들이 좋은 커피에 해당하는 것)

 

온도와 로스팅 시간을 모두 포함하는 특징 벡터 \(x\) (섭씨 200도, 17분)가 주어진다. 그러면 신경망을 통해, 주어진 설정이 좋은 커피를 만들지 여부를 예측하게 된다.

 

그럼 신경망에서 이러한 추론을 수행하려면 어떻게 해야 할까?

 

단계별로 설명해보겠다.

 

첫 번째 은닉 계층 계산
첫 번째 은닉 계층인 Layer 1Dense Layer로, 세 개의 뉴런(unit)과 시그모이드 활성화 함수를 사용한다. 즉, 이 계층은 세 개의 출력값을 계산하는데, 입력값 \(x\)와 해당 가중치, 편향을 곱하고 시그모이드 함수를 적용한다. 이를 통해 a1을 얻게 됩니다. 예를 들어, a1은 [0.2, 0.7, 0.3]과 같은 값이 될 수 있습니다.

 

두 번째 은닉 계층 계산
두 번째 은닉 계층인 Layer 2Dense Layer이지만, 이번에는 단위가 하나만 있다. 즉, a1을 입력받아 하나의 출력값 a2를 계산한다. 이 출력값은 예를 들어 0.8일 수 있다.

 

출력값에 임계값 적용
출력값 a2가 계산되면, 이 값이 0.5보다 큰지 확인하여 최종 예측값 y-hat을 구한다. 예를 들어, a20.5 이상이면 y-hat1, 그렇지 않으면 0으로 설정된다.

 

 

또다른 예시인, 손으로 쓴 숫자 분류 문제이다.

 

입력값 \(x\)는 픽셀 강도 값의 목록이다. \(x\)는 numpy 배열로, 각 픽셀의 밝기 값으로 구성된다. 신경망 구조는 이전과 비슷하지만, 첫 번째 은닉 계층에 25개의 뉴런을 사용한다.

 

  • Layer 1: 25개의 뉴런과 시그모이드 활성화 함수로 구성된 고밀도 계층
  • a1: x를 Layer 1에 입력하여 a1 계산

 

 

 

  • Layer 2: 15개의 뉴런으로 이루어진 계층
  • a2: a1을 Layer 2에 입력하여 a2 계산

 

  • Layer 3: 출력 계층이며, 하나의 뉴런을 갖는다
  • a3: a2를 Layer 3에 입력하여 최종 출력값 a3 계산

 

 

마지막으로, a3에 임계값을 적용하여 최종 예측값 y-hat을 얻는다.

 

이 방식으로 TensorFlow에서 순방향 전파 알고리즘을 구현하여 신경망의 추론을 수행할 수 있다.


TensorFlow Implementation - Data in TensorFlow 

 

NumPy와 TensorFlow에서 데이터가 어떻게 표현되는지 알아보는 것은 신경망을 제대로 구현하는 데 필수적이다. 특히, 이 두 프레임워크에서 벡터와 행렬을 다루는 방식에 대한 차이를 이해해야 한다. (NumPy와 텐서플로우에서 데이터가 표현되는 방식 간에는 약간의 불일치가 존재함)

 

먼저 TensorFlow가 데이터를 나타내는 방법을 살펴보겠다.

 

이전에 봤던 coffee roasting 예제에 다음과 같은 데이터 세트가 있다고 가정해 보겠다. 

 

\(x\)를 다음과 같이 표현할때, 왜 여기에 이중 대괄호가 있는 거죠? 이거에 대해서 알아보자.

 

우선, NumPy가 벡터와 행렬을 저장하는 방법을 알아야한다.

 

NumPy는 수치 연산을 쉽게 처리할 수 있도록 설계된 Python의 라이브러리로,

데이터를 1차원 배열(벡터)과 2차원 배열(행렬)로 저장할 수 있다.

 

다음과 같이 2 x 3 행렬, 4 x 2 행렬을 만들 수 있다. 

 

행렬의 차원은 다양한 방식으로 표현될 수 있다.

 

예를 들어, 다음은 1 x 2 행렬, 2 x 1 행렬이다. 여기서, 1 x 2 행렬은 "행 벡터"라고 부르며, 2 x 1 행렬은 "열 벡터"라고 한다. 이는 벡터의 모양에 따라 구분되며, 각각의 벡터는 하나의 행 또는 하나의 열로 표현된다. 

 

NumPy에서는 대괄호 한 쌍을 사용하면 1D 배열(벡터)을 생성한다. 이 배열은 차원이 1인 벡터이며, 행이나 열의 구분 없이 데이터가 나열된 형태(숫자의 목록)이다.

 

반면, 2D 배열은 대괄호를 두 번 사용해 행과 열을 명시적으로 지정한다.

 

선형 회귀와 로지스틱 회귀를 다룰 때는 1D 벡터를 사용하여 입력 특징 \(x\)를 표현하는 반면, TensorFlow에서는 행렬을 사용하여 데이터를 표현하는 것이 관례이다.

그리고 왜 이런 전환 규칙이 있는 걸까?

알고 보니 TensorFlow는 매우 큰 데이터 세트를 처리하도록 설계되었고 데이터를 1D 배열 대신 행렬로 표현함으로써 TensorFlow의 내부 계산 효율성이 조금 더 높아진다. 

 

 

따라서 17분 동안 200°C의 특성을 갖는 이 데이터 세트의 예제로 돌아가서 다음과 같이 표현되었다. 이것은 실제로 1 x 2 행렬로, 숫자 217을 저장하는 행 1개와 열 2개로 구성된 행렬이다. 

신경망에서 전파(Forward Propagation)를 설명하는 데 있어 중요한 개념은 입력 데이터가 각 레이어를 거치면서 변환되는 방식입니다. 여기서는 a1과 a2와 같은 레이어의 출력이 어떻게 계산되고, TensorFlow와 NumPy에서 데이터를 어떻게 다루는지 알아보겠다.

 

입력 값 \(x\)가 layer1을 통과하면 a1이라는 결과를 얻게 되는데, 이 값은 1 x 3 행렬의 형태로 표현된다. 

예를 들어, a1의 출력이 tf.tensor([0.2, 0.7, 0.3])라면, 이 값은 TensorFlow가 계산한 1x3 형태의 tensor이다. 여기서 1x3이란, 행이 1개이고 열이 3개인 2차원 배열(행렬)을 뜻한다.

 

** Tensor(텐서)란 무엇인가?

tensorTensorFlow가 수학적인 행렬 연산을 수행하기 위해 사용하는 데이터 타입이다. tensor행렬을 일반화한 개념으로, 다양한 차원을 가질 수 있다. tensor는 NumPy의 배열과 유사하게 동작하지만, 더 효율적인 연산 처리를 위해 설계되었다. 따라서 tensor는 데이터의 효율적 처리를 위해 사용되며, 이 강의에서는 tensor를 주로 행렬과 동일한 방식으로 생각하면 된다.

 

TensorFlow는 내부적으로 데이터를 tensor 형식으로 처리하지만, 이를 NumPy 배열로 변환할 수 있다. 예를 들어, a1이라는 tensor를 NumPy 배열로 변환하고 싶다면, a1.numpy()를 사용하면 된다. 이렇게 하면 TensorFlow 텐서가 NumPy 배열로 변환되어, NumPy의 기능을 사용할 수 있게 된다.

 

두 번째 레이어의 출력을 살펴보겠다. 두 번째 레이어는 하나의 단위(unit)로 구성되어 있고, 시그모이드 활성화 함수가 적용된다. 이 레이어를 통과한 후 a2라는 값이 계산되는데, a2는 1x1 행렬이다. 이는 행과 열이 각각 하나씩 있는 2D 배열이다. 예를 들어, a2의 출력이 tf.tensor([0.8])이라면, 이는 1x1 행렬이며, 32비트 부동소수점(float32) 형식으로 저장된다.

 

마찬가지로, a2도 NumPy 배열로 변환할 수 있다. 

 

TensorFlow와 NumPy의 데이터 표현 차이

TensorFlow는 데이터를 텐서로 처리하고, NumPy는 배열로 처리한다. 이 두 라이브러리는 내부적으로 데이터를 처리하는 방식이 조금 다르지만, 서로 데이터를 쉽게 변환할 수 있다. 예를 들어, NumPy 배열을 TensorFlow로 전달하면, TensorFlow는 이를 자동으로 텐서로 변환한다. 반대로, TensorFlow 텐서를 NumPy 배열로 변환할 수도 있다. 이 과정은 두 라이브러리 간의 호환성을 높여준다.

 

TensorFlow는 특히 대규모 데이터 세트를 처리할 때 더 효율적이기 때문에, 데이터는 주로 텐서로 표현된다. NumPy에서 데이터를 로드하거나 처리한 후 TensorFlow로 전달하는 경우, 이 변환 과정을 이해하고 사용하는 것이 중요하다.


TensorFlow Implementation - Building a neural network

 

TensorFlow에서 신경망을 구축하고 순방향 전파(forward propagation)를 수행하는 방법에 대해 단계별로 설명해 보겠다.

 

forward propagation을 수행하려면 데이터 \(x\)를 초기화하고 layer1을 생성하고  a1을 계산한 다음, layer 2를 만들고 a2를 계산한다. 이것은 forward propagation의 수행하는 명시적인 방법이었다. 

 

TensorFlow에서는 이 과정을 더 쉽게 자동화할 수 있는 방법이 있다. Sequential API를 사용하는 것이다.

 

TensorFlow의 Sequential API여러 층을 순차적으로 쌓아 신경망을 만들 수 있는 방법을 제공한다. 즉, 각각의 레이어를 수동으로 연결하지 않아도, TensorFlow가 알아서 신경망을 구성해 준다. 예를 들어, 첫 번째 레이어와 두 번째 레이어를 정의한 후, TensorFlow에 두 레이어를 순서대로 연결하도록 지시할 수 있다. 이렇게 하면 우리가 직접 데이터를 전달하고 출력을 관리하는 대신, TensorFlow가 자동으로 신경망을 처리한다.

 

 

coffee roasting 예시를 들어, 입력 데이터 \(x\)와 레이블 \(y\)가 있다고 가정하자.

 

1. 데이터 준비 

입력 데이터 \(x\)는 크기가 4x2인 행렬로, 4개의 샘플과 2개의 특징을 가지고 있다. 반면, 레이블 \(y\)는 크기가 4인 1차원 배열로, 각각의 샘플에 대한 목표 값이다.

 

2. 모델 컴파일
모델을 훈련시키기 전에 model.compile()을 통해 손실 함수, 옵티마이저, 평가 지표 등을 설정해야 한다. 이는 모델이 학습할 때 사용할 규칙을 정의하는 단계이다. 

 

3. 모델 학습

데이터 X와 Y를 준비한 후에는 model.fit()을 사용하여 모델을 학습시킨다. fit() 함수는 입력 데이터 \(x\)와 레이블 \(y\)를 바탕으로 신경망을 훈련시킨다.

 

4. 모델 예측(추론)
학습이 완료되면, 새로운 데이터를 사용해 예측을 수행할 수 있다. model.predict() 함수를 사용하면 새로운 입력값에 대해 신경망이 예측한 결과를 얻을 수 있다.



그리고 다음과 같이 코드를 단순화시킬 수 있다.

 

TensorFlow에서는 layer를 직접 변수에 할당하는 대신, 위에서 설명한 Sequential API로 간단히 모델을 정의할 수 있다. 이 방식은 간결하고 직관적이며, 신경망을 구성하는 코드를 훨씬 쉽게 관리할 수 있다.

 

 

숫자 분류 예제를 TensorFlow를 사용해 실행하는 방법을 다시 살펴보자.

 

 


Practice quiz - Tensorflow implementation

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
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 30
글 보관함