ตอบคำถามด้วย Android

ตัวอย่างแอปตอบคำถามใน Android

บทช่วยสอนนี้แสดงวิธีสร้างแอปพลิเคชัน Android โดยใช้ TensorFlow Lite เพื่อให้คำตอบสำหรับคำถามที่มีโครงสร้างเป็นข้อความภาษาธรรมชาติ แอปพลิเคชันตัวอย่าง ใช้ API ตัวตอบคำถาม BERT ( BertQuestionAnswerer ) ภายใน ไลบรารีงานสำหรับภาษาธรรมชาติ (NL) เพื่อเปิดใช้งานโมเดลการเรียนรู้ของเครื่องตอบคำถาม แอปพลิเคชันนี้ออกแบบมาสำหรับอุปกรณ์ Android จริง แต่สามารถทำงานบนอุปกรณ์จำลองได้

หากคุณกำลังอัปเดตโปรเจ็กต์ที่มีอยู่ คุณสามารถใช้แอปพลิเคชันตัวอย่างเป็นข้อมูลอ้างอิงหรือเทมเพลตได้ สำหรับคำแนะนำเกี่ยวกับวิธีการเพิ่มคำถามเพื่อตอบคำถามไปยังแอปพลิเคชันที่มีอยู่ โปรดดูที่ การอัปเดตและการแก้ไขแอปพลิเคชันของคุณ

ภาพรวมการตอบคำถาม

การตอบคำถาม เป็นงานการเรียนรู้ของเครื่องในการตอบคำถามที่ใช้ภาษาธรรมชาติ โมเดลการตอบคำถามที่ได้รับการฝึกอบรมจะได้รับข้อความและคำถามเป็นข้อมูลป้อนเข้า และพยายามตอบคำถามตามการตีความข้อมูลภายในเนื้อเรื่อง

โมเดลการตอบคำถามได้รับการฝึกอบรมเกี่ยวกับชุดข้อมูลการตอบคำถาม ซึ่งประกอบด้วยชุดข้อมูลเพื่อความเข้าใจในการอ่าน พร้อมด้วยคู่คำถาม-คำตอบโดยอิงตามส่วนต่างๆ ของข้อความ

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการสร้างโมเดลในบทช่วยสอนนี้ โปรดดูบท ช่วยสอน BERT Question Answer with TensorFlow Lite Model Maker

โมเดลและชุดข้อมูล

แอปตัวอย่างใช้โมเดล Mobile BERT Q&A ( mobilebert ) ซึ่งเป็นเวอร์ชันที่เบากว่าและเร็วกว่าของ BERT (การแสดงตัวเข้ารหัสแบบสองทิศทางจาก Transformers) สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ mobilebert โปรดดูเอกสารวิจัย MobileBERT: a Compact Task-Agnostic BERT for Resource-Limited Devices

โมเดล mobilebert ได้รับการฝึกโดยใช้ชุดข้อมูล Stanford Question Answering Dataset ( SQuAD ) ซึ่งเป็นชุดข้อมูลเพื่อความเข้าใจในการอ่านที่ประกอบด้วยบทความจาก Wikipedia และชุดคู่คำถาม-คำตอบสำหรับแต่ละบทความ

ตั้งค่าและเรียกใช้แอปตัวอย่าง

หากต้องการตั้งค่าแอปพลิเคชันตอบคำถาม ให้ดาวน์โหลดแอปตัวอย่างจาก GitHub และเรียกใช้โดยใช้ Android Studio

ความต้องการของระบบ

  • Android Studio เวอร์ชัน 2021.1.1 (Bumblebee) หรือสูงกว่า
  • Android SDK เวอร์ชัน 31 ขึ้นไป
  • อุปกรณ์ Android ที่มีระบบปฏิบัติการเวอร์ชันขั้นต่ำ SDK 21 (Android 7.0 - Nougat) พร้อมเปิดใช้งาน โหมดนักพัฒนาซอฟต์แวร์ หรือ Android Emulator

รับโค้ดตัวอย่าง

