ตั้งแต่ Android 10 เป็นต้นไป Neural Networks API (NNAPI)
มีฟังก์ชันที่รองรับ
การแคชอาร์ติแฟกต์การคอมไพล์ ซึ่งช่วยลดเวลาที่ใช้ในการคอมไพล์
เมื่อแอปเริ่มต้น เมื่อใช้ฟังก์ชันการแคชนี้ คนขับไม่จำเป็นต้องจัดการหรือล้างไฟล์ที่แคชไว้
ฟีเจอร์นี้เป็นฟีเจอร์เสริมที่
สามารถใช้กับ NN HAL 1.2 ได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับฟังก์ชันนี้ได้ที่
ANeuralNetworksCompilation_setCaching
นอกจากนี้ ไดรเวอร์ยังสามารถใช้การแคชการคอมไพล์โดยไม่ขึ้นอยู่กับ NNAPI ได้ด้วย ซึ่งสามารถนำไปใช้ได้ไม่ว่าจะใช้ฟีเจอร์แคช NDK และ HAL ของ NNAPI หรือไม่ก็ตาม AOSP มีไลบรารียูทิลิตีระดับต่ำ (เครื่องมือแคช) ดูข้อมูลเพิ่มเติมได้ที่การติดตั้งใช้งานเครื่องมือแคช
ภาพรวมของเวิร์กโฟลว์
ส่วนนี้จะอธิบายเวิร์กโฟลว์ทั่วไปที่มีการใช้ฟีเจอร์แคชการคอมไพล์
ระบุข้อมูลแคชและแคชที่ตรงกัน
- แอปจะส่งผ่านไดเรกทอรีแคชและผลรวมตรวจสอบที่ไม่ซ้ำกันสำหรับโมเดล
- รันไทม์ NNAPI จะค้นหาไฟล์แคชตามผลรวมตรวจสอบ ค่ากำหนดการดำเนินการ และผลลัพธ์การแบ่งพาร์ติชัน แล้วค้นหาไฟล์
- NNAPI จะเปิดไฟล์แคชและส่งผ่านแฮนเดิลไปยังไดรเวอร์
ด้วย
prepareModelFromCache
- ไดรเวอร์จะเตรียมโมเดลจากไฟล์แคชโดยตรงและส่งคืน โมเดลที่เตรียมไว้
ข้อมูลแคชที่ระบุและการไม่พบแคช
- แอปจะส่ง Checksum ที่ไม่ซ้ำกันสำหรับโมเดลและแคช ไดเรกทอรี
- รันไทม์ NNAPI จะค้นหาไฟล์แคชตามผลรวมตรวจสอบ ค่ากำหนดการดำเนินการ และผลลัพธ์การแบ่งพาร์ติชัน แต่ไม่พบ ไฟล์แคช
- NNAPI จะสร้างไฟล์แคชที่ว่างเปล่าตามผลรวมตรวจสอบ ค่ากำหนดการดำเนินการ และการแบ่งพาร์ติชัน เปิดไฟล์แคช และส่งแฮนเดิลและโมเดลไปยังไดรเวอร์ด้วย
prepareModel_1_2
- ไดรเวอร์จะคอมไพล์โมเดล เขียนข้อมูลการแคชลงในไฟล์แคช และส่งคืนโมเดลที่เตรียมไว้
ไม่ได้ระบุข้อมูลแคช
- แอปจะเรียกใช้การคอมไพล์โดยไม่มีข้อมูลการแคช
- แอปจะไม่ส่งข้อมูลใดๆ ที่เกี่ยวข้องกับการแคช
- รันไทม์ NNAPI จะส่งโมเดลไปยังไดรเวอร์พร้อมกับ
prepareModel_1_2
- ไดรเวอร์จะคอมไพล์โมเดลและแสดงโมเดลที่เตรียมไว้
ข้อมูลแคช
ข้อมูลการแคชที่ให้แก่ไดรเวอร์ประกอบด้วยโทเค็นและ แฮนเดิลไฟล์แคช
โทเค็น
โทเค็น
คือโทเค็นการแคชที่มีความยาว
Constant::BYTE_SIZE_OF_CACHE_TOKEN
ซึ่งระบุโมเดลที่เตรียมไว้ ระบบจะแสดงโทเค็นเดียวกันเมื่อบันทึกไฟล์แคชด้วย prepareModel_1_2
และเรียกข้อมูลโมเดลที่เตรียมไว้ด้วย prepareModelFromCache
ไคลเอ็นต์ของไดรเวอร์ควรเลือกโทเค็นที่มี
อัตราการชนต่ำ ไดรเวอร์ตรวจไม่พบการชนกันของโทเค็น การชนกัน
ส่งผลให้การดำเนินการล้มเหลวหรือดำเนินการสำเร็จแต่
สร้างค่าเอาต์พุตที่ไม่ถูกต้อง
แฮนเดิลไฟล์แคช (ไฟล์แคช 2 ประเภท)
ไฟล์แคชมี 2 ประเภท ได้แก่ แคชข้อมูลและแคชโมเดล
- แคชข้อมูล: ใช้สำหรับแคชข้อมูลคงที่ รวมถึงบัฟเฟอร์เทนเซอร์ที่ประมวลผลล่วงหน้าและ แปลงแล้ว การแก้ไขแคชข้อมูลไม่ควร ส่งผลกระทบที่แย่กว่าการสร้างค่าเอาต์พุตที่ไม่ถูกต้องในเวลา ดำเนินการ
- แคชโมเดล: ใช้สำหรับแคชข้อมูลที่มีความละเอียดอ่อนด้านความปลอดภัย เช่น โค้ดแมชชีนที่คอมไพล์แล้วซึ่งเป็นไฟล์ปฏิบัติการ ในรูปแบบไบนารีดั้งเดิมของอุปกรณ์ การแก้ไขแคชโมเดลอาจส่งผลต่อลักษณะการทำงานของไดรเวอร์ และไคลเอ็นต์ที่เป็นอันตรายอาจใช้ประโยชน์จากสิ่งนี้เพื่อดำเนินการนอกเหนือจาก สิทธิ์ที่ได้รับ ดังนั้น ไดรเวอร์ต้องตรวจสอบว่าแคชโมเดล เสียหายหรือไม่ก่อนที่จะเตรียมโมเดลจากแคช ดูข้อมูลเพิ่มเติมได้ที่ความปลอดภัย
ไดรเวอร์ต้องตัดสินใจว่าจะกระจายข้อมูลแคชระหว่างไฟล์แคช 2 ประเภทอย่างไร
และรายงานจำนวนไฟล์แคชที่ต้องการสำหรับแต่ละประเภท
ด้วย
getNumberOfCacheFilesNeeded
รันไทม์ของ NNAPI จะเปิดแฮนเดิลไฟล์แคชด้วยสิทธิ์ทั้งอ่านและเขียนเสมอ
ความปลอดภัย
ในการแคชการคอมไพล์ แคชโมเดลอาจมีข้อมูลที่ละเอียดอ่อนด้านความปลอดภัย เช่น โค้ดแมชชีนที่คอมไพล์แล้วซึ่งเรียกใช้งานได้ในรูปแบบไบนารีดั้งเดิมของอุปกรณ์ หากไม่ได้ป้องกันอย่างเหมาะสม การแก้ไขแคชโมเดลอาจส่งผลต่อลักษณะการทำงานของไดรเวอร์ เนื่องจากเนื้อหาแคชจะจัดเก็บไว้ในไดเรกทอรีแอป ไคลเอ็นต์จึงแก้ไขไฟล์แคชได้ ไคลเอ็นต์ที่มีข้อบกพร่องอาจ ทำให้แคชเสียหายโดยไม่ตั้งใจ และไคลเอ็นต์ที่เป็นอันตรายอาจจงใจ ใช้สิ่งนี้เพื่อเรียกใช้โค้ดที่ไม่ได้รับการยืนยันในอุปกรณ์ ซึ่งอาจเป็นปัญหาด้านความปลอดภัย ทั้งนี้ขึ้นอยู่กับ ลักษณะของอุปกรณ์ ดังนั้น ไดรเวอร์ต้องตรวจพบ การเสียหายของแคชโมเดลที่อาจเกิดขึ้นก่อนที่จะเตรียมโมเดลจากแคช
วิธีหนึ่งในการทำเช่นนี้คือให้คนขับดูแลแผนที่จากโทเค็นไปยัง
แฮชที่เข้ารหัสของแคชโมเดล ไดรเวอร์สามารถจัดเก็บโทเค็นและ
แฮชของแคชโมเดลเมื่อบันทึกการคอมไพล์ลงในแคช ไดรเวอร์จะตรวจสอบ
แฮชใหม่ของแคชโมเดลกับคู่โทเค็นและแฮชที่บันทึกไว้เมื่อ
เรียกข้อมูลการคอมไพล์จากแคช การแมปนี้ควรคงอยู่ตลอด
การรีบูตระบบ ไดรเวอร์สามารถใช้บริการที่เก็บคีย์ของ Android, ไลบรารียูทิลิตีใน
framework/ml/nn/driver/cache
หรือกลไกอื่นๆ ที่เหมาะสมเพื่อใช้ตัวจัดการการแมป เมื่ออัปเดตไดรเวอร์แล้ว ควรเริ่มต้นตัวจัดการการแมปนี้ใหม่เพื่อป้องกันไม่ให้เตรียมไฟล์แคชจากเวอร์ชันก่อนหน้า
ไดรเวอร์ต้องคำนวณแฮชที่บันทึกไว้ก่อนบันทึกลงในไฟล์ และคำนวณแฮชใหม่หลังจากคัดลอกเนื้อหาไฟล์ไปยังบัฟเฟอร์ภายใน เพื่อป้องกันการโจมตีแบบ เวลาตรวจสอบถึงเวลาใช้งาน (TOCTOU)
โค้ดตัวอย่างนี้แสดงวิธีใช้ตรรกะนี้
bool saveToCache(const sp<V1_2::IPreparedModel> preparedModel,
const hidl_vec<hidl_handle>& modelFds, const hidl_vec<hidl_handle>& dataFds,
const HidlToken& token) {
// Serialize the prepared model to internal buffers.
auto buffers = serialize(preparedModel);
// This implementation detail is important: the cache hash must be computed from internal
// buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
auto hash = computeHash(buffers);
// Store the {token, hash} pair to a mapping manager that is persistent across reboots.
CacheManager::get()->store(token, hash);
// Write the cache contents from internal buffers to cache files.
return writeToFds(buffers, modelFds, dataFds);
}
sp<V1_2::IPreparedModel> prepareFromCache(const hidl_vec<hidl_handle>& modelFds,
const hidl_vec<hidl_handle>& dataFds,
const HidlToken& token) {
// Copy the cache contents from cache files to internal buffers.
auto buffers = readFromFds(modelFds, dataFds);
// This implementation detail is important: the cache hash must be computed from internal
// buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
auto hash = computeHash(buffers);
// Validate the {token, hash} pair by a mapping manager that is persistent across reboots.
if (CacheManager::get()->validate(token, hash)) {
// Retrieve the prepared model from internal buffers.
return deserialize<V1_2::IPreparedModel>(buffers);
} else {
return nullptr;
}
}
Use Case ขั้นสูง
ในกรณีการใช้งานขั้นสูงบางอย่าง ไดรเวอร์ต้องเข้าถึงเนื้อหาแคช (อ่านหรือเขียน) หลังจากเรียกใช้การคอมไพล์ ตัวอย่างกรณีการใช้งานมีดังนี้
- การคอมไพล์แบบทันที: การคอมไพล์จะล่าช้าจนกว่าจะมีการ ดำเนินการครั้งแรก
- การคอมไพล์แบบหลายขั้นตอน: ระบบจะทำการคอมไพล์อย่างรวดเร็วในตอนแรก และจะทำการคอมไพล์ที่เพิ่มประสิทธิภาพ (ไม่บังคับ) ในภายหลัง โดยขึ้นอยู่กับความถี่ในการใช้งาน
หากต้องการเข้าถึงเนื้อหาแคช (อ่านหรือเขียน) หลังจากเรียกใช้การคอมไพล์ ให้ตรวจสอบว่าไดรเวอร์มีคุณสมบัติดังนี้
- ทำซ้ำแฮนเดิลของไฟล์ระหว่างการเรียกใช้
prepareModel_1_2
หรือprepareModelFromCache
และอ่าน/อัปเดตเนื้อหาแคชในภายหลัง - ใช้ตรรกะการล็อกไฟล์นอกการเรียกใช้การคอมไพล์ปกติ เพื่อป้องกันไม่ให้มีการเขียนพร้อมกับการอ่านหรือการเขียนอื่น
ใช้เครื่องมือแคช
นอกจากอินเทอร์เฟซการแคชการคอมไพล์ NN HAL 1.2 แล้ว คุณยังดู
ไลบรารียูทิลิตีการแคชได้ในไดเรกทอรี
frameworks/ml/nn/driver/cache
ไดเรกทอรีย่อย
nnCache
มีโค้ดพื้นที่เก็บข้อมูลแบบถาวรสำหรับไดรเวอร์เพื่อใช้
การแคชการคอมไพล์โดยไม่ต้องใช้ฟีเจอร์การแคช NNAPI การแคชการคอมไพล์รูปแบบนี้สามารถใช้ได้กับ NN HAL ทุกเวอร์ชัน หาก
ไดรเวอร์เลือกใช้การแคชที่ไม่ได้เชื่อมต่อกับอินเทอร์เฟซ HAL
ไดรเวอร์จะต้อง
รับผิดชอบในการล้างอาร์ติแฟกต์ที่แคชไว้เมื่อไม่จำเป็นอีกต่อไป