Skip to content
This repository was archived by the owner on Jul 1, 2023. It is now read-only.

Commit 02f31d5

Browse files
Adding dilations argument inside DepthwiseConv2D API (#1129)
* Update NN.swift Add dilations argument inside depthwiseConv2D function. * Update Convolutional.swift Updated depthwiseConv2D struct to include the dilations functionality as well. * Update Convolutional.swift Dilations argument added in SeparableConv2D * Updating X10 tests with dilations parameter. * Update ops_test.swift Correcting dilation argument inside depthwiseConv2D function. * Update NN.swift Update depthwiseconv2D() function's strides and dilations argument with default (1, 1, 1, 1) value. Co-authored-by: Brad Larson <bradlarson@google.com>
1 parent 66ae638 commit 02f31d5

File tree

3 files changed

+71
-34
lines changed

3 files changed

+71
-34
lines changed

Sources/TensorFlow/Layers/Convolutional.swift

+37-10
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,8 @@ public struct DepthwiseConv2D<Scalar: TensorFlowFloatingPoint>: Layer {
708708
@noDerivative public let strides: (Int, Int)
709709
/// The padding algorithm for convolution.
710710
@noDerivative public let padding: Padding
711+
/// The dilation factor for spatial dimensions.
712+
@noDerivative public let dilations: (Int, Int)
711713
/// Note: `useBias` is a workaround for TF-1153: optional differentiation support.
712714
@noDerivative private let useBias: Bool
713715

@@ -723,18 +725,21 @@ public struct DepthwiseConv2D<Scalar: TensorFlowFloatingPoint>: Layer {
723725
/// - activation: The element-wise activation function.
724726
/// - strides: The strides of the sliding window for spatial dimensions.
725727
/// - padding: The padding algorithm for convolution.
728+
/// - dilations: The dilation factors for spatial dimensions.
726729
public init(
727730
filter: Tensor<Scalar>,
728731
bias: Tensor<Scalar>? = nil,
729732
activation: @escaping Activation = identity,
730733
strides: (Int, Int) = (1, 1),
731-
padding: Padding = .valid
734+
padding: Padding = .valid,
735+
dilations: (Int, Int) = (1, 1)
732736
) {
733737
self.filter = filter
734738
self.bias = bias ?? .zero
735739
self.activation = activation
736740
self.strides = strides
737741
self.padding = padding
742+
self.dilations = dilations
738743
useBias = (bias != nil)
739744
}
740745

@@ -750,7 +755,8 @@ public struct DepthwiseConv2D<Scalar: TensorFlowFloatingPoint>: Layer {
750755
input,
751756
filter: filter,
752757
strides: (1, strides.0, strides.1, 1),
753-
padding: padding)
758+
padding: padding,
759+
dilations: (1, dilations.0, dilations.1, 1))
754760
return activation(useBias ? (conv + bias) : conv)
755761
}
756762
}
@@ -771,6 +777,7 @@ extension DepthwiseConv2D {
771777
filterShape: (Int, Int, Int, Int),
772778
strides: (Int, Int) = (1, 1),
773779
padding: Padding = .valid,
780+
dilations: (Int, Int) = (1, 1),
774781
activation: @escaping Activation = identity,
775782
useBias: Bool = true,
776783
filterInitializer: ParameterInitializer<Scalar> = glorotUniform(),
@@ -784,7 +791,8 @@ extension DepthwiseConv2D {
784791
bias: useBias ? biasInitializer([filterShape.2 * filterShape.3]) : nil,
785792
activation: activation,
786793
strides: strides,
787-
padding: padding)
794+
padding: padding,
795+
dilations: dilations)
788796
}
789797
}
790798

