Введение

Птицы являются отличными индикаторами изменения биоразнообразия, поскольку они очень мобильны и имеют разнообразные требования к среде обитания. Таким образом, изменения в сообществе видов и количестве птиц могут указывать на успех или неудачу проекта восстановления. Однако частое проведение традиционных обследований биоразнообразия птиц с привлечением наблюдателей на больших территориях является дорогостоящим и сложным с точки зрения логистики. Для сравнения, пассивный акустический мониторинг (PAM) в сочетании с новыми аналитическими инструментами, основанными на машинном обучении, позволяет специалистам по охране природы отбирать образцы в гораздо больших пространственных масштабах с более высоким временным разрешением и глубоко исследовать взаимосвязь между мероприятиями по восстановлению и биоразнообразием.

В этом конкурсе мы будем использовать навыки машинного обучения, чтобы идентифицировать восточноафриканские виды птиц по звуку. В частности, мы разработаем вычислительные решения для обработки непрерывных аудиоданных и распознавания видов по их крикам. Лучшие записи смогут обучать надежные классификаторы с ограниченными обучающими данными. В случае успеха мы будем способствовать продвижению текущих усилий по защите птичьего биоразнообразия в Африке, в том числе под руководством кенийской природоохранной организации NATURAL STATE. ГОТОВЫ К ЭТОЙ ПОЕЗДКЕ?? Давайте начнем!

Контекст

NATURAL STATE работает на экспериментальных территориях вокруг Северной горы Кения, чтобы проверить влияние различных режимов управления и степени деградации на биоразнообразие птиц в системах пастбищных угодий. Используя алгоритмы машинного обучения, разработанные в рамках этого конкурса, NATURAL STATE сможет продемонстрировать эффективность этого подхода для измерения успеха проектов восстановления и экономической эффективности метода. Кроме того, возможность экономичного мониторинга воздействия усилий по восстановлению на биоразнообразие позволит NATURAL STATE протестировать и создать некоторые из первых финансовых механизмов, ориентированных на биоразнообразие, для направления столь необходимых инвестиций в восстановление и защиту этого ландшафта, на котором так много людей зависят. Эти инструменты необходимы для экономически эффективного масштабирования за пределами проектной зоны и достижения нашего видения восстановления и защиты планеты в масштабе.

Идеи анализа 💡

В этой статье мы выполним следующие шаги:

  1. Импортируйте библиотеки
  2. Исследуйте обучающие данные
  3. Сопоставьте выходные данные модели с видами птиц в соревновании
  4. Предварительно обработайте данные
  5. Делайте прогнозы
  6. Создать представление

Шаг 1: Импорт

На этом этапе мы импортируем библиотеки, которые будем использовать в проекте.

import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_io as tfio

import pandas as pd
import numpy as np
import librosa
import glob

import csv
import io

from IPython.display import Audio

Шаг 2. Изучите данные обучения

Мы начнем с загрузки нескольких обучающих примеров и использования модуля IPython.display.audio для их воспроизведения.

audio_abe, sr_abe = librosa.load("/kaggle/input/birdclef-2023/train_audio/abethr1/XC128013.ogg")
audio_abh, sr_abh = librosa.load("/kaggle/input/birdclef-2023/train_audio/abhori1/XC127317.ogg")
Audio(data=audio_abe, rate=sr_abe)
Audio(data=audio_abh, rate=sr_abh)

Шаг 3: Сопоставьте выходные данные модели с видами птиц в соревновании.

В конкурсе участвуют 264 класса птиц, 261 из которых существует в этой модели. Мы настроим способ сопоставления выходных логитов модели с нашими конкурентами.

model = hub.load('https://kaggle.com/models/google/bird-vocalization-classifier/frameworks/tensorFlow2/variations/bird-vocalization-classifier/versions/1')
labels_path = hub.resolve('https://kaggle.com/models/google/bird-vocalization-classifier/frameworks/tensorFlow2/variations/bird-vocalization-classifier/versions/1') + "/assets/label.csv"

def class_names_from_csv(class_map_csv_text):
    """Returns list of class names corresponding to score vector."""
    with open(labels_path) as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        class_names = [mid for mid, desc in csv_reader]
        return class_names[1:]
classes = class_names_from_csv(labels_path)
train_metadata = pd.read_csv("/kaggle/input/birdclef-2023/train_metadata.csv")
train_metadata.head()
competition_classes = sorted(train_metadata.primary_label.unique())