สร้างสำเนาโค้ดตัวอย่างในเครื่อง คุณจะใช้โค้ดนี้เพื่อสร้างโปรเจ็กต์ใน Android Studio และเรียกใช้แอปพลิเคชันตัวอย่าง

หากต้องการโคลนและตั้งค่าโค้ดตัวอย่าง:

  1. โคลนที่เก็บ git
    git clone https://github.com/tensorflow/examples.git
    
  2. คุณสามารถเลือกกำหนดค่าอินสแตนซ์ git ของคุณเพื่อใช้การชำระเงินแบบกระจัดกระจาย เพื่อให้คุณมีเฉพาะไฟล์สำหรับแอปตัวอย่างการตอบคำถาม:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/bert_qa/android
    

นำเข้าและรันโครงการ

สร้างโปรเจ็กต์จากโค้ดตัวอย่างที่ดาวน์โหลด สร้างโปรเจ็กต์ จากนั้นรัน

หากต้องการนำเข้าและสร้างโปรเจ็กต์โค้ดตัวอย่าง:

  1. เริ่ม Android สตูดิโอ
  2. จาก Android Studio ให้เลือก File > New > Import Project
  3. นำทางไปยังไดเร็กทอรีโค้ดตัวอย่างที่มีไฟล์ build.gradle ( .../examples/lite/examples/bert_qa/android/build.gradle ) และเลือกไดเร็กทอรีนั้น
  4. หาก Android Studio ขอ Gradle Sync ให้เลือกตกลง
  5. ตรวจสอบให้แน่ใจว่าอุปกรณ์ Android ของคุณเชื่อมต่อกับคอมพิวเตอร์และเปิดใช้งานโหมดนักพัฒนาซอฟต์แวร์แล้ว คลิกลูก Run สีเขียว

หากคุณเลือกไดเร็กทอรีที่ถูกต้อง Android Studio จะสร้างโปรเจ็กต์ใหม่และสร้างมันขึ้นมา กระบวนการนี้อาจใช้เวลาสักครู่ ขึ้นอยู่กับความเร็วของคอมพิวเตอร์ และหากคุณใช้ Android Studio สำหรับโปรเจ็กต์อื่นหรือไม่ เมื่อการสร้างเสร็จสมบูรณ์ Android Studio จะแสดงข้อความ BUILD SUCCESSFUL ในแผงสถานะ Build Output

ในการดำเนินโครงการ:

  1. จาก Android Studio ให้รันโปรเจ็กต์โดยเลือก Run > Run…
  2. เลือกอุปกรณ์ Android (หรือโปรแกรมจำลอง) ที่แนบมาเพื่อทดสอบแอป

การใช้แอพพลิเคชั่น

หลังจากรันโปรเจ็กต์ใน Android Studio แอปพลิเคชันจะเปิดขึ้นโดยอัตโนมัติบนอุปกรณ์ที่เชื่อมต่อหรือโปรแกรมจำลองอุปกรณ์

วิธีใช้แอปตัวอย่างการตอบคำถาม:

  1. เลือกหัวข้อจากรายการวิชา
  2. เลือกคำถามที่แนะนำหรือป้อนคำถามของคุณเองในกล่องข้อความ
  3. สลับลูกศรสีส้มเพื่อเรียกใช้โมเดล

แอปพลิเคชันพยายามระบุคำตอบของคำถามจากข้อความเนื้อเรื่อง หากแบบจำลองตรวจพบคำตอบภายในข้อความ แอปพลิเคชันจะเน้นช่วงข้อความที่เกี่ยวข้องสำหรับผู้ใช้

ตอนนี้คุณมีแอปพลิเคชันตอบคำถามที่ใช้งานได้แล้ว ใช้ส่วนต่อไปนี้เพื่อทำความเข้าใจวิธีการทำงานของแอปพลิเคชันตัวอย่างให้ดียิ่งขึ้น และวิธีการใช้คุณลักษณะการตอบคำถามในแอปพลิเคชันที่ใช้งานจริงของคุณ:

แอปตัวอย่างทำงานอย่างไร

