機械学習ツールによる音声認識

私の仕事では、クライアントとの会話スクリプトに対する従業員のコンプライアンスについて、通話記録を確認する必要に直面しました。通常、これには従業員が割り当てられ、会話の録音を聞くのに多くの時間を費やします。自動音声認識(ASR)ツールを使用して検証に費やす時間を削減するというタスクを設定しました。これらのツールの1つを詳しく見ていきます。





Nvidia NeMoは、  GPUを利用したモデルを構築およびトレーニングするための機械学習ツールのセットです。





NeMoのモデルは、音声認識に最新のアプローチであるコネクショニスト時間分類(CTC)を使用しています。





CTCの前は、入力オーディオファイルを個別の音声セグメントに分割し、それらからトークンを予測するアプローチが使用されていました。次に、トークンが結合され、繰り返されたトークンが1つにまとめられ、結果がモデル出力に送られました。





この場合、文字が繰り返されている単語は100%正しく認識されているとは見なされなかったため、認識精度が低下しました。たとえば、「coOperation」は「coOperation」に短縮されました。





CTCを使用する場合-音声の時間セグメントごとに1つのトークンを予測し、さらに空のトークンを使用して、重複するトークンを折りたたむ場所を特定します。空のトークンの外観は、折りたたまれてはならない重複する文字を分離するのに役立ちます。





私の仕事では、モデルの1つ(Jasper 10×5)を取り、最初からトレーニングしました。トレーニングのために、カットされた音声録音とその文字起こしを含む、電話での会話の公開データセットが選択されました。





モデルをトレーニングするには、オーディオファイルとこのファイルの文字起こしに関する情報を含むマニフェストファイルを準備する必要があります。マニフェストファイルには独自の形式があります。





{{"audio_filepath": "path/to/audio.wav", "duration": 3.45, "text": "sometext"}…{"audio_filepath": "path/to/audio.wav", "duration": 3.45, "text": "sometext"}}
      
      



このモデルは、*。wav形式のオーディオファイルのみを受け入れます。オーディオファイルのリスト全体をループし、コンソールユーティリティを使用して、必要な解像度以外の解像度でオーディオファイルを再コーディングする必要があります。





def convertToWav(self, ext):
        if not os.path.exists(self.datadir + '/dataset'):
            tar = tarfile.open(self.an4Path);
            tar.extractall(path=self.datadir);
        sphList = glob.glob(self.datadir + '/dataset/**/*' + ext, recursive=True);
        for sph in sphList:
            wav = sph[:-4] + '.wav';
            cmd = ["sox", sph, wav];
            subprocess.run(cmd);
            print('renamed ' + ext + ' to ' + wav);
      
      



, getduration(filename=audiopath) Librosa, :





def buildManifest(self, transcript_path, manifest_path, wav_path):
        with open(transcript_paths, 'r') as fin:
            with open(manifest_path, 'w') as fout:
                for line in fin:
                    transcript = line[: line.find('(')-1].lower();
                    transcript = transcript.replace('<s>', '').replace('</s>', '');
                    transcript = transcript.strip();
                    file_id = line[line.find('(')+1 : -2];
                    audio_path = os.path.join(self.datadir, wav_paths, file_id[file_id.find('-')+1 : file_id.rfind('-')], file_id +'.wav');
                    duration = librosa.core.get_duration(filename=audio_path);
                    metadata = {
                        "audio_filepath": audio_path,
                        "duration": duration,
                        "text": transcript
                    }
                    print(metadata);
                    json.dump(metadata, fout);
                    fout.write('\n');
      
      



, :





config.yaml:
name: &name "Jasper10x5"
model:
  sample_rate: &sample_rate 16000
  labels: &labels [" ", "a", "", "", "", "", "", "", "", "", "", "", "", "",
                   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "'"]
 preprocessor:
    _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor
    normalize: "per_feature"
    sample_rate: *sample_rate
    features: &n_mels 64
    n_fft: 512
    frame_splicing: 1
    dither: 0.00001
    stft_conv: false
      
      



. pytorch_lighting :





import nemo;
class NemoASR:
    def __init__(self, dataDir):
        self.datadir = dataDir;
        self.CONF_PATH = './config.yaml';
        yaml = YAML(typ="safe");
        with open(self.CONF_PATH) as f:
            self.CONFIG = yaml.load(f);

    def train(self, transcriptionPATH, manifestPATH, wavPATH, testTranscriptionPATH, testManifestPATH, testWavPATH):
        print("begin train");
        train_transcripts = self.datadir + transcriptionPATH;
        train_manifest = self.datadir + manifestPATH;
        if not os.path.isfile(train_manifest):
            self.buildManifest(train_transcripts, train_manifest, wavPATH);
        test_transcripts = self.datadir + testTranscriptionPATH;
        test_manifest = self.datadir + testManifestPATH;
        if not os.path.isfile(test_manifest):
            self.buildManifest(test_transcripts, test_manifest, testWavPATH);
        # params from ./config.yaml
        self.CONFIG['model']['train_ds']['manifest_filepath'] = train_manifest;
        self.CONFIG['model']['validation_ds']['manifest_filepath'] = test_manifest;
        trainer = pl.Trainer(max_epochs=500, gpus=1);
        self.model = nemo_asr.models.EncDecCTCModel(cfg=DictConfig(self.CONFIG['model']), trainer=trainer);
        trainer.fit(self.model);
        print("end train");
#-------------------------------------------------------------
nemoASR = NemoASR('.');
if (nemoASR.checkExistsDataSet()):
    print('dataset loaded');
    nemoASR.train('./dataset/etc/train.transcription',  './dataset/train_manifest.json','./dataset/wav/an4_clstk', './dataset/etc/test.transcription', './dataset/test_manifest.json', './dataset/wav/an4test_clstk');
    nemoASR.model.save_to('./model.sbc');
      
      



:





files = ['./an4/wav/an4_clstk/mgah/cen2-mgah-b.wav'];
    for fname, transcription in zip(files, nemoASR.model.transcribe(paths2audio_files=files)):
        print(f"Audio in {fname} was recognized as: {transcription}");
      
      



, .





NeMo   :





  • GPU;





  • , ;





  • .





  , , -.





ASR . .





, (TTS) (speaker recognition).








All Articles