Trả lời câu hỏi với Android

Ứng dụng ví dụ trả lời câu hỏi trong Android

Hướng dẫn này chỉ cho bạn cách xây dựng một ứng dụng Android bằng TensorFlow Lite để cung cấp câu trả lời cho các câu hỏi có cấu trúc bằng văn bản ngôn ngữ tự nhiên. Ứng dụng ví dụ sử dụng API trình trả lời câu hỏi BERT ( BertQuestionAnswerer ) trong Thư viện tác vụ cho ngôn ngữ tự nhiên (NL) để kích hoạt các mô hình máy học trả lời câu hỏi. Ứng dụng này được thiết kế cho thiết bị Android vật lý nhưng cũng có thể chạy trên trình mô phỏng thiết bị.

Nếu bạn đang cập nhật một dự án hiện có, bạn có thể sử dụng ứng dụng mẫu làm tài liệu tham khảo hoặc mẫu. Để biết hướng dẫn về cách thêm phần trả lời câu hỏi vào ứng dụng hiện có, hãy tham khảo Cập nhật và sửa đổi ứng dụng của bạn .

Tổng quan về trả lời câu hỏi

Trả lời câu hỏi là nhiệm vụ học máy trả lời các câu hỏi được đặt ra bằng ngôn ngữ tự nhiên. Mô hình trả lời câu hỏi đã được đào tạo sẽ nhận một đoạn văn bản và câu hỏi làm đầu vào và cố gắng trả lời câu hỏi dựa trên việc diễn giải thông tin trong đoạn văn đó.

Mô hình trả lời câu hỏi được đào tạo trên tập dữ liệu trả lời câu hỏi, bao gồm tập dữ liệu đọc hiểu cùng với các cặp câu hỏi-trả lời dựa trên các đoạn văn bản khác nhau.

Để biết thêm thông tin về cách tạo các mô hình trong hướng dẫn này, hãy tham khảo phần Trả lời câu hỏi BERT với hướng dẫn TensorFlow Lite Model Maker .

Mô hình và tập dữ liệu

Ứng dụng ví dụ sử dụng mô hình Hỏi & Đáp BERT di động ( mobilebert ), đây là phiên bản nhẹ hơn và nhanh hơn của BERT (Biểu diễn bộ mã hóa hai chiều từ Transformers). Để biết thêm thông tin về mobilebert , hãy xem MobileBERT: tài liệu nghiên cứu về BERT không xác định nhiệm vụ nhỏ gọn dành cho các thiết bị có tài nguyên hạn chế .

Mô hình mobilebert được đào tạo bằng cách sử dụng bộ dữ liệu Bộ dữ liệu trả lời câu hỏi Stanford ( SQuAD ), bộ dữ liệu đọc hiểu bao gồm các bài viết từ Wikipedia và một tập hợp các cặp câu hỏi-trả lời cho mỗi bài viết.

Thiết lập và chạy ứng dụng mẫu

Để thiết lập ứng dụng trả lời câu hỏi, hãy tải xuống ứng dụng mẫu từ GitHub và chạy ứng dụng đó bằng Android Studio .

Yêu cầu hệ thống

  • Android Studio phiên bản 2021.1.1 (Bumblebee) trở lên.
  • SDK Android phiên bản 31 trở lên
  • Thiết bị Android có phiên bản hệ điều hành tối thiểu là SDK 21 (Android 7.0 - Nougat) đã bật chế độ nhà phát triển hoặc Trình mô phỏng Android.

Lấy mã ví dụ

Tạo một bản sao cục bộ của mã ví dụ. Bạn sẽ sử dụng mã này để tạo một dự án trong Android Studio và chạy ứng dụng mẫu.

Để sao chép và thiết lập mã ví dụ:

  1. Sao chép kho git
    git clone https://github.com/tensorflow/examples.git
    
  2. Bạn có thể tùy ý định cấu hình phiên bản git của mình để sử dụng tính năng kiểm tra thưa thớt, để bạn chỉ có các tệp cho ứng dụng mẫu trả lời câu hỏi:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/bert_qa/android
    

