fn optimize_chain(
        &mut self,
        chain: &[(String, Arc<Node<'model>>)],
    ) -> Result<Option<Sequence<'model>>, OptimizerError> {
        let path_slices: Vec<&str> = chain.iter().rev().map(|x| x.0.as_str()).collect();
        match &path_slices[..] {
            // Conv+Relu or Conv+LeakyRelu: combine into ConvRelu/ConvLeakyRelu
            ["Conv", "Relu", ..] | ["Conv", "LeakyRelu", ..] => {
                let conv = chain[chain.len() - 1].1.clone();
                let relu = chain[chain.len() - 2].1.clone();

                if let (NodeDefinition::Operator(conv_def), NodeDefinition::Operator(relu_def)) =
                    (&conv.definition, &relu.definition)
                {
                    // Use the Conv node as template for the new fused Conv[Leaky]Relu node
                    let mut convrelu_def = *conv_def.clone();
                    let mut convrelu_proto = conv_def.proto.clone().into_owned();
                    let new_op_type = match relu_def.proto.get_op_type() {
                        "LeakyRelu" => "ConvLeakyRelu",
                        "Relu" => "ConvRelu",
                        _ => unreachable!(),
                    };
                    convrelu_proto.set_op_type(new_op_type.to_string());

                    // Copy all Relu attributes over to the copy of the Conv node
                    let mut attributes = conv_def.proto.get_attribute().to_vec();
                    attributes.extend(relu_def.proto.get_attribute().iter().cloned());
                    convrelu_proto.set_attribute(RepeatedField::from(attributes));
                    convrelu_proto.set_name(format!(
                        "{}+{}",
                        conv.definition.get_name(),
                        relu.definition.get_name()
                    ));

                    log::debug!(
                        "can fuse chain of Conv/[Leaky]Relu to Conv[Leaky]Relu: {:?}: {:?} + {:?} = {}",
                        path_slices,
                        conv.definition(),
                        relu.definition(),
                        convrelu_proto.get_name()
                    );

                    convrelu_def.proto = Cow::Owned(convrelu_proto);

                    let new_inputs = conv
                        .inputs
                        .iter()
                        .map(|input| -> Result<Input, OptimizerError> {
                            Ok(Input {
                                source_node: self.optimize(input.source_node.clone())?,
                                output_index: input.output_index,
                            })
                        })
                        .collect::<Result<Vec<_>, _>>()?;

                    let node = Arc::new(Node {
                        inputs: conv.inputs.clone(),
                        definition: NodeDefinition::Operator(Box::new(convrelu_def)),
                    });

                    Ok(Some(Sequence {
                        node: self.optimized_with(&node, new_inputs)?,
                        skip: 1,
                    }))
                } else {
                    unreachable!();
                }
            }
            _ => Ok(None),
        }
    }
/// Attempt to fuse several operators in a chain of operators with no other dynamic inputs.
Attempt to fuse several operators in a chain of operators with no other dynamic inputs.
Attempt to fuse several operators in a chain of operators with no other dynamic inputs .
fn optimize_chain(
        &mut self,
        chain: &[(String, Arc<Node<'model>>)],
    ) -> Result<Option<Sequence<'model>>, OptimizerError> {
        let path_slices: Vec<&str> = chain.iter().rev().map(|x| x.0.as_str()).collect();
        match &path_slices[..] {
            // Conv+Relu or Conv+LeakyRelu: combine into ConvRelu/ConvLeakyRelu
            ["Conv", "Relu", ..] | ["Conv", "LeakyRelu", ..] => {
                let conv = chain[chain.len() - 1].1.clone();
                let relu = chain[chain.len() - 2].1.clone();
                if let (NodeDefinition::Operator(conv_def), NodeDefinition::Operator(relu_def)) =
                    (&conv.definition, &relu.definition)
                {
                    // Use the Conv node as template for the new fused Conv[Leaky]Relu node
                    let mut convrelu_def = *conv_def.clone();
                    let mut convrelu_proto = conv_def.proto.clone().into_owned();
                    let new_op_type = match relu_def.proto.get_op_type() {
                        "LeakyRelu" => "ConvLeakyRelu",
                        "Relu" => "ConvRelu",
                        _ => unreachable!(),
                    };
                    convrelu_proto.set_op_type(new_op_type.to_string());
                    // Copy all Relu attributes over to the copy of the Conv node
                    let mut attributes = conv_def.proto.get_attribute().to_vec();
                    attributes.extend(relu_def.proto.get_attribute().iter().cloned());
                    convrelu_proto.set_attribute(RepeatedField::from(attributes));
                    convrelu_proto.set_name(format!(
                        "{}+{}",
                        conv.definition.get_name(),
                        relu.definition.get_name()
                    ));
                    log::debug!(
                        "can fuse chain of Conv/[Leaky]Relu to Conv[Leaky]Relu: {:?}: {:?} + {:?} = {}",
                        path_slices,
                        conv.definition(),
                        relu.definition(),
                        convrelu_proto.get_name()
                    );
                    convrelu_def.proto = Cow::Owned(convrelu_proto);
                    let new_inputs = conv
                        .inputs
                        .iter()
                        .map(|input| -> Result<Input, OptimizerError> {
                            Ok(Input {
                                source_node: self.optimize(input.source_node.clone())?,
                                output_index: input.output_index,
                            })
                        })
                        .collect::<Result<Vec<_>, _>>()?;
                    let node = Arc::new(Node {
                        inputs: conv.inputs.clone(),
                        definition: NodeDefinition::Operator(Box::new(convrelu_def)),
                    });
                    Ok(Some(Sequence {
                        node: self.optimized_with(&node, new_inputs)?,
                        skip: 1,
                    }))
                } else {
                    unreachable!();
                }
            }
            _ => Ok(None),
        }
    }
fn optimize_chain ( & mut self , chain : & [ ( String , Arc < Node < ' model > > ) ] , ) -> Result < Option < Sequence < ' model > > , OptimizerError > { let path_slices : Vec < & str > = chain . iter ( ) . rev ( ) . map ( | x | x . 0 . as_str ( ) ) . collect ( ) ; match & path_slices [ .. ] { // Conv+Relu or Conv+LeakyRelu: combine into ConvRelu/ConvLeakyRelu [ " " , " " , .. ] | [ " " , " " , .. ] => { let conv = chain [ chain . len ( ) - 1 ] . 1 . clone ( ) ; let relu = chain [ chain . len ( ) - 2 ] . 1 . clone ( ) ; if let ( NodeDefinition :: Operator ( conv_def ) , NodeDefinition :: Operator ( relu_def ) ) = ( & conv . definition , & relu . definition ) { // Use the Conv node as template for the new fused Conv[Leaky]Relu node let mut convrelu_def = * conv_def . clone ( ) ; let mut convrelu_proto = conv_def . proto . clone ( ) . into_owned ( ) ; let new_op_type = match relu_def . proto . get_op_type ( ) { " " => " " , " " => " " , _ => unreachable ! ( ) , } ; convrelu_proto . set_op_type ( new_op_type . to_string ( ) ) ; // Copy all Relu attributes over to the copy of the Conv node let mut attributes = conv_def . proto . get_attribute ( ) . to_vec ( ) ; attributes . extend ( relu_def . proto . get_attribute ( ) . iter ( ) . cloned ( ) ) ; convrelu_proto . set_attribute ( RepeatedField :: from ( attributes ) ) ; convrelu_proto . set_name ( format ! ( " " conv definition get_name ( ) relu definition get_name ( ) ) ) ; log :: debug ! ( " " path_slices conv definition ( ) relu definition ( ) convrelu_proto get_name ( ) ) ; convrelu_def . proto = Cow :: Owned ( convrelu_proto ) ; let new_inputs = conv . inputs . iter ( ) . map ( | input | -> Result < Input , OptimizerError > { Ok ( Input { source_node : self . optimize ( input . source_node . clone ( ) ) ? , output_index : input . output_index , } ) } ) . collect :: < Result < Vec < _ > , _ > > ( ) ? ; let node = Arc :: new ( Node { inputs : conv . inputs . clone ( ) , definition : NodeDefinition :: Operator ( Box :: new ( convrelu_def ) ) , } ) ; Ok ( Some ( Sequence { node : self . optimized_with ( & node , new_inputs ) ? , skip : 1 , } ) ) } else { unreachable ! ( ) ; } } _ => Ok ( None ) , } }
Attempt to fuse several operators in a chain of operators with no other dynamic inputs.
Attempt to fuse several operators in a chain of operators with no other dynamic inputs .
&mut self
chain
&[(String, Arc<Node<'model>>)]
&mut self
chain
&[(String, Arc<Node<'model>>)]