Rispondere alle domande con Android

App di esempio per la risposta alle domande in Android

Questo tutorial mostra come creare un'applicazione Android utilizzando TensorFlow Lite per fornire risposte a domande strutturate in testo in linguaggio naturale. L' applicazione di esempio utilizza l'API del risponditore di domande BERT ( BertQuestionAnswerer ) all'interno della libreria Task per il linguaggio naturale (NL) per abilitare i modelli di apprendimento automatico delle risposte alle domande. L'applicazione è progettata per un dispositivo Android fisico ma può essere eseguita anche su un emulatore di dispositivo.

Se stai aggiornando un progetto esistente, puoi utilizzare l'applicazione di esempio come riferimento o modello. Per istruzioni su come aggiungere risposte alle domande a un'applicazione esistente, fare riferimento a Aggiornamento e modifica dell'applicazione .

Panoramica sulla risposta alle domande

La risposta alle domande è il compito di apprendimento automatico di rispondere a domande poste in linguaggio naturale. Un modello di risposta alle domande addestrato riceve un passaggio di testo e una domanda come input e tenta di rispondere alla domanda in base alla sua interpretazione delle informazioni all'interno del passaggio.

Un modello di risposta alle domande viene addestrato su un set di dati di risposta alle domande, che consiste in un set di dati sulla comprensione della lettura insieme a coppie domanda-risposta basate su diversi segmenti di testo.

Per ulteriori informazioni su come vengono generati i modelli in questo tutorial, fare riferimento al tutorial BERT Question Answer with TensorFlow Lite Model Maker .

Modelli e set di dati

L'app di esempio utilizza il modello Mobile BERT Q&A ( mobilebert ), che è una versione più leggera e veloce di BERT (Bidirection Encoder Representations from Transformers). Per ulteriori informazioni su mobilebert , consultare il documento di ricerca MobileBERT: a Compact Task-Agnostic BERT for Resource-Limited Devices .

Il modello mobilebert è stato addestrato utilizzando il set di dati Stanford Question Answering Dataset ( SQuAD ), un set di dati sulla comprensione della lettura composto da articoli di Wikipedia e una serie di coppie domanda-risposta per ciascun articolo.

Configura ed esegui l'app di esempio

Per configurare l'applicazione di risposta alle domande, scarica l'app di esempio da GitHub ed eseguila utilizzando Android Studio .

Requisiti di sistema

  • Android Studio versione 2021.1.1 (Bumblebee) o successiva.
  • Android SDK versione 31 o successiva
  • Dispositivo Android con una versione minima del sistema operativo SDK 21 (Android 7.0 - Nougat) con modalità sviluppatore abilitata o un emulatore Android.

Ottieni il codice di esempio

Crea una copia locale del codice di esempio. Utilizzerai questo codice per creare un progetto in Android Studio ed eseguire l'applicazione di esempio.

Per clonare e configurare il codice di esempio:

  1. Clona il repository git
    git clone https://github.com/tensorflow/examples.git
    
  2. Facoltativamente, configura la tua istanza git per utilizzare il checkout sparse, in modo da avere solo i file per l'app di esempio di risposta alle domande:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/bert_qa/android
    

Importare ed eseguire il progetto

Crea un progetto dal codice di esempio scaricato, crea il progetto e quindi eseguilo.

Per importare e creare il progetto di codice di esempio:

  1. Avvia Android Studio .
  2. Da Android Studio, seleziona File > Nuovo > Importa progetto .
  3. Passare alla directory del codice di esempio contenente il file build.gradle ( .../examples/lite/examples/bert_qa/android/build.gradle ) e selezionare quella directory.
  4. Se Android Studio richiede una sincronizzazione Gradle, scegli OK.
  5. Assicurati che il tuo dispositivo Android sia collegato al computer e che la modalità sviluppatore sia abilitata. Fare clic sulla freccia verde Run .

Se selezioni la directory corretta, Android Studio crea un nuovo progetto e lo crea. Questo processo può richiedere alcuni minuti, a seconda della velocità del tuo computer e se hai utilizzato Android Studio per altri progetti. Una volta completata la build, Android Studio visualizza un messaggio BUILD SUCCESSFUL nel pannello di stato dell'output della build .

Per eseguire il progetto:

  1. Da Android Studio, esegui il progetto selezionando Esegui > Esegui… .
  2. Seleziona un dispositivo Android collegato (o un emulatore) per testare l'app.