Nhập và chạy dự án

Tạo một dự án từ mã ví dụ đã tải xuống, xây dựng dự án rồi chạy nó.

Để nhập và xây dựng dự án mã ví dụ:

  1. Khởi động Android Studio .
  2. Từ Android Studio, chọn Tệp > Mới > Nhập dự án .
  3. Điều hướng đến thư mục mã ví dụ chứa tệp build.gradle ( .../examples/lite/examples/bert_qa/android/build.gradle ) và chọn thư mục đó.
  4. Nếu Android Studio yêu cầu Đồng bộ hóa Gradle, hãy chọn OK.
  5. Đảm bảo rằng thiết bị Android của bạn được kết nối với máy tính và chế độ nhà phát triển được bật. Nhấp vào mũi Run màu xanh lá cây.

Nếu bạn chọn đúng thư mục, Android Studio sẽ tạo một dự án mới và xây dựng nó. Quá trình này có thể mất vài phút, tùy thuộc vào tốc độ máy tính của bạn và liệu bạn có sử dụng Android Studio cho các dự án khác hay không. Khi quá trình xây dựng hoàn tất, Android Studio sẽ hiển thị thông báo BUILD SUCCESSFUL trong bảng trạng thái Build Output .

Để chạy dự án:

  1. Từ Android Studio, chạy dự án bằng cách chọn Run > Run… .
  2. Chọn một thiết bị Android (hoặc trình mô phỏng) được đính kèm để kiểm tra ứng dụng.

Sử dụng ứng dụng

Sau khi chạy dự án trong Android Studio, ứng dụng sẽ tự động mở trên thiết bị được kết nối hoặc trình mô phỏng thiết bị.

Để sử dụng ứng dụng ví dụ về Người trả lời câu hỏi:

  1. Chọn một chủ đề từ danh sách các chủ đề.
  2. Chọn một câu hỏi gợi ý hoặc nhập câu hỏi của riêng bạn vào hộp văn bản.
  3. Chuyển đổi mũi tên màu cam để chạy mô hình.

Ứng dụng cố gắng xác định câu trả lời cho câu hỏi từ văn bản đoạn văn. Nếu mô hình phát hiện câu trả lời trong đoạn văn, ứng dụng sẽ đánh dấu đoạn văn bản có liên quan cho người dùng.

Bây giờ bạn có một ứng dụng trả lời câu hỏi đang hoạt động. Sử dụng các phần sau để hiểu rõ hơn cách hoạt động của ứng dụng mẫu và cách triển khai các tính năng trả lời câu hỏi trong ứng dụng sản xuất của bạn:

Cách ứng dụng ví dụ hoạt động

Ứng dụng sử dụng API BertQuestionAnswerer trong thư viện Tác vụ cho gói ngôn ngữ tự nhiên (NL) . Mô hình MobileBERT được đào tạo bằng TensorFlow Lite Model Maker . Ứng dụng chạy trên CPU theo mặc định, với tùy chọn tăng tốc phần cứng bằng cách sử dụng đại biểu GPU hoặc NNAPI.

Các tệp và thư mục sau chứa mã quan trọng cho ứng dụng này:

  • BertQaHelper.kt - Khởi tạo người trả lời câu hỏi và xử lý việc lựa chọn mô hình và đại biểu.
  • QaFragment.kt - Xử lý và định dạng kết quả.
  • MainActivity.kt - Cung cấp logic tổ chức của ứng dụng.

Sửa đổi ứng dụng của bạn

Các phần sau đây giải thích các bước chính để sửa đổi ứng dụng Android của riêng bạn nhằm chạy mô hình được hiển thị trong ứng dụng ví dụ. Những hướng dẫn này sử dụng ứng dụng mẫu làm điểm tham chiếu. Những thay đổi cụ thể cần thiết cho ứng dụng của riêng bạn có thể khác với ứng dụng mẫu.

Mở hoặc tạo dự án Android

