diff --git a/docs/user-guide/layers/util-layer.rst b/docs/user-guide/layers/util-layer.rst index bbb6c35..729c988 100644 --- a/docs/user-guide/layers/util-layer.rst +++ b/docs/user-guide/layers/util-layer.rst @@ -49,6 +49,20 @@ Utility Layers file. If this attribute is given, the corresponding symbol in this list is used as the dataset name instead of the original blob's name. +.. class:: IdentityLayer + + Identity layer maps inputs to outputs without changing anything. This could + be useful as glue layers to rename some blobs. There is no data-copying for + this layer. + + .. attribute:: + tops + bottoms + + Blob names for output and input. This layer could take multiple input + blobs and produce the corresponding number of output blobs. The shapes of + the input blobs do not need to be the same. + .. class:: ReshapeLayer Reshape a blob. Can be useful if, for example, you want to make the *flat* diff --git a/src/layers.jl b/src/layers.jl index 6eb4370..f517127 100644 --- a/src/layers.jl +++ b/src/layers.jl @@ -5,6 +5,7 @@ export InnerProductLayer, ConvolutionLayer, PoolingLayer, SoftmaxLayer export PowerLayer, SplitLayer, ElementWiseLayer, ChannelPoolingLayer export LRNLayer, DropoutLayer, ReshapeLayer, ArgmaxLayer, HDF5OutputLayer export CropLayer, ConcatLayer, RandomMaskLayer, TiedInnerProductLayer +export IdentityLayer export SquareLossLayer, SoftmaxLossLayer, MultinomialLogisticLossLayer export AccuracyLayer @@ -201,6 +202,7 @@ include("layers/crop.jl") include("layers/concat.jl") include("layers/random-mask.jl") include("layers/tied-inner-product.jl") +include("layers/identity.jl") ############################################################# # Utility layers diff --git a/src/layers/identity.jl b/src/layers/identity.jl new file mode 100644 index 0000000..f4b35fe --- /dev/null +++ b/src/layers/identity.jl @@ -0,0 +1,34 @@ +############################################################ +# Identity Layer +############################################################ +@defstruct IdentityLayer Layer ( + name :: String = "identity", + (tops :: Vector{Symbol} = Symbol[], length(tops) > 0), + (bottoms :: Vector{Symbol} = Symbol[], length(bottoms) == length(tops)), +) +@characterize_layer(IdentityLayer, + can_do_bp => true +) + +type IdentityLayerState <: LayerState + layer :: IdentityLayer + blobs :: Vector{Blob} + blobs_diff :: Vector{Blob} +end + +function setup(backend::Backend, layer::IdentityLayer, inputs::Vector{Blob}, diffs::Vector{Blob}) + blobs = inputs[:] # shallow copy + blobs_diff = diffs[:] # shallow_copy + + IdentityLayerState(layer, blobs, blobs_diff) +end +function shutdown(backend::Backend, state::IdentityLayerState) +end + +function forward(backend::Backend, state::IdentityLayerState, inputs::Vector{Blob}) + # do nothing +end + +function backward(backend::Backend, state::IdentityLayerState, inputs::Vector{Blob}, diffs::Vector{Blob}) + # do nothing +end diff --git a/test/layers/identity.jl b/test/layers/identity.jl new file mode 100644 index 0000000..19ef366 --- /dev/null +++ b/test/layers/identity.jl @@ -0,0 +1,32 @@ +function test_identity_layer(backend::Backend, T) + println("-- Testing IdentityLayer on $(typeof(backend)){$T}...") + + eps = 1e-10 + input = rand(T, 3, 4, 5) + input_blob = make_blob(backend, input) + + println(" > Setup") + layer = IdentityLayer(tops=[:foo], bottoms=[:bar]) + state = setup(backend, layer, Blob[input_blob], Blob[NullBlob()]) + @test all(map(x -> isa(x, NullBlob), state.blobs_diff)) + + println(" > Forward") + forward(backend, state, Blob[input_blob]) + got_output = to_array(state.blobs[1]) + @test all(abs(got_output-input) .< eps) + + shutdown(backend, state) +end + +function test_identity_layer(backend::Backend) + test_identity_layer(backend, Float32) + test_identity_layer(backend, Float64) +end + +if test_cpu + test_identity_layer(backend_cpu) +end +if test_gpu + test_identity_layer(backend_gpu) +end +