forced_defaults = 0
competition_class_map = []
for c in competition_classes:
    try:
        i = classes.index(c)
        competition_class_map.append(i)
    except:
        competition_class_map.append(0)
        forced_defaults += 1
        
## this is the count of classes not supported by our pretrained model
## you could choose to simply not predict these, set a default as above,
## or create your own model using the pretrained model as a base.
forced_defaults

Шаг 4: Предварительно обработайте данные

Следующие функции являются одним из способов загрузки предоставленного аудио и разбиения его на пятисекундные сэмплы с частотой дискретизации 32 000, необходимой для соревнований.

def frame_audio(
      audio_array: np.ndarray,
      window_size_s: float = 5.0,
      hop_size_s: float = 5.0,
      sample_rate = 32000,
      ) -> np.ndarray:
    
    """Helper function for framing audio for inference."""
    """ using tf.signal """
    if window_size_s is None or window_size_s < 0:
        return audio_array[np.newaxis, :]
    frame_length = int(window_size_s * sample_rate)
    hop_length = int(hop_size_s * sample_rate)
    framed_audio = tf.signal.frame(audio_array, frame_length, hop_length, pad_end=True)
    return framed_audio

def ensure_sample_rate(waveform, original_sample_rate,
                       desired_sample_rate=32000):
    """Resample waveform if required."""
    if original_sample_rate != desired_sample_rate:
        waveform = tfio.audio.resample(waveform, original_sample_rate, desired_sample_rate)
    return desired_sample_rate, waveform

Ниже мы загружаем один обучающий образец — используйте функцию «Аудио», чтобы прослушать образцы внутри блокнота!

audio, sample_rate = librosa.load("/kaggle/input/birdclef-2023/train_audio/afghor1/XC156639.ogg")
sample_rate, wav_data = ensure_sample_rate(audio, sample_rate)
Audio(wav_data, rate=sample_rate)

Шаг 5: Делайте прогнозы

Каждый тестовый образец разрезается на 5-секундные фрагменты. Мы используем предварительно обученную модель, чтобы вернуть вероятности для всех 10 000 птиц, включенных в модель, а затем извлекаем классы, используемые в этом соревновании, чтобы создать окончательную строку представления. Обратите внимание, что мы НЕ делаем ничего особенного для обработки трех отсутствующих классов; они потребуют тонкой настройки/переноса обучения, которые будут обрабатываться в отдельной записной книжке.

fixed_tm = frame_audio(wav_data)
logits, embeddings = model.infer_tf(fixed_tm[:1])
probabilities = tf.nn.softmax(logits)
argmax = np.argmax(probabilities)
print(f"The audio is from the class {classes[argmax]} (element:{argmax} in the label.csv file), with probability of {probabilities[0][argmax]}")
def predict_for_sample(filename, sample_submission, frame_limit_secs=None):
    file_id = filename.split(".ogg")[0].split("/")[-1]
    
    audio, sample_rate = librosa.load(filename)
    sample_rate, wav_data = ensure_sample_rate(audio, sample_rate)
    
    fixed_tm = frame_audio(wav_data)
    
    frame = 5
    all_logits, all_embeddings = model.infer_tf(fixed_tm[:1])
    for window in fixed_tm[1:]:
        if frame_limit_secs and frame > frame_limit_secs:
            continue
        
        logits, embeddings = model.infer_tf(window[np.newaxis, :])
        all_logits = np.concatenate([all_logits, logits], axis=0)
        frame += 5
    
    frame = 5
    all_probabilities = []
    for frame_logits in all_logits:
        probabilities = tf.nn.softmax(frame_logits).numpy()
        
        ## set the appropriate row in the sample submission
        sample_submission.loc[sample_submission.row_id == file_id + "_" + str(frame), competition_classes] = probabilities[competition_class_map]
        frame += 5

Шаг 6: Создайте представление

Теперь мы обрабатываем все тестовые образцы, как обсуждалось выше, создавая выходные строки и сохраняя их в предоставленном файле sample_submission.csv.

test_samples = list(glob.glob("/kaggle/input/birdclef-2023/test_soundscapes/*.ogg"))
test_samples
sample_sub = pd.read_csv("/kaggle/input/birdclef-2023/sample_submission.csv")
sample_sub[competition_classes] = sample_sub[competition_classes].astype(np.float32)
sample_sub.head()
frame_limit_secs = 15 if sample_sub.shape[0] == 3 else None
for sample_filename in test_samples:
    predict_for_sample(sample_filename, sample_sub, frame_limit_secs=15)
sample_sub.to_csv("submission.csv", index=False)