return ker_fused;
}
+/**
+ * @note This creates fused ker:2 from ker:1, 'mulparam' and
+ * new precedingOp:2 that uses ker:2 as the kernel.
+ * Then make C to use precedingOp:2 as new input.
+ *
+ * <Before>
+ * mulparam-\
+ * ker:1 --\ \
+ * ifm ----- precedingOp:1 ----------- Mul --- C
+ *
+ *
+ * <After>
+ * mulparam-\
+ * ker:1 --\ \
+ * - precedingOp:1 ----------- Mul ---
+ * /
+ * ifm ----- precedingOp:2 ------------------- C
+ * ker:2 ---/
+ *
+ *
+ * [Where]
+ * - precedingOp:1 can be one of TFConv2D, TFDepthwiseConv2dNative, FullyConnected
+ * - 'mulparam' and Mul will be disconnected from the Output.
+ * - ker:2 is added with fused values of ker:1 and mulparam
+ * - precedingOp:2 is added using ifm and ker:2 and other parameters
+ * same as precedingOp:1.
+ * - ker:1, precedingOp:1, 'mulparam' and Mul should be removed in
+ * RemoveDeadNodeTransform if not used.
+ */
bool fuse_to_preceding(loco::Graph *graph, moco::tf::TFMul *node)
{
- /**
- * @note We'll create fused ker' from ker and mulparam and new TFConv2D'
- * that uses ker' as the kernel and tell C to use TFConv2D' as new
- * input.
- *
- * Before
- * mulparam-\
- * ker -----\ \
- * ifm ----- TFConv2D ------ Mul --- C
- *
- * After
- * mulparam-\
- * ker -----\ \
- * - TFConv2D ----- Mul ---
- * /
- * ifm ------ TFConv2D' ------------ C
- * ker' -----/
- *
- * Where
- * mulparam and Mul will be disconnected from the Output.
- * ker' is added with fused values of ker and mulparam
- * TFConv2D' is added using ifm and ker' and other parameters
- * same as TFConv2D.
- * ker, TGConv2D, mulparam and Mul should be removed in
- * RemoveDeadNodeTransform if not used.
- */
-
LOGGER(l);
auto xc = dynamic_cast<moco::tf::TFConst *>(node->x());
if (ker == nullptr)
{
// Wait until ker is becomes TFConst: there are cases when it's Identity.
- INFO(l) << "Mul fuse_to_preceding: preceding Conv2D ker is not TFConst";
+ INFO(l) << "Mul fuse_to_preceding: precedingOp ker is not TFConst";
return false;
}
auto ifm = conv2d->ifm();
// we need shape information, if not wait till it's ready
if (ker->annot<moco::tf::ShapeInferenceData>() == nullptr)
{
- INFO(l) << "Mul fuse_to_preceding: preceding Conv2D ker has no shape";
+ INFO(l) << "Mul fuse_to_preceding: precedingOp ker has no shape";
return false;
}
auto mulparam_shape_inf = mulparam->annot<moco::tf::ShapeInferenceData>();
if (mulparam_shape_inf == nullptr)
{
- INFO(l) << "Mul fuse_to_preceding: preceding Conv2D mulparam has no shape";
+ INFO(l) << "Mul fuse_to_preceding: mulparam has no shape";
return false;
}
// if MulParam rank is not 1 we cannot fuse, just skip
conv2d_fused->data_layout(conv2d->data_layout());
conv2d_fused->strides(conv2d->strides());
- // Replace TFMul node with new TFConv2D with fused kernel
- // This will leave existing TFConv2D as-is but can be removed if not used
+ // Replace TFMul node with new precedingOp with fused kernel
+ // This will leave existing precedingOp as-is but can be removed if not used
// from other transformations
replace(node).with(conv2d_fused);
// TODO check if need to disconnect
return true;
}
+/**
+ * @note TFAdd will be fused to TFBiasAdd
+ *
+ * <Before>
+ * If precedingOp is not TFBiasAdd, then insert TFConst:1 + TFBiasAdd that
+ * TFConst:1 has zero values.
+ *
+ * addparam --\
+ * \
+ * precedingOp ---------------------------- TFAdd ----- C
+ *
+ *
+ * <Intermediate>
+ * If it's TFBiasAdd and one of the input is TFConst type,
+ * then we can fuse 'addparam' to the input TFConst:2 value of TFBiasAdd, where
+ * TFConst:2 has added values from 'addparam'
+ *
+ * addparam --\
+ * TFConst:1 --------\ \
+ * precedingOp ------- TFBiasAdd ---------- TFAdd ----- C
+ *
+ *
+ * <After>
+ * addparam --\
+ * TFConst:2 --------\ \
+ * precedingOp ------- TFBiasAdd ---------- TFAdd -----
+ * \--------------------- C
+ *
+ *
+ * [Where]
+ * - precedingOp can be TFConv2D, TFDepthwiseConv2dNative, FullyConnected,
+ * TFBiasAdd.
+ * - Intermediate is to insert TFBiasAdd + TFConst:1
+ * - After is to fuse 'addparam' of TFAdd into TFConst:1 + TFBiasAdd
+ * that becomes TFConst:2 + TFBiasAdd
+ */
bool fuse_to_preceding(loco::Graph *graph, moco::tf::TFAdd *node)
{
- /**
- * @note Preceding can be TFConv2D, TFBiasAdd.
- * If preceding is TFConv2D then insert TFConst:2 + TFBiasAdd like
- * Intermediate with TFConst:2 having zero values. If it's TFBiasAdd,
- * like Intermediate, and if one of the input is TFConst type then we
- * can fuse 'addparam' to the input TFConst:3 value of TFBiasAdd, where
- * TFConst:3 has added values from TFConst:1.
- *
- * Before
- * TFConv2D -------------- TFAdd ----- C
- * TFConst:1 --/
- *
- * Intermediate
- * TFConv2D -------- TFBiasAdd -------------- TFAdd ----- C
- * TFConst:2 --/ /
- * TFConst:1 --/
- *
- * After
- * ------------- TFBiasAdd ---------------- C
- * TFConst:3 --/ \
- * \-- TFAdd --
- * TFConst:1 --/
- *
- * Where
- * Intermediate is to insert TFBiasAdd + TFConst:2
- * After is to fuse TFConst:1 of TFAdd into TFConst:2 + TFBiasAdd
- * that becomes TFConst:3 + TFBiasAdd
- */
-
LOGGER(l);
auto xc = dynamic_cast<moco::tf::TFConst *>(node->x());
auto addparam_shape_inf = addparam->annot<moco::tf::ShapeInferenceData>();
if (addparam_shape_inf == nullptr)
{
- INFO(l) << "Add fuse_to_preceding: preceding Conv2D addparam has no shape";
+ INFO(l) << "Add fuse_to_preceding: addparam has no shape";
return false;
}
// if AddParam rank is not 1 we cannot fuse, just skip
if (conv2d != nullptr && addparam != nullptr)
{
- // Preceding is TFConv2D. Let's insert TFConst - TFBiasAdd
+ // precedingOp is TFConv2D. Let's insert TFConst - TFBiasAdd
// The plan is to fuse 'addparam' to TFBiasAdd bias
auto dtype = addparam->dtype();