처음부터 레이어와 모델 작성

기사 목록

  • 준비
  • 레이어 컨텐츠
  • 층의 권중은 훈련에 참여하지 않아도 된다
  • 재작성 지연
  • 레이어는 중첩될 수 있음
  • 추가 손실 회수
  • 정렬화
  • `call'방법 중 특수한 훈련 매개 변수
  • 준비

    !pip3 install tensorflow==2.0.0a0
    %matplotlib inline
    import tensorflow as tf
    from tensorflow import keras
    
    Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
    Requirement already satisfied: tensorflow==2.0.0a0 in /usr/local/lib/python3.7/site-packages (2.0.0a0)
    Requirement already satisfied: google-pasta>=0.1.2 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (0.1.4)
    Requirement already satisfied: numpy<2.0,>=1.14.5 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (1.16.2)
    Requirement already satisfied: astor>=0.6.0 in /Users/fei/Library/Python/3.7/lib/python/site-packages (from tensorflow==2.0.0a0) (0.7.1)
    Requirement already satisfied: keras-preprocessing>=1.0.5 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (1.0.9)
    Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (0.33.1)
    Requirement already satisfied: tf-estimator-nightly<1.14.0.dev2019030116,>=1.14.0.dev2019030115 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (1.14.0.dev2019030115)
    Requirement already satisfied: keras-applications>=1.0.6 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (1.0.7)
    Requirement already satisfied: gast>=0.2.0 in /Users/fei/Library/Python/3.7/lib/python/site-packages (from tensorflow==2.0.0a0) (0.2.2)
    Requirement already satisfied: six>=1.10.0 in /Users/fei/Library/Python/3.7/lib/python/site-packages (from tensorflow==2.0.0a0) (1.12.0)
    Requirement already satisfied: protobuf>=3.6.1 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (3.7.0)
    Requirement already satisfied: tb-nightly<1.14.0a20190302,>=1.14.0a20190301 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (1.14.0a20190301)
    Requirement already satisfied: absl-py>=0.7.0 in /Users/fei/Library/Python/3.7/lib/python/site-packages (from tensorflow==2.0.0a0) (0.7.0)
    Requirement already satisfied: termcolor>=1.1.0 in /Users/fei/Library/Python/3.7/lib/python/site-packages (from tensorflow==2.0.0a0) (1.1.0)
    Requirement already satisfied: grpcio>=1.8.6 in /usr/local/lib/python3.7/site-packages (from tensorflow==2.0.0a0) (1.19.0)
    Requirement already satisfied: h5py in /Users/fei/Library/Python/3.7/lib/python/site-packages (from keras-applications>=1.0.6->tensorflow==2.0.0a0) (2.9.0)
    Requirement already satisfied: setuptools in /usr/local/lib/python3.7/site-packages (from protobuf>=3.6.1->tensorflow==2.0.0a0) (40.8.0)
    Requirement already satisfied: markdown>=2.6.8 in /Users/fei/Library/Python/3.7/lib/python/site-packages (from tb-nightly<1.14.0a20190302,>=1.14.0a20190301->tensorflow==2.0.0a0) (3.0.1)
    Requirement already satisfied: werkzeug>=0.11.15 in /Users/fei/Library/Python/3.7/lib/python/site-packages (from tb-nightly<1.14.0a20190302,>=1.14.0a20190301->tensorflow==2.0.0a0) (0.14.1)
    

    레이어


    레이어 컨텐트


    레이어 내부에는 입력을 출력으로 변환하는 변수(권중)와 계산 방법이 포함되어 있습니다.
    class Linear(keras.layers.Layer):
        def __init__(self, units=32, input_dim=32):
            super(Linear, self).__init__()
            self.w = tf.Variable(initial_value=tf.random_normal_initializer()(shape=(input_dim, units), dtype='float32'))
            self.b = tf.Variable(initial_value=tf.zeros_initializer()(shape=(units, ), dtype='float32'))
            
        def call(self, inputs):
            return tf.matmul(inputs, self.w) + self.b
        
    x = tf.ones((2, 2))
    linear_layer = Linear(4, 2)
    print(linear_layer(x))
    
    tf.Tensor(
    [[ 0.0960293   0.09410477 -0.01649074  0.14715078]
     [ 0.0960293   0.09410477 -0.01649074  0.14715078]], shape=(2, 4), dtype=float32)
    

    주의해야 할 것은 wb 은 레이어의 weights 속성으로 설정되어 자동으로 추적된다는 것이다.
    assert linear_layer.weights == [linear_layer.w, linear_layer.b]
    

    레이어가 제공하는 내장 방법add_weight을 사용하여 권중과 편향을 신속하게 추가할 수 있습니다.
    class Linear(keras.layers.Layer):
        def __init__(self, units=32, input_dim=32):
            super(Linear, self).__init__()
            self.w = self.add_weight(shape=(input_dim, units), initializer='random_normal', trainable=True)
            self.b = self.add_weight(shape=(units, ), initializer='zeros', trainable=True)
            
        def call(self, inputs):
            return tf.matmul(inputs, self.w) + self.b
        
    x = tf.ones((2, 2))
    linear_layer = Linear(4, 2)
    print(linear_layer(x))
    
    tf.Tensor(
    [[ 0.03054511  0.01756009 -0.04622959 -0.10992575]
     [ 0.03054511  0.01756009 -0.04622959 -0.10992575]], shape=(2, 4), dtype=float32)
    

    층의 권중은 훈련에 참여하지 않아도 된다


    층에 추가된 권중도 훈련에 참여하지 않을 수 있다. 즉, 당신이 훈련하는 과정에서 이 권중은 역방향 전파의 계산에 참여하지 않는다는 것이다.다음은 불훈련권을 추가한 예다.
    class ComputeSum(keras.layers.Layer):
        def __init__(self, input_dim):
            super(ComputeSum, self).__init__()
            self.total = self.add_weight(shape=(input_dim, ), initializer='zeros', trainable=False)
        
        def call(self, inputs):
            self.total.assign_add(tf.reduce_sum(inputs, axis=0))
            return self.total
        
    x = tf.ones((2, 2))
    my_sum = ComputeSum(2)
    y = my_sum(x)
    print(y.numpy())
    y = my_sum(x)
    print(y.numpy())
    
    [2. 2.]
    [4. 4.]
    

    훈련에 참여하지 않는 권한은 여전히 weights의 일부분이지만 훈련에 참여하지 않는 것으로 표기된다.
    print('weights: ', len(my_sum.weights))
    print('non-trainable_weights: ', len(my_sum.non_trainable_weights))
    
    #  
    print('trainable_weights: ', len(my_sum.trainable_weights))
    
    weights:  1
    non-trainable_weights:  1
    trainable_weights:  0
    

    권한 재작성 지연


    상기 논리 회귀의 예에서 __init__ 방법은 input_dim 파라미터를 수신하여 권중의 사이즈를 계산하는 데 사용한다.그러나 입력한 치수를 미리 알 수 없는 경우가 많습니다. 이때 권중 생성을 미루거나 실례화 층 이후로 미뤄야 합니다.
    class Linear(keras.layers.Layer):
        def __init__(self, units=32,):
            super(Linear, self).__init__()
            self.units = units
        
        def build(self, input_shape):
            self.w = self.add_weight(shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True)
            self.b = self.add_weight(shape=(self.units, ), initializer='zeros', trainable=True)
            
        def call(self, inputs):
            return tf.matmul(inputs, self.w) + self.b
    
    __call__ 방법은 첫 번째 호출에서 build 방법으로 권중의 지연 생성을 완성합니다.이런 방식은 창설 지연 기능을 편리하게 실현할 수 있다.
    linear_layer = Linear(32)
    y = linear_layer(x)
    

    레이어는 중첩될 수 있습니다.


    때때로 한 층에서 다른 층을 다시 사용해야 하는데, 이때 외부 층은 내부 층의 권중 속성을 자동으로 추적한다.외부층__init__ 방법에서 내부층 대상을 실례화하는 것을 추천합니다. 그러면 내부층build 방법이 실현되면 권중의 초기화를 외부층이 입력할 때까지 늦출 수 있습니다.
    class MLPBlock(keras.layers.Layer):
        def __init__(self):
            super(MLPBlock, self).__init__()
            self.linear_1 = Linear(32)
            self.linear_2 = Linear(32)
            self.linear_3 = Linear(1)
            
        def call(self, inputs):
            x = self.linear_1(inputs)
            x = keras.activations.relu(x)
            x = self.linear_2(x)
            x = keras.activations.relu(x)
            return self.linear_3(x)
        
    x = tf.ones(shape=(3, 64))
    mlp = MLPBlock()
    y = mlp(x)
    print('weights: ', len(mlp.weights))
    print('trainable_weights: ', len(mlp.trainable_weights))
    
    weights:  6
    trainable_weights:  6
    

    추가된 손실을 차례로 수집하다


    실현층의 call 방법을 사용할 때 self.add_loss(value) 한 장량을 손실에 추가하여 뒤에 사용할 수 있다.
    class ActivityRegularizationLayer(keras.layers.Layer):
        def __init__(self, rate=1e-2):
            super(ActivityRegularizationLayer, self).__init__()
            self.rate = rate
        
        def call(self, inputs):
            self.add_loss(self.rate * tf.reduce_sum(inputs))
            return inputs
    

    추가된 손실(내부층 추가 포함)은 층의losses 집합을 통해 얻을 수 있으며, 이 집합은 __call__ 방법이 호출될 때마다 리셋되기 때문에 집합에는 마지막 전방향 전파에서 계산된 결과만 포함됩니다.
    class OuterLayer(keras.layers.Layer):
        def __init__(self):
            super(OuterLayer, self).__init__()
            self.activity_reg = ActivityRegularizationLayer()
        
        def call(self, inputs):
            return self.activity_reg(inputs)
        
    layer = OuterLayer()
    assert len(layer.losses) == 0   #  __call__ , loss 
    _ = layer(tf.zeros((1, 1)))
    assert len(layer.losses) == 1   #  __call__, loss 
    # loss __call__ 
    _ = layer(tf.zeros((1, 1)))
    assert len(layer.losses) == 1   #  __call__, , loss 
    

    또한 losses 집합에는 다른 내부층에 추가된 권한이나 편향에 대한 정규화도 포함된다.
    class OuterLayer(keras.layers.Layer):
        def __init__(self):
            super(OuterLayer, self).__init__()
            self.dense = keras.layers.Dense(32, kernel_regularizer=keras.regularizers.l2(1e-3))
        
        def call(self, inputs):
            return self.dense(inputs)
        
    layer = OuterLayer()
    _ = layer(tf.zeros((1, 1)))
    
    print(layer.losses)
    
    []
    

    훈련 과정을 작성할 때 이 집합의 손실을 추출하여 전체 손실에 추가해야 한다.
    optimizer = keras.optimizers.SGD(learning_rate=1e-3)
    loss_fn = keras.losses.SparseCategoricalCrossentropy(from_logits=True)
    
    for x_train_batch, y_train_batch in train_dataset:
        with tf.GradientTape() as tape:
            logits = model(x_train_batch)
            loss_value = loss_fn(y_train_batch, logits)
            
            loss_value += sum(model.losses)
        
            grads = tape.gradient(loss_value, model.trainable_variables)
            optimizer.apply_gradients(zip(grads, model.train_ables))
    

    더 많은 훈련 세부 사항은 훈련과 검증을 볼 수 있다.

    서열화


    뒤에서 사용자 정의 층을 서열화하기를 원한다면 get_config 을 통해 서열화할 수 있다.
    class Linear(keras.layers.Layer):
        def __init__(self, units=32):
            super(Linear, self).__init__()
            self.units = units
        
        def build(self, input_shape):
            self.w = self.add_weight(shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True)
            self.b = self.add_weight(shape=(self.units, ), initializer='zeros', trainable=True)
            
        def call(self, inputs):
            return tf.matmul(inputs, self.w) + self.b
        
        def get_config(self):
            return {'units': self.units}
        
    layer = Linear(64)
    config = layer.get_config()
    print(config)
    new_layer = Linear.from_config(config)
    
    {'units': 64}
    

    층의 기본 클래스__init__는 이름, 데이터 형식과 같은 관건적인 매개 변수를 받아들일 수 있다. 좋은 습관은 하위 클래스에서 이런 것을 상위 클래스에 전달하고 get_config 방법에 쓰는 것이다.
    class Linear(keras.layers.Layer):
        def __init__(self, units=32, **kwargs):
            super(Linear, self).__init__(**kwargs)
            self.units = units
        
        def build(self, input_shape):
            self.w = self.add_weight(shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True)
            self.b = self.add_weight(shape=(self.units, ), initializer='zeros', trainable=True)
            
        def call(self, inputs):
            return tf.matmul(inputs, self.w) + self.b
        
        def get_config(self):
            config = super(Linear, self).get_config()
            config.update({'units': self.units})
            return config
        
    layer = Linear(64)
    config = layer.get_config()
    print(config)
    new_layer = Linear.from_config(config)
    
    {'name': 'linear_10', 'trainable': True, 'dtype': None, 'units': 64}
    
    config 에서 회복층을 유연하게 하려면 다시 불러오기 from_config 를 통해 스스로 실현할 수 있습니다. 다음은 기본 from_config 방법입니다.
    @classmethod
    def from_config(cls, config):
        return cls(**config)
    

    정렬화 및 반정렬화 방법에 대한 자세한 내용은 모델 저장 및 정렬화 장을 볼 수 있습니다.

    call 방법 중 특수한 훈련 매개 변수


    일부 특수한 층에서 예를 들어 batch normalizationdropout는 훈련과 추측을 할 때 표현이 다르다. 이런 유형의 층에 대해 call 방법을 사용할 때 training 파라미터를 사용하여 그 행위를 제어할 수 있다.이 매개 변수를 통해 모델의 행위와 출력을 정확하게 제어하는 것을 훈련하고 추정할 수 있다.
    class CustomDropout(keras.layers.Layer):
        def __init__(self, rate, **kwargs):
            super(CustomDropout, self).__init__(**kwargs)
            self.rate = rate
    
        def call(self, inputs, training=None):
            if training:
                return tf.nn.dropout(inputs, rate=self.rate)
            return inputs
    

    좋은 웹페이지 즐겨찾기