Введение
Птицы являются отличными индикаторами изменения биоразнообразия, поскольку они очень мобильны и имеют разнообразные требования к среде обитания. Таким образом, изменения в сообществе видов и количестве птиц могут указывать на успех или неудачу проекта восстановления. Однако частое проведение традиционных обследований биоразнообразия птиц с привлечением наблюдателей на больших территориях является дорогостоящим и сложным с точки зрения логистики. Для сравнения, пассивный акустический мониторинг (PAM) в сочетании с новыми аналитическими инструментами, основанными на машинном обучении, позволяет специалистам по охране природы отбирать образцы в гораздо больших пространственных масштабах с более высоким временным разрешением и глубоко исследовать взаимосвязь между мероприятиями по восстановлению и биоразнообразием.
В этом конкурсе мы будем использовать навыки машинного обучения, чтобы идентифицировать восточноафриканские виды птиц по звуку. В частности, мы разработаем вычислительные решения для обработки непрерывных аудиоданных и распознавания видов по их крикам. Лучшие записи смогут обучать надежные классификаторы с ограниченными обучающими данными. В случае успеха мы будем способствовать продвижению текущих усилий по защите птичьего биоразнообразия в Африке, в том числе под руководством кенийской природоохранной организации NATURAL STATE. ГОТОВЫ К ЭТОЙ ПОЕЗДКЕ?? Давайте начнем!
Контекст
NATURAL STATE работает на экспериментальных территориях вокруг Северной горы Кения, чтобы проверить влияние различных режимов управления и степени деградации на биоразнообразие птиц в системах пастбищных угодий. Используя алгоритмы машинного обучения, разработанные в рамках этого конкурса, NATURAL STATE сможет продемонстрировать эффективность этого подхода для измерения успеха проектов восстановления и экономической эффективности метода. Кроме того, возможность экономичного мониторинга воздействия усилий по восстановлению на биоразнообразие позволит NATURAL STATE протестировать и создать некоторые из первых финансовых механизмов, ориентированных на биоразнообразие, для направления столь необходимых инвестиций в восстановление и защиту этого ландшафта, на котором так много людей зависят. Эти инструменты необходимы для экономически эффективного масштабирования за пределами проектной зоны и достижения нашего видения восстановления и защиты планеты в масштабе.
Идеи анализа 💡
В этой статье мы выполним следующие шаги:
- Импортируйте библиотеки
- Исследуйте обучающие данные
- Сопоставьте выходные данные модели с видами птиц в соревновании
- Предварительно обработайте данные
- Делайте прогнозы
- Создать представление
Шаг 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)