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

Adding conv transpose 1d & 3d #174

Merged
merged 20 commits into from
Nov 19, 2019
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 251 additions & 0 deletions Sources/TensorFlow/Layers/Convolutional.swift
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,130 @@ public extension Conv3D {
}
}

/// A 1-D transposed convolution layer (e.g. temporal transposed convolution over images).
///
/// This layer creates a convolution filter that is transpose-convolved with the layer input
/// to produce a tensor of outputs.
@_fixed_layout
public struct TransposedConv1D: Layer {
/// The 1-D convolution kernel.
public var filter: Tensor<Float>
/// The bias vector.
public var bias: Tensor<Float>
/// An activation function.
public typealias Activation = @differentiable (Tensor<Float>) -> Tensor<Float>
/// The element-wise activation function.
@noDerivative public let activation: Activation
/// The strides of the sliding window for spatial dimensions.
@noDerivative public let strides: Int
/// The padding algorithm for convolution.
@noDerivative public let padding: Padding
@noDerivative public let paddingIndex: Int
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a doc comment for this property.


/// Creates a `TransposedConv1D` layer with the specified filter, bias,
/// activation function, strides, and padding.
///
/// - Parameters:
/// - filter: The 3-D convolution kernel.
/// - bias: The bias vector.
/// - activation: The element-wise activation function.
/// - strides: The strides of the sliding window for spatial dimensions.
/// - padding: The padding algorithm for convolution.
public init(
filter: Tensor<Float>,
bias: Tensor<Float>,
activation: @escaping Activation,
strides: Int,
padding: Padding
) {
self.filter = filter
self.bias = bias
self.activation = activation
self.strides = strides
self.padding = padding
self.paddingIndex = padding == .same ? 0 : 1
}

/// Returns the output obtained from applying the layer to the given input.
///
/// - Parameter input: The input to the layer.
/// - Returns: The output.
@differentiable
public func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
let batchSize = input.shape[0]
let w = (input.shape[1] - (1 * paddingIndex)) *
strides + (filter.shape[0] * paddingIndex)
let c = filter.shape[2]
let newShape = Tensor<Int32>([Int32(batchSize), Int32(w), Int32(c), 1])
return activation(conv2DBackpropInput(input.expandingShape(at: 1), shape: newShape,
filter: filter.expandingShape(at: 0),
strides: (1, 1, strides, 1),
padding: padding) + bias)
}
}

public extension TransposedConv1D {
/// Creates a `TransposedConv1D` layer with the specified filter shape, strides, padding, and
/// element-wise activation function. The filter tensor is initialized using Glorot uniform
/// initialization with the specified generator. The bias vector is initialized with zeros.
///
/// - Parameters:
/// - filterShape: The shape of the 3-D convolution kernel.
/// - strides: The strides of the sliding window for spatial dimensions.
/// - padding: The padding algorithm for convolution.
/// - activation: The element-wise activation function.
/// - generator: The random number generator for initialization.
///
/// - Note: Use `init(filterShape:strides:padding:activation:seed:)` for faster random
/// initialization.
init<G: RandomNumberGenerator>(
filterShape: (Int, Int, Int),
strides: Int = 1,
padding: Padding = .valid,
activation: @escaping Activation = identity,
generator: inout G
) {
let filterTensorShape = TensorShape([
filterShape.0, filterShape.1, filterShape.2])
self.init(
filter: Tensor(glorotUniform: filterTensorShape, generator: &generator),
bias: Tensor(zeros: TensorShape([filterShape.2])),
activation: activation,
strides: strides,
padding: padding)
}
}

public extension TransposedConv1D {
/// Creates a `TransposedConv1D` layer with the specified filter shape, strides, padding, and
/// element-wise activation function. The filter tensor is initialized using Glorot uniform
/// initialization with the specified seed. The bias vector is initialized with zeros.
///
/// - Parameters:
/// - filterShape: The shape of the 3-D convolution kernel.
/// - strides: The strides of the sliding window for spatial dimensions.
/// - padding: The padding algorithm for convolution.
/// - activation: The element-wise activation function.
/// - seed: The random seed for initialization. The default value is random.
init(
filterShape: (Int, Int, Int),
strides: Int = 1,
padding: Padding = .valid,
activation: @escaping Activation = identity,
seed: (Int32, Int32) = (Int32.random(in: Int32.min..<Int32.max),
Int32.random(in: Int32.min..<Int32.max))
) {
let filterTensorShape = TensorShape([
filterShape.0, filterShape.1, filterShape.2])
self.init(
filter: Tensor(glorotUniform: filterTensorShape, seed: seed),
bias: Tensor(zeros: TensorShape([filterShape.2])),
activation: activation,
strides: strides,
padding: padding)
}
}

/// A 2-D transposed convolution layer (e.g. spatial transposed convolution over images).
///
/// This layer creates a convolution filter that is transpose-convolved with the layer input
Expand Down Expand Up @@ -485,3 +609,130 @@ public extension TransposedConv2D {
padding: padding)
}
}