Utilizzando l'applicazione

Dopo aver eseguito il progetto in Android Studio, l'applicazione si apre automaticamente sul dispositivo connesso o sull'emulatore del dispositivo.

Per utilizzare l'app di esempio Rispondi domande:

  1. Scegli un argomento dall'elenco degli argomenti.
  2. Scegli una domanda suggerita o inserisci la tua nella casella di testo.
  3. Attiva la freccia arancione per eseguire il modello.

L'applicazione tenta di identificare la risposta alla domanda dal testo del brano. Se il modello rileva una risposta all'interno del passaggio, l'applicazione evidenzia l'intervallo di testo rilevante per l'utente.

Ora disponi di un'applicazione di risposta alle domande funzionante. Utilizza le seguenti sezioni per comprendere meglio come funziona l'applicazione di esempio e come implementare le funzionalità di risposta alle domande nelle tue applicazioni di produzione:

Come funziona l'app di esempio

L'applicazione utilizza l'API BertQuestionAnswerer all'interno della libreria Task per il pacchetto Natural Language (NL) . Il modello MobileBERT è stato addestrato utilizzando TensorFlow Lite Model Maker . L'applicazione viene eseguita sulla CPU per impostazione predefinita, con l'opzione di accelerazione hardware tramite GPU o delegato NNAPI.

I seguenti file e directory contengono il codice cruciale per questa applicazione:

  • BertQaHelper.kt : inizializza il risponditore della domanda e gestisce la selezione del modello e del delegato.
  • QaFragment.kt : gestisce e formatta i risultati.
  • MainActivity.kt : fornisce la logica organizzativa dell'app.

Modifica la tua richiesta

Le sezioni seguenti spiegano i passaggi chiave per modificare la tua app Android per eseguire il modello mostrato nell'app di esempio. Queste istruzioni utilizzano l'app di esempio come punto di riferimento. Le modifiche specifiche necessarie per la tua app possono variare rispetto all'app di esempio.

Apri o crea un progetto Android

È necessario un progetto di sviluppo Android in Android Studio da seguire insieme al resto di queste istruzioni. Seguire le istruzioni seguenti per aprire un progetto esistente o crearne uno nuovo.

Per aprire un progetto di sviluppo Android esistente:

  • In Android Studio, seleziona File > Apri e seleziona un progetto esistente.

Per creare un progetto di sviluppo Android di base:

Per ulteriori informazioni sull'utilizzo di Android Studio, fare riferimento alla documentazione di Android Studio .

Aggiungi dipendenze del progetto

Nella tua applicazione, aggiungi dipendenze di progetto specifiche per eseguire modelli di machine learning TensorFlow Lite e accedere alle funzioni di utilità. Queste funzioni convertono dati come stringhe in un formato dati tensoriale che può essere elaborato dal modello. Le seguenti istruzioni spiegano come aggiungere il progetto richiesto e le dipendenze del modulo al tuo progetto di app Android.

Per aggiungere dipendenze del modulo:

  1. Nel modulo che utilizza TensorFlow Lite, aggiorna il file build.gradle del modulo per includere le seguenti dipendenze.

    Nell'applicazione di esempio, le dipendenze si trovano in app/build.gradle :

    dependencies {
      ...
      // Import tensorflow library
      implementation 'org.tensorflow:tensorflow-lite-task-text:0.3.0'
    
      // Import the GPU delegate plugin Library for GPU inference
      implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0'
      implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0'
    }
    

    Il progetto deve includere la libreria delle attività Text ( tensorflow-lite-task-text ).

    Se desideri modificare questa app per l'esecuzione su un'unità di elaborazione grafica (GPU), la libreria GPU ( tensorflow-lite-gpu-delegate-plugin ) fornisce l'infrastruttura per eseguire l'app su GPU e Delegate ( tensorflow-lite-gpu ) fornisce l'elenco di compatibilità.

  2. In Android Studio, sincronizza le dipendenze del progetto selezionando: File > Sincronizza progetto con file Gradle .

Inizializza i modelli ML

Nella tua app Android, devi inizializzare il modello di machine learning TensorFlow Lite con i parametri prima di eseguire previsioni con il modello.

Un modello TensorFlow Lite viene archiviato come file *.tflite . Il file del modello contiene la logica della previsione e in genere include metadati su come interpretare i risultati della previsione. In genere, i file del modello vengono archiviati nella directory src/main/assets del progetto di sviluppo, come nell'esempio di codice:

  • <project>/src/main/assets/mobilebert_qa.tflite