@@ -901,12 +909,15 @@ public struct SeparableConv1D<Scalar: TensorFlowFloatingPoint>: Layer {
901909
public var pointwiseFilter: Tensor<Scalar>
902910
/// The bias vector.
903911
public var bias: Tensor<Scalar>
912+
904913
/// The element-wise activation function.
905914
@noDerivative public let activation: Activation
906915
/// The strides of the sliding window for spatial dimensions.
907916
@noDerivative public let stride: Int
908917
/// The padding algorithm for convolution.
909918
@noDerivative public let padding: Padding
919+
/// The dilation factor for the temporal dimension.
920+
@noDerivative public let dilation: Int
910921
/// Note: `useBias` is a workaround for TF-1153: optional differentiation support.
911922
@noDerivative private let useBias: Bool
912923

@@ -925,20 +936,23 @@ public struct SeparableConv1D<Scalar: TensorFlowFloatingPoint>: Layer {
925936
/// - activation: The element-wise activation function.
926937
/// - strides: The strides of the sliding window for spatial dimensions.
927938
/// - padding: The padding algorithm for convolution.
939+
/// - dilation: The dilation factor for the temporal dimension.
928940
public init(
929941
depthwiseFilter: Tensor<Scalar>,
930942
pointwiseFilter: Tensor<Scalar>,
931943
bias: Tensor<Scalar>? = nil,
932944
activation: @escaping Activation = identity,
933945
stride: Int = 1,
934-
padding: Padding = .valid
946+
padding: Padding = .valid,
947+
dilation: Int = 1
935948
) {
936949
self.depthwiseFilter = depthwiseFilter
937950
self.pointwiseFilter = pointwiseFilter
938951
self.bias = bias ?? .zero
939952
self.activation = activation
940953
self.stride = stride
941954
self.padding = padding
955+
self.dilation = dilation
942956
useBias = (bias != nil)
943957
}
944958

@@ -952,7 +966,8 @@ public struct SeparableConv1D<Scalar: TensorFlowFloatingPoint>: Layer {
952966
input.expandingShape(at: 1),
953967
filter: depthwiseFilter.expandingShape(at: 1),
954968
strides: (1, stride, stride, 1),
955-
padding: padding)
969+
padding: padding,
970+
dilations: (1, dilation, dilation, 1))
956971
let x = conv2D(
957972
depthwise,
958973
filter: pointwiseFilter.expandingShape(at: 1),
@@ -970,8 +985,9 @@ extension SeparableConv1D {
970985
/// - Parameters:
971986
/// - depthwiseFilterShape: The shape of the 3-D depthwise convolution kernel.
972987
/// - pointwiseFilterShape: The shape of the 3-D pointwise convolution kernel.
973-
/// - strides: The strides of the sliding window for temporal dimensions.
988+
/// - stride: The stride of the sliding window for temporal dimensions.
974989
/// - padding: The padding algorithm for convolution.
990+
/// - dilation: The dilation factor for the temporal dimension.
975991
/// - activation: The element-wise activation function.
976992
/// - filterInitializer: Initializer to use for the filter parameters.
977993
/// - biasInitializer: Initializer to use for the bias parameters.
@@ -980,6 +996,7 @@ extension SeparableConv1D {
980996
pointwiseFilterShape: (Int, Int, Int),
981997
stride: Int = 1,
982998
padding: Padding = .valid,
999+
dilation: Int = 1,
9831000
activation: @escaping Activation = identity,
9841001
useBias: Bool = true,
9851002
depthwiseFilterInitializer: ParameterInitializer<Scalar> = glorotUniform(),
@@ -998,7 +1015,8 @@ extension SeparableConv1D {
9981015
bias: useBias ? biasInitializer([pointwiseFilterShape.2]) : nil,
9991016
activation: activation,
10001017
stride: stride,
1001-
padding: padding)
1018+
padding: padding,
1019+
dilation: dilation)
10021020
}
10031021
}
10041022

@@ -1020,6 +1038,8 @@ public struct SeparableConv2D<Scalar: TensorFlowFloatingPoint>: Layer {
10201038
@noDerivative public let strides: (Int, Int)
10211039
/// The padding algorithm for convolution.
10221040
@noDerivative public let padding: Padding
1041+
/// The dilation factor for spatial dimensions.
1042+
@noDerivative public let dilations: (Int, Int)
10231043
/// Note: `useBias` is a workaround for TF-1153: optional differentiation support.
10241044
@noDerivative private let useBias: Bool
10251045

@@ -1038,20 +1058,23 @@ public struct SeparableConv2D<Scalar: TensorFlowFloatingPoint>: Layer {
10381058
/// - activation: The element-wise activation function.
10391059
/// - strides: The strides of the sliding window for spatial dimensions.
10401060
/// - padding: The padding algorithm for convolution.
1061+
/// - dilations: The dilation factors for spatial dimensions.
10411062
public init(
10421063
depthwiseFilter: Tensor<Scalar>,
10431064
pointwiseFilter: Tensor<Scalar>,
10441065
bias: Tensor<Scalar>? = nil,
10451066
activation: @escaping Activation = identity,
10461067
strides: (Int, Int) = (1, 1),
1047-
padding: Padding = .valid
1068+
padding: Padding = .valid,
1069+
dilations: (Int, Int) = (1, 1)
10481070
) {
10491071
self.depthwiseFilter = depthwiseFilter
10501072
self.pointwiseFilter = pointwiseFilter
10511073
self.bias = bias ?? .zero
10521074
self.activation = activation
10531075
self.strides = strides
10541076
self.padding = padding
1077+
self.dilations = dilations
10551078
useBias = (bias != nil)
10561079
}
10571080

@@ -1065,7 +1088,8 @@ public struct SeparableConv2D<Scalar: TensorFlowFloatingPoint>: Layer {
10651088
input,
10661089
filter: depthwiseFilter,
10671090
strides: (1, strides.0, strides.1, 1),
1068-
padding: padding)
1091+
padding: padding,
1092+
dilations: (1, dilations.0, dilations.1, 1))
10691093
let conv = conv2D(
10701094
depthwise,
10711095
filter: pointwiseFilter,
@@ -1085,6 +1109,7 @@ extension SeparableConv2D {
10851109
/// - pointwiseFilterShape: The shape of the 4-D pointwise convolution kernel.
10861110
/// - strides: The strides of the sliding window for spatial/spatio-temporal dimensions.
10871111
/// - padding: The padding algorithm for convolution.
1112+
/// - dilations: The dilation factors for spatial dimensions.
10881113
/// - activation: The element-wise activation function.
10891114
/// - filterInitializer: Initializer to use for the filter parameters.
10901115
/// - biasInitializer: Initializer to use for the bias parameters.
@@ -1093,6 +1118,7 @@ extension SeparableConv2D {
10931118
pointwiseFilterShape: (Int, Int, Int, Int),
10941119
strides: (Int, Int) = (1, 1),
10951120
padding: Padding = .valid,
1121+
dilations: (Int, Int) = (1, 1),
10961122
activation: @escaping Activation = identity,
10971123
useBias: Bool = true,
10981124
depthwiseFilterInitializer: ParameterInitializer<Scalar> = glorotUniform(),
@@ -1113,6 +1139,7 @@ extension SeparableConv2D {
11131139
bias: useBias ? biasInitializer([pointwiseFilterShape.3]) : nil,
11141140
activation: activation,
11151141
strides: strides,
1116-
padding: padding)
1142+
padding: padding,
1143+
dilations: dilations)
11171144
}
11181145
}

Sources/TensorFlow/Operators/NN.swift

+30-21
Original file line numberDiff line numberDiff line change
@@ -460,16 +460,18 @@ func _vjpConv3DBackpropFilter<Scalar: TensorFlowFloatingPoint>(
460460
public func depthwiseConv2D<Scalar: TensorFlowFloatingPoint>(
461461
_ input: Tensor<Scalar>,
462462
filter: Tensor<Scalar>,
463-
strides: (Int, Int, Int, Int),
464-
padding: Padding
463+
strides: (Int, Int, Int, Int) = (1, 1, 1, 1),
464+
padding: Padding,
465+
dilations: (Int, Int, Int, Int) = (1, 1, 1, 1)
465466
) -> Tensor<Scalar> {
466467
precondition(input.shape.rank == 4, "The input must have rank 4.")
467468
precondition(filter.shape.rank == 4, "The filter must have rank 4.")
468469
return _Raw.depthwiseConv2dNative(
469470
input,
470471
filter: filter,
471472
strides: [Int32(strides.0), Int32(strides.1), Int32(strides.2), Int32(strides.3)],
472-
padding: padding.raw)
473+
padding: padding.raw,
474+
dilations: [Int32(dilations.0), Int32(dilations.1), Int32(dilations.2), Int32(dilations.3)])
473475
}
474476

475477
@usableFromInline
@@ -478,21 +480,22 @@ func _vjpDepthwiseConv2D<Scalar: TensorFlowFloatingPoint>(
478480
_ x: Tensor<Scalar>,
479481
filter: Tensor<Scalar>,
480482
strides: (Int, Int, Int, Int),
481-
padding: Padding
483+
padding: Padding,
484+
dilations: (Int, Int, Int, Int)
482485
) -> (value: Tensor<Scalar>, pullback: (Tensor<Scalar>) -> (Tensor<Scalar>, Tensor<Scalar>)) {
483486
let value = depthwiseConv2D(
484487
x, filter: filter, strides: strides,
485-
padding: padding)
488+
padding: padding, dilations: dilations)
486489
return (
487490
value,
488491
{ v in
489492
(
490493
depthwiseConv2dBackpropInput(
491494
v, shape: x.shapeTensor, filter: filter,
492-
strides: strides, padding: padding),
495+
strides: strides, padding: padding, dilations: dilations),
493496
depthwiseConv2dBackpropFilter(
494497
v, input: x, filterSizes: filter.shapeTensor,
495-
strides: strides, padding: padding)
498+
strides: strides, padding: padding, dilations: dilations)
496499
)
497500
}
498501
)
@@ -505,15 +508,17 @@ func depthwiseConv2dBackpropInput<Scalar: TensorFlowFloatingPoint>(
505508
_ x: Tensor<Scalar>,
506509
shape: Tensor<Int32>,
507510
filter: Tensor<Scalar>,
508-
strides: (Int, Int, Int, Int),
509-
padding: Padding
511+
strides: (Int, Int, Int, Int) = (1, 1, 1, 1),
512+
padding: Padding,
513+
dilations: (Int, Int, Int, Int) = (1, 1, 1, 1)
510514
) -> Tensor<Scalar> {
511515
return _Raw.depthwiseConv2dNativeBackpropInput(
512516
inputSizes: shape,
513517
filter: filter,
514518
outBackprop: x,
515519
strides: [Int32(strides.0), Int32(strides.1), Int32(strides.2), Int32(strides.3)],
516-
padding: padding.raw)
520+
padding: padding.raw,
521+
dilations: [Int32(dilations.0), Int32(dilations.1), Int32(dilations.2), Int32(dilations.3)])
517522
}
518523

