constructor(attrs = {}) {
    super(attrs)
    this.layerClass = 'Conv1D'

    const {
      filters = 1,
      kernel_size = 1,
      strides = 1,
      padding = 'valid',
      dilation_rate = 1,
      activation = 'linear',
      use_bias = true
    } = attrs

    this.description = `${filters} filters of size ${kernel_size}, striding ${strides}`
    this.description += padding === 'valid' ? `, no border padding` : ', pad to same borders'
    this.description += dilation_rate > 1 ? `, dilation rate ${dilation_rate}` : ''
    this.description += activation !== 'linear' ? `, ${activation} activation` : ''

    if (padding !== 'valid' && padding !== 'same') {
      this.throwError('Invalid padding.')
    }

    if (dilation_rate !== 1 && strides !== 1) {
      // Currently, specifying any dilation_rate value != 1 is incompatible with specifying any stride value != 1
      // https://keras.io/layers/convolutional/#conv1d
      this.throwError('Incompatible combination of dilation_rate with strides.')
    }

    this.use_bias = use_bias

    // Layer weights specification
    this.params = this.use_bias ? ['kernel', 'bias'] : ['kernel']

    // Bootstrap Conv2D layer:
    // Conv1D is actually a shim on top of Conv2D, where
    // all of the computational action is performed
    // Note that we use `channels_first` dim ordering here.
    const conv2dAttrs = {
      filters,
      kernel_size: [kernel_size, 1],
      strides: [strides, 1],
      padding,
      data_format: 'channels_first',
      dilation_rate,
      activation,
      use_bias
    }
    this._conv2dAttrs = conv2dAttrs
    this._conv2d = new Conv2D(Object.assign(conv2dAttrs, { gpu: attrs.gpu }))
  }
Creates a Conv1D layer

@param {Object} [attrs] - layer config attributes
@param {number} [attrs.filters] - Number of convolution filters to use
@param {number} [attrs.kernel_size] - Length of 1D convolution kernel