Bạn cần có một dự án phát triển Android trong Android Studio để làm theo những hướng dẫn còn lại. Thực hiện theo các hướng dẫn bên dưới để mở một dự án hiện có hoặc tạo một dự án mới.

Để mở một dự án phát triển Android hiện có:

  • Trong Android Studio, chọn Tệp > Mở và chọn dự án hiện có.

Để tạo một dự án phát triển Android cơ bản:

Để biết thêm thông tin về cách sử dụng Android Studio, hãy tham khảo tài liệu về Android Studio .

Thêm phụ thuộc dự án

Trong ứng dụng của riêng bạn, hãy thêm các phần phụ thuộc dự án cụ thể để chạy các mô hình học máy TensorFlow Lite và truy cập các chức năng tiện ích. Các hàm này chuyển đổi dữ liệu như chuỗi thành định dạng dữ liệu tensor mà mô hình có thể xử lý. Hướng dẫn sau đây giải thích cách thêm các phần phụ thuộc mô-đun và dự án bắt buộc vào dự án ứng dụng Android của riêng bạn.

Để thêm phụ thuộc mô-đun:

  1. Trong mô-đun sử dụng TensorFlow Lite, hãy cập nhật tệp build.gradle của mô-đun để bao gồm các phần phụ thuộc sau.

    Trong ứng dụng ví dụ, các phần phụ thuộc được đặt trong 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'
    }
    

    Dự án phải bao gồm thư viện tác vụ Text ( tensorflow-lite-task-text ).

    Nếu bạn muốn sửa đổi ứng dụng này để chạy trên bộ xử lý đồ họa (GPU), thư viện GPU ( tensorflow-lite-gpu-delegate-plugin ) cung cấp cơ sở hạ tầng để chạy ứng dụng trên GPU và Delegate ( tensorflow-lite-gpu ) cung cấp danh sách tương thích.

  2. Trong Android Studio, đồng bộ hóa các phần phụ thuộc của dự án bằng cách chọn: File > Sync Project with Gradle Files .

Khởi tạo các mô hình ML

Trong ứng dụng Android, bạn phải khởi tạo mô hình học máy TensorFlow Lite với các tham số trước khi chạy dự đoán bằng mô hình.

Mô hình TensorFlow Lite được lưu trữ dưới dạng tệp *.tflite . Tệp mô hình chứa logic dự đoán và thường bao gồm siêu dữ liệu về cách diễn giải kết quả dự đoán. Thông thường, các tệp mô hình được lưu trữ trong thư mục src/main/assets của dự án phát triển của bạn, như trong ví dụ về mã:

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

Để thuận tiện và dễ đọc mã, ví dụ khai báo một đối tượng đồng hành xác định cài đặt cho mô hình.

Để khởi tạo mô hình trong ứng dụng của bạn:

  1. Tạo một đối tượng đồng hành để xác định cài đặt cho mô hình. Trong ứng dụng ví dụ, đối tượng này được đặt tại 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. Tạo cài đặt cho mô hình bằng cách xây dựng đối tượng BertQaHelper và xây dựng đối tượng TensorFlow Lite với bertQuestionAnswerer .

    Trong ứng dụng ví dụ, điều này nằm trong hàm setupBertQuestionAnswerer() trong 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)
            }
        }
        ...
        }
    

Kích hoạt tính năng tăng tốc phần cứng (tùy chọn)

Khi khởi tạo mô hình TensorFlow Lite trong ứng dụng của mình, bạn nên cân nhắc sử dụng các tính năng tăng tốc phần cứng để tăng tốc độ tính toán dự đoán của mô hình. Các đại biểu TensorFlow Lite là các mô-đun phần mềm giúp tăng tốc việc thực thi các mô hình học máy bằng cách sử dụng phần cứng xử lý chuyên dụng trên thiết bị di động, chẳng hạn như bộ xử lý đồ họa (GPU) hoặc bộ xử lý tensor (TPU).