Per comodità e leggibilità del codice, l'esempio dichiara un oggetto associato che definisce le impostazioni per il modello.

Per inizializzare il modello nella tua app:

  1. Creare un oggetto associato per definire le impostazioni per il modello. Nell'applicazione di esempio, questo oggetto si trova in BertQaHelper.kt :

    companion object {
        private const val BERT_QA_MODEL = "mobilebert.tflite"
        private const val TAG = "BertQaHelper"
        const val DELEGATE_CPU = 0
        const val DELEGATE_GPU = 1
        const val DELEGATE_NNAPI = 2
    }
    
  2. Crea le impostazioni per il modello creando un oggetto BertQaHelper e costruisci un oggetto TensorFlow Lite con bertQuestionAnswerer .

    Nell'applicazione di esempio, questo si trova nella funzione setupBertQuestionAnswerer() all'interno di BertQaHelper.kt :

    class BertQaHelper(
        ...
    ) {
        ...
        init {
            setupBertQuestionAnswerer()
        }
    
        fun clearBertQuestionAnswerer() {
            bertQuestionAnswerer = null
        }
    
        private fun setupBertQuestionAnswerer() {
            val baseOptionsBuilder = BaseOptions.builder().setNumThreads(numThreads)
            ...
            val options = BertQuestionAnswererOptions.builder()
                .setBaseOptions(baseOptionsBuilder.build())
                .build()
    
            try {
                bertQuestionAnswerer =
                    BertQuestionAnswerer.createFromFileAndOptions(context, BERT_QA_MODEL, options)
            } catch (e: IllegalStateException) {
                answererListener
                    ?.onError("Bert Question Answerer failed to initialize. See error logs for details")
                Log.e(TAG, "TFLite failed to load model with error: " + e.message)
            }
        }
        ...
        }
    

Abilita l'accelerazione hardware (facoltativo)

Quando inizializzi un modello TensorFlow Lite nella tua app, dovresti prendere in considerazione l'utilizzo delle funzionalità di accelerazione hardware per accelerare i calcoli di previsione del modello. I delegati TensorFlow Lite sono moduli software che accelerano l'esecuzione di modelli di machine learning utilizzando hardware di elaborazione specializzato su un dispositivo mobile, come unità di elaborazione grafica (GPU) o unità di elaborazione tensore (TPU).

Per abilitare l'accelerazione hardware nella tua app:

  1. Creare una variabile per definire il delegato che verrà utilizzato dall'applicazione. Nell'applicazione di esempio, questa variabile si trova all'inizio di BertQaHelper.kt :

    var currentDelegate: Int = 0
    
  2. Creare un selettore di delegati. Nell'applicazione di esempio, il selettore del delegato si trova nella funzione setupBertQuestionAnswerer all'interno di BertQaHelper.kt :

    when (currentDelegate) {
        DELEGATE_CPU -> {
            // Default
        }
        DELEGATE_GPU -> {
            if (CompatibilityList().isDelegateSupportedOnThisDevice) {
                baseOptionsBuilder.useGpu()
            } else {
                answererListener?.onError("GPU is not supported on this device")
            }
        }
        DELEGATE_NNAPI -> {
            baseOptionsBuilder.useNnapi()
        }
    }
    

L'utilizzo dei delegati per l'esecuzione dei modelli TensorFlow Lite è consigliato, ma non obbligatorio. Per ulteriori informazioni sull'utilizzo dei delegati con TensorFlow Lite, consulta Delegati TensorFlow Lite .

Preparare i dati per il modello

Nella tua app Android, il tuo codice fornisce dati al modello per l'interpretazione trasformando i dati esistenti come il testo non elaborato in un formato dati Tensor che può essere elaborato dal tuo modello. Il tensore che passi a un modello deve avere dimensioni, o forma, specifiche che corrispondono al formato dei dati utilizzati per addestrare il modello. Questa app di risposta alle domande accetta stringhe come input sia per il passaggio di testo che per la domanda. Il modello non riconosce caratteri speciali e parole non inglesi.

