@@ -138,7 +138,7 @@ public struct Conv2D<Scalar: TensorFlowFloatingPoint>: Layer {
138
138
@noDerivative public let padding : Padding
139
139
/// The dilation factor for spatial dimensions.
140
140
@noDerivative public let dilations : ( Int , Int )
141
-
141
+
142
142
/// The element-wise activation function type.
143
143
public typealias Activation = @differentiable ( Tensor < Scalar > ) -> Tensor < Scalar >
144
144
@@ -470,7 +470,7 @@ public struct DepthwiseConv2D<Scalar: TensorFlowFloatingPoint>: Layer {
470
470
/// The element-wise activation function type.
471
471
public typealias Activation = @differentiable ( Tensor < Scalar > ) -> Tensor < Scalar >
472
472
473
- /// Creates a `DepthwiseConv2D` layer with the specified filter, bias, activation function,
473
+ /// Creates a `DepthwiseConv2D` layer with the specified filter, bias, activation function,
474
474
/// strides, and padding.
475
475
///
476
476
/// - Parameters:
@@ -631,3 +631,111 @@ public struct ZeroPadding3D<Scalar: TensorFlowFloatingPoint>: ParameterlessLayer
631
631
return input. padded ( forSizes: [ padding. 0 , padding. 1 , padding. 2 ] )
632
632
}
633
633
}
634
+
635
+ /// A 2-D Separable convolution layer.
636
+ ///
637
+ /// This layer performs a depthwise convolution that acts separately on channels followed by
638
+ /// a pointwise convolution that mixes channels.
639
+ @frozen
640
+ public struct SeparableConv2D < Scalar: TensorFlowFloatingPoint > : Layer {
641
+ /// The 4-D depthwise convolution kernel.
642
+ public var depthwiseFilter : Tensor < Scalar >
643
+ /// The 4-D pointwise convolution kernel.
644
+ public var pointwiseFilter : Tensor < Scalar >
645
+ /// The bias vector.
646
+ public var bias : Tensor < Scalar >
647
+ /// The element-wise activation function.
648
+ @noDerivative public let activation : Activation
649
+ /// The strides of the sliding window for spatial dimensions.
650
+ @noDerivative public let strides : ( Int , Int )
651
+ /// The padding algorithm for convolution.
652
+ @noDerivative public let padding : Padding
653
+
654
+ /// The element-wise activation function type.
655
+ public typealias Activation = @differentiable ( Tensor < Scalar > ) -> Tensor < Scalar >
656
+
657
+ /// Creates a `SeparableConv2D` layer with the specified depthwise and pointwise filter,
658
+ /// bias, activation function, strides, and padding.
659
+ ///
660
+ /// - Parameters:
661
+ /// - depthwiseFilter: The 4-D depthwise convolution kernel
662
+ /// `[filter height, filter width, input channels count, channel multiplier]`.
663
+ /// - pointwiseFilter: The 4-D pointwise convolution kernel
664
+ /// `[1, 1, channel multiplier * input channels count, output channels count]`.
665
+ /// - bias: The bias vector.
666
+ /// - activation: The element-wise activation function.
667
+ /// - strides: The strides of the sliding window for spatial dimensions.
668
+ /// - padding: The padding algorithm for convolution.
669
+ public init (
670
+ depthwiseFilter: Tensor < Scalar > ,
671
+ pointwiseFilter: Tensor < Scalar > ,
672
+ bias: Tensor < Scalar > ,
673
+ activation: @escaping Activation = identity,
674
+ strides: ( Int , Int ) = ( 1 , 1 ) ,
675
+ padding: Padding = . valid
676
+ ) {
677
+ self . depthwiseFilter = depthwiseFilter
678
+ self . pointwiseFilter = pointwiseFilter
679
+ self . bias = bias
680
+ self . activation = activation
681
+ self . strides = strides
682
+ self . padding = padding
683
+ }
684
+
685
+ /// Returns the output obtained from applying the layer to the given input.
686
+ ///
687
+ /// - Parameter input: The input to the layer.
688
+ /// - Returns: The output.
689
+ @differentiable
690
+ public func callAsFunction( _ input: Tensor < Scalar > ) -> Tensor < Scalar > {
691
+ let depthwise = depthwiseConv2D (
692
+ input,
693
+ filter: depthwiseFilter,
694
+ strides: ( 1 , strides. 0 , strides. 1 , 1 ) ,
695
+ padding: padding)
696
+ return activation ( conv2D (
697
+ depthwise,
698
+ filter: pointwiseFilter,
699
+ strides: ( 1 , 1 , 1 , 1 ) ,
700
+ padding: padding,
701
+ dilations: ( 1 , 1 , 1 , 1 ) ) + bias)
702
+ }
703
+ }
704
+
705
+ public extension SeparableConv2D {
706
+ /// Creates a `SeparableConv2D` layer with the specified depthwise and pointwise filter shape,
707
+ /// strides, padding, and element-wise activation function.
708
+ ///
709
+ /// - Parameters:
710
+ /// - depthwiseFilterShape: The shape of the 4-D depthwise convolution kernel.
711
+ /// - pointwiseFilterShape: The shape of the 4-D pointwise convolution kernel.
712
+ /// - strides: The strides of the sliding window for spatial/spatio-temporal dimensions.
713
+ /// - padding: The padding algorithm for convolution.
714
+ /// - activation: The element-wise activation function.
715
+ /// - filterInitializer: Initializer to use for the filter parameters.
716
+ /// - biasInitializer: Initializer to use for the bias parameters.
717
+ init (
718
+ depthwiseFilterShape: ( Int , Int , Int , Int ) ,
719
+ pointwiseFilterShape: ( Int , Int , Int , Int ) ,
720
+ strides: ( Int , Int ) = ( 1 , 1 ) ,
721
+ padding: Padding = . valid,
722
+ activation: @escaping Activation = identity,
723
+ depthwiseFilterInitializer: ParameterInitializer < Scalar > = glorotUniform ( ) ,
724
+ pointwiseFilterInitializer: ParameterInitializer < Scalar > = glorotUniform ( ) ,
725
+ biasInitializer: ParameterInitializer < Scalar > = zeros ( )
726
+ ) {
727
+ let depthwiseFilterTensorShape = TensorShape ( [
728
+ depthwiseFilterShape. 0 , depthwiseFilterShape. 1 , depthwiseFilterShape. 2 ,
729
+ depthwiseFilterShape. 3 ] )
730
+ let pointwiseFilterTensorShape = TensorShape ( [
731
+ pointwiseFilterShape. 0 , pointwiseFilterShape. 1 , pointwiseFilterShape. 2 ,
732
+ pointwiseFilterShape. 3 ] )
733
+ self . init (
734
+ depthwiseFilter: depthwiseFilterInitializer ( depthwiseFilterTensorShape) ,
735
+ pointwiseFilter: pointwiseFilterInitializer ( pointwiseFilterTensorShape) ,
736
+ bias: biasInitializer ( [ pointwiseFilterShape. 3 ] ) ,
737
+ activation: activation,
738
+ strides: strides,
739
+ padding: padding)
740
+ }
741
+ }
0 commit comments