/// A 3-D transposed convolution layer (e.g. spatial transposed convolution over images).
///
/// This layer creates a convolution filter that is transpose-convolved with the layer input
/// to produce a tensor of outputs.
@_fixed_layout
public struct TransposedConv3D: Layer {
/// The 5-D convolution kernel.
public var filter: Tensor<Float>
/// The bias vector.
public var bias: Tensor<Float>
/// An activation function.
public typealias Activation = @differentiable (Tensor<Float>) -> Tensor<Float>
/// The element-wise activation function.
@noDerivative public let activation: Activation
/// The strides of the sliding window for spatial dimensions.
@noDerivative public let strides: (Int, Int, Int)
/// The padding algorithm for convolution.
@noDerivative public let padding: Padding
@noDerivative public let paddingIndex: Int
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a doc comment for this property.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rxwei this property isn't really exposed to the users, it's a temporary property which allows us to handle computation based on what kind of padding it is. we currently support .same and .valid.
Do we still document this?


/// Creates a `TransposedConv3D` layer with the specified filter, bias,
/// activation function, strides, and padding.
///
/// - Parameters:
/// - filter: The 5-D convolution kernel.
/// - bias: The bias vector.
/// - activation: The element-wise activation function.
/// - strides: The strides of the sliding window for spatial dimensions.
/// - padding: The padding algorithm for convolution.
public init(
filter: Tensor<Float>,
bias: Tensor<Float>,
activation: @escaping Activation,
strides: (Int, Int, Int),
padding: Padding
) {
self.filter = filter
self.bias = bias
self.activation = activation
self.strides = strides
self.padding = padding
self.paddingIndex = padding == .same ? 0 : 1
}

/// Returns the output obtained from applying the layer to the given input.
///
/// - Parameter input: The input to the layer.
/// - Returns: The output.
@differentiable
public func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
let batchSize = input.shape[0]
let w = (input.shape[1] - (1 * paddingIndex)) *
strides.0 + (filter.shape[0] * paddingIndex)
let h = (input.shape[2] - (1 * paddingIndex)) *
strides.1 + (filter.shape[1] * paddingIndex)
let d = (input.shape[3] - (1 * paddingIndex)) *
strides.2 + (filter.shape[2] * paddingIndex)
let c = filter.shape[3]
let newShape = Tensor<Int32>([Int32(batchSize), Int32(w), Int32(h), Int32(d), Int32(c)])
return activation(conv3DBackpropInput(input, shape: newShape, filter: filter,
strides: (1, strides.0, strides.1,strides.2, 1),
padding: padding) + bias)
}
}

public extension TransposedConv3D {
/// Creates a `TransposedConv3D` layer with the specified filter shape, strides, padding, and
/// element-wise activation function. The filter tensor is initialized using Glorot uniform
/// initialization with the specified generator. The bias vector is initialized with zeros.
///
/// - Parameters:
/// - filterShape: The shape of the 5-D convolution kernel.
/// - strides: The strides of the sliding window for spatial dimensions.
/// - padding: The padding algorithm for convolution.
/// - activation: The element-wise activation function.
/// - generator: The random number generator for initialization.
///
/// - Note: Use `init(filterShape:strides:padding:activation:seed:)` for faster random
/// initialization.
init<G: RandomNumberGenerator>(
filterShape: (Int, Int, Int, Int, Int),
strides: (Int, Int, Int) = (1, 1, 1),
padding: Padding = .valid,
activation: @escaping Activation = identity,
generator: inout G
) {
let filterTensorShape = TensorShape([
filterShape.0, filterShape.1, filterShape.2, filterShape.3, filterShape.4])
self.init(
filter: Tensor(glorotUniform: filterTensorShape, generator: &generator),
bias: Tensor(zeros: TensorShape([filterShape.4])),
activation: activation,
strides: strides,
padding: padding)
}
}

public extension TransposedConv3D {
/// Creates a `TransposedConv3D` layer with the specified filter shape, strides, padding, and
/// element-wise activation function. The filter tensor is initialized using Glorot uniform
/// initialization with the specified seed. The bias vector is initialized with zeros.
///
/// - Parameters:
/// - filterShape: The shape of the 5-D convolution kernel.
/// - strides: The strides of the sliding window for spatial dimensions.
/// - padding: The padding algorithm for convolution.
/// - activation: The element-wise activation function.
/// - seed: The random seed for initialization. The default value is random.
init(
filterShape: (Int, Int, Int, Int, Int),
strides: (Int, Int, Int) = (1, 1, 1),
padding: Padding = .valid,
activation: @escaping Activation = identity,
seed: (Int32, Int32) = (Int32.random(in: Int32.min..<Int32.max),
Int32.random(in: Int32.min..<Int32.max))
) {
let filterTensorShape = TensorShape([
filterShape.0, filterShape.1, filterShape.2, filterShape.3, filterShape.4])
self.init(
filter: Tensor(glorotUniform: filterTensorShape, seed: seed),
bias: Tensor(zeros: TensorShape([filterShape.4])),
activation: activation,
strides: strides,
padding: padding)
}
}