519524
@usableFromInline
@@ -523,19 +528,20 @@ func _vjpDepthwiseConv2dBackpropInput<Scalar: TensorFlowFloatingPoint>(
523528
_ shape: Tensor<Int32>,
524529
_ filter: Tensor<Scalar>,
525530
_ strides: (Int, Int, Int, Int),
526-
_ padding: Padding
531+
_ padding: Padding,
532+
_ dilations: (Int, Int, Int, Int)
527533
) -> (value: Tensor<Scalar>, pullback: (Tensor<Scalar>) -> (Tensor<Scalar>, Tensor<Scalar>)) {
528534
let value = depthwiseConv2dBackpropInput(
529535
x, shape: shape, filter: filter, strides: strides,
530-
padding: padding)
536+
padding: padding, dilations: dilations)
531537
return (
532538
value,
533539
{ v in
534540
(
535-
depthwiseConv2D(v, filter: filter, strides: strides, padding: padding),
541+
depthwiseConv2D(v, filter: filter, strides: strides, padding: padding, dilations: dilations),
536542
depthwiseConv2dBackpropFilter(
537543
x, input: v, filterSizes: filter.shapeTensor,
538-
strides: strides, padding: padding)
544+
strides: strides, padding: padding, dilations: dilations)
539545
)
540546

541547
}
@@ -549,15 +555,17 @@ func depthwiseConv2dBackpropFilter<Scalar: TensorFlowFloatingPoint>(
549555
_ x: Tensor<Scalar>,
550556
input: Tensor<Scalar>,
551557
filterSizes: Tensor<Int32>,
552-
strides: (Int, Int, Int, Int),
553-
padding: Padding
558+
strides: (Int, Int, Int, Int) = (1, 1, 1, 1),
559+
padding: Padding,
560+
dilations: (Int, Int, Int, Int) = (1, 1, 1, 1)
554561
) -> Tensor<Scalar> {
555562
return _Raw.depthwiseConv2dNativeBackpropFilter(
556563
input,
557564
filterSizes: filterSizes,
558565
outBackprop: x,
559566
strides: [Int32(strides.0), Int32(strides.1), Int32(strides.2), Int32(strides.3)],
560-
padding: padding.raw)
567+
padding: padding.raw,
568+
dilations: [Int32(dilations.0), Int32(dilations.1), Int32(dilations.2), Int32(dilations.3)])
561569
}
562570

