Skip to content

[BUG] Is this not support with CUDA 12+ with pytorch? #31

Description

@papaya0481

Debugging checklist

  • Have you updated to latest MFA version?
  • Have you tried rerunning the command with the --clean flag?

Describe the issue
A clear and concise description of what the bug is.

I was trying to align wavs using python interfaces without CLI, since I need an end-to-end application. Thanks to this issue#885 in MFA, I have written a small script to test it like the following (Adapted from mfa_align_one).

"""Command line functions for aligning single files"""
from __future__ import annotations

from pathlib import Path

import pywrapfst
import rich_click as click
from kalpy.aligner import KalpyAligner
from kalpy.feat.cmvn import CmvnComputer
from kalpy.fstext.lexicon import HierarchicalCtm, LexiconCompiler
from kalpy.utterance import Segment
from kalpy.utterance import Utterance as KalpyUtterance

from montreal_forced_aligner import config
from montreal_forced_aligner.alignment import PretrainedAligner

from montreal_forced_aligner.corpus.classes import FileData
from montreal_forced_aligner.data import (
    BRACKETED_WORD,
    CUTOFF_WORD,
    LAUGHTER_WORD,
    OOV_WORD,
    Language,
)
from montreal_forced_aligner.dictionary.mixins import (
    DEFAULT_BRACKETS,
    DEFAULT_CLITIC_MARKERS,
    DEFAULT_COMPOUND_MARKERS,
    DEFAULT_PUNCTUATION,
    DEFAULT_WORD_BREAK_MARKERS,
)
from montreal_forced_aligner.models import AcousticModel, G2PModel
from montreal_forced_aligner.online.alignment import tokenize_utterance_text
from montreal_forced_aligner.tokenization.simple import SimpleTokenizer
from montreal_forced_aligner.tokenization.spacy import generate_language_tokenizer

import librosa



def test_align_one(
    **kwargs,
):
    """
    Align a single file with a pronunciation dictionary and a pretrained acoustic model.
    """
    config_path = kwargs.get("config_path", None)
    sound_file_path: Path = kwargs["sound_file_path"]
    text_file_path: Path = kwargs["text_file_path"]
    dictionary_path: Path = kwargs["dictionary_path"]
    acoustic_model_path = kwargs["acoustic_model_path"]
    output_path: Path = kwargs["output_path"]
    if output_path.is_dir():
        output_path = output_path.joinpath(sound_file_path.stem + ".TextGrid")
    output_format = kwargs.get("output_format", "long_textgrid")
    no_tokenization = kwargs.get("no_tokenization", False)
    g2p_model_path = kwargs.get("g2p_model_path", None)

    acoustic_model = AcousticModel(acoustic_model_path)
    g2p_model = None
    if g2p_model_path:
        g2p_model = G2PModel(g2p_model_path)
        
    args = {"clean": True}
    c = PretrainedAligner.parse_parameters(config_path, args=args)
    extracted_models_dir = config.TEMPORARY_DIRECTORY.joinpath("extracted_models", "dictionary")
    dictionary_directory = extracted_models_dir.joinpath(dictionary_path.stem)
    dictionary_directory.mkdir(parents=True, exist_ok=True)
    lexicon_compiler = LexiconCompiler(
        disambiguation=False,
        silence_probability=acoustic_model.parameters["silence_probability"],
        initial_silence_probability=acoustic_model.parameters["initial_silence_probability"],
        final_silence_correction=acoustic_model.parameters["final_silence_correction"],
        final_non_silence_correction=acoustic_model.parameters["final_non_silence_correction"],
        silence_phone=acoustic_model.parameters["optional_silence_phone"],
        oov_phone=acoustic_model.parameters["oov_phone"],
        position_dependent_phones=acoustic_model.parameters["position_dependent_phones"],
        phones=acoustic_model.parameters["non_silence_phones"],
        ignore_case=c.get("ignore_case", True),
    )
    l_fst_path = dictionary_directory.joinpath("L.fst")
    l_align_fst_path = dictionary_directory.joinpath("L_align.fst")
    words_path = dictionary_directory.joinpath("words.txt")
    phones_path = dictionary_directory.joinpath("phones.txt")
    if l_fst_path.exists() and not config.CLEAN:
        lexicon_compiler.load_l_from_file(l_fst_path)
        lexicon_compiler.load_l_align_from_file(l_align_fst_path)
        lexicon_compiler.word_table = pywrapfst.SymbolTable.read_text(words_path)
        lexicon_compiler.phone_table = pywrapfst.SymbolTable.read_text(phones_path)
    else:
        lexicon_compiler.load_pronunciations(dictionary_path)
        lexicon_compiler.create_fsts()
        lexicon_compiler.clear()

    if no_tokenization or acoustic_model.language is Language.unknown:
        tokenizer = SimpleTokenizer(
            word_table=lexicon_compiler.word_table,
            word_break_markers=c.get("word_break_markers", DEFAULT_WORD_BREAK_MARKERS),
            punctuation=c.get("punctuation", DEFAULT_PUNCTUATION),
            clitic_markers=c.get("clitic_markers", DEFAULT_CLITIC_MARKERS),
            compound_markers=c.get("compound_markers", DEFAULT_COMPOUND_MARKERS),
            brackets=c.get("brackets", DEFAULT_BRACKETS),
            laughter_word=c.get("laughter_word", LAUGHTER_WORD),
            oov_word=c.get("oov_word", OOV_WORD),
            bracketed_word=c.get("bracketed_word", BRACKETED_WORD),
            cutoff_word=c.get("cutoff_word", CUTOFF_WORD),
            ignore_case=c.get("ignore_case", True),
        )
    else:
        tokenizer = generate_language_tokenizer(acoustic_model.language)
    file_name = sound_file_path.stem
    file = FileData.parse_file(file_name, sound_file_path, text_file_path, "", 0)
    file_ctm = HierarchicalCtm([])
    utterances = []
    cmvn_computer = CmvnComputer()
    for utterance in file.utterances:
        seg = Segment(None, utterance.begin, utterance.end, utterance.channel)
        print(f"{utterance}")
        audio = librosa.load(sound_file_path, sr=16000,)[0]
        if audio.ndim > 1:
            audio = audio.mean(axis=0)
        seg._wave = audio
        normalized_text = tokenize_utterance_text(
            utterance.text,
            lexicon_compiler,
            tokenizer,
            g2p_model,
            language=acoustic_model.language,
        )
        utt = KalpyUtterance(seg, normalized_text)
        utt.generate_mfccs(acoustic_model.mfcc_computer)
        utterances.append(utt)

    cmvn = cmvn_computer.compute_cmvn_from_features([utt.mfccs for utt in utterances])
    align_options = {
        k: v
        for k, v in c.items()
        if k
        in [
            "beam",
            "retry_beam",
            "acoustic_scale",
            "transition_scale",
            "self_loop_scale",
            "boost_silence",
        ]
    }
    if g2p_model is not None or not (l_fst_path.exists() and not config.CLEAN):
        lexicon_compiler.fst.write(str(l_fst_path))
        lexicon_compiler.align_fst.write(str(l_align_fst_path))
        lexicon_compiler.word_table.write_text(words_path)
        lexicon_compiler.phone_table.write_text(phones_path)
    kalpy_aligner = KalpyAligner(acoustic_model, lexicon_compiler, **align_options)
    for utt in utterances:
        utt.apply_cmvn(cmvn)
        ctm = kalpy_aligner.align_utterance(utt)
        file_ctm.word_intervals.extend(ctm.word_intervals)
    if str(output_path) != "-":
        output_path.parent.mkdir(parents=True, exist_ok=True)
    file_ctm.export_textgrid(
        output_path, file_duration=file.wav_info.duration, output_format=output_format
    )
    
