iconv2dFilter :: KernelProgram '[MTensorCL [k, k, c1, c2],
                                 TensorCL [ow + k - 1, oh + k - 1, c1],
                                 TensorCL [ow, oh, c2]]
iconv2dFilter = compile $ \d_flt input d_output -> do
  ~[kx, ky, ic, oc] <- get_global_id 0 >>= splitIndex (dimsOf d_flt)
  let [ow, oh, _] = dimsOf d_output
  acc <- eval 0
  forEach 0 ow $ \ox -> do
    forEach 0 oh $ \oy -> do
      acc .= acc + input![ox + kx, oy + ky, ic] * d_output![ox, oy, oc]
  d_flt![kx, ky, ic, oc] .= acc
iconv2dFilter :: KernelProgram '[MTensorCL [k, k, c1, c2],
                                 TensorCL [ow + k - 1, oh + k - 1, c1],
                                 TensorCL [ow, oh, c2]]
iconv2dFilter = compile $ \d_flt input d_output -> do
  ~[kx, ky, ic, oc] <- get_global_id 0 >>= splitIndex (dimsOf d_flt)
  let [ow, oh, _] = dimsOf d_output
  acc <- eval 0
  forEach 0 ow $ \ox -> do
    forEach 0 oh $ \oy -> do
      acc .= acc + input![ox + kx, oy + ky, ic] * d_output![ox, oy, oc]
  d_flt![kx, ky, ic, oc] .= acc
iconv2dFilter = compile $ \d_flt input d_output -> do
  ~[kx, ky, ic, oc] <- get_global_id 0 >>= splitIndex (dimsOf d_flt)
  let [ow, oh, _] = dimsOf d_output
  acc <- eval 0
  forEach 0 ow $ \ox -> do
    forEach 0 oh $ \oy -> do
      acc .= acc + input![ox + kx, oy + ky, ic] * d_output![ox, oy, oc]
  d_flt![kx, ky, ic, oc] .= acc