class_docstr: This module implements the Functionally Equivalent Extraction attack for neural networks with two dense layers,
  ReLU activation at the first layer and logits output after the second layer.
  
  | Paper link: https://arxiv.org/abs/1909.01838
class_docstr_tok: ["This","module","implements","the","Functionally","Equivalent","Extraction","attack","for","neural","networks","with","two","dense","layers",",","ReLU","activation","at","the","first","layer","and","logits","output","after","the","second","layer",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/1909.01838"]
docstr: Extract weights and biases of the second layer.
  
  :param x: Samples of input data of shape `(num_samples, num_features)`.
  :param ftol: Tolerance for termination by the change of the cost function.
docstr_tok: ["Extract","weights","and","biases","of","the","second","layer",".",":","param","x",":","Samples","of","input","data","of","shape","`","(","num_samples",",","num_features",")","`",".",":","param","ftol",":","Tolerance","for","termination","by","the","change","of","the","cost","function","."]
code: def _last_layer_extraction(self, x: np.ndarray, ftol: float) -> None:
      """
      Extract weights and biases of the second layer.
  
      :param x: Samples of input data of shape `(num_samples, num_features)`.
      :param ftol: Tolerance for termination by the change of the cost function.
      """
      logger.info("Extract second layer.")
  
      if self.num_neurons is None:
          raise ValueError(
              "The value of `num_neurons` is required for critical point search."
          )
  
      predictions = self._o_l(x)
      w_1_b_1_0 = np.random.normal(
          0, 1, ((self.num_neurons + 1) * self.num_classes)
      ).astype(dtype=NUMPY_DTYPE)
  
      def f_w_1_b_1(w_1_b_1_i):
          layer_0 = np.maximum(
              np.matmul(self.w_0.T, x.T) + self.b_0, 0.0
          )
  
          w_1 = w_1_b_1_i[
              0 : self.num_neurons * self.num_classes
          ].reshape(self.num_neurons, self.num_classes)
          b_1 = w_1_b_1_i[
              self.num_neurons * self.num_classes :
          ].reshape(self.num_classes, 1)
  
          layer_1 = np.matmul(w_1.T, layer_0) + b_1
  
          return np.squeeze((layer_1.T - predictions).flatten())
  
      result_a1_b1 = least_squares(f_w_1_b_1, w_1_b_1_0, ftol=ftol)
  
      self.w_1 = result_a1_b1.x[
          0 : self.num_neurons * self.num_classes
      ].reshape(self.num_neurons, self.num_classes)
      self.b_1 = result_a1_b1.x[
          self.num_neurons * self.num_classes :
      ].reshape(self.num_classes, 1)
  
file_path: adversarial-robustness-toolbox/art/attacks/extraction/functionally_equivalent_extraction.py
imports: import logging
  import os
  from typing import List, Optional, TYPE_CHECKING
  import numpy
  from scipy.optimize import least_squares
  from art.attacks.attack import ExtractionAttack
  from art.estimators.estimator import BaseEstimator, NeuralNetworkMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.estimators.classification.keras import KerasClassifier
  from art.estimators.classification.blackbox import BlackBoxClassifier
label_desc: Use image node_id 8 for calling the FunctionallyEquivalentExtraction obj's underlying member method code with example usage: obj._last_layer_extraction(x, ftol) and returns: np