563571
@usableFromInline
@@ -567,19 +575,20 @@ func _vjpDepthwiseConv2dBackpropFilter<Scalar: TensorFlowFloatingPoint>(
567575
_ input: Tensor<Scalar>,
568576
_ filterSizes: Tensor<Int32>,
569577
_ strides: (Int, Int, Int, Int),
570-
_ padding: Padding
578+
_ padding: Padding,
579+
_ dilations: (Int, Int, Int, Int)
571580
) -> (value: Tensor<Scalar>, pullback: (Tensor<Scalar>) -> (Tensor<Scalar>, Tensor<Scalar>)) {
572581
let value = depthwiseConv2dBackpropFilter(
573582
x, input: input, filterSizes: filterSizes,
574-
strides: strides, padding: padding)
583+
strides: strides, padding: padding, dilations: dilations)
575584
return (
576585
value,
577586
{ v in
578587
(
579-
depthwiseConv2D(input, filter: v, strides: strides, padding: padding),
588+
depthwiseConv2D(input, filter: v, strides: strides, padding: padding, dilations: dilations),
580589
depthwiseConv2dBackpropInput(
581590
x, shape: x.shapeTensor, filter: v, strides: strides,
582-
padding: padding)
591+
padding: padding, dilations: dilations)
583592
)
584593
}
585594
)

