# Дообучение модели для классификации музыки

В этом разделе мы представим пошаговое руководство по дообучению модели трансформера, использующей только кодеровщик,
для классификации музыки. Для демонстрации мы будем использовать облегченную модель и достаточно небольшой набор данных, что означает,
что код может быть запущен на любом GPU потребительского класса, включая GPU T4 16GB, предоставляемый в рамках бесплатного уровня Google Colab.
В разделе приведены различные советы, которые можно попробовать при использовании GPU меньшего размера и возникновении проблем с нехваткой памяти.


## Набор данных

Для обучения нашей модели мы будем использовать набор данных [GTZAN](https://huggingface.co/datasets/marsyas/gtzan), который представляет собой
популярный набор данных из 1000 песен для классификации музыкальных жанров. Каждая песня представляет собой 30-секундный клип из одного из 10
музыкальных жанров - от диско до металла. Мы можем получить аудиофайлы и соответствующие им метки из Hugging Face Hub с помощью функции
`load_dataset()` из 🤗 Datasets:

```python
from datasets import load_dataset

gtzan = load_dataset("marsyas/gtzan", "all")
gtzan
```

**Output:**
```out
Dataset({
    features: ['file', 'audio', 'genre'],
    num_rows: 999
})
```

<Tip warning={true}>

Одна из записей в GTZAN повреждена, поэтому она была удалена из набора данных. Поэтому мы имеем 999 примеров
вместо 1000.

</Tip>


GTZAN не предоставляет предопределенного валидационного набора, поэтому нам придется создать его самостоятельно.
Набор данных сбалансирован по жанрам, поэтому мы можем использовать метод `train_test_split()` для быстрого
создания разбиения в пропорции 90/10 следующим образом:

```python
gtzan = gtzan.train_test_split(seed=42, shuffle=True, test_size=0.1)
gtzan
```

**Output:**
```out
DatasetDict({
    train: Dataset({
        features: ['file', 'audio', 'genre'],
        num_rows: 899
    })
    test: Dataset({
        features: ['file', 'audio', 'genre'],
        num_rows: 100
    })
})
```

Отлично, теперь, когда у нас есть обучающий и тестовый наборы, давайте посмотрим на один из аудиофайлов:

```python
gtzan["train"][0]
```

**Output:**
```out
{
    "file": "~/.cache/huggingface/datasets/downloads/extracted/fa06ce46130d3467683100aca945d6deafb642315765a784456e1d81c94715a8/genres/pop/pop.00098.wav",
    "audio": {
        "path": "~/.cache/huggingface/datasets/downloads/extracted/fa06ce46130d3467683100aca945d6deafb642315765a784456e1d81c94715a8/genres/pop/pop.00098.wav",
        "array": array(
            [
                0.10720825,
                0.16122437,
                0.28585815,
                ...,
                -0.22924805,
                -0.20629883,
                -0.11334229,
            ],
            dtype=float32,
        ),
        "sampling_rate": 22050,
    },
    "genre": 7,
}
```

Как мы видели в [Разделе 1](../chapter1/audio_data), аудиофайлы представлены в виде одномерных массивов NumPy,
где значение массива представляет собой амплитуду на заданном временном интервале. Для этих композиций частота дискретизации
составляет 22 050 Гц, то есть в секунду дискретизируется 22 050 значений амплитуды. Это необходимо учитывать при использовании
предварительно обученной модели с другой частотой дискретизации, самостоятельно преобразуя частоты дискретизации для обеспечения
их соответствия. Мы также видим, что жанр представлен в виде целого числа, или _class label_, то есть в том формате, в котором модель
будет делать свои предсказания. Воспользуемся методом `int2str()` функции `genre` для преобразования этих целых чисел в человекочитаемые имена:

```python
id2label_fn = gtzan["train"].features["genre"].int2str
id2label_fn(gtzan["train"][0]["genre"])
```

**Output:**
```out
'pop'
```

Эта метка выглядит корректно, поскольку совпадает с именем аудиофайла. Теперь рассмотрим еще несколько примеров на примере Gradio для создания простого
интерфейса с API `Blocks`:

```python
import gradio as gr


def generate_audio():
    example = gtzan["train"].shuffle()[0]
    audio = example["audio"]
    return (
        audio["sampling_rate"],
        audio["array"],
    ), id2label_fn(example["genre"])


with gr.Blocks() as demo:
    with gr.Column():
        for _ in range(4):
            audio, label = generate_audio()
            output = gr.Audio(audio, label=label)

demo.launch(debug=True)
```

<iframe src="https://course-demos-gtzan-samples.hf.space" frameBorder="0" height="450" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

Из этих образцов мы, конечно, можем услышать разницу между жанрами, но может ли это сделать трансформер? Давайте обучим модель,
чтобы выяснить это! Для начала нам нужно найти подходящую для этой задачи предварительно обученную модель. Посмотрим, как это можно сделать.

## Выбор предварительно обученной модели для классификации звука

Для начала выберем подходящую предварительно обученную модель для классификации звука. В этой области предварительное обучение обычно проводится
на больших объемах немаркированных аудиоданных, используя такие наборы данных, как [LibriSpeech](https://huggingface.co/datasets/librispeech_asr)
и [Voxpopuli](https://huggingface.co/datasets/facebook/voxpopuli). Лучший способ найти эти модели на Hugging Face Hub - использовать фильтр
"Audio Classification", как описано в предыдущем разделе. Хотя такие модели, как Wav2Vec2 и HuBERT, очень популярны, мы будем использовать модель
под названием _DistilHuBERT_. Это гораздо более компактная (или _дистиллированная_) версия модели [HuBERT](https://huggingface.co/docs/transformers/model_doc/hubert),
которая обучается примерно на 73% быстрее, сохраняя при этом большую часть производительности.

<iframe src="https://autoevaluate-leaderboards.hf.space" frameBorder="0" height="450" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

## От аудио к машинному обучению

## Предварительная обработка данных

Подобно токенизации в NLP, аудио- и речевые модели требуют, чтобы входные данные были закодированы в формате, который модель может обрабатывать.
В 🤗 Transformers преобразование звука во входной формат осуществляется с помощью _feature extractor_ модели. Подобно токенизаторам, 🤗 Transformers
предоставляет удобный класс `AutoFeatureExtractor`, который может автоматически выбирать нужный экстрактор признаков для заданной модели. Для того
чтобы увидеть, как мы можем обрабатывать наши аудиофайлы, давайте начнем с инстанцирования экстрактора признаков для DistilHuBERT из предварительно
обученной контрольной точки:

```python
from transformers import AutoFeatureExtractor

model_id = "ntu-spml/distilhubert"
feature_extractor = AutoFeatureExtractor.from_pretrained(
    model_id, do_normalize=True, return_attention_mask=True
)
```

Поскольку частота дискретизации модели и набора данных различна, перед передачей аудиофайла в программу извлечения признаков его необходимо
передискретизировать до 16 000 Гц. Для этого сначала нужно получить частоту дискретизации модели от экстрактора признаков:

```python
sampling_rate = feature_extractor.sampling_rate
sampling_rate
```

**Output:**
```out
16000
```

Далее мы проводим повторную выборку набора данных, используя метод `cast_column()` и функцию `Audio` из 🤗 Datasets:

```python
from datasets import Audio

gtzan = gtzan.cast_column("audio", Audio(sampling_rate=sampling_rate))
```

Теперь мы можем проверить первый сэмпл train-split нашего набора данных, чтобы убедиться, что он действительно находится
на частоте 16 000 Гц. При загрузке каждого сэмпла Datasets производит повторную дискретизацию аудиофайла "на лету":

```python
gtzan["train"][0]
```

**Output:**
```out
{
    "file": "~/.cache/huggingface/datasets/downloads/extracted/fa06ce46130d3467683100aca945d6deafb642315765a784456e1d81c94715a8/genres/pop/pop.00098.wav",
    "audio": {
        "path": "~/.cache/huggingface/datasets/downloads/extracted/fa06ce46130d3467683100aca945d6deafb642315765a784456e1d81c94715a8/genres/pop/pop.00098.wav",
        "array": array(
            [
                0.0873509,
                0.20183384,
                0.4790867,
                ...,
                -0.18743178,
                -0.23294401,
                -0.13517427,
            ],
            dtype=float32,
        ),
        "sampling_rate": 16000,
    },
    "genre": 7,
}
```

Отлично! Мы видим, что частота дискретизации была понижена до 16 кГц. Значения массива также отличаются, так как теперь на каждые 1,5 значения
амплитуды приходится примерно одно значение, которое мы имели раньше.

Отличительной особенностью моделей типа Wav2Vec2 и HuBERT является то, что они принимают на вход массив float, соответствующий исходной форме
речевого сигнала. В отличие от других моделей, например Whisper, в которых мы предварительно обрабатываем исходную форму звукового сигнала
до формата спектрограммы.

Мы уже упоминали, что аудиоданные представлены в виде одномерного массива, поэтому они уже имеют правильный формат для чтения моделью
(набор непрерывных входов с дискретными временными шагами). Чтож, что именно делает экстрактор признаков?

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

Для этого мы _нормализуем_ наши аудиоданные, приводя каждую выборку к нулевому среднему и единичной дисперсии - этот процесс называется
_масштабированием признаков_. Именно эту нормализацию и выполняет наш экстрактор признаков!

Мы можем посмотреть, как работает экстрактор признаков, применив его к нашему первому аудиосэмплу. Сначала вычислим среднее значение и дисперсию
наших исходных аудиоданных:

```python
import numpy as np

sample = gtzan["train"][0]["audio"]

print(f"Mean: {np.mean(sample['array']):.3}, Variance: {np.var(sample['array']):.3}")
```

**Output:**
```out
Mean: 0.000185, Variance: 0.0493
```

Видно, что среднее значение уже близко к нулю, но дисперсия ближе к 0,05. Если бы дисперсия для выборки была больше, это могло бы
вызвать проблемы с нашей моделью, так как динамический диапазон аудиоданных был бы очень мал и, следовательно, трудноразделим. Применим экстрактор
признаков и посмотрим, что получится на выходе:

```python
inputs = feature_extractor(sample["array"], sampling_rate=sample["sampling_rate"])

print(f"inputs keys: {list(inputs.keys())}")

print(
    f"Mean: {np.mean(inputs['input_values']):.3}, Variance: {np.var(inputs['input_values']):.3}"
)
```

**Output:**
```out
inputs keys: ['input_values', 'attention_mask']
Mean: -4.53e-09, Variance: 1.0
```

Отлично! Наш экстрактор признаков возвращает словарь, состоящий из двух массивов: `input_values` and `attention_mask`. `input_values`
это предварительно обработанные входные аудиоданные, которые мы передадим в модель HuBERT. [`attention_mask`](https://huggingface.co/docs/transformers/glossary#attention-mask)
используется, когда мы обрабатываем _batch_ аудиовходов одновременно - она используется для того, чтобы сообщить модели, где
у нас есть входы разной длины.

Мы видим, что среднее значение теперь очень сильно приближается к нулю, а дисперсия - к единице! Именно в таком виде мы хотим получить
наши аудиосэмплы перед подачей их в модель HuBERT.

<Tip warning={true}>

Обратите внимание, как мы передали частоту дискретизации наших аудиоданных нашему экстрактору признаков. Это хорошая практика, так как
экстрактор признаков выполняет проверку под капотом, чтобы убедиться, что частота дискретизации наших аудиоданных соответствует частоте
дискретизации, ожидаемой моделью. Если частота дискретизации аудиоданных не совпадает с частотой дискретизации нашей модели, то необходимо
увеличить или уменьшить частоту дискретизации аудиоданных до нужной.

</Tip>

Отлично, теперь мы знаем, как обрабатывать наши ресэмплированные аудиофайлы, осталось определить функцию, которую мы можем применить ко всем
примерам в наборе данных. Поскольку мы ожидаем, что длина аудиоклипов будет составлять 30 секунд, мы также будем обрезать все более длинные клипы,
используя аргументы `max_length` и `truncation` в экстракторе признаков следующим образом:

```python
max_duration = 30.0


def preprocess_function(examples):
    audio_arrays = [x["array"] for x in examples["audio"]]
    inputs = feature_extractor(
        audio_arrays,
        sampling_rate=feature_extractor.sampling_rate,
        max_length=int(feature_extractor.sampling_rate * max_duration),
        truncation=True,
        return_attention_mask=True,
    )
    return inputs
```

Определив эту функцию, мы можем применить ее к набору данных с помощью метода [`map()`](https://huggingface.co/docs/datasets/v2.14.0/en/package_reference/main_classes#datasets.Dataset.map).
Метод `.map()` поддерживает работу с пакетами сэмплов, что мы и сделаем, установив `batched=True`. По умолчанию размер
пакета составляет 1000, но мы уменьшим его до 100, чтобы пиковая оперативная память оставалась в разумных пределах для бесплатного уровня Google Colab:

<!--- TODO(SG): вернуться к многопроцессорной обработке, когда будет исправлена ошибка в наборах данных
Поскольку наборы аудиоданных могут обрабатываться довольно медленно, обычно целесообразно использовать многопроцессорную обработку.
Для этого мы можем передать аргумент `num_proc` в команду `map()` и с помощью модуля Python `psutil`
определить количество процессорных ядер в системе:
--->

```python
gtzan_encoded = gtzan.map(
    preprocess_function,
    remove_columns=["audio", "file"],
    batched=True,
    batch_size=100,
    num_proc=1,
)
gtzan_encoded
```

**Output:**
```out
DatasetDict({
    train: Dataset({
        features: ['genre', 'input_values','attention_mask'],
        num_rows: 899
    })
    test: Dataset({
        features: ['genre', 'input_values','attention_mask'],
        num_rows: 100
    })
})
```

<Tip warning={true}>
    Если при выполнении приведенного выше кода оперативная память устройства будет исчерпана, можно настроить параметры пакетной обработки,
    чтобы уменьшить пиковое потребление оперативной памяти. В частности, можно модифицировать следующие два аргумента:
    * `batch_size`: по умолчанию 1000, но выше было установлено значение 100. Попробуйте еще раз уменьшить в 2 раза до 50
    * `writer_batch_size`: по умолчанию равен 1000. Попробуйте уменьшить его до 500, а если это не сработает, то уменьшите его еще раз в 2 раза до 250
</Tip>


Для упрощения обучения мы удалили из набора данных столбцы `audio` и `file`. Столбец `input_values` содержит закодированные аудиофайлы,
 `attention_mask` - двоичную маску из значений 0/1, указывающую на то, куда мы добавили входной аудиосигнал, а столбец `genre` - соответствующие
 метки (или цели). Для того чтобы `Trainer` мог обрабатывать метки классов, необходимо переименовать колонку `genre` в `label`:

```python
gtzan_encoded = gtzan_encoded.rename_column("genre", "label")
```

Наконец, нам необходимо получить отображения меток из набора данных. Это отображение позволит нам перейти от целочисленных идентификаторов (например, `7`)
к человекочитаемым меткам классов (например, `"поп"`) и обратно. Таким образом, мы можем преобразовать целочисленное предсказание id нашей модели в человекочитаемый формат,
что позволит нам использовать модель в любом последующем приложении. Для этого можно использовать метод `int2str()` следующим образом:

```python
id2label = {
    str(i): id2label_fn(i)
    for i in range(len(gtzan_encoded["train"].features["label"].names))
}
label2id = {v: k for k, v in id2label.items()}

id2label["7"]
```

```out
'pop'
```

Итак, у нас есть набор данных, готовый к обучению! Давайте рассмотрим, как можно обучить модель на этом наборе данных.


## Дообучение модели

Для дообучения модели мы воспользуемся классом `Trainer` из раздела 🤗 Transformers. Как мы уже видели в других
главах, `Trainer` - это высокоуровневый API, предназначенный для работы с наиболее распространенными сценариями обучения.
В данном случае мы будем использовать `Trainer` для дообучения модели на GTZAN. Для этого сначала нужно загрузить модель для данной задачи.
Для этого мы можем использовать класс `AutoModelForAudioClassification`, который автоматически добавит соответствующую классификационную голову
в нашу предварительно обученную модель DistilHuBERT. Давайте перейдем к инстанцированию модели:

```python
from transformers import AutoModelForAudioClassification

num_labels = len(id2label)

model = AutoModelForAudioClassification.from_pretrained(
    model_id,
    num_labels=num_labels,
    label2id=label2id,
    id2label=id2label,
)
```

Мы настоятельно рекомендуем во время тренировок загружать контрольные точки моделей непосредственно на [Hugging Face Hub](https://huggingface.co/).
Hugging Face Hub предоставляет:
- Встроенный контроль версий: вы можете быть уверены, что ни одна контрольная точка модели не будет потеряна в процессе обучения.
- Журналы Tensorboard: отслеживание важных показателей в процессе обучения.
- Карты моделей: документирование того, что делает модель, и предполагаемых вариантов ее использования.
- Сообщество: простой способ обмена информацией и сотрудничества с сообществом! 🤗

Связать ноутбук с Hugging Face Hub очень просто - для этого достаточно ввести аутентификационный токен при появлении соответствующего запроса.
Найдите свой токен аутентификации [здесь](https://huggingface.co/settings/tokens):

```python
from huggingface_hub import notebook_login

notebook_login()
```

**Output:**
```bash
Login successful
Your token has been saved to /root/.huggingface/token
```

Следующим шагом является определение аргументов обучения, включая размер пакета, шаги накопления градиента, количество
эпох обучения и скорость обучения:

```python
from transformers import TrainingArguments

model_name = model_id.split("/")[-1]
batch_size = 8
gradient_accumulation_steps = 1
num_train_epochs = 10

training_args = TrainingArguments(
    f"{model_name}-finetuned-gtzan",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    learning_rate=5e-5,
    per_device_train_batch_size=batch_size,
    gradient_accumulation_steps=gradient_accumulation_steps,
    per_device_eval_batch_size=batch_size,
    num_train_epochs=num_train_epochs,
    warmup_ratio=0.1,
    logging_steps=5,
    load_best_model_at_end=True,
    metric_for_best_model="accuracy",
    fp16=True,
    push_to_hub=True,
)
```

<Tip warning={true}>
    Здесь мы установили значение `push_to_hub=True`, чтобы включить автоматическую загрузку настроенных контрольных точек во время обучения.
    Если вы не хотите, чтобы ваши контрольные точки загружались на Hugging Face Hub, вы можете установить значение `False`.
</Tip>

Последнее, что нам необходимо сделать, это определить метрики. Поскольку набор данных сбалансирован, в качестве метрики мы будем использовать
accuracy и загружать ее с помощью библиотеки 🤗 Evaluate:

```python
import evaluate
import numpy as np

metric = evaluate.load("accuracy")


def compute_metrics(eval_pred):
    """Computes accuracy on a batch of predictions"""
    predictions = np.argmax(eval_pred.predictions, axis=1)
    return metric.compute(predictions=predictions, references=eval_pred.label_ids)
```

Теперь у нас есть все необходимые компоненты! Давайте инстанцируем `Trainer` и обучим модель:

```python
from transformers import Trainer

trainer = Trainer(
    model,
    training_args,
    train_dataset=gtzan_encoded["train"],
    eval_dataset=gtzan_encoded["test"],
    tokenizer=feature_extractor,
    compute_metrics=compute_metrics,
)

trainer.train()
```

<Tip warning={true}>
    
    В зависимости от используемого графического процессора, при запуске обучения возможно возникновение ошибки CUDA `"out-of-memory"`.
    В этом случае можно уменьшать `batch_size` постепенно в 2 раза, а для компенсации использовать [`gradient_accumulation_steps`](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments.gradient_accumulation_steps)

</Tip>

**Output:**
```out
| Training Loss | Epoch | Step | Validation Loss | Accuracy |
|:-------------:|:-----:|:----:|:---------------:|:--------:|
| 1.7297        | 1.0   | 113  | 1.8011          | 0.44     |
| 1.24          | 2.0   | 226  | 1.3045          | 0.64     |
| 0.9805        | 3.0   | 339  | 0.9888          | 0.7      |
| 0.6853        | 4.0   | 452  | 0.7508          | 0.79     |
| 0.4502        | 5.0   | 565  | 0.6224          | 0.81     |
| 0.3015        | 6.0   | 678  | 0.5411          | 0.83     |
| 0.2244        | 7.0   | 791  | 0.6293          | 0.78     |
| 0.3108        | 8.0   | 904  | 0.5857          | 0.81     |
| 0.1644        | 9.0   | 1017 | 0.5355          | 0.83     |
| 0.1198        | 10.0  | 1130 | 0.5716          | 0.82     |
```

Обучение займет примерно 1 час в зависимости от вашего GPU или выделенного для Google Colab. Наша лучшая доля верных ответов
составляет 83% - неплохо для 10 эпох с 899 примерами обучающих данных! Конечно, мы могли бы улучшить этот результат,
тренируясь на большем количестве эпох, используя методы регуляризации, такие как _dropout_, или разбивая каждый аудиопример
на сегменты по 30 и 15 секунд, чтобы использовать более эффективную стратегию предварительной обработки данных.

Большой вопрос, как это соотносится с другими системами классификации музыки 🤔
Для этого мы можем просмотреть [autoevaluate leaderboard](https://huggingface.co/spaces/autoevaluate/leaderboards?dataset=marsyas%2Fgtzan&only_verified=0&task=audio-classification&config=all&split=train&metric=accuracy),
таблицу лидеров, которая классифицирует модели по языку и набору данных, а затем ранжирует их по accuracy.

Мы можем автоматически отправить нашу контрольную точку в таблицу лидеров при передаче результатов обучения в
Hugging Face Hub - для этого достаточно задать соответствующие аргументы ключевых слов (kwargs). Вы можете изменить эти значения
в соответствии с набором данных, языком и названием модели:

```python
kwargs = {
    "dataset_tags": "marsyas/gtzan",
    "dataset": "GTZAN",
    "model_name": f"{model_name}-finetuned-gtzan",
    "finetuned_from": model_id,
    "tasks": "audio-classification",
}
```

Теперь результаты обучения можно загрузить в Hugging Face Hub. Для этого выполните команду `.push_to_hub`:

```python
trainer.push_to_hub(**kwargs)
```

При этом журналы обучения и веса моделей будут сохранены под именем `"your-username/distilhubert-finetuned-gtzan"`. Для примера
посмотрите загрузку по адресу [`"sanchit-gandhi/distilhubert-finetuned-gtzan"`](https://huggingface.co/sanchit-gandhi/distilhubert-finetuned-gtzan).

## Поделиться моделью

Теперь вы можете поделиться этой моделью со всеми желающими, воспользовавшись ссылкой на Hub. Они могут загрузить его с идентификатором `"your-username/distilhubert-finetuned-gtzan"`
непосредственно в `pipeline()`. Например, для загрузки точно настроенной контрольной точки [`"sanchit-gandhi/distilhubert-finetuned-gtzan"`](https://huggingface.co/sanchit-gandhi/distilhubert-finetuned-gtzan):

```python
from transformers import pipeline

pipe = pipeline(
    "audio-classification", model="sanchit-gandhi/distilhubert-finetuned-gtzan"
)
```

## Заключение

В этом разделе мы рассмотрели пошаговое руководство по тонкой настройке модели DistilHuBERT для классификации музыки. Хотя мы
сосредоточились на задаче классификации музыки и на наборе данных GTZAN, представленные здесь шаги применимы в более общем случае
к любой задаче классификации звука - тот же сценарий может быть использован для задач классификации звука разговорного языка,
таких как выделение ключевых слов или идентификация языка. Вам просто нужно поменять набор данных на тот, который соответствует
интересующей вас задаче! Если вы заинтересованы в тонкой настройке других моделей Hugging Face Hub для классификации звука,
мы рекомендуем вам ознакомиться с другими [примерами](https://github.com/huggingface/transformers/tree/main/examples/pytorch/audio-classification)
в 🤗 репозитории Transformers.

В следующем разделе мы возьмем модель, которую вы только что отладили, и создадим демонстрационный образец классификации музыки, который
вы сможете опубликовать на Hugging Face Hub.

<EditOnGithub source="https://github.com/huggingface/audio-transformers-course/blob/main/chapters/ru/chapter4/fine-tuning.mdx" />