Moshi-Finetune

repository·main·Indexed 19 days ago

https://github.com/kyutai-labs/moshi-finetune

A toolset for efficiently fine-tuning Moshi models using LoRA (Low-Rank Adaptation) or full fine-tuning. It provides a complete pipeline including stereo audio dataset preparation, transcript annotation, training via torchrun, and interactive inference using the Moshi server.

Tokens
8.6K
Snippets
35
Records
38
Agent score
67%

What's inside moshi-finetune

  1. Monitor training with Weights & Biases (W&B)

    main

    To monitor training metrics (loss, learning rate, etc.) in real-time, use Weights & Biases.

    1. Install the library: pip install wandb.
    2. Configure the wandb: section in your training YAML file with your key and project name.
  2. Run inference with a fine-tuned model

    main

    After training, you can run the Moshi server for interactive inference. First, ensure moshi is installed:

    pip install git+https://github.com/kyutai-labs/moshi.git#egg=moshi&subdirectory=moshi

    Running LoRA adapters

    If you trained using LoRA and set save_adapters: true, use the --lora-weight flag:

    python -m moshi.server \
      --lora-weight=$CHECKPOINT_DIR/consolidated/lora.safetensors \
      --config-path=$CHECKPOINT_DIR/consolidated/config.json

    Running full fine-tuned models

    If you performed full fine-tuning or did not save only adapters, use the --moshi-weight flag:

    python -m moshi.server \
    --moshi-weight=$CHECKPOINT_DIR/consolidated/consolidated.safetensors \
    --config-path=$CHECKPOINT_DIR/consolidated/consolidated/config.json 
    python -m moshi.server \
      --lora-weight=$CHECKPOINT_DIR/consolidated/lora.safetensors \
      --config-path=$CHECKPOINT_DIR/consolidated/config.json
  3. Install Moshi-Finetune

    main

    To install Moshi-Finetune, clone the repository and install dependencies.

    If you have uv installed, you do not need to run an explicit install command. Simply prefix your commands with uv run (e.g., uv run torchrun ...) to automatically manage dependencies based on pyproject.toml.

    Using pip

    If using pip, ensure you have Python 3.10+ and a virtual environment. Install the package in editable mode:

    cd moshi-finetune
    pip install -e .
    git clone git@github.com:kyutai-labs/moshi-finetune.git
    cd moshi-finetune
    pip install -e .
  4. Start Moshi fine-tuning training

    main

    Training is executed using torchrun. You can run on a single GPU or multiple GPUs.

    Single GPU

    torchrun --nproc-per-node 1 -m train example/moshi_7B.yaml

    Multiple GPUs (e.g., 8 GPUs)

    torchrun --nproc-per-node 8 --master_port $RANDOM -m train example/moshi_7B.yaml

    Troubleshooting Out-of-Memory (OOM)

    If you encounter OOM errors:

    1. Reduce batch_size in your config.
    2. If the issue persists, lower duration_sec (note: this may impact inference quality/silence behavior).
    torchrun --nproc-per-node 1 -m train example/moshi_7B.yaml
  5. Prepare the stereo audio dataset

    main

    The pipeline requires a dataset of stereo audio files where:

    • Left channel: Audio generated by Moshi.
    • Right channel: User input.

    Dataset Structure

    1. A .jsonl file listing all files with their paths and durations.
    2. For every .wav file, a corresponding .json file containing the transcript with timestamps.

    Example directory structure:

    data/
    ├── mycooldataset.jsonl
    └── data_stereo
        ├── a.json
        ├── a.wav
        ├── b.json
        ├── b.wav

    Generating the .jsonl file

    You can generate the .jsonl manifest using the following Python snippet:

    import sphn
    import json
    from pathlib import Path
    
    paths = [str(f) for f in Path("wav-dir").glob("*.wav")]
    durations = sphn.durations(paths)
    
    with open("data.jsonl", "w") as fobj:
        for p, d in zip(paths, durations):
            if d is None:
                continue
            json.dump({"path": p, "duration": d}, fobj)
            fobj.write("\n")

    Annotating transcripts

    To generate the required .json transcript files for your audio, run the annotate.py script:

    python annotate.py {your_jsonl_file}

    This script supports SLURM for distributed annotation using --shards and --partition flags.

    python annotate.py {your_jsonl_file}
  6. Configure the Moshi model source

    main

    The training setup is defined via a YAML configuration file. To use an official Moshi model from the Hugging Face Hub, include the moshi_paths section in your config file with the hf_repo_id key.

    moshi_paths:
       hf_repo_id: "kyutai/moshiko-pytorch-bf16"
  7. How FSDP wrapping policies work for LoRA vs Full Fine-tuning

    main

    The get_fsdp_policy function determines how the model is partitioned across GPUs using PyTorch's auto_wrap_policy. The strategy changes depending on whether you are doing LoRA or full fine-tuning:

    1. Standard Transformer Wrapping: In both modes, each StreamingTransformerLayer is treated as an individual FSDP group to ensure efficient sharding of transformer blocks.
    2. LoRA-specific Wrapping: When is_lora=True, an additional lambda_auto_wrap_policy is applied. This is required because FSDP requires that parameters with different requires_grad statuses (trainable LoRA weights vs. frozen base weights) reside in different FSDP groups.

    The resulting policy is an _or_policy that combines the transformer block wrapping with the LoRA parameter grouping.

  8. Manage checkpoint rotation with num_ckpt_keep

    main

    To prevent disk space exhaustion, you can limit the number of saved checkpoints by passing num_ckpt_keep to the Checkpointer constructor.

    When save_checkpoint is called, the class automatically identifies the oldest checkpoint directories (sorted by creation time) and deletes them if the total count exceeds num_ckpt_keep.

    # Keep only the 5 most recent checkpoints
    checkpointer = Checkpointer(
        model=model,
        state=state,
        run_dir="./runs/exp",
        config=config,
        num_ckpt_keep=5
    )
    
    # This call will trigger deletion of old checkpoints if necessary
    checkpointer.save_checkpoint(save_only_lora=False)
  9. Prepare the dataset for training

    main

    Datasets should be downloaded and organized in a local directory. The training process expects a .jsonl file containing the training data. In the provided example, the kyutai/DailyTalkContiguous dataset is used.

    from pathlib import Path
    from huggingface_hub import snapshot_download
    
    # Create directory and download dataset
    Path("/content/data/daily-talk-contiguous").mkdir(parents=True, exist_ok=True)
    local_dir = snapshot_download(
        "kyutai/DailyTalkContiguous",
        repo_type="dataset",
        local_dir="/content/data/daily-talk-contiguous",
    )
  10. Configure training via YAML

    main

    Training is controlled by a YAML configuration file. Key sections include:

    • data: Specifies train_data (path to .jsonl), eval_data, and shuffle settings.
    • moshi_paths: Contains the hf_repo_id for the base model.
    • full_finetuning: Set to false to enable LoRA.
    • lora: Configuration for LoRA, including enable, rank, scaling, and ft_embed.
    • training hyperparameters: Includes first_codebook_weight_multiplier, text_padding_weight, duration_sec (recommended ~300s), batch_size, and max_steps.
    • optim: Optimizer settings like lr, weight_decay, and pct_start.
    • other: Controls seed, log_freq, eval_freq, ckpt_freq, and run_dir (where outputs are saved).
    # Example configuration snippet
    data:
      train_data: '/content/data/daily-talk-contiguous/dailytalk.jsonl'
      eval_data: ''
      shuffle: true
    
    moshi_paths:
      hf_repo_id: "kyutai/moshiko-pytorch-bf16"
    
    full_finetuning: false
    lora:
      enable: true
      rank: 128
      scaling: 2.
      ft_embed: false
    
    duration_sec: 100
    batch_size: 1
    max_steps: 300
    
    run_dir: "/content/test"
  11. Reference: Training configuration parameters

    main

    The following keys are available in the training YAML configuration file:

    ParameterDescription
    moshi_pathsDefines model paths. Use hf_repo_id to import from Hugging Face Hub.
    run_dirDirectory for checkpoints and logs.
    duration_secMaximum sequence length in seconds for training.
    first_codebook_weight_multiplierWeight multiplier for the semantic token codebook.
    text_padding_weightWeight for text padding loss (decrease to avoid over-focusing on padding).
    gradient_checkpointingBoolean to enable gradient checkpointing per transformer layer.
    batch_sizeNumber of training examples per GPU.
    max_stepsTotal number of training steps.
    optim.lrLearning rate (Recommended: 2e-6).
    optim.weight_decayWeight decay for regularization (Default: 0.1).
    optim.pct_startPercentage of steps for learning rate warm-up.
    lora.rankSize of LoRA adapters (Recommended $\le 128$).
    lora.ft_embedWhether to full-finetune embedding matrices during LoRA training.
    seedRandom seed for reproducibility.
    log_freqFrequency of logging metrics in steps.
    data.train_dataPath to training dataset.
    data.eval_data(Optional) Path to evaluation dataset.
    data.shuffleWhether to shuffle training samples.
    eval_freqSteps between evaluations.
    no_evalIf True, disables periodic evaluation.
    ckpt_freqSteps between saving checkpoints.
    full_finetuningTrue for full fine-tuning, False for LoRA.
    save_adaptersTrue to save only LoRA adapters; False to merge into base model.
    wandb.keyAPI key for Weights & Biases.
    wandb.projectName of the W&B project.
  12. Save only LoRA weights using Checkpointer

    main

    When performing LoRA fine-tuning, you can save only the adapter weights instead of the full model. This is done by calling save_checkpoint with save_only_lora=True.

    Note: You cannot save only LoRA weights if full_finetuning=True was set during Checkpointer initialization. The resulting file will be named lora.safetensors inside the checkpoint directory.

    # To save only the LoRA adapters
    checkpointer.save_checkpoint(save_only_lora=True)