3
$\begingroup$

I tried to implement a NetGraph similar to UNet in Mathematica, but I found an error in the dimension.

conv[n_] := NetGraph[{
    ConvolutionLayer[n, {3, 3}],
    ConvolutionLayer[n, {3, 3}],
    ConvolutionLayer[n, {3, 3}, "Stride" -> {1, 2}]
    }, {
    NetPort["In"] -> 1 -> 2 -> 3,
    3 -> NetPort["Res"],
    3 -> NetPort["Out"]
    }];

dec[n_] := NetGraph[{
    CatenateLayer[1],
    DeconvolutionLayer[n, {3, 3}, "Stride" -> {1, 2}],
    DeconvolutionLayer[n, {3, 3}],
    DeconvolutionLayer[n, {3, 3}]
    }, {
    NetPort["In"] -> 1,
    NetPort["Res"] -> 1,
    1 -> 2 -> 3 -> 4 -> NetPort["Out"]
    }];

NetGraph[<|
  "re" -> ReshapeLayer[{1, 32, 300}],
  "c1" -> conv[32],
  "c2" -> conv[64],
  "m" -> {
    ConvolutionLayer[64, {3, 3}, "PaddingSize" -> "Same"],
    ConvolutionLayer[64, {3, 3}, "PaddingSize" -> "Same"],
    ConvolutionLayer[64, {3, 3}, "PaddingSize" -> "Same"]
    },
  "d2" -> dec[64],
  "d1" -> dec[32],
  "map" -> {
    ConvolutionLayer[16, {3, 3}, "PaddingSize" -> "Same"],
    ConvolutionLayer[16, {3, 3}, "PaddingSize" -> "Same"],
    ConvolutionLayer[1, {3, 3}, "PaddingSize" -> "Same"]
    }
  |>, {
  NetPort["Input"] -> "re" -> "c1",
  NetPort[{"c1", "Out"}] -> "c2",
  NetPort[{"c1", "Res"}] -> NetPort[{"d1", "Res"}],
  NetPort[{"c2", "Out"}] -> "m",
  NetPort[{"c2", "Res"}] -> NetPort[{"d2", "Res"}],
  "m" -> NetPort[{"d2", "In"}],
  "d2" -> NetPort[{"d1", "In"}],
  "d1" -> "map" -> NetPort["Output"]
  }]

The NetGraph

Then I found that the error occurred in the output dimension of Deconvolution.

ConvolutionLayer[32, {3, 3}, "Input" -> {32, 28, 296}, "Stride" -> {1, 2}]
DeconvolutionLayer[32, {3, 3}, "Input" -> {32, 26, 147}, "Stride" -> {1, 2}]

Dimension failed to align

I have tried to use the paddingSize and other parameters to adjust it, but it failed to solve this problem.

Is my understanding wrong? How can I solve this problem?

$\endgroup$

1 Answer 1

2
$\begingroup$

I don't know how other languages handle this edge case but in Mathematica, this behaviour is not an error but is expected. Consider this simple example:

Partition[{2, 4, 8, 16}, 2]
(* Out: {{2, 4}, {8, 16}} *)

Partition[{2, 4, 8, 16, 32}, 2]
(* Out: {{2, 4}, {8, 16}} *)

First, we gave a 4-length list and second a 5-length one, but by default, it's partitioned base on the size of the window, not the input size. You can see the same behaviour with the following code:

conv1 = ConvolutionLayer[1, 2, "Input" -> {1, 4}, "Stride" -> 2]

enter image description here

conv2 = ConvolutionLayer[1, 2, "Input" -> {1, 5}, "Stride" -> 2]

enter image description here

Even though the input size differs, the output size is the same. In fact, this behaviour is documented and the formula for calculating the new dimension is also mentioned (the Floor function is involved).

If we place your dimension in the formula we see the output dimensions:

Floor[{(28 - (3 - 1) - 1)/1 + 1, (296 - (3 - 1) - 1)/2 + 1}]

(* Out: {26, 147} *)

If you replace 296 with 295, you'll still get 147 as a new dimension.

Following DeconvolutionLayer formula, we can calculate the output dimensions too:

Floor[{1*(26 - 1) + 3, 2*(147 - 1) + 3}]

(* Out: {28, 295} *)

You can define the right-side padding in ConvolutionLayer to make use of that extra column but as of 13.2, asymmetric padding is not yet implemented for DeconvolutionLayer.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.