Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/keras/src/layers/locally_connected/locally_connected1d.py: 24%
94 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
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# ==============================================================================
16"""Locally-connected layer for 1D input."""
18from keras.src import activations
19from keras.src import backend
20from keras.src import constraints
21from keras.src import initializers
22from keras.src import regularizers
23from keras.src.engine.base_layer import Layer
24from keras.src.engine.input_spec import InputSpec
25from keras.src.layers.locally_connected import locally_connected_utils
26from keras.src.utils import conv_utils
27from keras.src.utils import tf_utils
29# isort: off
30from tensorflow.python.util.tf_export import keras_export
33@keras_export("keras.layers.LocallyConnected1D")
34class LocallyConnected1D(Layer):
35 """Locally-connected layer for 1D inputs.
37 The `LocallyConnected1D` layer works similarly to
38 the `Conv1D` layer, except that weights are unshared,
39 that is, a different set of filters is applied at each different patch
40 of the input.
42 Note: layer attributes cannot be modified after the layer has been called
43 once (except the `trainable` attribute).
45 Example:
46 ```python
47 # apply a unshared weight convolution 1d of length 3 to a sequence with
48 # 10 timesteps, with 64 output filters
49 model = Sequential()
50 model.add(LocallyConnected1D(64, 3, input_shape=(10, 32)))
51 # now model.output_shape == (None, 8, 64)
52 # add a new conv1d on top
53 model.add(LocallyConnected1D(32, 3))
54 # now model.output_shape == (None, 6, 32)
55 ```
57 Args:
58 filters: Integer, the dimensionality of the output space (i.e. the
59 number of output filters in the convolution).
60 kernel_size: An integer or tuple/list of a single integer, specifying
61 the length of the 1D convolution window.
62 strides: An integer or tuple/list of a single integer, specifying the
63 stride length of the convolution.
64 padding: Currently only supports `"valid"` (case-insensitive). `"same"`
65 may be supported in the future. `"valid"` means no padding.
66 data_format: A string, one of `channels_last` (default) or
67 `channels_first`. The ordering of the dimensions in the inputs.
68 `channels_last` corresponds to inputs with shape `(batch, length,
69 channels)` while `channels_first` corresponds to inputs with shape
70 `(batch, channels, length)`. When unspecified, uses
71 `image_data_format` value found in your Keras config file at
72 `~/.keras/keras.json` (if exists) else 'channels_last'.
73 Defaults to 'channels_last'.
74 activation: Activation function to use. If you don't specify anything,
75 no activation is applied (ie. "linear" activation: `a(x) = x`).
76 use_bias: Boolean, whether the layer uses a bias vector.
77 kernel_initializer: Initializer for the `kernel` weights matrix.
78 bias_initializer: Initializer for the bias vector.
79 kernel_regularizer: Regularizer function applied to the `kernel` weights
80 matrix.
81 bias_regularizer: Regularizer function applied to the bias vector.
82 activity_regularizer: Regularizer function applied to the output of the
83 layer (its "activation")..
84 kernel_constraint: Constraint function applied to the kernel matrix.
85 bias_constraint: Constraint function applied to the bias vector.
86 implementation: implementation mode, either `1`, `2`, or `3`. `1` loops
87 over input spatial locations to perform the forward pass. It is
88 memory-efficient but performs a lot of (small) ops. `2` stores layer
89 weights in a dense but sparsely-populated 2D matrix and implements the
90 forward pass as a single matrix-multiply. It uses a lot of RAM but
91 performs few (large) ops. `3` stores layer weights in a sparse tensor
92 and implements the forward pass as a single sparse matrix-multiply.
93 How to choose:
94 `1`: large, dense models,
95 `2`: small models,
96 `3`: large, sparse models, where "large" stands for large
97 input/output activations (i.e. many `filters`, `input_filters`,
98 large `input_size`, `output_size`), and "sparse" stands for few
99 connections between inputs and outputs, i.e. small ratio
100 `filters * input_filters * kernel_size / (input_size * strides)`,
101 where inputs to and outputs of the layer are assumed to have
102 shapes `(input_size, input_filters)`, `(output_size, filters)`
103 respectively. It is recommended to benchmark each in the setting
104 of interest to pick the most efficient one (in terms of speed and
105 memory usage). Correct choice of implementation can lead to
106 dramatic speed improvements (e.g. 50X), potentially at the expense
107 of RAM. Also, only `padding="valid"` is supported by
108 `implementation=1`.
109 Input shape:
110 3D tensor with shape: `(batch_size, steps, input_dim)`
111 Output shape:
112 3D tensor with shape: `(batch_size, new_steps, filters)` `steps` value
113 might have changed due to padding or strides.
114 """
116 def __init__(
117 self,
118 filters,
119 kernel_size,
120 strides=1,
121 padding="valid",
122 data_format=None,
123 activation=None,
124 use_bias=True,
125 kernel_initializer="glorot_uniform",
126 bias_initializer="zeros",
127 kernel_regularizer=None,
128 bias_regularizer=None,
129 activity_regularizer=None,
130 kernel_constraint=None,
131 bias_constraint=None,
132 implementation=1,
133 **kwargs,
134 ):
135 super().__init__(**kwargs)
136 self.filters = filters
137 self.kernel_size = conv_utils.normalize_tuple(
138 kernel_size, 1, "kernel_size"
139 )
140 self.strides = conv_utils.normalize_tuple(
141 strides, 1, "strides", allow_zero=True
142 )
143 self.padding = conv_utils.normalize_padding(padding)
144 if self.padding != "valid" and implementation == 1:
145 raise ValueError(
146 "Invalid border mode for LocallyConnected1D "
147 '(only "valid" is supported if implementation is 1): ' + padding
148 )
149 self.data_format = conv_utils.normalize_data_format(data_format)
150 self.activation = activations.get(activation)
151 self.use_bias = use_bias
152 self.kernel_initializer = initializers.get(kernel_initializer)
153 self.bias_initializer = initializers.get(bias_initializer)
154 self.kernel_regularizer = regularizers.get(kernel_regularizer)
155 self.bias_regularizer = regularizers.get(bias_regularizer)
156 self.activity_regularizer = regularizers.get(activity_regularizer)
157 self.kernel_constraint = constraints.get(kernel_constraint)
158 self.bias_constraint = constraints.get(bias_constraint)
159 self.implementation = implementation
160 self.input_spec = InputSpec(ndim=3)
162 @property
163 def _use_input_spec_as_call_signature(self):
164 return False
166 @tf_utils.shape_type_conversion
167 def build(self, input_shape):
168 if self.data_format == "channels_first":
169 input_dim, input_length = input_shape[1], input_shape[2]
170 else:
171 input_dim, input_length = input_shape[2], input_shape[1]
173 if input_dim is None:
174 raise ValueError(
175 "Axis 2 of input should be fully-defined. Found shape:",
176 input_shape,
177 )
178 self.output_length = conv_utils.conv_output_length(
179 input_length, self.kernel_size[0], self.padding, self.strides[0]
180 )
182 if self.output_length <= 0:
183 raise ValueError(
184 "One of the dimensions in the output is <= 0 "
185 f"due to downsampling in {self.name}. Consider "
186 "increasing the input size. "
187 f"Received input shape {input_shape} which would produce "
188 "output shape with a zero or negative value in a "
189 "dimension."
190 )
192 if self.implementation == 1:
193 self.kernel_shape = (
194 self.output_length,
195 self.kernel_size[0] * input_dim,
196 self.filters,
197 )
199 self.kernel = self.add_weight(
200 shape=self.kernel_shape,
201 initializer=self.kernel_initializer,
202 name="kernel",
203 regularizer=self.kernel_regularizer,
204 constraint=self.kernel_constraint,
205 )
207 elif self.implementation == 2:
208 if self.data_format == "channels_first":
209 self.kernel_shape = (
210 input_dim,
211 input_length,
212 self.filters,
213 self.output_length,
214 )
215 else:
216 self.kernel_shape = (
217 input_length,
218 input_dim,
219 self.output_length,
220 self.filters,
221 )
223 self.kernel = self.add_weight(
224 shape=self.kernel_shape,
225 initializer=self.kernel_initializer,
226 name="kernel",
227 regularizer=self.kernel_regularizer,
228 constraint=self.kernel_constraint,
229 )
231 self.kernel_mask = (
232 locally_connected_utils.get_locallyconnected_mask(
233 input_shape=(input_length,),
234 kernel_shape=self.kernel_size,
235 strides=self.strides,
236 padding=self.padding,
237 data_format=self.data_format,
238 )
239 )
241 elif self.implementation == 3:
242 self.kernel_shape = (
243 self.output_length * self.filters,
244 input_length * input_dim,
245 )
247 self.kernel_idxs = sorted(
248 conv_utils.conv_kernel_idxs(
249 input_shape=(input_length,),
250 kernel_shape=self.kernel_size,
251 strides=self.strides,
252 padding=self.padding,
253 filters_in=input_dim,
254 filters_out=self.filters,
255 data_format=self.data_format,
256 )
257 )
259 self.kernel = self.add_weight(
260 shape=(len(self.kernel_idxs),),
261 initializer=self.kernel_initializer,
262 name="kernel",
263 regularizer=self.kernel_regularizer,
264 constraint=self.kernel_constraint,
265 )
267 else:
268 raise ValueError(
269 "Unrecognized implementation mode: %d." % self.implementation
270 )
272 if self.use_bias:
273 self.bias = self.add_weight(
274 shape=(self.output_length, self.filters),
275 initializer=self.bias_initializer,
276 name="bias",
277 regularizer=self.bias_regularizer,
278 constraint=self.bias_constraint,
279 )
280 else:
281 self.bias = None
283 if self.data_format == "channels_first":
284 self.input_spec = InputSpec(ndim=3, axes={1: input_dim})
285 else:
286 self.input_spec = InputSpec(ndim=3, axes={-1: input_dim})
287 self.built = True
289 @tf_utils.shape_type_conversion
290 def compute_output_shape(self, input_shape):
291 if self.data_format == "channels_first":
292 input_length = input_shape[2]
293 else:
294 input_length = input_shape[1]
296 length = conv_utils.conv_output_length(
297 input_length, self.kernel_size[0], self.padding, self.strides[0]
298 )
300 if self.data_format == "channels_first":
301 return (input_shape[0], self.filters, length)
302 elif self.data_format == "channels_last":
303 return (input_shape[0], length, self.filters)
305 def call(self, inputs):
306 if self.implementation == 1:
307 output = backend.local_conv(
308 inputs,
309 self.kernel,
310 self.kernel_size,
311 self.strides,
312 (self.output_length,),
313 self.data_format,
314 )
316 elif self.implementation == 2:
317 output = locally_connected_utils.local_conv_matmul(
318 inputs,
319 self.kernel,
320 self.kernel_mask,
321 self.compute_output_shape(inputs.shape),
322 )
324 elif self.implementation == 3:
325 output = locally_connected_utils.local_conv_sparse_matmul(
326 inputs,
327 self.kernel,
328 self.kernel_idxs,
329 self.kernel_shape,
330 self.compute_output_shape(inputs.shape),
331 )
333 else:
334 raise ValueError(
335 "Unrecognized implementation mode: %d." % self.implementation
336 )
338 if self.use_bias:
339 output = backend.bias_add(
340 output, self.bias, data_format=self.data_format
341 )
343 output = self.activation(output)
344 return output
346 def get_config(self):
347 config = {
348 "filters": self.filters,
349 "kernel_size": self.kernel_size,
350 "strides": self.strides,
351 "padding": self.padding,
352 "data_format": self.data_format,
353 "activation": activations.serialize(self.activation),
354 "use_bias": self.use_bias,
355 "kernel_initializer": initializers.serialize(
356 self.kernel_initializer
357 ),
358 "bias_initializer": initializers.serialize(self.bias_initializer),
359 "kernel_regularizer": regularizers.serialize(
360 self.kernel_regularizer
361 ),
362 "bias_regularizer": regularizers.serialize(self.bias_regularizer),
363 "activity_regularizer": regularizers.serialize(
364 self.activity_regularizer
365 ),
366 "kernel_constraint": constraints.serialize(self.kernel_constraint),
367 "bias_constraint": constraints.serialize(self.bias_constraint),
368 "implementation": self.implementation,
369 }
370 base_config = super().get_config()
371 return dict(list(base_config.items()) + list(config.items()))