แอปพลิเคชันใช้ BertQuestionAnswerer API ภายใน ไลบรารีงานสำหรับแพ็คเกจภาษาธรรมชาติ (NL) โมเดล MobileBERT ได้รับการฝึกโดยใช้ TensorFlow Lite Model Maker แอปพลิเคชันทำงานบน CPU ตามค่าเริ่มต้น พร้อมตัวเลือกในการเร่งความเร็วด้วยฮาร์ดแวร์โดยใช้ GPU หรือตัวแทน NNAPI

ไฟล์และไดเร็กทอรีต่อไปนี้มีรหัสสำคัญสำหรับแอปพลิเคชันนี้:

  • BertQaHelper.kt - เริ่มต้นผู้ตอบคำถามและจัดการการเลือกแบบจำลองและผู้รับมอบสิทธิ์
  • QaFragment.kt - จัดการและจัดรูปแบบผลลัพธ์
  • MainActivity.kt - จัดเตรียมตรรกะการจัดระเบียบของแอป

แก้ไขใบสมัครของคุณ

ส่วนต่อไปนี้อธิบายขั้นตอนสำคัญในการแก้ไขแอป Android ของคุณเองเพื่อรันโมเดลที่แสดงในแอปตัวอย่าง คำแนะนำเหล่านี้ใช้แอปตัวอย่างเป็นจุดอ้างอิง การเปลี่ยนแปลงเฉพาะที่จำเป็นสำหรับแอปของคุณอาจแตกต่างกันไปจากแอปตัวอย่าง

เปิดหรือสร้างโครงการ Android

คุณต้องมีโครงการพัฒนา Android ใน Android Studio เพื่อปฏิบัติตามคำแนะนำที่เหลือ ทำตามคำแนะนำด้านล่างเพื่อเปิดโปรเจ็กต์ที่มีอยู่หรือสร้างโปรเจ็กต์ใหม่

หากต้องการเปิดโครงการพัฒนา Android ที่มีอยู่:

  • ใน Android Studio ให้เลือก ไฟล์ > เปิด และเลือกโปรเจ็กต์ที่มีอยู่

ในการสร้างโครงการพัฒนา Android ขั้นพื้นฐาน:

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Android Studio โปรดดู เอกสารประกอบของ Android Studio

เพิ่มการพึ่งพาโครงการ

ในแอปพลิเคชันของคุณเอง ให้เพิ่มการพึ่งพาโปรเจ็กต์เฉพาะเพื่อรันโมเดลแมชชีนเลิร์นนิงของ TensorFlow Lite และเข้าถึงฟังก์ชันยูทิลิตี้ ฟังก์ชันเหล่านี้จะแปลงข้อมูล เช่น สตริง ให้เป็นรูปแบบข้อมูลเทนเซอร์ที่โมเดลสามารถประมวลผลได้ คำแนะนำต่อไปนี้จะอธิบายวิธีเพิ่มการขึ้นต่อกันของโปรเจ็กต์และโมดูลที่จำเป็นให้กับโปรเจ็กต์แอป Android ของคุณเอง

ในการเพิ่มการพึ่งพาโมดูล:

  1. ในโมดูลที่ใช้ TensorFlow Lite ให้อัปเดตไฟล์ build.gradle ของโมดูลเพื่อรวมการอ้างอิงต่อไปนี้

    ในแอปพลิเคชันตัวอย่าง การขึ้นต่อกันจะอยู่ใน 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'
    }
    

    โครงการจะต้องมีไลบรารีงานข้อความ ( tensorflow-lite-task-text )

    หากคุณต้องการแก้ไขแอปนี้ให้ทำงานบนหน่วยประมวลผลกราฟิก (GPU) ไลบรารี GPU ( tensorflow-lite-gpu-delegate-plugin ) จะจัดเตรียมโครงสร้างพื้นฐานเพื่อเรียกใช้แอปบน GPU และ Delegate ( tensorflow-lite-gpu ) แสดงรายการความเข้ากันได้

  2. ใน Android Studio ให้ซิงค์การขึ้นต่อกันของโปรเจ็กต์โดยเลือก: ไฟล์ > ซิงค์โปรเจ็กต์กับไฟล์ Gradle

