opus/dnn/gatedconv.py
Jean-Marc Valin b6af21f31c wip...
2018-07-23 17:05:21 -04:00

65 lines
2.5 KiB
Python

from keras import backend as K
from keras.engine.topology import Layer
from keras.layers import activations, initializers, regularizers, constraints, InputSpec, Conv1D, Dense
import numpy as np
class GatedConv(Conv1D):
def __init__(self, filters,
kernel_size,
dilation_rate=1,
activation='tanh',
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='zeros',
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
return_memory=False,
**kwargs):
super(GatedConv, self).__init__(
filters=2*filters,
kernel_size=kernel_size,
strides=1,
padding='valid',
data_format='channels_last',
dilation_rate=dilation_rate,
activation='linear',
use_bias=use_bias,
kernel_initializer=kernel_initializer,
bias_initializer=bias_initializer,
kernel_regularizer=kernel_regularizer,
bias_regularizer=bias_regularizer,
activity_regularizer=activity_regularizer,
kernel_constraint=kernel_constraint,
bias_constraint=bias_constraint,
**kwargs)
self.mem_size = dilation_rate*(kernel_size-1)
self.return_memory = return_memory
self.out_dims = filters
self.nongate_activation = activations.get(activation)
def call(self, inputs, cond=None, memory=None):
if memory is None:
mem = K.zeros((K.shape(inputs)[0], self.mem_size, K.shape(inputs)[-1]))
else:
mem = K.variable(K.cast_to_floatx(memory))
inputs = K.concatenate([mem, inputs], axis=1)
ret = super(GatedConv, self).call(inputs)
if cond is not None:
d = Dense(2*self.out_dims, use_bias=False, activation='linear')
ret = ret + d(cond)
ret = self.nongate_activation(ret[:, :, :self.out_dims]) * activations.sigmoid(ret[:, :, self.out_dims:])
if self.return_memory:
ret = ret, inputs[:, :self.mem_size, :]
return ret
def compute_output_shape(self, input_shape):
assert input_shape and len(input_shape) >= 2
assert input_shape[-1]
output_shape = list(input_shape)
output_shape[-1] = self.out_dims
return tuple(output_shape)