딥러닝 프레임워크, Tensorflow로 모델 구축하기

김지원·2022년 11월 30일
0

NLP(자연어 처리)

목록 보기
12/15

💡Tensorflow, 텐서플로우

구글에서 2015년에 오픈소스로 발표한 머신러닝 라이브러리이다.

Python을 기반으로 한 라이브러리로, 상용 서비스까지 고려해서 최적화되어 있다.

"Tensorflow"에서
Tensor(텐서)는 N차원 매트릭스를 의미하고,
Tensor을 flow한다는 것은 Data flow graph(데이터 흐름 그래프)를 사용해 수치 연산을 하는 과정을 의미한다.

🧩tf.keras.layers

Tensorflow를 이용해 하나의 딥러닝 모델을 만들 때, 각 블록 역할을 할 수 있는 모듈의 종류를 알아보자.

Keras는 Tensorflow와 같은 별개의 딥러닝 오픈소스인데, Tensorflow에서도 Keras를 사용할 수 있다.

Tensorflow 2.0버전 이후부터는 대부분을 tf.keras.layers의 모듈로 통합하고 이를 표준으로 사용하고 있다.

🪵tf.keras.layers.Dense

Dense란 신경망 구조의 가장 기본저긴 형태를 의미한다.

아래의 수식을 만족하는 기본적인 신경망 형태의 층을 이루는 함수다.

y=f(Wx+b)
  • x: 입력벡터
  • b: 편향벡터
  • W: 가중치 행렬

즉, 가중치와 입력 벡터를 곱한 후 편향을 더해준다.
그 이후 f 활성화 함수(Activation function)을 적용한다.

입력 노드와 출력 노드 사이를 잇는 선은 가중치(W)를 곱하는 과정을 의미한다.

Wb의 경우 각각 변수로 선언 및 정의해줘야 한다.

W = tf.Variable(tf.random_uniform([5,10], -1.0, 1.0))
b = tf.Variable(tf.zeros[10]))

y = tf.matmul(W, x)+b

이후 하나하나 직접 곱하고 더해야 한다.

하지만 Tensorflow의 Dense를 사용하면 한 줄의 코드로 간단하게 작성할 수 있다.

객체를 생성하여 사용할 수 있다. 또한 입력값을 넣기 위해서는 객체를 생성할 때 함께 넣거나 생성한 후 따로 적용하는 방법이 있다.

dense = tf.keras.layers.Dense(...)(input)
# 또는
output = tf.keras.layers.Dense(...)
output = dense(input)

📌 Parameters

