tensorflow/lite/delegates/gpu/common/lstm_parser.cc
// Build subgraph for a single LSTM OP.
// Returns a mapping for the used variable tensors' updated Values.
//
// High-level parameters:
//   - Has CIFG:
//       If false, calculate input_gate regularly.
//       If true, calculate input_gate to 1-forget_gate.
//   - Has peephole: see BuildLstmGate. Applies to all gates.
//   - Has normalization: see BuildLstmGate. Applies to all gates.
//   - Has projection, projection_bias, proj_clip: see BuildOutputStateUpdate
//   - Which activation to use:
//       Applies to only cell gate and output state update.
//       Other gates always use Sigmoid.
//
Build subgraph for a single LSTM OP.
Returns a mapping for the used variable tensors' updated Values.

High-level parameters:
Has CIFG:
If false, calculate input_gate regularly.
Build subgraph for a single LSTM OP . Returns a mapping for the used variable tensors ' updated Values . High - level parameters : Has CIFG : If false calculate input_gate regularly .
absl::Status ParseLSTMAttributes(
    const TfLiteNode* tflite_node, const TfLiteRegistration* registration,
    GraphFloat32* graph, ObjectReader* reader, const TfLiteLSTMParams* params,
    absl::flat_hash_map<int, ValueId>* new_variable_input_values) {
  const bool has_cifg = HasCifg(tflite_node);
  const bool has_peephole = HasPeephole(tflite_node);
  const bool has_normalization = HasNormalization(tflite_node);
  const bool has_projection = HasProjection(tflite_node);
  Value* old_cell_state;
  RETURN_IF_ERROR(reader->ReadValue(
      tflite::ops::builtin::lstm::full::kCellStateTensor, &old_cell_state));
  if (old_cell_state->tensor.shape.b != 1) {
    return absl::InvalidArgumentError(
        "Batched execution is not supported for LSTM");
  }
  Value* old_output_state;
  RETURN_IF_ERROR(reader->ReadValue(
      tflite::ops::builtin::lstm::full::kOutputStateTensor, &old_output_state));
  Value* forget_gate;
  RETURN_IF_ERROR(BuildLstmGate(
      graph, reader, old_output_state, old_cell_state,
      tflite::ops::builtin::lstm::full::kInputToForgetWeightsTensor,
      tflite::ops::builtin::lstm::full::kRecurrentToForgetWeightsTensor,
      tflite::ops::builtin::lstm::full::kCellToForgetWeightsTensor,
      tflite::ops::builtin::lstm::full::kForgetGateBiasTensor,
      tflite::ops::builtin::lstm::full::kForgetLayerNormCoefficientsTensor,
      kTfLiteActSigmoid, has_peephole, has_normalization, &forget_gate));
  Value* input_gate;
  if (has_cifg) {
    Node* node = graph->NewNode();
    input_gate = CreateNewSimilarValue(graph, forget_gate);
    node->operation.type = ToString(OperationType::SUB);
    ElementwiseAttributes attr;
    attr.param = 1.0f;
    attr.runtime_tensor_is_second = true;
    node->operation.attributes = std::move(attr);
    RETURN_IF_ERROR(graph->AddConsumer(node->id, forget_gate->id));
    RETURN_IF_ERROR(graph->SetProducer(node->id, input_gate->id));
  } else {
    RETURN_IF_ERROR(BuildLstmGate(
        graph, reader, old_output_state, old_cell_state,
        tflite::ops::builtin::lstm::full::kInputToInputWeightsTensor,
        tflite::ops::builtin::lstm::full::kRecurrentToInputWeightsTensor,
        tflite::ops::builtin::lstm::full::kCellToInputWeightsTensor,
        tflite::ops::builtin::lstm::full::kInputGateBiasTensor,
        tflite::ops::builtin::lstm::full::kInputLayerNormCoefficientsTensor,
        kTfLiteActSigmoid, has_peephole, has_normalization, &input_gate));
  }
  Value* cell_gate;
  RETURN_IF_ERROR(BuildLstmGate(
      graph, reader, old_output_state, old_cell_state,
      tflite::ops::builtin::lstm::full::kInputToCellWeightsTensor,
      tflite::ops::builtin::lstm::full::kRecurrentToCellWeightsTensor,
      -1,
      tflite::ops::builtin::lstm::full::kCellGateBiasTensor,
      tflite::ops::builtin::lstm::full::kCellLayerNormCoefficientsTensor,
      params->activation, false, has_normalization,
      &cell_gate));
  Value* new_cell_state;
  RETURN_IF_ERROR(BuildCellStateUpdate(graph, reader, forget_gate, input_gate,
                                       cell_gate, params->cell_clip,
                                       &new_cell_state));
  Value* output_gate;
  RETURN_IF_ERROR(BuildLstmGate(
      graph, reader, old_output_state, new_cell_state,
      tflite::ops::builtin::lstm::full::kInputToOutputWeightsTensor,
      tflite::ops::builtin::lstm::full::kRecurrentToOutputWeightsTensor,
      tflite::ops::builtin::lstm::full::kCellToOutputWeightsTensor,
      tflite::ops::builtin::lstm::full::kOutputGateBiasTensor,
      tflite::ops::builtin::lstm::full::kOutputLayerNormCoefficientsTensor,
      kTfLiteActSigmoid, has_peephole, has_normalization, &output_gate));
  Value* new_output_state;
  RETURN_IF_ERROR(BuildOutputStateUpdate(graph, reader, old_output_state,
                                         output_gate, new_cell_state,
                                         params->activation, has_projection,
                                         params->proj_clip, &new_output_state));
  {
    Node* node = graph->NewNode();
    node->operation.type = ToString(OperationType::COPY);
    RETURN_IF_ERROR(graph->AddConsumer(node->id, new_output_state->id));
    RETURN_IF_ERROR(reader->AddOutput(
        node, tflite::ops::builtin::lstm::full::kOutputTensor));
  }
  new_variable_input_values->clear();
  new_variable_input_values->emplace(
      tflite::ops::builtin::lstm::full::kCellStateTensor, new_cell_state->id);
  new_variable_input_values->emplace(
      tflite::ops::builtin::lstm::full::kOutputStateTensor,
      new_output_state->id);
  return absl::OkStatus();
}
absl :: Status ParseLSTMAttributes ( const TfLiteNode * tflite_node , const TfLiteRegistration * registration , GraphFloat32 * graph , ObjectReader * reader , const TfLiteLSTMParams * params , absl :: flat_hash_map < int , ValueId > * new_variable_input_values ) { const bool has_cifg = HasCifg ( tflite_node ) ; const bool has_peephole = HasPeephole ( tflite_node ) ; const bool has_normalization = HasNormalization ( tflite_node ) ; const bool has_projection = HasProjection ( tflite_node ) ; Value * old_cell_state ; RETURN_IF_ERROR ( reader -> ReadValue ( tflite :: ops :: builtin :: lstm :: full :: kCellStateTensor , & old_cell_state ) ) ; if ( old_cell_state -> tensor . shape . b != 1 ) { return absl :: InvalidArgumentError ( " " ) ; } Value * old_output_state ; RETURN_IF_ERROR ( reader -> ReadValue ( tflite :: ops :: builtin :: lstm :: full :: kOutputStateTensor , & old_output_state ) ) ; Value * forget_gate ; RETURN_IF_ERROR ( BuildLstmGate ( graph , reader , old_output_state , old_cell_state , tflite :: ops :: builtin :: lstm :: full :: kInputToForgetWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kRecurrentToForgetWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kCellToForgetWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kForgetGateBiasTensor , tflite :: ops :: builtin :: lstm :: full :: kForgetLayerNormCoefficientsTensor , kTfLiteActSigmoid , has_peephole , has_normalization , & forget_gate ) ) ; Value * input_gate ; if ( has_cifg ) { Node * node = graph -> NewNode ( ) ; input_gate = CreateNewSimilarValue ( graph , forget_gate ) ; node -> operation . type = ToString ( OperationType :: SUB ) ; ElementwiseAttributes attr ; attr . param = 1.0f ; attr . runtime_tensor_is_second = true ; node -> operation . attributes = std :: move ( attr ) ; RETURN_IF_ERROR ( graph -> AddConsumer ( node -> id , forget_gate -> id ) ) ; RETURN_IF_ERROR ( graph -> SetProducer ( node -> id , input_gate -> id ) ) ; } else { RETURN_IF_ERROR ( BuildLstmGate ( graph , reader , old_output_state , old_cell_state , tflite :: ops :: builtin :: lstm :: full :: kInputToInputWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kRecurrentToInputWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kCellToInputWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kInputGateBiasTensor , tflite :: ops :: builtin :: lstm :: full :: kInputLayerNormCoefficientsTensor , kTfLiteActSigmoid , has_peephole , has_normalization , & input_gate ) ) ; } Value * cell_gate ; RETURN_IF_ERROR ( BuildLstmGate ( graph , reader , old_output_state , old_cell_state , tflite :: ops :: builtin :: lstm :: full :: kInputToCellWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kRecurrentToCellWeightsTensor , -1 , tflite :: ops :: builtin :: lstm :: full :: kCellGateBiasTensor , tflite :: ops :: builtin :: lstm :: full :: kCellLayerNormCoefficientsTensor , params -> activation , false , has_normalization , & cell_gate ) ) ; Value * new_cell_state ; RETURN_IF_ERROR ( BuildCellStateUpdate ( graph , reader , forget_gate , input_gate , cell_gate , params -> cell_clip , & new_cell_state ) ) ; Value * output_gate ; RETURN_IF_ERROR ( BuildLstmGate ( graph , reader , old_output_state , new_cell_state , tflite :: ops :: builtin :: lstm :: full :: kInputToOutputWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kRecurrentToOutputWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kCellToOutputWeightsTensor , tflite :: ops :: builtin :: lstm :: full :: kOutputGateBiasTensor , tflite :: ops :: builtin :: lstm :: full :: kOutputLayerNormCoefficientsTensor , kTfLiteActSigmoid , has_peephole , has_normalization , & output_gate ) ) ; Value * new_output_state ; RETURN_IF_ERROR ( BuildOutputStateUpdate ( graph , reader , old_output_state , output_gate , new_cell_state , params -> activation , has_projection , params -> proj_clip , & new_output_state ) ) ; { Node * node = graph -> NewNode ( ) ; node -> operation . type = ToString ( OperationType :: COPY ) ; RETURN_IF_ERROR ( graph -> AddConsumer ( node -> id , new_output_state -> id ) ) ; RETURN_IF_ERROR ( reader -> AddOutput ( node , tflite :: ops :: builtin :: lstm :: full :: kOutputTensor ) ) ; } new_variable_input_values -> clear ( ) ; new_variable_input_values -> emplace ( tflite :: ops :: builtin :: lstm :: full :: kCellStateTensor , new_cell_state -> id ) ; new_variable_input_values -> emplace ( tflite :: ops :: builtin :: lstm :: full :: kOutputStateTensor , new_output_state -> id ) ; return absl :: OkStatus ( ) ; }
Build subgraph for a single LSTM OP.
Build subgraph for a single LSTM OP .
// When using cifg, input_gate is computed as (1 - forget_gate). // Cell state will not have peephole connections to itself /*cell_weight_id=*/ /*has_peephole=*/ // Copy updated output state to output.