[핸즈온 머신러닝] 12. 텐서플로를 사용한 사용자 정의 모델과 훈련

박경민·2023년 5월 19일
0

[Hands-On Machine Learning]

목록 보기
19/23

텐서플로를 통해 저수준 파이썬 API를 만들어보자!

  • 손실함수
  • 지표
  • 모델
  • 초기화
  • 규제
  • 가중치 규제
    등을 직접 제어해보자.

텐서플로를 훑어보자

텐서플로는 대규모 머신러닝에 맞도록 튜닝된 수치 계산용 라이브러리이다.

  • GPU / 분산 컴퓨팅을 지원한다
  • 계산 그래프를 추출하고 최적화하여 JIT 컴파일러를 포함한다
  • 자동 미분 기능과 고성능 옵티마이저를 제공한다

API를 살펴보자.

구조를 살펴보자. 고수준의 API부터 저수준까지 직접 다룰 수 있다.

넘파이처럼 텐서플로 사용하기

텐서는 일반적으로 다차원 배열, 혹은 스칼라도 가능하다. 따라서 넘파이 ndarray 와 비슷한데 텐서를 직접 만들고 조작하는 방법을 알아보자.

  1. 텐서와 연산
tf.constant([[1., 2., 3.], [4., 5., 6.]]) # 행렬
tf.constant(42) # 스칼라

위는 행렬, 아래는 스칼라이다.

  • 텐서역시 크기와 타임을 가진다. .shape , dtype 으로 확인할 수 있다.
  • 인덱스참조도 자유롭게 가능하다. 저장된 텐서에 [:,1:] 을 찍으면 1열부터 모든 행 출력, [..., 1, newaxis] 은 1열의 모든 행에 대해 새로운 차원을 추가하는 것을 말한다.
  • 텐서 연산이 가능하다. t+10 을 하면 모든 텐서에 10을 더한다. 외에도 tf.add(), tf.multiply, tf.square, tf.exp, tf.sqrt() 등이 제공된다.
  1. 텐서와 넘파이
  • 넘파이 배열에 텐서플로 연산을 적용할 수 있고 텐서에 넘파이 연산을 적용할 수도 있다. (코드 생략)
  1. 타입변환
    타입 변환은 성능을 감소시킬 수 있으므로 자동 타입 변환을 지원하지 않는다.

  2. 변수
    일반적인 tf.Tensor 는 변경이 불가능한 객체이므로 변경하고 싶은 대상일 경우 tf.Variable 을 사용한다.

v = tf.Variable([[1., 2., 3.], [4., 5., 6.]]
  • assign() 메서드를 사용하면 변숫값을 바꿀 수 있다.
  • scatter_nd_update() 를 사용하면 개별 원소를 수정할 수 있다.
  1. 다른 데이터 구조
    텐서플로는 이외에도 tf.SparseTensor, tf.TensorArray, tf.RaggedTensor 등 다른 데이터 구조도 지원한다. 집합과 큐도 가능!

사용자 정의 모델과 훈련 알고리즘

  1. 사용자 정의 손실 함수
  • 손실함수로 MSE 대신 후보 손실을 구현해볼 수 있다.
  • 레이블과 예측을 매개변수로 받자.
def huber_fn(y_true, y_pred):
    error = y_true - y_pred
    is_small_error = tf.abs(error) < 1
    squared_loss = tf.square(error) / 2
    linear_loss  = tf.abs(error) - 0.5
    return tf.where(is_small_error, squared_loss, linear_loss)

모델을 컴파일할 때 만들어놓은 후버 손실을 쓰면 된다.

  1. 사용자 정의 요소를 가진 모델을 저장하고 로드하기
    저장한 huber_fn 을 포함한 모델을 로드할 때는 이름과 객체를 매핑해야 한다.
model = keras.models.load_model("my_model_with_a_custom_loss.h5",
                                custom_objects={"huber_fn": huber_fn})
  1. 추가로 활성화 함수, 초기화, 규제, 제한을 커스터마이징 해보자
    유사한 방법으로 위의 것들을 커스터마이징 할 수 있다.
def my_softplus(z): # tf.nn.softplus(z) 값을 반환합니다
    return tf.math.log(tf.exp(z) + 1.0)

def my_glorot_initializer(shape, dtype=tf.float32):
    stddev = tf.sqrt(2. / (shape[0] + shape[1]))
    return tf.random.normal(shape, stddev=stddev, dtype=dtype)

def my_l1_regularizer(weights):
    return tf.reduce_sum(tf.abs(0.01 * weights))

def my_positive_weights(weights): # tf.nn.relu(weights) 값을 반환합니다
    return tf.where(weights < 0., tf.zeros_like(weights), weights)

이제 모델의 층을 정의할 때 다음과 같이 넣으면 된다.

layer = keras.layers.Dense(1, activation=my_softplus,
                           kernel_initializer=my_glorot_initializer,
                           kernel_regularizer=my_l1_regularizer,
                           kernel_constraint=my_positive_weights)
  1. 사용자 정의 지표
    평가 지표도 실제로 정의할 수 있다. (앞서 만든 후보 손실 함수는 metrics 로도 사용이 가능하다.)
  • keras.metrics.Precision 클래스로 정밀도 값을 체크하는 객체를 생성할 수 있다.
precision = keras.metrics.Precision()
precision([0, 1, 1, 1, 0, 1, 0, 1], [1, 1, 0, 1, 0, 1, 0, 1])
  • 배치마다 점진적으로 업데이트가 가능하여 이를 스트리밍 지표라 한다.
  • result() 를 쓰면 현재 지표값, variables 을 쓰면 변수 확인, reset_states() 를 쓰면 변수 리셋이 가능하다
  1. 사용자 정의 층
  2. 사용자 정의 모델
  3. 손실과 지표
  4. 그레디언트 계산
  5. 반복
profile
Mathematics, Algorithm, and IDEA for AI research🦖

0개의 댓글