njs03332 / ml_study

3 stars 0 forks source link

2023/02/23 ~ 2023/03/08 #60

Open njs03332 opened 1 year ago

njs03332 commented 1 year ago
스크린샷 2023-02-22 오후 10 27 54
njs03332 commented 1 year ago

12.3.6 사용자 정의 모델

danbi5228 commented 1 year ago

12.3.5 사용자 정의 층


# case1. 가중치가 필요없는 가장 간단한 사용자 정의 층 만들기
exponential_layer = keras.layers.Lambda(lambda x: tf.exp(x))

# case2. 상태가 있는, 가중치를 가지는 사용자 정의 층 만들기: keras.layser.Layer 상속 필요
class MyDense(keras.layers.Layer):

    # 모든 하이퍼파라미터를 매개변수를 받음 (units, activation)
    # 부모 생성자 kwargs; input_shape, trainable, name 과 같은 기본 매개변수 처리
    def __init__(self, units, activation=None, **kwargs):
        super().__init__(**kwargs)
        self.units = units
        self.acitivation = keras.activations.get(activation) # 적절한 활성화 함수로 바꾸는데 이용

    # weight 초기화; 가중치마다 add_weight 메서드를 호출하여 층의 변수 생성
    def build(self, batch_input_shape):
        self.kernel = self.add_weight(
            name='kernel', shape=[batch_input_shape[-1], self.units],
            initailizer='glorot_normal')
        self.bias = self.add_weight(
            name='bias', shape=[self.units], initializer="zeros"
        )
        super().build(batch_input_shape) # 이 명령어를 통해 층이 만들어 졌다는 것을 keras가 인식함(마지막에 호출 필수)

    # 층에서 필요한 연산 수행
    # 이 경우 행렬 곱셈 후 편향을 더한 뒤 활성화 함수 적용 - 이 값이 층의 출력
    def call(self, X):
        return self.activation(X @ self.kernel + self.bias)

    # 이 층의 출력 크기를 반환
    # 예시의 경우 마지막 차원(뉴런 개수0을 제외하고 입력과 크기가 같음.
    def compute_output_shape(self, batch_input_shape):
        return tf.TensorShape(batch_input_shape.as_list()[:-1] + [self.units])

    # 활성화 함수의 설정 저장
    def get_config(self):
        base_config = super().get_config()
        return {**base_config, "unit":self.units, "activation": keras.activations.serialize(self.activation)}

# case 3. 여러가지 입력을 받는 층을 만들고 싶을 때 + 여러 출력을 가진 층을 만들고 싶을 때
# 두개의 입력 층과 세개의 출력 층을 만드는 경우
# 이 경우, 함수형 API와 서브클래싱API에만 사용할 수 있음
# 하나의 입력과 하나의 출력 층만 사용하는 시퀀셜 API에는 사용할 수 없음
class MyMultiLayer(keras.layers.Layer):
    def call(self, X):
        X1, X2 = X # 모든 입력이 포함된 튜플
        return [X1+X2, X1*X2, X1/X2] # 출력 리스트 반환

    def compute_output_shape(self, batch_input_shape):
        b1, b2 = batch_input_shape # 각 입력의 배치 크기를 담은 튜플
        return [b1, b1, b1] 

# case4. 훈련과 테스트에서 다르게 동작하는 층이 필요한 경우
# 훈련 과정에서 가우시안 잡음을 추가해준 형태 - 테스트 시에는 아무것도 하지 않음
# keras.layers.GussianNoise 층과 동작이 동일
class MyGaussianNoise(keras.layers.Layer):
    def __init__(self, stddev, **kwargs):
        super().__init__(**kwargs)
        self.stddev = stddev

    def call(self, X, training=None):
        if training:
            noise = tf.random.normal(tf.shape(X), stddev=self.stddev)
            return X+noise
        else:
            return X

    def compute_output_shape(self, batch_input_shape):
        return batch_input_shape
givitallugot commented 1 year ago

12.3.4 사용자 정의 지표

precision = keras.metrics.Precision()
precision([0, 1, 1, 1, 0, 1, 0, 1], [1, 1, 0, 1, 0, 1, 0, 1])
# <tf.Tensor: shape=(), dtype=float32, numpy=0.8>
precision([0, 1, 0, 0, 1, 0, 1, 1], [1, 0, 1, 1, 0, 0, 0, 0])
# <tf.Tensor: shape=(), dtype=float32, numpy=0.5>
precision.result()
# <tf.Tensor: shape=(), dtype=float32, numpy=0.5>
precision.variables
# [<tf.Variable 'true_positives:0' shape=(1,) dtype=float32, numpy=array([4.], dtype=float32)>,
#  <tf.Variable 'false_positives:0' shape=(1,) dtype=float32, numpy=array([4.], dtype=float32)>]
precision.reset_states()