if __name__ == "__main__":
    from montreal_forced_aligner.models import DictionaryModel, AcousticModel

    dict_path = DictionaryModel.get_pretrained_path("english_us_arpa")
    acoustic_path = AcousticModel.get_pretrained_path("english_us_arpa")
    
    test_align_one(
        dictionary_path=dict_path,
        acoustic_model_path=acoustic_path,
        sound_file_path=Path("test2/wavs/test_short1_1.wav"),
        text_file_path=Path("test2/wavs/test_short1_1.txt"),
        output_path=Path("test2/wavs/test_short1_1.TextGrid"),
    )

This works fine and can return some results. However, if I import torch before this program or specifically import it before from kalpy.aligner import KalpyAligner like this

import torch
from kalpy.aligner import KalpyAligner

the program would raise an error

  File "/home/user/Montreal-Forced-Aligner/test2/test_align.py", line 9, in <module>
    from kalpy.aligner import KalpyAligner
  File "/data2/user/Miniconda3/envs/dub3/lib/python3.11/site-packages/kalpy/aligner.py", line 6, in <module>
    from _kalpy.gmm import gmm_interpolate_boundary_fast
ImportError: /data2/user/Miniconda3/envs/dub3/lib/python3.11/site-packages/../.././libcusolver.so.11: undefined symbol: cublasSetEnvironmentMode, version libcublas.so.12

Although temporary workarounds such as downgrading CUDA or changing the import order (late importing) can resolve the issue, these solutions conflict with my project requirements. I would prefer a stable solution that allows both torch and MFA/Kalpy to coexist within the same Python process.

PS: simply installing cpu version can solve this but I would like to keep this issue as a report.

conda install -c conda-forge kaldi=*=*cpu*

For Reproducing your issue
Please fill out the following:

  1. Corpus structure
    • What language is the corpus in?
      English.
    • How many files/speakers?
      1 file with only 1 speaker.
    • Are you using lab files or TextGrid files for input?
      Yes.
  2. Dictionary
    • Are you using a dictionary from MFA? If so, which one?
      english_us_arpa
    • If it's a custom dictionary, what is the phoneset?
  3. Acoustic model
    • If you're using an acoustic model, is it one download through MFA? If so, which one?
      english_us_arpa
    • If it's a model you've trained, what data was it trained on?

Log file
No logs are created since it is a python program.

Desktop (please complete the following information):

  • OS: [e.g. Windows, OSX, Linux]
  • Version [e.g. MacOSX 10.15, Ubuntu 20.04, Windows 10, etc]
  • Any other details about the setup (Cloud, Docker, etc)

Ubuntu 24.04 x86_64. Pytorch version 2.8.0 with CUDA 12.6. Run directly through python **.py.
Installing MFA through

conda install -c conda-forge montreal-forced-aligner

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions