מדריך סיווג אודיו ל-Android

המשימה 'מסווג אודיו של MediaPipe' מאפשרת לך לבצע סיווג של נתוני אודיו. אפשר להשתמש במשימה הזו כדי לזהות אירועים של זיהוי צלילים מקבוצה של קטגוריות מאומנות. בהוראות שכאן מוסבר איך להשתמש במסווג אודיו באפליקציות ל-Android.

למידע נוסף על היכולות, המודלים ואפשרויות ההגדרה של המשימה הזו, קראו את הסקירה הכללית.

קוד לדוגמה

הקוד לדוגמה של משימות MediaPipe הוא יישום פשוט של אפליקציה של Audio Classifier ל-Android. בדוגמה נעשה שימוש במיקרופון במכשיר Android פיזי כדי לסווג צלילים באופן רציף, והיא יכולה גם להפעיל את המסווג בקובצי קול שמאוחסנים במכשיר.

אפשר להשתמש באפליקציה כנקודת התחלה לאפליקציה שלכם ל-Android, או להתייחס אליה כשמשנים אפליקציה קיימת. הקוד לדוגמה של מסווג אודיו מתארח ב-GitHub.

הורדת הקוד

בהוראות הבאות מוסבר איך ליצור עותק מקומי של הקוד לדוגמה באמצעות כלי שורת הפקודה git.

כדי להוריד את הקוד לדוגמה:

  1. משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. אפשר גם להגדיר את מכונת ה-Git לשימוש בקופה עם נפח נתונים נמוך, כך שיהיו לכם רק את הקבצים של האפליקציה לדוגמה של Audio Classifier:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/audio_classifier/android
    

אחרי שיוצרים גרסה מקומית של הקוד לדוגמה, אפשר לייבא את הפרויקט ל-Android Studio ולהפעיל את האפליקציה. הוראות מפורטות זמינות במדריך ההגדרה ל-Android.

רכיבים עיקריים

הקבצים הבאים מכילים את הקוד החיוני לאפליקציה הזו לדוגמה לסיווג אודיו:

  • AudioClassifierHelper.kt – מפעיל את מסווג האודיו ומטפל במודל ובבחירת הגישה.
  • RecorderFragment.kt – יצירת ממשק המשתמש ושליטה בקוד להקלטת אודיו בשידור חי.
  • LibraryFragment.kt – יצירת ממשק המשתמש וקוד בקרה לבחירת קובצי אודיו.
  • ProbabilitiesAdapter.kt – כינויים ופורמטים של תוצאות החיזוי של המסווג.

הגדרה

בקטע הזה מתוארים שלבי המפתח להגדרת סביבת הפיתוח ופרויקטים של קוד, במיוחד לשימוש במסווג אודיו. במדריך ההגדרה ל-Android תוכלו לקרוא מידע כללי על הגדרת סביבת הפיתוח לשימוש במשימות של MediaPipe, כולל הדרישות לגרסת הפלטפורמה.

יחסי תלות

מסווג האודיו משתמש בספרייה com.google.mediapipe:tasks-audio. מוסיפים את התלות הזאת לקובץ build.gradle של פרויקט פיתוח האפליקציה ל-Android. מייבאים את יחסי התלות הנדרשים באמצעות הקוד הבא:

dependencies {
    ...
    implementation 'com.google.mediapipe:tasks-audio:latest.release'
}

מודל

כדי לבצע את המשימה 'מסווג אודיו של MediaPipe' צריך מודל מאומן שתואם למשימה הזו. למידע נוסף על המודלים הזמינים למסווג אודיו, עיינו בסקירה הכללית על המשימות בקטע Models.

בוחרים ומורידים את המודל, ולאחר מכן מאחסנים אותו בספריית הפרויקט:

<dev-project-root>/src/main/assets

משתמשים ב-method BaseOptions.Builder.setModelAssetPath() כדי לציין את הנתיב שהמודל משתמש בו. ניתן למצוא את השיטה הזו בקטע הקוד בדוגמה הבאה.

בקוד לדוגמה של סיווג האודיו, המודל מוגדר בקובץ AudioClassifierHelper.kt.

יצירת המשימה

אפשר ליצור את המשימה באמצעות הפונקציה createFromOptions. הפונקציה createFromOptions מקבלת אפשרויות הגדרה, כולל מצב ריצה, הלוקאל של השמות המוצגים, מספר התוצאות המקסימלי, סף המהימנות ורשימת הרשאות מתאימה או רשימת ישויות שנחסמו בקטגוריה. מידע נוסף על אפשרויות ההגדרה זמין במאמר סקירה כללית על הגדרות.

המשימה 'מסווג אודיו' תומכת בסוגי נתוני הקלט הבאים: קליפים של אודיו ושידורי אודיו. כשיוצרים משימה, צריך לציין את מצב הריצה שתואם לסוג נתוני הקלט. בחרו את הכרטיסייה המתאימה לסוג נתוני הקלט, כדי לראות איך ליצור את המשימה ולהסיק את ההסקה.

קטעי אודיו

AudioClassifierOptions options =
    AudioClassifierOptions.builder()
        .setBaseOptions(
            BaseOptions.builder().setModelAssetPath("model.tflite").build())
        .setRunningMode(RunningMode.AUDIO_CLIPS)
        .setMaxResults(5)
        .build();
audioClassifier = AudioClassifier.createFromOptions(context, options);
    

שידור האודיו

AudioClassifierOptions options =
    AudioClassifierOptions.builder()
        .setBaseOptions(
            BaseOptions.builder().setModelAssetPath("model.tflite").build())
        .setRunningMode(RunningMode.AUDIO_STREAM)
        .setMaxResults(5)
        .setResultListener(audioClassifierResult -> {
             // Process the classification result here.
        })
        .build();
audioClassifier = AudioClassifier.createFromOptions(context, options);
    

הטמעת הקוד לדוגמה של מסווג אודיו מאפשרת למשתמש לעבור בין מצבי עיבוד. הגישה הזו יוצרת את הקוד ליצירת משימה ועשויה לא להתאים לתרחיש שלכם לדוגמה. אפשר לראות את מצב החלפת הקוד בפונקציה initClassifier() של AudioClassifierHelper.

אפשרויות הגדרה

המשימה כוללת את אפשרויות ההגדרה הבאות לאפליקציות ל-Android:

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
runningMode מגדיר את מצב הריצה של המשימה. למסווג האודיו יש שני מצבים:

AUDIO_CLIPS: המצב להרצת משימת אודיו בקטעי אודיו עצמאיים.

AUDIO_STREAM: המצב להרצת משימת אודיו בשידור אודיו, למשל דרך המיקרופון. במצב הזה, יש לקרוא ל- resultListener על מנת להגדיר listener כדי לקבל את תוצאות הסיווג באופן אסינכרוני.
{AUDIO_CLIPS, AUDIO_STREAM} AUDIO_CLIPS
displayNamesLocale ההגדרה הזו מגדירה את השפה של התוויות שישמשו לשמות תצוגה שנמסרים במטא-נתונים של מודל המשימה, אם יש כאלה. ברירת המחדל היא en עבור אנגלית. אפשר להוסיף תוויות שהותאמו לשוק המקומי למטא-נתונים של מודל מותאם אישית באמצעות TensorFlow Lite Metadata Writer API קוד הלוקאל en
maxResults הפונקציה מגדירה את המספר המקסימלי האופציונלי של תוצאות מהסיווג הגבוה ביותר להחזרה. אם הערך קטן מ-0, יוחזרו כל התוצאות הזמינות. כל מספר חיובי -1
scoreThreshold השדה הזה מגדיר את סף הציון של החיזוי ששונה מהסף שצוין במטא-נתונים של המודל (אם יש כזה). תוצאות מתחת לערך הזה יידחו. [0.0, 1.0] לא הוגדרה
categoryAllowlist מגדיר את הרשימה האופציונלית של שמות הקטגוריות המותרות. אם השדה לא ריק, תוצאות סיווג ששם הקטגוריה שלהן לא נכלל בקבוצה הזו יסוננו. המערכת מתעלמת משמות כפולים או לא ידועים של קטגוריות. האפשרות הזו בלעדית ל-categoryDenylist ומשתמשת בשתי התוצאות כשגיאה. כל מחרוזת לא הוגדרה
categoryDenylist מגדיר את הרשימה האופציונלית של שמות קטגוריות אסורים. אם התוצאות לא ריקות, תוצאות הסיווג ששם הקטגוריה שלהן נכלל בקבוצה הזו יסוננו. המערכת מתעלמת משמות כפולים או לא ידועים של קטגוריות. האפשרות הזו בלעדית ל-categoryAllowlist, והשימוש בשתי האפשרויות האלה גורם לשגיאה. כל מחרוזת לא הוגדרה
resultListener מגדיר את מאזן התוצאות לקבל את תוצאות הסיווג באופן אסינכרוני כאשר מסווג האודיו נמצא במצב שידור אודיו. אפשר להשתמש רק כשמצב ריצה מוגדר ל-AUDIO_STREAM לא רלוונטי לא הוגדרה
errorListener מגדירה האזנה לשגיאות כאופציונלי. לא רלוונטי לא הוגדרה

הכנת הנתונים

סיווג האודיו פועל עם קטעי אודיו ועם שידורי אודיו. המשימה מטפלת בעיבוד מראש של קלט הנתונים, כולל דגימה מחדש, אגירת נתונים ופריים. עם זאת, צריך להמיר את נתוני הקלט של האודיו לאובייקט com.google.mediapipe.tasks.components.containers.AudioData לפני שמעבירים אותו למשימה של מסווג האודיו.

קטעי אודיו

import com.google.mediapipe.tasks.components.containers.AudioData;

// Load an audio on the user’s device as a float array.

// Convert a float array to a MediaPipe’s AudioData object.
AudioData audioData =
    AudioData.create(
        AudioData.AudioDataFormat.builder()
            .setNumOfChannels(numOfChannels)
            .setSampleRate(sampleRate)
            .build(),
        floatData.length);
audioData.load(floatData);
    

שידור האודיו

import android.media.AudioRecord;
import com.google.mediapipe.tasks.components.containers.AudioData;

AudioRecord audioRecord =
    audioClassifier.createAudioRecord(/* numChannels= */ 1, /* sampleRate= */ 16000);
audioRecord.startRecording();

...

// To get a one second clip from the AudioRecord object:
AudioData audioData =
    AudioData.create(
        16000 /*sample counts per second*/);
        AudioData.AudioDataFormat.create(audioRecord.getFormat()),
audioData.load(audioRecord)
    

מריצים את המשימה.

אפשר לקרוא לפונקציה classify שתואמת למצב הריצה כדי להפעיל מסקנות. ה-API של סיווג האודיו מחזיר את הקטגוריות האפשריות לאירועי האודיו שזוהו בנתוני האודיו שהוזנו.

קטעי אודיו

AudioClassifierResult classifierResult = audioClassifier.classify(audioData);
    

שידור האודיו

// Run inference on the audio block. The classifications results will be available
// via the `resultListener` provided in the `AudioClassifierOptions` when
// the audio classifier was created.
audioClassifier.classifyAsync(audioBlock, timestampMs);
    

שימו לב לנקודות הבאות:

  • כשמפעילים את מצב שידור האודיו, צריך גם לספק את המשימה של 'סיווג האודיו' עם חותמת זמן כדי לעקוב אחר נתוני האודיו במהלך השידור ששימשו לצורך ההסקה.
  • כשמפעילים את המודל של קטעי האודיו, המשימה 'מסווג אודיו' חוסמת את ה-thread הנוכחי עד לסיום העיבוד של הקלט. כדי לא לחסום את התשובות של ממשק המשתמש, צריך להפעיל עיבוד בשרשור ברקע.

תוכלו לראות דוגמה להפעלת מסווג אודיו עם קטעי אודיו. בקוד לדוגמה תוכלו לראות את המחלקה AudioClassifierHelper.

טיפול בתוצאות והצגתן

לאחר הרצת היסקה, המשימה 'מסווג אודיו' מחזירה רשימה של קטגוריות אפשריות לאירועי האודיו באודיו של הקלט. ברשימה הבאה מוצגת דוגמה לנתוני הפלט מהמשימה הזו:

AudioClassifierResult:
  Timestamp in microseconds: 100
  ClassificationResult #0:
    Timestamp in microseconds: 100  
    Classifications #0 (single classification head):
      head index: 0
      category #0:
        category name: "Speech"
        score: 0.6
        index: 0
      category #1:
        category name: "Music"
        score: 0.2
        index: 1

באפליקציה ל-Android, המשימה מחזירה ClassificationResult שמכיל רשימה של AudioClassifierResult אובייקטים, שמייצגים חיזויים לאירוע אודיו, כולל תווית הקטגוריה וציון המהימנות.

קטעי אודיו

// In the audio clips mode, the classification results are for the entire audio
// clip. The results are timestamped AudioClassifierResult objects, each
// classifying an interval of the entire audio clip that starts at
// ClassificationResult.timestampMs().get().

for (ClassificationResult result : audioClassifierResult.classificationResults()) {
  // Audio interval start timestamp:
  result.timestampMs().get();
  // Classification result of the audio interval.
  result.classifications();
}
    

שידור האודיו

// In the audio stream mode, the classification results list only contains one
// element, representing the classification result of the audio block that
// starts at ClassificationResult.timestampMs in the audio stream.

ClassificationResult result = audioClassifierResult.classificationResults().get(0);
// The audio block start timestamp
audioClassifierResult.timestampMs();
// Alternatively, the same timestamp can be retrieved from
// result.timestampMs().get();

// Classification result.
result.classifications();
    

תוכלו לראות דוגמה לאופן ההצגה של תוצאות הסיווג שהוחזרו מהמשימה הזו במחלקה ProbabilitiesAdapter, בקוד לדוגמה.