เริ่มต้นโมเดล ML

ในแอป Android คุณต้องเริ่มต้นโมเดลแมชชีนเลิร์นนิง TensorFlow Lite ด้วยพารามิเตอร์ก่อนที่จะเรียกใช้การคาดการณ์ด้วยโมเดล

โมเดล TensorFlow Lite จะถูกจัดเก็บเป็นไฟล์ *.tflite ไฟล์โมเดลประกอบด้วยตรรกะการทำนาย และโดยทั่วไปจะมี ข้อมูลเมตา เกี่ยวกับวิธีการตีความผลลัพธ์การทำนาย โดยทั่วไป ไฟล์โมเดลจะถูกจัดเก็บไว้ในไดเร็กทอรี src/main/assets ของโปรเจ็กต์การพัฒนาของคุณ ดังตัวอย่างโค้ด:

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

เพื่อความสะดวกและความสามารถในการอ่านโค้ด ตัวอย่างจะประกาศออบเจ็กต์ที่แสดงร่วมกันซึ่งกำหนดการตั้งค่าสำหรับโมเดล

ในการเริ่มต้นโมเดลในแอปของคุณ:

  1. สร้างออบเจ็กต์ร่วมเพื่อกำหนดการตั้งค่าสำหรับโมเดล ในแอปพลิเคชันตัวอย่าง อ็อบเจ็กต์นี้จะอยู่ใน 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. สร้างการตั้งค่าสำหรับโมเดลโดยการสร้างวัตถุ BertQaHelper และสร้างวัตถุ TensorFlow Lite ด้วย bertQuestionAnswerer

    ในแอปพลิเคชันตัวอย่าง ค่านี้จะอยู่ในฟังก์ชัน setupBertQuestionAnswerer() ภายใน 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)
            }
        }
        ...
        }
    

เปิดใช้งานการเร่งด้วยฮาร์ดแวร์ (ไม่จำเป็น)

เมื่อเริ่มต้นโมเดล TensorFlow Lite ในแอปของคุณ คุณควรพิจารณาใช้ฟีเจอร์การเร่งด้วยฮาร์ดแวร์เพื่อเพิ่มความเร็วในการคำนวณการคาดการณ์ของโมเดล ผู้ร่วมประชุม TensorFlow Lite คือโมดูลซอฟต์แวร์ที่เร่งการดำเนินการโมเดลการเรียนรู้ของเครื่องโดยใช้ฮาร์ดแวร์การประมวลผลเฉพาะทางบนอุปกรณ์เคลื่อนที่ เช่น หน่วยประมวลผลกราฟิก (GPU) หรือหน่วยประมวลผลเทนเซอร์ (TPU)

หากต้องการเปิดใช้งานการเร่งด้วยฮาร์ดแวร์ในแอปของคุณ:

  1. สร้างตัวแปรเพื่อกำหนดผู้รับมอบสิทธิ์ที่แอปพลิเคชันจะใช้ ในแอปพลิเคชันตัวอย่าง ตัวแปรนี้อยู่ที่ช่วงต้นของ BertQaHelper.kt :

    var currentDelegate: Int = 0
    
  2. สร้างตัวเลือกผู้รับมอบสิทธิ์ ในแอปพลิเคชันตัวอย่าง ตัวเลือกผู้รับมอบสิทธิ์จะอยู่ในฟังก์ชัน setupBertQuestionAnswerer ภายใน 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()
        }
    }
    

แนะนำให้ใช้ผู้รับมอบสิทธิ์เพื่อเรียกใช้โมเดล TensorFlow Lite แต่ไม่จำเป็น สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ผู้ร่วมประชุมกับ TensorFlow Lite โปรดดูที่ TensorFlow Lite Delegates

เตรียมข้อมูลสำหรับโมเดล

