-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathmisc_layers.py
270 lines (233 loc) · 12.2 KB
/
misc_layers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 13 19:14:48 2017
"""
import os
os.environ["KERAS_BACKEND"] = "tensorflow"
import numpy as np
from keras import backend as K
from keras.engine import InputSpec, Layer
from keras import initializers, regularizers, constraints
from keras.utils.generic_utils import get_custom_objects
from keras.utils.conv_utils import conv_output_length
from keras.utils.conv_utils import normalize_data_format
from keras.layers import Conv2D, Conv2DTranspose, SeparableConv2D
from keras.initializers import Constant
K.set_image_dim_ordering('tf')
#From:
#https://github.com/mcgibbon/keras/blob/aaf924ca86f819c1d2493b9e7b3dfd4d3d6c729d/keras/layers/discrimination.py
class MinibatchDiscrimination(Layer):
"""Concatenates to each sample information about how different the input
features for that sample are from features of other samples in the same
minibatch, as described in Salimans et. al. (2016). Useful for preventing
GANs from collapsing to a single output. When using this layer, generated
samples and reference samples should be in separate batches.
# Example
```python
# apply a convolution 1d of length 3 to a sequence with 10 timesteps,
# with 64 output filters
model = Sequential()
model.add(Convolution1D(64, 3, border_mode='same', input_shape=(10, 32)))
# now model.output_shape == (None, 10, 64)
# flatten the output so it can be fed into a minibatch discrimination layer
model.add(Flatten())
# now model.output_shape == (None, 640)
# add the minibatch discrimination layer
model.add(MinibatchDiscrimination(5, 3))
# now model.output_shape = (None, 645)
```
# Arguments
nb_kernels: Number of discrimination kernels to use
(dimensionality concatenated to output).
kernel_dim: The dimensionality of the space where closeness of samples
is calculated.
init: name of initialization function for the weights of the layer
(see [initializations](../initializations.md)),
or alternatively, Theano function to use for weights initialization.
This parameter is only relevant if you don't pass a `weights` argument.
weights: list of numpy arrays to set as initial weights.
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
(eg. L1 or L2 regularization), applied to the main weights matrix.
activity_regularizer: instance of [ActivityRegularizer](../regularizers.md),
applied to the network output.
W_constraint: instance of the [constraints](../constraints.md) module
(eg. maxnorm, nonneg), applied to the main weights matrix.
input_dim: Number of channels/dimensions in the input.
Either this argument or the keyword argument `input_shape`must be
provided when using this layer as the first layer in a model.
# Input shape
2D tensor with shape: `(samples, input_dim)`.
# Output shape
2D tensor with shape: `(samples, input_dim + nb_kernels)`.
# References
- [Improved Techniques for Training GANs](https://arxiv.org/abs/1606.03498)
"""
def __init__(self, nb_kernels, kernel_dim, init='glorot_uniform', weights=None,
W_regularizer=None, activity_regularizer=None,
W_constraint=None, input_dim=None, **kwargs):
self.init = initializers.get(init)
self.nb_kernels = nb_kernels
self.kernel_dim = kernel_dim
self.input_dim = input_dim
self.W_regularizer = regularizers.get(W_regularizer)
self.activity_regularizer = regularizers.get(activity_regularizer)
self.W_constraint = constraints.get(W_constraint)
self.initial_weights = weights
self.input_spec = [InputSpec(ndim=2)]
if self.input_dim:
kwargs['input_shape'] = (self.input_dim,)
super(MinibatchDiscrimination, self).__init__(**kwargs)
def build(self, input_shape):
assert len(input_shape) == 2
input_dim = input_shape[1]
self.input_spec = [InputSpec(dtype=K.floatx(),
shape=(None, input_dim))]
"""
self.W = self.init((self.nb_kernels, input_dim, self.kernel_dim))
self.trainable_weights = [self.W]
self.regularizers = []
if self.W_regularizer:
self.W_regularizer.set_param(self.W)
self.regularizers.append(self.W_regularizer)
if self.activity_regularizer:
self.activity_regularizer.set_layer(self)
self.regularizers.append(self.activity_regularizer)
self.constraints = {}
if self.W_constraint:
self.constraints[self.W] = self.W_constraint
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
del self.initial_weights
"""
self.W = self.add_weight(shape=(self.nb_kernels, input_dim, self.kernel_dim),
initializer=self.init,
name='mbd_kernel',
regularizer=self.W_regularizer,
trainable=True,
constraint=self.W_constraint)
super(MinibatchDiscrimination, self).build(input_shape)
def call(self, x, mask=None):
activation = K.reshape(K.dot(x, self.W), (-1, self.nb_kernels, self.kernel_dim))
diffs = K.expand_dims(activation, 3) - K.expand_dims(K.permute_dimensions(activation, [1, 2, 0]), 0)
abs_diffs = K.sum(K.abs(diffs), axis=2)
minibatch_features = K.sum(K.exp(-abs_diffs), axis=2)
return K.concatenate([x, minibatch_features], 1)
#return minibatch_features
def compute_output_shape(self, input_shape): #renamed from get_output_shape_for (keras 2 support)
assert input_shape and len(input_shape) == 2
return input_shape[0], input_shape[1]+self.nb_kernels
def get_config(self):
config = {'nb_kernels': self.nb_kernels,
'kernel_dim': self.kernel_dim,
'init': self.init.__name__,
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
'input_dim': self.input_dim}
base_config = super(MinibatchDiscrimination, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
#https://github.com/WeidiXie/New_Layers-Keras-Tensorflow/blob/master/src/subpix_upsampling.py
#OR
#BELOW (https://github.com/farizrahman4u/keras-contrib/blob/a7520c8f520bb5643ff9a62d1b3532fe72ab7283/keras_contrib/layers/convolutional.py)
class SubPixelUpscaling(Layer):
""" Sub-pixel convolutional upscaling layer based on the paper "Real-Time Single Image
and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network"
(https://arxiv.org/abs/1609.05158).
This layer requires a Convolution2D prior to it, having output filters computed according to
the formula :
filters = k * (scale_factor * scale_factor)
where k = a user defined number of filters (generally larger than 32)
scale_factor = the upscaling factor (generally 2)
This layer performs the depth to space operation on the convolution filters, and returns a
tensor with the size as defined below.
# Example :
```python
# A standard subpixel upscaling block
x = Convolution2D(256, 3, 3, padding='same', activation='relu')(...)
u = SubPixelUpscaling(scale_factor=2)(x)
[Optional]
x = Convolution2D(256, 3, 3, padding='same', activation='relu')(u)
```
In practice, it is useful to have a second convolution layer after the
SubPixelUpscaling layer to speed up the learning process.
However, if you are stacking multiple SubPixelUpscaling blocks, it may increase
the number of parameters greatly, so the Convolution layer after SubPixelUpscaling
layer can be removed.
# Arguments
scale_factor: Upscaling factor.
data_format: Can be None, 'channels_first' or 'channels_last'.
# Input shape
4D tensor with shape:
`(samples, k * (scale_factor * scale_factor) channels, rows, cols)` if data_format='channels_first'
or 4D tensor with shape:
`(samples, rows, cols, k * (scale_factor * scale_factor) channels)` if data_format='channels_last'.
# Output shape
4D tensor with shape:
`(samples, k channels, rows * scale_factor, cols * scale_factor))` if data_format='channels_first'
or 4D tensor with shape:
`(samples, rows * scale_factor, cols * scale_factor, k channels)` if data_format='channels_last'.
"""
def __init__(self, scale_factor=2, data_format=None, **kwargs):
super(SubPixelUpscaling, self).__init__(**kwargs)
self.scale_factor = scale_factor
self.data_format = normalize_data_format(data_format)
def build(self, input_shape):
pass
def call(self, x, mask=None):
y = K.depth_to_space(x, self.scale_factor, self.data_format)
return y
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
b, k, r, c = input_shape
return (b, k // (self.scale_factor ** 2), r * self.scale_factor, c * self.scale_factor)
else:
b, r, c, k = input_shape
return (b, r * self.scale_factor, c * self.scale_factor, k // (self.scale_factor ** 2))
def get_config(self):
config = {'scale_factor': self.scale_factor,
'data_format': self.data_format}
base_config = super(SubPixelUpscaling, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
#https://github.com/tdrussell/IllustrationGAN/blob/master/custom_ops.py
class CustomLRELU(Layer):
"""
https://github.com/tdrussell/IllustrationGAN/blob/master/custom_ops.py
"""
def __init__(self, alpha=0.3, **kwargs):
super(CustomLRELU, self).__init__(**kwargs)
self.supports_masking = True
self.alpha = K.cast_to_floatx(alpha)
def call(self, inputs):
return K.maximum(inputs, self.alpha * inputs)
def get_config(self):
config = {'alpha': float(self.alpha)}
base_config = super(CustomLRELU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
def upsample_filt(size):
factor = (size + 1) // 2
if size % 2 == 1:
center = factor - 1
else:
center = factor - 0.5
og = np.ogrid[:size, :size]
return (1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor)
def bilinear_upsample_weights(factor, number_of_classes):
filter_size = factor*2 - factor%2
weights = np.zeros((filter_size, filter_size, number_of_classes, number_of_classes),
dtype=np.float32)
upsample_kernel = upsample_filt(filter_size)
for i in range(number_of_classes):
weights[:, :, i, i] = upsample_kernel
return weights
#https://github.com/rcmalli/keras-mobilenet/blob/master/keras_mobilenet/depthwise_conv2d.py
def bilinear2x(layer,num_kernels,kernel_size=(5,5),strides=(2,2),factor = 2):
"""
https://kivantium.net/keras-bilinear
#NHWC format
filter_shape = [kernel_size[0], kernel_size[0], num_inp_channels, num_filters]
https://www.tensorflow.org/api_docs/python/tf/nn/depthwise_conv2d_native_backprop_input
"""
#new_layer = Conv2DTranspose(filters = num_kernels, kernel_size = kernel_size, strides = strides, padding='same', kernel_initializer=Constant(bilinear_upsample_weights(factor, num_kernels)),trainable=False)(layer)
new_layer = Conv2DTranspose(filters = num_kernels, kernel_size = kernel_size, strides = strides, padding='same', kernel_initializer=Constant(bilinear_upsample_weights(factor, num_kernels)))(layer)
#print('ello')
return new_layer