iconv2dDiff :: forall k ow oh c1 c2 m. (MonadIO m, KnownDims [k, ow, oh, c1, c2],
                                        (1 <=? k) ~ 'True)
            => Diff m
               (Tensor [k, k, c1, c2], Tensor [ow + k - 1, oh + k - 1, c1])
               (Tensor [ow, oh, c2])
iconv2dDiff = Diff run
  where
    run (flt, input) = do
      output <- Tensor.new @ [ow, oh, c2]
      liftIO (clfun iconv2dForward (dimVal output) flt input output :: IO ())
      return (Tensor.unsafeFreeze output, backward flt input)

    backward flt input d_output = do
      d_input <- Tensor.new
      liftIO (clfun iconv2dBackward (dimVal d_input) flt d_input d_output :: IO ())
      d_flt <- Tensor.new
      liftIO (clfun iconv2dFilter [dimSize d_flt] d_flt input d_output :: IO ())
      return (Tensor.unsafeFreeze d_flt, Tensor.unsafeFreeze d_input)
iconv2dDiff :: forall k ow oh c1 c2 m. (MonadIO m, KnownDims [k, ow, oh, c1, c2],
                                        (1 <=? k) ~ 'True)
            => Diff m
               (Tensor [k, k, c1, c2], Tensor [ow + k - 1, oh + k - 1, c1])
               (Tensor [ow, oh, c2])
iconv2dDiff = Diff run
  where
    run (flt, input) = do
      output <- Tensor.new @ [ow, oh, c2]
      liftIO (clfun iconv2dForward (dimVal output) flt input output :: IO ())
      return (Tensor.unsafeFreeze output, backward flt input)

    backward flt input d_output = do
      d_input <- Tensor.new
      liftIO (clfun iconv2dBackward (dimVal d_input) flt d_input d_output :: IO ())
      d_flt <- Tensor.new
      liftIO (clfun iconv2dFilter [dimSize d_flt] d_flt input d_output :: IO ())
      return (Tensor.unsafeFreeze d_flt, Tensor.unsafeFreeze d_input)
iconv2dDiff = Diff run
  where
    run (flt, input) = do
      output <- Tensor.new @ [ow, oh, c2]
      liftIO (clfun iconv2dForward (dimVal output) flt input output :: IO ())
      return (Tensor.unsafeFreeze output, backward flt input)

    backward flt input d_output = do
      d_input <- Tensor.new
      liftIO (clfun iconv2dBackward (dimVal d_input) flt d_input d_output :: IO ())
      d_flt <- Tensor.new
      liftIO (clfun iconv2dFilter [dimSize d_flt] d_flt input d_output :: IO ())
      return (Tensor.unsafeFreeze d_flt, Tensor.unsafeFreeze d_input)