ในแอป Android โค้ดของคุณจะให้ข้อมูลแก่โมเดลสำหรับการตีความโดยการแปลงข้อมูลที่มีอยู่ เช่น ข้อความดิบ ให้เป็นรูปแบบข้อมูล Tensor ที่โมเดลของคุณสามารถประมวลผลได้ เทนเซอร์ที่คุณส่งไปยังโมเดลจะต้องมีขนาดหรือรูปร่างเฉพาะที่ตรงกับรูปแบบของข้อมูลที่ใช้ในการฝึกโมเดล แอปตอบคำถามนี้ยอมรับ สตริง เป็นอินพุตสำหรับทั้งข้อความและคำถาม โมเดลไม่รู้จักอักขระพิเศษและคำที่ไม่ใช่ภาษาอังกฤษ

ในการจัดเตรียมข้อมูลข้อความให้กับโมเดล:

  1. ใช้ออบเจ็กต์ LoadDataSetClient เพื่อโหลดข้อมูลข้อความไปยังแอป ในแอปพลิเคชันตัวอย่าง จะอยู่ใน 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. ใช้ออบเจ็กต์ DatasetFragment เพื่อแสดงรายการชื่อเรื่องสำหรับข้อความแต่ละตอน และเริ่มหน้าจอ คำถามและคำตอบ TFL ในแอปพลิเคชันตัวอย่าง จะอยู่ใน 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. ใช้ฟังก์ชัน onCreateViewHolder ภายในออบเจ็กต์ DatasetAdapter เพื่อแสดงชื่อเรื่องสำหรับข้อความแต่ละตอน ในแอปพลิเคชันตัวอย่าง จะอยู่ใน DatasetAdapter.kt :

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

หากต้องการให้คำถามแก่ผู้ใช้กับโมเดล:

  1. ใช้วัตถุ QaAdapter เพื่อตั้งคำถามให้กับโมเดล ในแอปพลิเคชันตัวอย่าง จะอยู่ใน 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
          }
      }
      ...
    }
    

เรียกใช้การคาดการณ์

ในแอป Android ของคุณ เมื่อคุณเริ่มต้นออบเจ็กต์ BertQuestionAnswerer แล้ว คุณสามารถเริ่มป้อนคำถามในรูปแบบข้อความภาษาธรรมชาติให้กับโมเดลได้ แบบจำลองพยายามระบุคำตอบภายในข้อความ

หากต้องการเรียกใช้การคาดการณ์:

  1. สร้างฟังก์ชัน answer ซึ่งรันโมเดลและวัดเวลาที่ใช้ในการระบุคำตอบ ( inferenceTime ) ในแอปพลิเคชันตัวอย่าง ฟังก์ชัน answer จะอยู่ใน 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. ส่งผ่านผลลัพธ์จาก answer ไปยังวัตถุผู้ฟัง

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

จัดการเอาต์พุตโมเดล

หลังจากที่คุณป้อนคำถาม โมเดลจะให้คำตอบที่เป็นไปได้สูงสุดห้าคำตอบภายในข้อความ

หากต้องการรับผลลัพธ์จากแบบจำลอง:

  1. สร้างฟังก์ชัน onResult สำหรับออบเจ็กต์ Listener เพื่อจัดการเอาต์พุต ในแอปพลิเคชันตัวอย่าง ออบเจ็กต์ Listener จะอยู่ใน BertQaHelper.kt

    interface AnswererListener {
        fun onError(error: String)
        fun onResults(
            results: List<QaAnswer>?,
            inferenceTime: Long
        )
    }
    
  2. เน้นส่วนต่างๆ ของข้อความตามผลลัพธ์ ในแอปพลิเคชันตัวอย่าง จะอยู่ใน 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
        )
    }
    

เมื่อแบบจำลองส่งคืนชุดผลลัพธ์แล้ว แอปพลิเคชันของคุณสามารถดำเนินการตามการคาดการณ์เหล่านั้นได้โดยการนำเสนอผลลัพธ์แก่ผู้ใช้ของคุณหรือดำเนินการตรรกะเพิ่มเติม

ขั้นตอนถัดไป