code: def bprop(self, error, epsilon, permute=False):
      inputs = self.inputs
      if self.pos > 0:
          # Propagate the errors backwards.
          self.berror.fill(0.0)
          self.bprop_naive(error, permute=permute)
      bshp = [
          self.berror.shape[0],
          self.nifm,
          self.ifmshape[0],
          self.ifmshape[1],
      ]
      pad = self.padding
  
      # clip the padding out for neon comparison
      if pad > 0:
          self.berror_nopad = self.berror.reshape(bshp)[
              :, :, pad:-pad, pad:-pad
          ]
          self.berror_nopad = self.berror_nopad.reshape(
              (bshp[0], -1)
          ).copy()
      else:
          self.berror_nopad = self.berror.copy()
  
      self.updates.fill(0.0)
      for dst in range(self.ofmsize):
          # Accumulate weight updates, going over all
          # corresponding cells in the output feature maps.
          rflinks = self.links[dst]
          deltaslice = error[:, self.ofmlocs[dst]]
  
          A = deltaslice.T
          B = inputs[:, rflinks]
          if permute:
              inds = np.random.permutation(A.shape[1])
              np.dot(A[:, inds], B[inds, :], out=self.updatebuf)
          else:
              np.dot(A, B, out=self.updatebuf)
          self.updates += self.updatebuf
  
      # Update the weights.
      np.multiply(self.updates, epsilon, out=self.updates)
  
imports: import itertools
  import numpy
  import pytest
  from neon import NervanaObject
  from neon.layers.layer import Convolution
  from neon.initializers.initializer import Uniform
  from utils import allclose_with_out
label_desc: Use image node_id 5 for calling the ConvLayerRef obj's underlying member method code with example usage: obj.bprop(error, epsilon, permute) without return types