Class: Chainer::Functions::Connection::Convolution2DFunction

Inherits:
Chainer::FunctionNode show all
Defined in:
lib/chainer/functions/connection/convolution_2d.rb

Instance Attribute Summary collapse

Attributes inherited from Chainer::FunctionNode

#inputs, #outputs, #rank

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Chainer::FunctionNode

#apply, #backward_accumulate, #forward_cpu, #get_retained_inputs, #get_retained_outputs, #label, #output_data, #retain_inputs, #retain_outputs, #unchain

Constructor Details

#initialize(stride: 1, pad: 0, cover_all: false) ⇒ Convolution2DFunction

Returns a new instance of Convolution2DFunction.



55
56
57
58
59
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 55

def initialize(stride: 1, pad: 0, cover_all: false)
  @sy, @sx = stride.is_a?(::Array) ? stride : [stride, stride]
  @ph, @pw = pad.is_a?(::Array) ? pad : [pad, pad]
  @cover_all = cover_all
end

Instance Attribute Details

#cover_allObject (readonly)

Returns the value of attribute cover_all.



5
6
7
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 5

def cover_all
  @cover_all
end

#phObject (readonly)

Returns the value of attribute ph.



5
6
7
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 5

def ph
  @ph
end

#pwObject (readonly)

Returns the value of attribute pw.



5
6
7
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 5

def pw
  @pw
end

#sxObject (readonly)

Returns the value of attribute sx.



5
6
7
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 5

def sx
  @sx
end

#syObject (readonly)

Returns the value of attribute sy.



5
6
7
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 5

def sy
  @sy
end

Class Method Details

.convolution_2d(x, w, b: nil, stride: 1, pad: 0, cover_all: false) ⇒ Chainer::Variable

Two-dimensional convolution function. This is an implementation of two-dimensional convolution in ConvNets. It takes three variables: the input image ‘x`, the filter weight `w`, and the bias vector `b`.

a notation for dimensionalities.

  • :math:‘n` is the batch size.

  • :math:‘c_I` and :math:`c_O` are the number of the input and output channels, respectively.

  • :math:‘h_I` and :math:`w_I` are the height and width of the input image, respectively.

  • :math:‘h_K` and :math:`w_K` are the height and width of the filters, respectively.

  • :math:‘h_P` and :math:`w_P` are the height and width of the spatial padding size, respectively.

Then the ‘Convolution2D` function computes correlations between filters and patches of size :math:`(h_K, w_K)` in `x`. Patches are extracted at positions shifted by multiples of `stride` from the first position `(-h_P, -w_P)` for each spatial axis. The right-most (or bottom-most) patches do not run over the padded spatial size. Let :math:`(s_Y, s_X)` be the stride of filter application. Then, the output size :math:`(h_O, w_O)` is determined by the following equations:

math:

h_O &= (h_I + 2h_P - h_K) / s_Y + 1,\\\\
 w_O &= (w_I + 2w_P - w_K) / s_X + 1.

If ‘cover_all` option is `true`, the filter will cover the all spatial locations. So, if the last stride of filter does not cover the end of spatial locations, an addtional stride will be applied to the end part of spatial locations. In this case, the output size :math:`(h_O, w_O)` is determined by the following equations:

math:

h_O &= (h_I + 2h_P - h_K + s_Y - 1) / s_Y + 1,\\\\
w_O &= (w_I + 2w_P - w_K + s_X - 1) / s_X + 1.

If the bias vector is given, then it is added to all spatial locations of the output of convolution.

Parameters:

  • x (Chainer::Variable or Numo::NArray or Cumo::NArray)

    Input variable of shape :math:‘(n, c_I, h_I, w_I)`.

  • w (Chainer::Variable or Numo::NArray or Cumo::NArray)

    Weight variable of shape :math:‘(c_O, c_I, h_K, w_K)`.

  • b (Chainer::Variable or Numo::NArray or Cumo::NArray) (defaults to: nil)

    Bias variable of length :math:‘c_O`

  • stride (Int or 2-D Array) (defaults to: 1)

    Stride of filter applications. ‘stride=s` and `stride=(s, s)` are equivalent.

  • pad (Int or 2-D Array) (defaults to: 0)

    Spatial padding width for input arrays.

  • cover_all (Boolean) (defaults to: false)

    If ‘true`, all spatial locations are convoluted into some output pixels.

Returns:



44
45
46
47
48
49
50
51
52
53
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 44

def self.convolution_2d(x, w, b: nil, stride: 1, pad: 0, cover_all: false)
  func = self.new(stride: stride, pad: pad, cover_all: cover_all)
  if b.nil?
    args = [x, w]
  else
    args = [x, w, b]
  end

  func.apply(args).first
end

Instance Method Details

#backward(indexes, grad_outputs) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 83

def backward(indexes, grad_outputs)
  x, w = get_retained_inputs
  gy = grad_outputs.first

  ret = []
  if indexes.include?(0)
    xh, xw = x.shape[2..-1]
    gx = Deconvolution2DFunction.deconvolution_2d(gy, w, stride: [@sy, @sx], pad: [@ph, @pw], outsize: [xh, xw])
    ret << gx
  end

  if indexes.include?(1)
    gw = Chainer::Functions::Connection::Convolution2DGradW.new(self).apply([x, gy]).first
    ret << gw
  end

  if indexes.include?(2)
    gb = Chainer::Functions::Math::Sum.sum(gy, axis: [0, 2, 3])
    ret << gb
  end

  ret
end

#forward(inputs) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/chainer/functions/connection/convolution_2d.rb', line 61

def forward(inputs)
  retain_inputs([0, 1])
  x = inputs[0]
  w = inputs[1]
  b = inputs.size == 3 ? inputs[2] : nil

  unless inputs.all? { |i| i.is_a?(Numo::NArray) }
    if b.nil?
      raise TypeError, "Numo::NArray must not be used together w: #{w.class}, x: #{x.class}"
    else
      raise TypeError, "Numo::NArray must not be used together w: #{w.class}, x: #{x.class}, b: #{b.class}"
    end
  end

  kh, kw = w.shape[2..-1]
  col = Chainer::Utils::Conv.im2col(x, kh, kw, @sy, @sx, @ph, @pw, cover_all: @cover_all)
  y = Chainer::Utils::Math.tensordot(col, w, [[1, 2, 3], [1, 2, 3]]).cast_to(x.class)
  y += b if b

  [y.transpose(0, 3, 1, 2)]
end