Tests/x10/ops_test.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -1069,14 +1069,15 @@ final class TensorTests: XCTestCase {
10691069
let kernelSize = 5
10701070
let inputSize = 14
10711071
let batch = 2
1072+
let dilation = 1
10721073
for useReducedPrecision in [false, true] {
10731074
for stride in 1..<4 {
10741075
for padSame in [false, true] {
10751076
var input = Tensor<Float>.rand([batch, inputSize, inputSize, inChannels])
10761077
var filter = Tensor<Float>.rand([kernelSize, kernelSize, inChannels, channelMultiplier])
10771078
let outShape = depthwiseConv2D(
10781079
TF(input), filter: TF(filter), strides: (1, stride, stride, 1),
1079-
padding: padSame ? Padding.same : Padding.valid
1080+
padding: padSame ? Padding.same : Padding.valid, dilations: (1, dilation, dilation, 1)
10801081
)
10811082
.shape
10821083
var outGrad = Tensor<Float>.rand(outShape.dimensions)
@@ -1091,13 +1092,13 @@ final class TensorTests: XCTestCase {
10911092
(_ input: Tensor<Float>, _ filter: Tensor<Float>) -> Tensor<Float> in
10921093
depthwiseConv2D(
10931094
input, filter: filter, strides: (1, stride, stride, 1),
1094-
padding: padSame ? Padding.same : Padding.valid
1095+
padding: padSame ? Padding.same : Padding.valid, dilations: (1, dilation, dilation, 1)
10951096
)
10961097
},
10971098
{ (_ input: Tensor<Float>, _ filter: Tensor<Float>) -> Tensor<Float> in
10981099
depthwiseConv2D(
10991100
input, filter: filter, strides: (1, stride, stride, 1),
1100-
padding: padSame ? Padding.same : Padding.valid
1101+
padding: padSame ? Padding.same : Padding.valid, dilations: (1, dilation, dilation, 1)
11011102
)
11021103
}, input, filter, outGrad, relTolerance: relTolerance, absTolerance: 1e-4)
11031104
}

0 commit comments

Comments
 (0)