__init__(
	units,
    activation= None,
    use_bias=True,
    kernel_initializer='glorot_uniform',
    bias_initializer='zeros',
    kernel_regularizer=None,
    bias_regularizer=None,
    activity_regularizer=None,
    kernel_constraint=None,
    bias_constraint=None,
    **kwargs
  • units: 출력값의 크기, Integer 혹은 Long 형태
  • activation: 활성화 함수
  • use_bias: 편향(b)을 사용할지 여부, Boolean 값 형태
  • kernel_initializer: 가중치(W) 초기화 함수
  • bias_initializer: 편향 초기화 함수
  • kernel_regularizer: 가중치 정규화 방법
  • bias_regularizer: 편향 정규화 방법
  • activity_regularizer: 출력 값 정규화 방법
  • kernel_constraint: Optimizer에 의해 업데이트된 이후에 가중치에 적용되는 부가적인 제약 함수(예: norm constraint, value constraint)
  • bias_constraint:Optimizer에 의해 업데이트된 이후에 편향에 적용되는 부가적인 제약 함수(예: norm constraint, value constraint)

📌 예시

입력값에 대해 활성화 함수로 Sigmoid 함수 사용, 출력값으로 10개의 값을 출력하는 완전 연결 계층(Fully Connected Layer)

INPUT_SIZE=(20,1)

inputs=tf.keras.Input(shape=INPUT_SIZE)
hidden=tf.kears.layers.Dense(units=10, activation=tf.nn.sigmoid)(inputs)
output=tf.keras.layers.Dense(units=2, activation=tf.nn.sigmoid)(hidden)

🪵tf.keras.layers.Dropout

Neural Network, 신경망 모델을 만들 때 해결해야 할 문제가 ❗과적합(Overfitting) 이다.

예를 들어 Training Dataset 정확도는 높은데 Test Dataset 정확도가 낮게 나온다면, overfitting을 의심해보아야 한다.

또한 layer(레이어)가 깊어질수록 Overfitting 가능성이 더 커진다.

정규화(Regularization) 방법을 사용해서 해결하는데, 그중 가장 대표적인 방법이 💡Dropout(드롭아웃)이다.

Dropout이란, "randomly set some neurons to zero in the forward pass".

중요한 것은 학습 데이터에 과적합되는 상황을 방지하기 위해 학습 시에만 Dropout을 적용하고, 예측 혹은 테스트할 때는 적용되지 않아야 한다.

Keras의 Dropout을 사용하면 자동으로 적용된다.

사용 방법은 Dense와 동일하다.

📌 Parameters

__init__(
	rate,
    noise_shape=None,
    seed=None,
    **kwargs
  • rate: Dropout 적용할 확률. 0.2일 경우 20%0으로 만든다.
  • noise_shape: 정수형 1D-tensor 값을 받는다. 이 값을 지정함으로써 특정 값만 Dropout 적용할 수 있다. 예를 들어 입력값이 이미지일 경우, noise_shape을 지정하면 특정 채널에만 Dropout을 적용할 수 있다.
  • seed: randomly하게 드롭아웃을 적용하는데, 이를 위한 seed값이다. 같은 seed 값을 가지는 드롭아웃의 경우 동일한 드롭아웃 결과를 만든다.

📌 예시

INPUT_SIZE=(20,1)

inputs=tf.keras.Input(shape=INPUT_SIZE)
dropout=tf.keras.layers.Dropout(rate=0.2)(inputs)
hidden=tf.keras.layers.Dense(units=10, activation=tf.nn.sigmoid)(dropout)
output=tf.keras.layers.Dense(units=2, activation=tf.nn.sigmoid)(hidden)

🪵tf.keras.layers.Conv1D

Tensorflow의 합성곱(Convolution) 연산은 3가지로 나눠진다.
기준은 아래와 같이 합성곱의 방향출력값의 형태로 나눌 수 있다.

합성곱의 방향출력값
Conv1D한 방향(가로)1-D Array(vector)
Conv2D두 방향(가로, 세로)2-D Array(matrix)
Conv3D세 방향(가로, 세로, 높이)3-D Array(tensor)

Conv1D의 경우 filter을 가로 방향으로만 sliding하므로 출력 값은 1차원 벡터가 된다.

자연어 처리 분야에서 사용하는 합성곱의 경우 각 단어(or 문자) 벡터 차원 전체에 대해 filter을 적용시키기 위해 주로 Conv1D를 사용한다.

📌 Parameters

tf.keras.layers.Conv1D(
    filters,
    kernel_size,
    strides=1,
    padding='valid',
    data_format='channels_last',
    dilation_rate=1,
    groups=1,
    activation=None,
    use_bias=True,
    kernel_initializer='glorot_uniform',
    bias_initializer='zeros',
    kernel_regularizer=None,
    bias_regularizer=None,
    activity_regularizer=None,
    kernel_constraint=None,
    bias_constraint=None,
    **kwargs
)

인자 값을 어떻게 설정하느냐에 따라 학습 성능이 크게 달라지므로 각 인자가 의미하는 바에 대해 정확히 알고 있어야 한다.

  • filters: filter 개수, 정수형. 출력의 차원 수를 나타냄
  • kernel_size: filter의 크기, 정수 혹은 정수의 리스트, 튜플 형태로 지정. 합성곱이 적용되는 window의 크기
  • strides: stride 값, 정수 혹은 정수의 리스트, 튜플 형태로 지정, 1이 아닌 값 지정할 경우 dilation_rate1 이외의 값 지정 못함
  • padding: 패딩 방법 결정, "valid" 또는 "same"
  • data_forma: 데이터의 표현 방법 선택, "channel_last" ->(batch, length, channels)형태, "channel_first" -> (batch, channels, length) 형태, 를 지정.
  • dilation_rate: dilation 값, 정수 혹은 정수의 리스트, 튜플 형태로 지정.
  • activation: 활성화 함수
  • use_bias: 편향(b) 사용할지 여부, Boolean 값 형태

📌 예시

INPUT_SIZE=(1,28,28)

inputs=tf.keras.Input(shape=INPUT_SIZE)
conv = tf.keras.layers.Conv1D(
		filters=10,
        kernel_size=3,
        padding='same',
        activation=tf.nn.relu)(inputs)

🪵tf.keras.layers.MaxPool1D

Pooling(풀링) 기법은 보통 feature map의 크기를 줄이거나 주요한 특징을 뽑아내기 위해 합성곱 이후에 적용되는 기법이다.

Max-Pooling & Average-Pooling이 있다.

Max Pooling도 합성공처럼 세 가지 형태가 있고, 원리가 동일하다.

📌 Parameters

tf.keras.layers.MaxPool1D(
    pool_size=2,
    strides=None,
    padding='valid',
    data_format='channels_last',
    **kwargs
  • pool_size: pooling 적용 filter 크기, 정숫값
  • strides: stride 값, 정수 or None

📌 예시

입력값이 합성곱과 맥스 풀링을 사용한 후 완전 연결 계층을 통해 최종 출력 값이 나오는 구조. 입력값에 드롭아웃 적용. 그리고 맥스 풀링 결과값을 완전 연결 계층으로 연결하기 위해서는 행렬을 벡터로 만들어야 한다. 이 때 tf.keras.layers.Flatten을 사용.

INPUT_SIZE=(1,28,28)

inputs=tf.keras.Input(shape=INPUT_SIZE
dropout=tf.keras.layers.Dropout(rate=0.2)(inputs)
conv = tf.keras.layers.Conv1D(
		filters=10,
        kernel_size=3,
        padding='same',
        activation=tf.nn.relu)(dropout)
max_pool=tf.keras.layers.MaxPool1D(pool_size=3, padding='same')(conv)
flatten=tf.keras.layers.Flatten()(max_pool)
hidden=tf.keras.layers.Dense(units=50, activation=tf.nn.relu)(flatten)
output=tf.keras.layers.Dense(units=10, activation=tf.nn.softmax)(hidden)

💡Tensorflow 2.0

  • API 정리(API Cleanup)
  • 이거 모드(eager execution)
  • 전역 메커니즘 제거(no more globals)
  • 세션을 대신하는 함수(Functions, not sessions)

Eager execution

기존 tensorflow는 tensorflow API를 이용해서 그래프를 만든 후 별도로 세션을 통해 해당 그래프를 실행하는 방식이었다.
2.0 이후 부터는 python과 동일한 Eager execution으로 실행되기 때문에 바로바로 값을 확인할 수 있게 되었다.

🔨 Model 구축

  • Sequential API
  • Functional API
  • Functional/Sequential API
    + Custom Layers
  • Subclassing (Custom Model)

🪵 Sequential API

tf.keras.Sequential은 keras를 활용해 모델을 구축할 수 있는 가장 간단한 형태의 API.

간단한 순차적인 레이어의 스택을 구현할 수 있다.

📌 예시

from tensorflow.keras import layers

model = tf.keras.Sequential()
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

위처럼 Sequential 모듈은 구현 자체가 매우 간단하다.

하지만 제약이 있어 복잡한 모델의 경우 구현이 어려울 수 있다.

모델의 층들이 순차적으로 구성돼 있지 않은 경우 Sequential 모듈을 사용해 구현하기가 어려울 수 있다.

예를 들어 VQA(Visual Question Answering) 문제처럼 사진 데이터에서 특징을 뽑는 레이어 & 질문 텍스트 데이터에서 특징을 뽑는 2개의 레이어가 각기 순차적으로 존재한다.

❗즉, Sequential 모듈은 1개의 플로만 계산할 수 있다.

Sequential 모듈로 구현하기 어려운 모델의 구조는 아래와 같다.

  • Multi-input models
  • Multi-output models
  • Models with shared layers
  • Models with non-sequential data flows

이런 경우 Functional APISubclassing 방식을 사용해야 한다.

🪵 Functional API

📌 예시

inputs=tf.keras.Input(shape=(32,))
x=layers.Dense(64, activation='relu')(inputs)
x=layers.Dense(64, activation='relu')(x)
predictions=layers.Dense(10, activation='softmax')(x)

Functional API를 사용하기 위해서는 Input 모듈을 선언해야 한다.

🪵 Custom Layer

구현하고자 하는 모듈의 대부분은 해당 패키지에 구현되어 있지만,

새로운 연산을 하는 레이어 혹은 편의를 위해 여러 레이어를 하나로 묶은 레이어를 구현해야 하는 경우, 사용자 정의 층, 즉 💡Custom Layer을 만들어 사용하면 된다.

📌 예시

예를 들어 아래는 재사용성을 높이는 코드이다.

class CustomLayer(layers.Layer):
	
    def __init__(self, hidden_dimension, hidden_dimension2, output_dimension):
    	self.hidden_dimension=hidden_dimension
        self.hidden_dimension2=hidden_dimension2
        self.output_dimension=output_dimension
        super((CustomLayer, self).__init__()
    def build(self, input_shape):
    	self.dense_layer1=layers.Dense(self.hidden_dimension, activation='relue')
        self.dense_layer2=layers.Dense(self.hidden_dimension2, activation='relue')
        self.dense_layer3=layers.Dense(self.output_dimension, activation='softmax')
    def call(self, inputs):
    	x=self.dense_layer1(inputs)
        x=self.dense_layer2(x)
        
        return self.dense_layer3(x)

layers 패키지읜 Layer 클래스를 상속받고 위와 같이 3개의 메서드를 정의하면 된다.

  • __init__: 객체 생성 시 hyperparameter 호출되도록 정의
  • build: 모델의 가중치와 관련된 값 생성
  • call: 이렇게 정의한 값들 이용해 해당 층의 로직 정의

이 사용자 정의 층은 Sequential APIFunctional API를 활용할 때 아래처럼 하나의 층으로 사용할 수 있다.

model=tf.keras.Sequential()
model.add(CustomLayer(64,64,10))

🪵 Subclassing(Custom Model)

가장 자유도가 높은 Subclassing.

💡tf.keras.Model을 상속받고 모델 내부 연산들을 직접 구현하면 된다.
모델 클래스 구현 시 👉객체를 생성할 때 호출되는 __init__() 와 생성된 인스턴스를 호출할 때(모델 연산이 사용될 때) 호출되는 call 메서드만 구현하면 된다.

class MyModel(tf.keras.Model):
	def __init__(self, hidden_dimension, hidden_dimension2, output_dimension):
    	super(MyModel, self).__init__(name='my model')
        self.dense_layer1=layers.Dense(hidden_dimension, activation='relu')
        self.dense_layer2=layers.Dense(hidden_dimension2, activation='relu')
        self.dense_layer3=layers.Dense(output_dimension, activation='softmax')
        
    def call(self, inputs):
    	x=self.dense_layer1(inputs)
        x=self.dense_layer2(x)
        
        return self.dense_layer3(x)              

구현 방법은 Custom Layer 때와 거의 비슷하다. 이 방법은 Pytorch 프레임워크에서 모델을 구현할 때 사용하는 방식과도 거의 유사하다.

  • __init__: 모델에서 사용될 dimension과 변수 정의
  • call: 이렇게 정의한 값들 이용해 해당 층의 로직 정의

출처: 텐서플로2와 머신러닝으로 시작하는 자연어 처리

profile
Make your lives Extraordinary!

0개의 댓글