Để bật tính năng tăng tốc phần cứng trong ứng dụng của bạn:

  1. Tạo một biến để xác định đại biểu mà ứng dụng sẽ sử dụng. Trong ứng dụng ví dụ, biến này nằm sớm trong BertQaHelper.kt :

    var currentDelegate: Int = 0
    
  2. Tạo bộ chọn đại biểu. Trong ứng dụng ví dụ, bộ chọn đại biểu được đặt trong hàm setupBertQuestionAnswerer trong 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()
        }
    }
    

Nên sử dụng đại biểu để chạy các mô hình TensorFlow Lite nhưng không bắt buộc. Để biết thêm thông tin về cách sử dụng đại biểu với TensorFlow Lite, hãy xem Đại biểu TensorFlow Lite .

Chuẩn bị dữ liệu cho mô hình

Trong ứng dụng Android, mã của bạn cung cấp dữ liệu cho mô hình để diễn giải bằng cách chuyển đổi dữ liệu hiện có như văn bản thô thành định dạng dữ liệu Tensor mà mô hình của bạn có thể xử lý. Tensor mà bạn chuyển đến một mô hình phải có kích thước hoặc hình dạng cụ thể phù hợp với định dạng dữ liệu được sử dụng để huấn luyện mô hình. Ứng dụng trả lời câu hỏi này chấp nhận các chuỗi làm đầu vào cho cả đoạn văn bản và câu hỏi. Mô hình không nhận dạng được các ký tự đặc biệt và các từ không phải tiếng Anh.

Để cung cấp dữ liệu văn bản đoạn văn cho mô hình:

  1. Sử dụng đối tượng LoadDataSetClient để tải dữ liệu văn bản đoạn văn vào ứng dụng. Trong ứng dụng ví dụ, ứng dụng này nằm ở 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. Sử dụng đối tượng DatasetFragment để liệt kê tiêu đề cho từng đoạn văn bản và bắt đầu màn hình Câu hỏi và Trả lời TFL . Trong ứng dụng ví dụ, nó nằm trong 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. Sử dụng hàm onCreateViewHolder trong đối tượng DatasetAdapter để trình bày tiêu đề cho mỗi đoạn văn bản. Trong ứng dụng ví dụ, nó nằm trong DatasetAdapter.kt :

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

Để cung cấp câu hỏi của người dùng cho mô hình:

  1. Sử dụng đối tượng QaAdapter để cung cấp câu hỏi cho mô hình. Trong ứng dụng ví dụ, ứng dụng này nằm trong 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
          }
      }
      ...
    }
    

Chạy dự đoán

Trong ứng dụng Android, sau khi khởi tạo đối tượng BertQuestionAnswerer , bạn có thể bắt đầu nhập câu hỏi dưới dạng văn bản ngôn ngữ tự nhiên vào mô hình. Mô hình cố gắng xác định câu trả lời trong đoạn văn bản.

Để chạy dự đoán:

  1. Tạo hàm answer để chạy mô hình và đo thời gian cần thiết để xác định câu trả lời ( inferenceTime ). Trong ứng dụng ví dụ, hàm answer nằm trong 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. Chuyển kết quả từ answer đến đối tượng người nghe.

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

Xử lý đầu ra mô hình

Sau khi bạn nhập câu hỏi, mô hình sẽ cung cấp tối đa năm câu trả lời có thể có trong đoạn văn.

Để có được kết quả từ mô hình:

  1. Tạo hàm onResult cho đối tượng người nghe để xử lý đầu ra. Trong ứng dụng ví dụ, đối tượng người nghe được đặt tại BertQaHelper.kt

    interface AnswererListener {
        fun onError(error: String)
        fun onResults(
            results: List<QaAnswer>?,
            inferenceTime: Long
        )
    }
    
  2. Đánh dấu các phần của đoạn văn dựa trên kết quả. Trong ứng dụng ví dụ, ứng dụng này nằm trong 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
        )
    }
    

Sau khi mô hình trả về một tập hợp kết quả, ứng dụng của bạn có thể hành động theo những dự đoán đó bằng cách hiển thị kết quả cho người dùng hoặc thực thi logic bổ sung.

Bước tiếp theo