njs03332 / ml_study

3 stars 0 forks source link

2023/02/15 ~ 2023/02/22 #59

Open givitallugot opened 1 year ago

givitallugot commented 1 year ago

1: 12.3.1 2: 12.3.2 3: 12.3.3

02/22 (수) 10:10

image

danbi5228 commented 1 year ago

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

12.3.1 사용자 정의 손실 함수

사용자 정의 손실 함수 구현

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

# tf.where(bool type 텐서, True일 때 출력값, False일 때 출력값)
return tf.where(is_small_error, squared_loss, linear_loss)

이 손실을 사용해 케라스 모델 훈련

huber_fn() 함수로 손실을 계산하며 경사 하강법 수행 및 에포크 시작부터 전체 손실을 기록하여 평균 손실을 출력

model.compile(loss=huber_fn, optimizer="nadam") model.fit(X_train, y_train, [...])


- (주의) 성능을 위해서는 위처럼 벡터화하여 구현해야하고, 텐서플로 그래프의 장점을 활용하려면 텐서플로 연산만 사용해야 함

### 후버 손실 Huber loss
<img width="344" alt="image" src="https://user-images.githubusercontent.com/26505830/219964633-e5531e4e-b1b3-4047-92d8-dc33a9d71ed3.png">

- MSE와 MAE를 절충
- 일정 범위 δ (델타)를 정해서 그 안에 있으면 오차(잔차. 보통 관측값과 예측값의 차이) 를 제곱하고, 그 밖에 있으면 오차의 절대값을 구하는 것
- 1/2가 붙는 이유는 δ에서 오차 제곱과 오차 절대값이 만날 때 매끄럽게 이어지도록 하게 만들기 위함
  -  <img width="458" alt="image" src="https://user-images.githubusercontent.com/26505830/219964880-e426064c-80e4-415c-a238-6da20594ede8.png">
  - `a = y - f(x)` 로 확장될 수 있음.
  - 녹색: δ=1. 후버 손실
  - 파랑: y-f(x). 제곱 오차 손실
- 참고
  - https://blog.naver.com/PostView.naver?blogId=jws2218&logNo=221890882708&parentCategoryNo=&categoryNo=12&viewDate=&isShowPopularPosts=true&from=search
  - https://soki.tistory.com/m/16
njs03332 commented 1 year ago

12.3.2 사용자 정의 요소를 가진 모델을 저장하고 로드하기

model  = keras.models.load_model("my_model_with_a_custom_loss_threshold_2.h5",
                          custom_objects={"huber_fn": create_huber(2.0)")

모델 컴파일 시 이 클래스 인스턴스 사용

model.compile(loss=HuberLoss(2.), optimizer="nadam")

모델 저장시 임곗값도 함께 저장됨

모델 로드시 클래스 이름과 클래스 자체를 매핑

model = keras.models.load_model("my_model_with_a_custom_loss_class.h5", custom_objects={"HuberLoss": HuberLoss})



- 모델 저장시 케라스는 손실 객체의 `get_config()` 메서드를 호출하여 반환되 설정을 HDF5 파일에 JSON 형태로 저장
- 모델 로드시 `HuberLoss` 클래스의 `from_config()` 클래스 메서드를 호출
  - 이 메서드는 생성자에게 `**config` 매개변수를 전달해 클래스 인스턴스를 만듦
givitallugot commented 1 year ago

12.3.3 활성화 함수, 초기화, 규제, 제한을 커스터마이징하기

사용자 정의 글로럿 초기화 (정규분포 이용 초기화)

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)

사용자 정의 l1 규제

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

양수인 가중치만 남기는 사용자 정의 제한

def my_positive_weights(weights): return tf.where(weights < 0., tf.zeros_like(weights), weights)

최종적으로 다음과 같이 사용자 정의 함수 사용

layer = keras.layers.Dense(30, activation = my_softplus, kernel_initializer = my_glorot_initializer, kernel_regularizer=my_l1_regularizer, kernel_constraint=my_positive_weights)


- 함수가 모델과 함께 저장해야 할 하이퍼파라미터를 가지고 있다면 keras.regularizers.Regularizer, keras.constraints.Constraint, keras.initializers.Initializer, keras.layers.Layer와 같이 적절한 클래스 상속

```python
# l1 규제를 위한 간단한 클래스

class MyL1Regularizer(keras.regularizers.Regularizer):
  def __init__(self, factor):
    self.factor = factor
  def __call__(self, weights): # call() 메서드를 구현해야 함
    return tf.reduce_sum(tf.abs(self.factor * weights))
  def get_config(self):
    return {"factor": self.factor}