1# Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Layers that operate regularization via the addition of noise.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import print_function 20 21import numpy as np 22 23from tensorflow.python.keras import backend as K 24from tensorflow.python.keras.engine.base_layer import Layer 25from tensorflow.python.keras.utils import tf_utils 26from tensorflow.python.ops import array_ops 27from tensorflow.python.ops import math_ops 28from tensorflow.python.util.tf_export import keras_export 29 30 31@keras_export('keras.layers.GaussianNoise') 32class GaussianNoise(Layer): 33 """Apply additive zero-centered Gaussian noise. 34 35 This is useful to mitigate overfitting 36 (you could see it as a form of random data augmentation). 37 Gaussian Noise (GS) is a natural choice as corruption process 38 for real valued inputs. 39 40 As it is a regularization layer, it is only active at training time. 41 42 Args: 43 stddev: Float, standard deviation of the noise distribution. 44 45 Call arguments: 46 inputs: Input tensor (of any rank). 47 training: Python boolean indicating whether the layer should behave in 48 training mode (adding noise) or in inference mode (doing nothing). 49 50 Input shape: 51 Arbitrary. Use the keyword argument `input_shape` 52 (tuple of integers, does not include the samples axis) 53 when using this layer as the first layer in a model. 54 55 Output shape: 56 Same shape as input. 57 """ 58 59 def __init__(self, stddev, **kwargs): 60 super(GaussianNoise, self).__init__(**kwargs) 61 self.supports_masking = True 62 self.stddev = stddev 63 64 def call(self, inputs, training=None): 65 66 def noised(): 67 return inputs + K.random_normal( 68 shape=array_ops.shape(inputs), 69 mean=0., 70 stddev=self.stddev, 71 dtype=inputs.dtype) 72 73 return K.in_train_phase(noised, inputs, training=training) 74 75 def get_config(self): 76 config = {'stddev': self.stddev} 77 base_config = super(GaussianNoise, self).get_config() 78 return dict(list(base_config.items()) + list(config.items())) 79 80 @tf_utils.shape_type_conversion 81 def compute_output_shape(self, input_shape): 82 return input_shape 83 84 85@keras_export('keras.layers.GaussianDropout') 86class GaussianDropout(Layer): 87 """Apply multiplicative 1-centered Gaussian noise. 88 89 As it is a regularization layer, it is only active at training time. 90 91 Args: 92 rate: Float, drop probability (as with `Dropout`). 93 The multiplicative noise will have 94 standard deviation `sqrt(rate / (1 - rate))`. 95 96 Call arguments: 97 inputs: Input tensor (of any rank). 98 training: Python boolean indicating whether the layer should behave in 99 training mode (adding dropout) or in inference mode (doing nothing). 100 101 Input shape: 102 Arbitrary. Use the keyword argument `input_shape` 103 (tuple of integers, does not include the samples axis) 104 when using this layer as the first layer in a model. 105 106 Output shape: 107 Same shape as input. 108 """ 109 110 def __init__(self, rate, **kwargs): 111 super(GaussianDropout, self).__init__(**kwargs) 112 self.supports_masking = True 113 self.rate = rate 114 115 def call(self, inputs, training=None): 116 if 0 < self.rate < 1: 117 118 def noised(): 119 stddev = np.sqrt(self.rate / (1.0 - self.rate)) 120 return inputs * K.random_normal( 121 shape=array_ops.shape(inputs), 122 mean=1.0, 123 stddev=stddev, 124 dtype=inputs.dtype) 125 126 return K.in_train_phase(noised, inputs, training=training) 127 return inputs 128 129 def get_config(self): 130 config = {'rate': self.rate} 131 base_config = super(GaussianDropout, self).get_config() 132 return dict(list(base_config.items()) + list(config.items())) 133 134 @tf_utils.shape_type_conversion 135 def compute_output_shape(self, input_shape): 136 return input_shape 137 138 139@keras_export('keras.layers.AlphaDropout') 140class AlphaDropout(Layer): 141 """Applies Alpha Dropout to the input. 142 143 Alpha Dropout is a `Dropout` that keeps mean and variance of inputs 144 to their original values, in order to ensure the self-normalizing property 145 even after this dropout. 146 Alpha Dropout fits well to Scaled Exponential Linear Units 147 by randomly setting activations to the negative saturation value. 148 149 Args: 150 rate: float, drop probability (as with `Dropout`). 151 The multiplicative noise will have 152 standard deviation `sqrt(rate / (1 - rate))`. 153 seed: A Python integer to use as random seed. 154 155 Call arguments: 156 inputs: Input tensor (of any rank). 157 training: Python boolean indicating whether the layer should behave in 158 training mode (adding dropout) or in inference mode (doing nothing). 159 160 Input shape: 161 Arbitrary. Use the keyword argument `input_shape` 162 (tuple of integers, does not include the samples axis) 163 when using this layer as the first layer in a model. 164 165 Output shape: 166 Same shape as input. 167 """ 168 169 def __init__(self, rate, noise_shape=None, seed=None, **kwargs): 170 super(AlphaDropout, self).__init__(**kwargs) 171 self.rate = rate 172 self.noise_shape = noise_shape 173 self.seed = seed 174 self.supports_masking = True 175 176 def _get_noise_shape(self, inputs): 177 return self.noise_shape if self.noise_shape else array_ops.shape(inputs) 178 179 def call(self, inputs, training=None): 180 if 0. < self.rate < 1.: 181 noise_shape = self._get_noise_shape(inputs) 182 183 def dropped_inputs(inputs=inputs, rate=self.rate, seed=self.seed): # pylint: disable=missing-docstring 184 alpha = 1.6732632423543772848170429916717 185 scale = 1.0507009873554804934193349852946 186 alpha_p = -alpha * scale 187 188 kept_idx = math_ops.greater_equal( 189 K.random_uniform(noise_shape, seed=seed), rate) 190 kept_idx = math_ops.cast(kept_idx, inputs.dtype) 191 192 # Get affine transformation params 193 a = ((1 - rate) * (1 + rate * alpha_p**2))**-0.5 194 b = -a * alpha_p * rate 195 196 # Apply mask 197 x = inputs * kept_idx + alpha_p * (1 - kept_idx) 198 199 # Do affine transformation 200 return a * x + b 201 202 return K.in_train_phase(dropped_inputs, inputs, training=training) 203 return inputs 204 205 def get_config(self): 206 config = {'rate': self.rate} 207 base_config = super(AlphaDropout, self).get_config() 208 return dict(list(base_config.items()) + list(config.items())) 209 210 @tf_utils.shape_type_conversion 211 def compute_output_shape(self, input_shape): 212 return input_shape 213