Per fornire dati di testo del passaggio al modello:

  1. Utilizza l'oggetto LoadDataSetClient per caricare i dati del testo del passaggio nell'app. Nell'applicazione di esempio, questo si trova in LoadDataSetClient.kt

    fun loadJson(): DataSet? {
        var dataSet: DataSet? = null
        try {
            val inputStream: InputStream = context.assets.open(JSON_DIR)
            val bufferReader = inputStream.bufferedReader()
            val stringJson: String = bufferReader.use { it.readText() }
            val datasetType = object : TypeToken<DataSet>() {}.type
            dataSet = Gson().fromJson(stringJson, datasetType)
        } catch (e: IOException) {
            Log.e(TAG, e.message.toString())
        }
        return dataSet
    }
    
  2. Utilizzare l'oggetto DatasetFragment per elencare i titoli per ogni passaggio di testo e avviare la schermata Domande e risposte TFL . Nell'applicazione di esempio, questo si trova in DatasetFragment.kt :

    class DatasetFragment : Fragment() {
        ...
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            val client = LoadDataSetClient(requireActivity())
            client.loadJson()?.let {
                titles = it.getTitles()
            }
            ...
        }
       ...
    }
    
  3. Utilizza la funzione onCreateViewHolder all'interno dell'oggetto DatasetAdapter per presentare i titoli per ogni passaggio di testo. Nell'applicazione di esempio, questo si trova in DatasetAdapter.kt :

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemDatasetBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        return ViewHolder(binding)
    }
    

Per fornire domande dell'utente al modello:

  1. Utilizza l'oggetto QaAdapter per fornire la domanda al modello. Nell'applicazione di esempio, questo si trova in QaAdapter.kt :

    class QaAdapter(private val question: List<String>, private val select: (Int) -> Unit) :
      RecyclerView.Adapter<QaAdapter.ViewHolder>() {
    
      inner class ViewHolder(private val binding: ItemQuestionBinding) :
          RecyclerView.ViewHolder(binding.root) {
          init {
              binding.tvQuestionSuggestion.setOnClickListener {
                  select.invoke(adapterPosition)
              }
          }
    
          fun bind(question: String) {
              binding.tvQuestionSuggestion.text = question
          }
      }
      ...
    }
    

Esegui previsioni

Nella tua app Android, dopo aver inizializzato un oggetto BertQuestionAnswerer , puoi iniziare a inserire domande sotto forma di testo in linguaggio naturale nel modello. Il modello tenta di identificare la risposta all'interno del passaggio di testo.

Per eseguire le previsioni:

  1. Creare una funzione answer , che esegue il modello e misura il tempo impiegato per identificare la risposta ( inferenceTime ). Nell'applicazione di esempio, la funzione answer si trova in BertQaHelper.kt :

    fun answer(contextOfQuestion: String, question: String) {
        if (bertQuestionAnswerer == null) {
            setupBertQuestionAnswerer()
        }
    
        var inferenceTime = SystemClock.uptimeMillis()
    
        val answers = bertQuestionAnswerer?.answer(contextOfQuestion, question)
        inferenceTime = SystemClock.uptimeMillis() - inferenceTime
        answererListener?.onResults(answers, inferenceTime)
    }
    
  2. Passa i risultati dalla answer all'oggetto listener.

    interface AnswererListener {
        fun onError(error: String)
        fun onResults(
            results: List<QaAnswer>?,
            inferenceTime: Long
        )
    }
    

Gestire l'output del modello

Dopo aver inserito una domanda, il modello fornisce un massimo di cinque possibili risposte all'interno del passaggio.

Per ottenere i risultati dal modello:

  1. Crea una funzione onResult affinché l'oggetto listener gestisca l'output. Nell'applicazione di esempio, l'oggetto listener si trova in BertQaHelper.kt

    interface AnswererListener {
        fun onError(error: String)
        fun onResults(
            results: List<QaAnswer>?,
            inferenceTime: Long
        )
    }
    
  2. Evidenzia le sezioni del passaggio in base ai risultati. Nell'applicazione di esempio, questo si trova in QaFragment.kt :

    override fun onResults(results: List<QaAnswer>?, inferenceTime: Long) {
        results?.first()?.let {
            highlightAnswer(it.text)
        }
    
        fragmentQaBinding.tvInferenceTime.text = String.format(
            requireActivity().getString(R.string.bottom_view_inference_time),
            inferenceTime
        )
    }
    

Una volta che il modello ha restituito una serie di risultati, la tua applicazione può agire in base a tali previsioni presentando il risultato all'utente o eseguendo logica aggiuntiva.

Prossimi passi