add merge tools
This commit is contained in:
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"service_port": 5042,
|
"service_port": 5042,
|
||||||
"model_path": "/mnt/cloud/llm/whisper/whisper-large-v3-russian",
|
"model_path": "/mnt/cloud/llm/whisper/whisper-large-v3-russian-ties-podlodka",
|
||||||
"language": "russian",
|
"language": "russian",
|
||||||
"enable_history": true,
|
"enable_history": true,
|
||||||
"chunk_length_s": 22,
|
"chunk_length_s": 25,
|
||||||
"batch_size": 20,
|
"batch_size": 20,
|
||||||
"max_new_tokens": 384,
|
"max_new_tokens": 384,
|
||||||
"return_timestamps": false,
|
"return_timestamps": false,
|
||||||
|
|||||||
Executable
+367
@@ -0,0 +1,367 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Имя окружения conda
|
||||||
|
CONDA_ENV_NAME="whisper-merge"
|
||||||
|
|
||||||
|
# Директории для моделей
|
||||||
|
MODEL_A="/mnt/cloud/llm/whisper/whisper-large-v3-russian"
|
||||||
|
MODEL_B="/mnt/cloud/llm/whisper/whisper-large-v3-ru-podlodka"
|
||||||
|
OUTPUT_DIR="/mnt/cloud/llm/whisper/whisper-large-v3-russian+podlodka"
|
||||||
|
|
||||||
|
# Флаг обновления (по умолчанию false)
|
||||||
|
UPDATE_ENV=false
|
||||||
|
|
||||||
|
# Метод слияния (по умолчанию all)
|
||||||
|
MERGE_METHOD="all"
|
||||||
|
|
||||||
|
# Дополнительные параметры (по умолчанию)
|
||||||
|
SLERP_T=0.5
|
||||||
|
TIES_DENSITY=0.8
|
||||||
|
ENCODER_WEIGHTS="0.6,0.4"
|
||||||
|
DECODER_WEIGHTS="0.4,0.6"
|
||||||
|
DIRECT_ALPHA=0.5
|
||||||
|
|
||||||
|
# Проверка аргументов
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--update) UPDATE_ENV=true ;;
|
||||||
|
--method) MERGE_METHOD="$2"; shift ;;
|
||||||
|
--slerp-t) SLERP_T="$2"; shift ;;
|
||||||
|
--ties-density) TIES_DENSITY="$2"; shift ;;
|
||||||
|
--encoder-weights) ENCODER_WEIGHTS="$2"; shift ;;
|
||||||
|
--decoder-weights) DECODER_WEIGHTS="$2"; shift ;;
|
||||||
|
--direct-alpha) DIRECT_ALPHA="$2"; shift ;;
|
||||||
|
*) echo "⚠️ Неизвестный параметр: $1"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Проверка наличия conda
|
||||||
|
if ! command -v conda &> /dev/null; then
|
||||||
|
echo "❌ Conda не установлен. Пожалуйста, установите conda и попробуйте снова."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Создание окружения conda, если оно не существует
|
||||||
|
if ! conda env list | grep -q "$CONDA_ENV_NAME"; then
|
||||||
|
echo "🔹 Создание окружения conda: $CONDA_ENV_NAME"
|
||||||
|
conda create -n "$CONDA_ENV_NAME" python=3.12 -y
|
||||||
|
else
|
||||||
|
echo "✅ Окружение conda '$CONDA_ENV_NAME' уже существует."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Получение пути к conda
|
||||||
|
CONDA_PATH=$(which conda)
|
||||||
|
|
||||||
|
# Проверка, что путь к conda найден
|
||||||
|
if [ -z "$CONDA_PATH" ]; then
|
||||||
|
echo "❌ Не удалось найти путь к conda."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Активация окружения conda
|
||||||
|
echo "🔹 Активация окружения conda: $CONDA_ENV_NAME"
|
||||||
|
source $(dirname "$CONDA_PATH")/../etc/profile.d/conda.sh
|
||||||
|
conda activate "$CONDA_ENV_NAME"
|
||||||
|
|
||||||
|
# Если флаг --update установлен, обновляем зависимости
|
||||||
|
if [[ "$UPDATE_ENV" == true ]]; then
|
||||||
|
echo "🔹 Установка и обновление зависимостей"
|
||||||
|
pip install --upgrade pip wheel
|
||||||
|
pip install torch torchaudio
|
||||||
|
pip install transformers datasets evaluate accelerate
|
||||||
|
pip install soundfile librosa tqdm
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Проверка установки torch и transformers
|
||||||
|
if ! python -c "import torch, transformers" &> /dev/null; then
|
||||||
|
echo "❌ PyTorch или Transformers не установлены. Запустите с опцией --update."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Создание временного Python-скрипта для слияния
|
||||||
|
cat > merge_models.py << EOL
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import torch
|
||||||
|
from transformers import WhisperForConditionalGeneration, WhisperProcessor
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
def direct_merge(model_a_path, model_b_path, output_path, alpha=0.5):
|
||||||
|
"""Простое прямое слияние весов моделей с коэффициентом alpha"""
|
||||||
|
print(f"🔹 Запуск прямого слияния с alpha={alpha}")
|
||||||
|
|
||||||
|
print(f"📂 Загрузка модели A из {model_a_path}")
|
||||||
|
model_a = WhisperForConditionalGeneration.from_pretrained(model_a_path)
|
||||||
|
|
||||||
|
print(f"📂 Загрузка модели B из {model_b_path}")
|
||||||
|
model_b = WhisperForConditionalGeneration.from_pretrained(model_b_path)
|
||||||
|
|
||||||
|
# Создаем новую модель для хранения объединенных весов
|
||||||
|
print("🔄 Объединение весов моделей...")
|
||||||
|
merged_model = WhisperForConditionalGeneration.from_pretrained(model_a_path)
|
||||||
|
|
||||||
|
# Подсчет общего количества параметров
|
||||||
|
param_count = len(list(merged_model.named_parameters()))
|
||||||
|
|
||||||
|
# Объединение весов
|
||||||
|
with torch.no_grad():
|
||||||
|
for i, (param_name, param) in enumerate(tqdm(merged_model.named_parameters(), total=param_count, desc="Слияние параметров")):
|
||||||
|
if param_name in model_a.state_dict() and param_name in model_b.state_dict():
|
||||||
|
# Объединяем веса с учетом коэффициента альфа
|
||||||
|
merged_param = alpha * model_a.state_dict()[param_name] + (1 - alpha) * model_b.state_dict()[param_name]
|
||||||
|
param.copy_(merged_param)
|
||||||
|
|
||||||
|
# Создаем директорию для выходных данных, если она не существует
|
||||||
|
os.makedirs(output_path, exist_ok=True)
|
||||||
|
|
||||||
|
# Сохраняем объединенную модель
|
||||||
|
print(f"💾 Сохранение объединенной модели в {output_path}")
|
||||||
|
merged_model.save_pretrained(output_path)
|
||||||
|
|
||||||
|
# Сохраняем процессор из модели A
|
||||||
|
print("💾 Сохранение процессора")
|
||||||
|
processor = WhisperProcessor.from_pretrained(model_a_path)
|
||||||
|
processor.save_pretrained(output_path)
|
||||||
|
|
||||||
|
print("✅ Прямое слияние успешно завершено!")
|
||||||
|
return merged_model
|
||||||
|
|
||||||
|
def slerp_weights(model_a, model_b, t):
|
||||||
|
"""Выполняет SLERP (Spherical Linear Interpolation) между весами моделей"""
|
||||||
|
# Получаем словари состояний моделей
|
||||||
|
state_dict_a = model_a.state_dict()
|
||||||
|
state_dict_b = model_b.state_dict()
|
||||||
|
|
||||||
|
# Создаем новый словарь для смешанных весов
|
||||||
|
mixed_weights = {}
|
||||||
|
|
||||||
|
for key in tqdm(state_dict_a.keys(), desc="SLERP слияние"):
|
||||||
|
if key in state_dict_b:
|
||||||
|
# Получаем веса для текущего параметра
|
||||||
|
weight_a = state_dict_a[key].float()
|
||||||
|
weight_b = state_dict_b[key].float()
|
||||||
|
|
||||||
|
# Выполняем SLERP
|
||||||
|
# Нормализуем веса
|
||||||
|
norm_a = torch.norm(weight_a)
|
||||||
|
norm_b = torch.norm(weight_b)
|
||||||
|
|
||||||
|
# Если норма близка к нулю, используем линейную интерполяцию
|
||||||
|
if norm_a < 1e-6 or norm_b < 1e-6:
|
||||||
|
mixed_weights[key] = (1 - t) * weight_a + t * weight_b
|
||||||
|
continue
|
||||||
|
|
||||||
|
weight_a_normalized = weight_a / norm_a
|
||||||
|
weight_b_normalized = weight_b / norm_b
|
||||||
|
|
||||||
|
# Вычисляем косинус угла между векторами
|
||||||
|
cos_theta = torch.sum(weight_a_normalized * weight_b_normalized)
|
||||||
|
cos_theta = torch.clamp(cos_theta, -1.0, 1.0)
|
||||||
|
|
||||||
|
# Вычисляем угол
|
||||||
|
theta = torch.acos(cos_theta)
|
||||||
|
|
||||||
|
# Если угол близок к 0 или π, используем линейную интерполяцию
|
||||||
|
if abs(theta) < 1e-6 or abs(theta - torch.pi) < 1e-6:
|
||||||
|
mixed_weights[key] = (1 - t) * weight_a + t * weight_b
|
||||||
|
else:
|
||||||
|
# SLERP формула: (sin((1-t)*theta) / sin(theta)) * weight_a + (sin(t*theta) / sin(theta)) * weight_b
|
||||||
|
sin_theta = torch.sin(theta)
|
||||||
|
mixed_weights[key] = (torch.sin((1 - t) * theta) / sin_theta) * weight_a + (torch.sin(t * theta) / sin_theta) * weight_b
|
||||||
|
|
||||||
|
# Проверка на NaN
|
||||||
|
if torch.isnan(mixed_weights[key]).any():
|
||||||
|
# Если появились NaN, используем линейную интерполяцию
|
||||||
|
mixed_weights[key] = (1 - t) * weight_a + t * weight_b
|
||||||
|
|
||||||
|
return mixed_weights
|
||||||
|
|
||||||
|
def slerp_merge(model_a_path, model_b_path, output_path, t=0.5):
|
||||||
|
"""Слияние методом SLERP, реализованное напрямую без использования mergekit"""
|
||||||
|
print(f"🔹 Запуск слияния методом SLERP с t={t}")
|
||||||
|
|
||||||
|
print(f"📂 Загрузка модели A из {model_a_path}")
|
||||||
|
model_a = WhisperForConditionalGeneration.from_pretrained(model_a_path)
|
||||||
|
|
||||||
|
print(f"📂 Загрузка модели B из {model_b_path}")
|
||||||
|
model_b = WhisperForConditionalGeneration.from_pretrained(model_b_path)
|
||||||
|
|
||||||
|
# Создаем новую модель для хранения смешанных весов
|
||||||
|
print("🔄 Применение метода SLERP...")
|
||||||
|
merged_model = WhisperForConditionalGeneration.from_pretrained(model_a_path)
|
||||||
|
|
||||||
|
# Получаем смешанные веса
|
||||||
|
mixed_weights = slerp_weights(model_a, model_b, t)
|
||||||
|
|
||||||
|
# Загружаем смешанные веса в модель
|
||||||
|
merged_model.load_state_dict(mixed_weights)
|
||||||
|
|
||||||
|
# Создаем директорию для выходных данных
|
||||||
|
os.makedirs(output_path, exist_ok=True)
|
||||||
|
|
||||||
|
# Сохраняем объединенную модель
|
||||||
|
print(f"💾 Сохранение объединенной модели в {output_path}")
|
||||||
|
merged_model.save_pretrained(output_path)
|
||||||
|
|
||||||
|
# Сохраняем процессор из модели A
|
||||||
|
processor = WhisperProcessor.from_pretrained(model_a_path)
|
||||||
|
processor.save_pretrained(output_path)
|
||||||
|
|
||||||
|
print("✅ Слияние методом SLERP успешно завершено!")
|
||||||
|
return merged_model
|
||||||
|
|
||||||
|
def ties_merge(model_a_path, model_b_path, output_path, density=0.8, encoder_weights=(0.6, 0.4), decoder_weights=(0.4, 0.6)):
|
||||||
|
"""Слияние, реализованное по принципу TIES без использования mergekit"""
|
||||||
|
print(f"🔹 Запуск слияния по принципу TIES с плотностью {density}")
|
||||||
|
print(f" Веса кодировщика: {encoder_weights}, веса декодера: {decoder_weights}")
|
||||||
|
|
||||||
|
print(f"📂 Загрузка модели A из {model_a_path}")
|
||||||
|
model_a = WhisperForConditionalGeneration.from_pretrained(model_a_path)
|
||||||
|
|
||||||
|
print(f"📂 Загрузка модели B из {model_b_path}")
|
||||||
|
model_b = WhisperForConditionalGeneration.from_pretrained(model_b_path)
|
||||||
|
|
||||||
|
# Создаем новую модель для хранения смешанных весов
|
||||||
|
print("🔄 Применение метода TIES...")
|
||||||
|
merged_model = WhisperForConditionalGeneration.from_pretrained(model_a_path)
|
||||||
|
|
||||||
|
# Получаем словари состояний моделей
|
||||||
|
state_dict_a = model_a.state_dict()
|
||||||
|
state_dict_b = model_b.state_dict()
|
||||||
|
|
||||||
|
# Создаем словарь для смешанных весов
|
||||||
|
mixed_weights = {}
|
||||||
|
|
||||||
|
# Для каждого параметра
|
||||||
|
for key in tqdm(state_dict_a.keys(), desc="TIES слияние"):
|
||||||
|
if key in state_dict_b:
|
||||||
|
# Определение типа слоя (кодировщик или декодер)
|
||||||
|
if "encoder" in key:
|
||||||
|
w_a, w_b = encoder_weights
|
||||||
|
elif "decoder" in key:
|
||||||
|
w_a, w_b = decoder_weights
|
||||||
|
else:
|
||||||
|
# Для других параметров используем среднее
|
||||||
|
w_a = (encoder_weights[0] + decoder_weights[0]) / 2
|
||||||
|
w_b = (encoder_weights[1] + decoder_weights[1]) / 2
|
||||||
|
|
||||||
|
# Получаем веса для текущего параметра
|
||||||
|
weight_a = state_dict_a[key]
|
||||||
|
weight_b = state_dict_b[key]
|
||||||
|
|
||||||
|
# Вычисляем абсолютную разницу между весами
|
||||||
|
abs_diff = torch.abs(weight_a - weight_b)
|
||||||
|
|
||||||
|
# Создаем маску для топ-k% элементов с наибольшей разницей
|
||||||
|
# если density=0.8, то мы сохраняем 80% элементов с наибольшей разницей
|
||||||
|
k = int((1 - density) * abs_diff.numel())
|
||||||
|
if k > 0:
|
||||||
|
threshold = torch.kthvalue(abs_diff.flatten(), k).values
|
||||||
|
mask = abs_diff >= threshold
|
||||||
|
else:
|
||||||
|
mask = torch.ones_like(abs_diff, dtype=torch.bool)
|
||||||
|
|
||||||
|
# Создаем смешанные веса:
|
||||||
|
# Для элементов с большой разницей используем веса w_a и w_b
|
||||||
|
# Для остальных используем среднее арифметическое
|
||||||
|
mixed = torch.zeros_like(weight_a)
|
||||||
|
mixed[mask] = w_a * weight_a[mask] + w_b * weight_b[mask]
|
||||||
|
mixed[~mask] = (weight_a[~mask] + weight_b[~mask]) / 2
|
||||||
|
|
||||||
|
mixed_weights[key] = mixed
|
||||||
|
|
||||||
|
# Загружаем смешанные веса в модель
|
||||||
|
merged_model.load_state_dict(mixed_weights)
|
||||||
|
|
||||||
|
# Создаем директорию для выходных данных
|
||||||
|
os.makedirs(output_path, exist_ok=True)
|
||||||
|
|
||||||
|
# Сохраняем объединенную модель
|
||||||
|
print(f"💾 Сохранение объединенной модели в {output_path}")
|
||||||
|
merged_model.save_pretrained(output_path)
|
||||||
|
|
||||||
|
# Сохраняем процессор из модели A
|
||||||
|
processor = WhisperProcessor.from_pretrained(model_a_path)
|
||||||
|
processor.save_pretrained(output_path)
|
||||||
|
|
||||||
|
print("✅ Слияние по принципу TIES успешно завершено!")
|
||||||
|
return merged_model
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Объединение моделей Whisper методами SLERP и TIES")
|
||||||
|
parser.add_argument("--model-a", default="$MODEL_A",
|
||||||
|
help="Путь к первой модели")
|
||||||
|
parser.add_argument("--model-b", default="$MODEL_B",
|
||||||
|
help="Путь к второй модели")
|
||||||
|
parser.add_argument("--output-dir", default="$OUTPUT_DIR",
|
||||||
|
help="Директория для сохранения результатов")
|
||||||
|
parser.add_argument("--method", choices=["slerp", "ties", "direct", "all"], default="$MERGE_METHOD",
|
||||||
|
help="Метод слияния: slerp, ties, direct или all")
|
||||||
|
|
||||||
|
# Параметры для SLERP
|
||||||
|
parser.add_argument("--slerp-t", type=float, default=$SLERP_T,
|
||||||
|
help="Коэффициент интерполяции для SLERP (0-1)")
|
||||||
|
|
||||||
|
# Параметры для TIES
|
||||||
|
parser.add_argument("--ties-density", type=float, default=$TIES_DENSITY,
|
||||||
|
help="Плотность смешивания для TIES (0-1)")
|
||||||
|
parser.add_argument("--encoder-weights", type=str, default="$ENCODER_WEIGHTS",
|
||||||
|
help="Веса для кодировщика в формате '0.6,0.4'")
|
||||||
|
parser.add_argument("--decoder-weights", type=str, default="$DECODER_WEIGHTS",
|
||||||
|
help="Веса для декодера в формате '0.4,0.6'")
|
||||||
|
|
||||||
|
# Параметры для прямого слияния
|
||||||
|
parser.add_argument("--direct-alpha", type=float, default=$DIRECT_ALPHA,
|
||||||
|
help="Коэффициент альфа для прямого слияния (0-1)")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Разбор весов для TIES
|
||||||
|
encoder_weights = tuple(map(float, args.encoder_weights.split(',')))
|
||||||
|
decoder_weights = tuple(map(float, args.decoder_weights.split(',')))
|
||||||
|
|
||||||
|
# Создание выходной директории
|
||||||
|
os.makedirs(args.output_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Выполнение слияния выбранным методом
|
||||||
|
if args.method == "direct" or args.method == "all":
|
||||||
|
direct_output = os.path.join(args.output_dir, "direct")
|
||||||
|
direct_merge(args.model_a, args.model_b, direct_output, args.direct_alpha)
|
||||||
|
|
||||||
|
if args.method == "slerp" or args.method == "all":
|
||||||
|
slerp_output = os.path.join(args.output_dir, "slerp")
|
||||||
|
try:
|
||||||
|
slerp_merge(args.model_a, args.model_b, slerp_output, args.slerp_t)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Ошибка при слиянии методом SLERP: {e}")
|
||||||
|
print("⚠️ Используется прямое слияние вместо SLERP.")
|
||||||
|
direct_merge(args.model_a, args.model_b, slerp_output, args.slerp_t)
|
||||||
|
|
||||||
|
if args.method == "ties" or args.method == "all":
|
||||||
|
ties_output = os.path.join(args.output_dir, "ties")
|
||||||
|
try:
|
||||||
|
ties_merge(args.model_a, args.model_b, ties_output, args.ties_density, encoder_weights, decoder_weights)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Ошибка при слиянии методом TIES: {e}")
|
||||||
|
print("⚠️ Используется прямое слияние вместо TIES.")
|
||||||
|
alpha = (encoder_weights[0] + decoder_weights[0]) / 2
|
||||||
|
direct_merge(args.model_a, args.model_b, ties_output, alpha)
|
||||||
|
|
||||||
|
print("\n✅ Все операции слияния успешно завершены!")
|
||||||
|
print(f"📂 Результаты сохранены в {args.output_dir}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
EOL
|
||||||
|
|
||||||
|
# Запуск Python-скрипта
|
||||||
|
python merge_models.py
|
||||||
|
|
||||||
|
# Удаление временного скрипта
|
||||||
|
rm merge_models.py
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Процесс слияния завершен. Результаты сохранены в $OUTPUT_DIR"
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
# Полное руководство по объединению моделей Whisper
|
||||||
|
|
||||||
|
## Содержание
|
||||||
|
1. [Введение](#введение)
|
||||||
|
2. [Установка и подготовка](#установка-и-подготовка)
|
||||||
|
3. [Базовое использование](#базовое-использование)
|
||||||
|
4. [Детальные настройки](#детальные-настройки)
|
||||||
|
- [Методы слияния](#методы-слияния)
|
||||||
|
- [Параметры для метода Direct](#параметры-для-метода-direct)
|
||||||
|
- [Параметры для метода SLERP](#параметры-для-метода-slerp)
|
||||||
|
- [Параметры для метода TIES](#параметры-для-метода-ties)
|
||||||
|
5. [Практические рекомендации](#практические-рекомендации)
|
||||||
|
6. [Тестирование и оценка](#тестирование-и-оценка)
|
||||||
|
7. [Устранение неполадок](#устранение-неполадок)
|
||||||
|
|
||||||
|
## Введение
|
||||||
|
|
||||||
|
Скрипт `whisper_merge.sh` позволяет объединять две модели Whisper, обученные на разных датасетах, для получения комбинированной модели с улучшенными характеристиками. Особенно полезно для моделей, обученных на разных типах данных одного языка (например, разные диалекты русского языка, формальная/неформальная речь и т.д.).
|
||||||
|
|
||||||
|
## Установка и подготовка
|
||||||
|
|
||||||
|
1. **Убедитесь, что Conda установлена** в вашей системе.
|
||||||
|
2. **Скачайте скрипт `whisper_merge.sh`** и сделайте его исполняемым:
|
||||||
|
```bash
|
||||||
|
chmod +x whisper_merge.sh
|
||||||
|
```
|
||||||
|
3. **Подготовьте модели для слияния**. По умолчанию скрипт ищет модели по следующим путям:
|
||||||
|
- Модель A: `/mnt/cloud/llm/whisper/whisper-large-v3-russian`
|
||||||
|
- Модель B: `/mnt/cloud/llm/whisper/whisper-large-v3-ru-podlodka`
|
||||||
|
- Директория для результатов: `/mnt/cloud/llm/whisper/whisper-large-v3-russian+podlodka`
|
||||||
|
|
||||||
|
Пути можно изменить, отредактировав переменные `MODEL_A`, `MODEL_B` и `OUTPUT_DIR` в начале скрипта.
|
||||||
|
|
||||||
|
## Базовое использование
|
||||||
|
|
||||||
|
### Первый запуск
|
||||||
|
|
||||||
|
Для первого запуска рекомендуется использовать флаг `--update` для установки всех зависимостей:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --update
|
||||||
|
```
|
||||||
|
|
||||||
|
Это создаст окружение conda с именем `whisper-merge` и установит необходимые пакеты.
|
||||||
|
|
||||||
|
### Стандартное слияние
|
||||||
|
|
||||||
|
Для выполнения слияния с настройками по умолчанию:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
По умолчанию будут использованы следующие параметры:
|
||||||
|
- Метод слияния: `all` (все методы)
|
||||||
|
- SLERP t: `0.5`
|
||||||
|
- TIES density: `0.8`
|
||||||
|
- Encoder weights: `0.6,0.4`
|
||||||
|
- Decoder weights: `0.4,0.6`
|
||||||
|
- Direct alpha: `0.5`
|
||||||
|
|
||||||
|
## Детальные настройки
|
||||||
|
|
||||||
|
### Методы слияния
|
||||||
|
|
||||||
|
Скрипт поддерживает три метода слияния моделей:
|
||||||
|
|
||||||
|
1. **Direct** (`--method direct`) — простое линейное смешивание весов:
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method direct
|
||||||
|
```
|
||||||
|
- **Преимущества**: простота, надежность, меньшие вычислительные требования
|
||||||
|
- **Недостатки**: может не сохранять геометрию пространства весов
|
||||||
|
- **Когда использовать**: для быстрого тестирования или когда модели очень близки
|
||||||
|
|
||||||
|
2. **SLERP** (`--method slerp`) — сферическая линейная интерполяция:
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method slerp
|
||||||
|
```
|
||||||
|
- **Преимущества**: лучше сохраняет геометрию пространства весов
|
||||||
|
- **Недостатки**: требует больше вычислений, может не работать корректно для некоторых моделей
|
||||||
|
- **Когда использовать**: для моделей, где важно сохранение пространственных отношений между параметрами
|
||||||
|
|
||||||
|
3. **TIES** (`--method ties`) — алгоритм Task Induced Expert Selection:
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method ties
|
||||||
|
```
|
||||||
|
- **Преимущества**: позволяет индивидуально настраивать веса для кодировщика и декодера
|
||||||
|
- **Недостатки**: более сложный, требует тонкой настройки параметров
|
||||||
|
- **Когда использовать**: для продвинутого слияния, когда известно, что одна модель лучше работает с определенными аспектами (например, фонетикой или грамматикой)
|
||||||
|
|
||||||
|
4. **All** (`--method all`) — применяет все три метода и сохраняет результаты в отдельные подпапки:
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method all
|
||||||
|
```
|
||||||
|
- **Преимущества**: позволяет сравнить результаты всех методов
|
||||||
|
- **Недостатки**: требует больше времени и дискового пространства
|
||||||
|
- **Когда использовать**: при первоначальном тестировании для выбора оптимального метода
|
||||||
|
|
||||||
|
### Параметры для метода Direct
|
||||||
|
|
||||||
|
#### Direct Alpha (`--direct-alpha`)
|
||||||
|
|
||||||
|
Определяет вес первой модели в процессе слияния:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method direct --direct-alpha 0.7
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Диапазон**: от 0.0 до 1.0
|
||||||
|
- **По умолчанию**: 0.5 (равный вес обеих моделей)
|
||||||
|
- **Влияние**:
|
||||||
|
- `0.0` — полностью использует веса второй модели (MODEL_B)
|
||||||
|
- `0.5` — равный вклад обеих моделей
|
||||||
|
- `1.0` — полностью использует веса первой модели (MODEL_A)
|
||||||
|
- **Рекомендации**:
|
||||||
|
- Если MODEL_A лучше справляется с задачей: увеличьте alpha (`0.6` — `0.8`)
|
||||||
|
- Если MODEL_B лучше справляется с задачей: уменьшите alpha (`0.2` — `0.4`)
|
||||||
|
- Для тонкой настройки изменяйте значение с шагом 0.05
|
||||||
|
|
||||||
|
### Параметры для метода SLERP
|
||||||
|
|
||||||
|
#### SLERP t (`--slerp-t`)
|
||||||
|
|
||||||
|
Определяет соотношение весов при сферической интерполяции:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method slerp --slerp-t 0.3
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Диапазон**: от 0.0 до 1.0
|
||||||
|
- **По умолчанию**: 0.5 (равный вклад)
|
||||||
|
- **Влияние**:
|
||||||
|
- `0.0` — полностью вес на MODEL_A
|
||||||
|
- `1.0` — полностью вес на MODEL_B
|
||||||
|
- Промежуточные значения дают нелинейную интерполяцию между моделями
|
||||||
|
- **Рекомендации**:
|
||||||
|
- В отличие от direct alpha, здесь значение `0` соответствует MODEL_A, а `1` соответствует MODEL_B
|
||||||
|
- SLERP обычно дает более гладкое слияние, чем direct
|
||||||
|
- Для русских моделей обычно хорошо работают значения `0.4` — `0.6`
|
||||||
|
|
||||||
|
### Параметры для метода TIES
|
||||||
|
|
||||||
|
#### TIES Density (`--ties-density`)
|
||||||
|
|
||||||
|
Определяет долю параметров, которые будут смешаны индивидуально, а не усреднены:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method ties --ties-density 0.85
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Диапазон**: от 0.0 до 1.0
|
||||||
|
- **По умолчанию**: 0.8
|
||||||
|
- **Влияние**:
|
||||||
|
- `0.0` — все параметры усредняются
|
||||||
|
- `1.0` — все параметры смешиваются индивидуально по заданным весам
|
||||||
|
- Промежуточные значения определяют процент параметров с наибольшей разницей, которые будут смешаны индивидуально
|
||||||
|
- **Рекомендации**:
|
||||||
|
- Более высокие значения (`0.8` — `0.9`) лучше сохраняют индивидуальные особенности каждой модели
|
||||||
|
- Более низкие значения (`0.5` — `0.7`) дают более стабильный результат
|
||||||
|
- Для русских моделей рекомендуется `0.85`, что позволяет сохранить уникальные особенности обеих моделей
|
||||||
|
|
||||||
|
#### Encoder Weights (`--encoder-weights`)
|
||||||
|
|
||||||
|
Определяет веса моделей для кодировщика (отвечает за обработку аудиосигнала):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method ties --encoder-weights "0.7,0.3"
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Формат**: два числа, разделенные запятой, сумма должна равняться 1.0
|
||||||
|
- **По умолчанию**: "0.6,0.4"
|
||||||
|
- **Влияние**:
|
||||||
|
- Первое число — вес MODEL_A для кодировщика
|
||||||
|
- Второе число — вес MODEL_B для кодировщика
|
||||||
|
- **Рекомендации**:
|
||||||
|
- Если MODEL_A лучше распознает фонетические особенности речи: увеличьте её вес (e.g., "0.7,0.3")
|
||||||
|
- Если MODEL_B лучше распознает акценты или диалекты: увеличьте её вес (e.g., "0.4,0.6")
|
||||||
|
- Для русских моделей, если одна из них лучше обрабатывает различные диалекты, дайте ей больший вес в кодировщике
|
||||||
|
|
||||||
|
#### Decoder Weights (`--decoder-weights`)
|
||||||
|
|
||||||
|
Определяет веса моделей для декодера (отвечает за формирование текста):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method ties --decoder-weights "0.3,0.7"
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Формат**: два числа, разделенные запятой, сумма должна равняться 1.0
|
||||||
|
- **По умолчанию**: "0.4,0.6"
|
||||||
|
- **Влияние**:
|
||||||
|
- Первое число — вес MODEL_A для декодера
|
||||||
|
- Второе число — вес MODEL_B для декодера
|
||||||
|
- **Рекомендации**:
|
||||||
|
- Если MODEL_A лучше справляется с грамматикой: увеличьте её вес (e.g., "0.6,0.4")
|
||||||
|
- Если MODEL_B имеет лучший языковой контекст: увеличьте её вес (e.g., "0.3,0.7")
|
||||||
|
- Для русских моделей, если одна модель лучше обрабатывает грамматические конструкции, дайте ей больший вес в декодере
|
||||||
|
|
||||||
|
## Практические рекомендации
|
||||||
|
|
||||||
|
### Для слияния русских моделей
|
||||||
|
|
||||||
|
1. **Общее правило**: начинайте с метода TIES с близкими к равным весами.
|
||||||
|
|
||||||
|
2. **Если модели обучены на разных типах данных**:
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method ties --ties-density 0.85 --encoder-weights "0.6,0.4" --decoder-weights "0.5,0.5"
|
||||||
|
```
|
||||||
|
Это даст больший приоритет первой модели в распознавании звуков, но обе модели будут равно влиять на грамматику.
|
||||||
|
|
||||||
|
3. **Если одна модель лучше с формальной речью, а другая с разговорной**:
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method ties --ties-density 0.9 --encoder-weights "0.5,0.5" --decoder-weights "0.6,0.4"
|
||||||
|
```
|
||||||
|
Высокая плотность (0.9) позволит сохранить уникальные особенности обеих моделей.
|
||||||
|
|
||||||
|
4. **Для моделей, где первая модель имеет высокое качество, но вторая содержит специфичные улучшения**:
|
||||||
|
```bash
|
||||||
|
./whisper_merge.sh --method slerp --slerp-t 0.3
|
||||||
|
```
|
||||||
|
Это сохранит основу первой модели (70%) и добавит 30% особенностей второй.
|
||||||
|
|
||||||
|
### Для наилучших результатов
|
||||||
|
|
||||||
|
Рекомендуется выполнить несколько экспериментов с разными настройками и сравнить результаты:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Эксперимент 1: TIES с приоритетом первой модели
|
||||||
|
./whisper_merge.sh --method ties --ties-density 0.85 --encoder-weights "0.65,0.35" --decoder-weights "0.6,0.4"
|
||||||
|
|
||||||
|
# Эксперимент 2: SLERP с уклоном к первой модели
|
||||||
|
./whisper_merge.sh --method slerp --slerp-t 0.4
|
||||||
|
|
||||||
|
# Эксперимент 3: Прямое слияние
|
||||||
|
./whisper_merge.sh --method direct --direct-alpha 0.6
|
||||||
|
```
|
||||||
|
|
||||||
|
## Тестирование и оценка
|
||||||
|
|
||||||
|
После слияния моделей важно оценить результаты:
|
||||||
|
|
||||||
|
1. **Подготовьте тестовый набор данных**, включающий:
|
||||||
|
- Формальную речь
|
||||||
|
- Разговорную речь
|
||||||
|
- Различные диалекты
|
||||||
|
- Различные шумовые условия
|
||||||
|
- Различные темпы речи
|
||||||
|
|
||||||
|
2. **Выполните транскрипцию** с помощью объединенной модели и сравните с исходными моделями.
|
||||||
|
|
||||||
|
3. **Оцените результаты** по следующим критериям:
|
||||||
|
- Word Error Rate (WER)
|
||||||
|
- Character Error Rate (CER)
|
||||||
|
- Обработка специфичных для русского языка особенностей (падежи, ударения)
|
||||||
|
- Скорость обработки
|
||||||
|
|
||||||
|
## Устранение неполадок
|
||||||
|
|
||||||
|
### Проблемы со слиянием SLERP или TIES
|
||||||
|
|
||||||
|
Если возникают ошибки при использовании методов SLERP или TIES, скрипт автоматически откатывается к методу Direct. Для решения проблем:
|
||||||
|
|
||||||
|
1. **Проверьте совместимость моделей**:
|
||||||
|
- Модели должны иметь одинаковую архитектуру
|
||||||
|
- Версии Whisper должны быть совместимы
|
||||||
|
|
||||||
|
2. **Увеличьте объем памяти**:
|
||||||
|
- SLERP и TIES требуют больше оперативной памяти
|
||||||
|
- Попробуйте запустить на машине с большим объемом RAM
|
||||||
|
|
||||||
|
3. **Проверьте логи** для определения конкретной проблемы
|
||||||
|
|
||||||
|
### Проблемы с окружением Conda
|
||||||
|
|
||||||
|
Если возникают проблемы с созданием или активацией окружения:
|
||||||
|
|
||||||
|
1. **Обновите Conda**:
|
||||||
|
```bash
|
||||||
|
conda update -n base conda
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Удалите и пересоздайте окружение**:
|
||||||
|
```bash
|
||||||
|
conda env remove -n whisper-merge
|
||||||
|
./whisper_merge.sh --update
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Проверьте пути к моделям** и убедитесь, что они корректны
|
||||||
Reference in New Issue
Block a user