ESPNet2を使った音声とテキストのアライメント処理

開発環境

ライブラリのインストール

以下で必要なライブラリを入れます

pip install soundfile espnet_model_zoo torch
sudo pip install soundfile espnet_model_zoo torch

アライメント処理

以下を参考にコードを書いていきます。

github.com

モデルは reazon-research/reazonspeech-espnet-v2を使用します

espnet_model_zooを使用する場合は、以下から任意のモデルを指定してください

github.com

import soundfile
from espnet_model_zoo.downloader import ModelDownloader
from espnet2.bin.asr_align import CTCSegmentation
d = ModelDownloader(cachedir="./modelcache")
# esp model zooの場合
# model = d.download_and_unpack("Shinji Watanabe/laborotv_asr_train_asr_conformer2_latest33_raw_char_sp_valid.acc.ave")

# hfの場合
model = d.download_and_unpack("reazon-research/reazonspeech-espnet-v2")
speech, rate = soundfile.read("VOICEACTRESS100_001.wav")

duration = len(speech) / rate

print(f"音声ファイルの長さ: {duration:.2f}秒")

aligner = CTCSegmentation(**model, kaldi_style_text=False)

text = ["また、東寺のように、五大明王と呼ばれる、主要な明王の中央に配されることも多い。"]

segments = aligner(speech, text)

print(segments)

実行結果は以下です

音声ファイルの長さ: 6.91秒
WARNING:root:No RNN model detected; memory consumption may be high.
utt_0000 utt 0.02 41.39 -4.9689 また、東寺のように、五大明王と呼ばれる、主要な明王の中央に配されることも多い。

音声の長さを正確には取れていないですが、アライメントの精度は取得できそうです

KenLMで日本語文章の品質の評価

初めに

以下でLLMを使って文章の評価をしていますが、速度が速いと言われるKenLMでも評価してみます

ayousanz.hatenadiary.jp

開発環境

  • Ubuntu22.02

環境構築

sudo apt install build-essential cmake libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev libeigen3-dev zlib1g-dev libbz2-dev liblzma-dev
pip install https://github.com/kpu/kenlm/archive/master.zip
mkdir -p data/lm_sp
wget -c  -P data/lm_sp http://dl.fbaipublicfiles.com/cc_net/lm/ja.arpa.bin
wget -c  -P data/lm_sp http://dl.fbaipublicfiles.com/cc_net/lm/ja.sp.model

評価コード

import sys
import json
import csv
import kenlm

if __name__ == '__main__':
    with open("testData.txt", "r", encoding="utf-8") as f:
        lines = [line.strip() for line in f.readlines()[:30]]

    m = kenlm.LanguageModel("data/lm_sp/ja.arpa.bin")
    results = []

    for inp in lines:
        sentence = " ".join(inp)
        ppl = m.perplexity(sentence)
        results.append({"text": inp, "perplexity": ppl})
        print(ppl, inp)

    # Save results to JSON
    with open("kenlm_results.json", "w", encoding="utf-8") as f:
        json.dump(results, f, ensure_ascii=False, indent=4)

    # Save results to CSV
    with open("kenlm_results.csv", "w", newline="", encoding="utf-8") as f:
        fieldnames = ["text", "perplexity"]
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(results)

結果

text perplexity
それと僕が材料をお伝えした時にバニラエッセンスを入れたじゃないですか 17708.545685079465
1弦の5フレット、2弦の5フレット、 3弦の5フレット、2弦の7フレット、 38831.77205605622
けどもこれでえっと木スキル使うとさらに カウンターが1個貯まる 24178.439407054473
長い年月をかけて韓国人朝鮮人 と向き合ってきた中国人は韓国人 4482.124515163107
ごいハマり始めて 48969.93621135036
50話 いらっしゃいませ♪ ヘラのグランプリ! 93303.59762963047
オムニテクでは人々を助けを上がっている。 11689.811696733246
ステーキってもんはね 11286.760319052344
これが聞こえてきた 32392.71212184362
なるほどねそうなんだやばいすげ えわ 61553.26800664746
殺菌得ながらを 29143.353748316073
じゃあ呼吸法やりましょう、呼吸、呼吸 38638.26899312117
カンタ : そこやれるの見たいと思ってるよ、みんな 9503.800827281371
すげーなんか色んなものがこう そうなんだそうそうばすごいね 25696.966294762613
前回は standard assets を使って 遊んでいました 11098.166969108926
を獲得しました 9788.759603258804
しかしながら本当の理由はそれ だけではないのです 19715.238260370395
病むなんですが 59993.44877269272
全体混ぜると これね混ぜたら数分蒸らした方がいいです 38897.14236642167
アプリはそういったことを解決して くれるアプリです 15731.816412536211
ご丁寧に 106622.48885797341
下に 20732.22627445443
合わせてかぶせれば... 4003.3841234749957
そういう言い方で 32015.60911488846
朝食 69290.91681309085
流行ったものだそうですが 59954.375082911676
こうなります 9752.564887711484
次は釣りレベルの上限解放です。今度は何を釣らされるんだろうと思っていましたが、タマカイでした。 13016.617360872806
守りたい 17245.44873923792
だってさっきの人从众… 107673.84311097601

sentencepieceを使った場合

以下のコードを実行します

import sys
import kenlm
import sentencepiece
import unicodedata


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print("Need ken_lm.arpa sentencepiece.model")
        sys.exit(-1)

    m = kenlm.LanguageModel(sys.argv[1])

    sp = sentencepiece.SentencePieceProcessor()
    sp.load(sys.argv[2])


    inputs = [
    '東京の夜景は美しい',
    '東京はいつも賑やかだ',
    '東京の街並みは独特だ',
    '東京の交通網は発達している',
    '東京は日本の経済の中心地だ',
    '東京の人口密度は高い',
    '東京の物価は高い',
    '東京の食文化は豊か',
    '東京のファッションは先進的',
    '東京の技術力は世界的だ',
    '東京の大学は有名だ',
    '東京の歴史は古い',
    '東京の伝統文化は守られている',
    '東京のサブカルチャーは多様だ',
    '東京のイベントは年中開催されている',
    '東京の公園は憩いの場だ',
    '東京の建築物はモダンだ',
    '東京の治安は良い',
    '東京の医療水準は高い',
    '東京の教育レベルは高い',
    '東京の環境対策は進んでいる',
    '東京の国際化は進んでいる',
    '東京のスポーツ施設は充実している',
    '東京の芸術活動は盛んだ',
    '東京の観光地は人気がある',
    '東京の祭りは活気がある',
    '東京の若者文化は独特だ',
    '東京の高齢化対策は課題だ',
    '東京の防災意識は高い',
    '東京の未来は明るい'
]

    for inp in inputs:
        # pretrained model in cc_net uses 'NFD' normalization?
        # TODO: Use https://github.com/facebookresearch/cc_net/blob/main/cc_net/text_normalizer.py
        text = unicodedata.normalize('NFD', inp)

        toks = sp.encode(text, out_type=str)
        print(toks)

        sentence = " ".join(toks)
        ppl = m.perplexity(sentence)
        print(ppl, inp)

実行コマンド

python sentencepiece2.py data/lm_sp/ja.arpa.bin data/lm_sp/ja.sp.model

結果

['▁東京', '', '', '晴れ', '']
4335.906162754335 東京はッ晴れ。
['▁東京', '', '元気', '', '', '']
4789.530541202564 東京は元気です。
['', '', '', '', '', '', 'ある', '.', '', '名前は', '', '', 'ない', '.']
677.481230499526 吾輩は猫である. 名前はまだない.
['▁東京', '', '晴れ', '']
1411.807566253476 東京は晴れ。
(venv) jovyan@yousan-0:~/lingua$ python sentencepiece1.py data/lm_sp/ja.arpa.bin data/lm_sp/ja.sp.model
['▁東京', '', '', '晴れ', '']
4335.906162754335 東京はッ晴れ。
['▁東京', '', '元気', '', '', '']
4789.530541202564 東京は元気です。
['', '', '', '', '', '', 'ある', '.', '', '名前は', '', '', 'ない', '.']
677.481230499526 吾輩は猫である. 名前はまだない.
['▁東京', '', '晴れ', '']
1411.807566253476 東京は晴れ。
(venv) jovyan@yousan-0:~/lingua$ python sentencepiece2.py data/lm_sp/ja.arpa.bin data/lm_sp/ja.sp.model
['▁東京', '', '夜景', '', '美しい']
1559.0554329452627 東京の夜景は美しい
['▁東京', '', 'いつも', '', '', '', '']
3771.668858772643 東京はいつも賑やかだ
['▁東京', '', '街並み', '', '', '', '']
2254.075478011484 東京の街並みは独特だ
['▁東京', '', '交通', '', '', '発達', 'している']
462.1914030627983 東京の交通網は発達している
['▁東京', 'は日本の', '経済', 'の中心地', '']
12523.705943574623 東京は日本の経済の中心地だ
['▁東京', '', '人口密度は', '高い']
1873.5702551396657 東京の人口密度は高い
['▁東京', '', '物価', '', '高い']
2306.9409256720432 東京の物価は高い
['▁東京', '', '食文化', '', '', '']
884.7496414993681 東京の食文化は豊か
['▁東京', '', 'ファッション', '', '先進', '']
942.4886609919694 東京のファッションは先進的
['▁東京', 'の技術', '', '', '世界的', '']
6352.528697589843 東京の技術力は世界的だ
['▁東京', '', '大学', '', '有名', '']
4518.518393639697 東京の大学は有名だ
['▁東京', 'の歴史', '', '古い']
1017.684104811051 東京の歴史は古い
['▁東京', '', '伝統文化', '', '', 'られている']
1318.7390808197645 東京の伝統文化は守られている
['▁東京', '', '', '', 'カルチャー', '', '多様', '']
16807.129140261182 東京のサブカルチャーは多様だ
['▁東京', '', '', '', 'ント', '', '', '', '開催されている']
5225.4904688694405 東京のイベントは年中開催されている
['▁東京', '', '公園', '', '憩いの場', '']
8311.233290969833 東京の公園は憩いの場だ
['▁東京', '', '建築物', '', '', '', '', '']
10915.668390212073 東京の建築物はモダンだ
['▁東京', '', '治安', '', '良い']
1337.6293205006057 東京の治安は良い
['▁東京', '', '医療', '水準', '', '高い']
859.5305593891276 東京の医療水準は高い
['▁東京', 'の教育', '', '', '', '', '高い']
11565.088896342308 東京の教育レベルは高い
['▁東京', '', '環境', '対策', '', '', '', '', 'いる']
5312.109623816024 東京の環境対策は進んでいる
['▁東京', 'の国際', '', '', '', '', '', 'いる']
8152.9475124097125 東京の国際化は進んでいる
['▁東京', '', '', '', 'ーツ', '施設は', '充実', 'している']
9341.116680821911 東京のスポーツ施設は充実している
['▁東京', '', '芸術', '活動', '', '盛ん', '']
1878.5996129207565 東京の芸術活動は盛んだ
['▁東京', '', '観光地', '', '人気', '', 'ある']
7621.730945021132 東京の観光地は人気がある
['▁東京', '', '祭り', '', '', '', '', 'ある']
2674.160008880571 東京の祭りは活気がある
['▁東京', '', '若者', '文化', '', '', '', '']
1578.6075972487467 東京の若者文化は独特だ
['▁東京', '', '高齢化', '対策', '', '課題', '']
4875.003477257479 東京の高齢化対策は課題だ
['▁東京', '', '防災', '意識', '', '高い']
1151.5175930579533 東京の防災意識は高い
['▁東京', '', '未来', '', '明るい']
1190.656783416366 東京の未来は明るい

参考サイト

zenn.dev

複数のLLMのPerplexityの精度を比較して、文章の自然さを判定を試す

初めに

環境

  • L4 GPU
  • ubuntu22.04

準備

ライブラリをインストールします

pip install torch transformers huggingface_hub

比較対象のモデル

  • stabilityai/StableBeluga-7B
  • mistralai/Mistral-7B-Instruct-v0.2
  • Rakuten/RakutenAI-7B-chat

対象のデータ

今回の対象のデータは yodasのja000の一部を使用します。

   Text
1   それと僕が材料をお伝えした時にバニラエッセンスを入れたじゃないですか
2   1弦の5フレット、2弦の5フレット、 3弦の5フレット、2弦の7フレット、
3   けどもこれでえっと木スキル使うとさらに カウンターが1個貯まる
4   長い年月をかけて韓国人朝鮮人 と向き合ってきた中国人は韓国人
5   ごいハマり始めて
6   50話 いらっしゃいませ♪ ヘラのグランプリ!
7   オムニテクでは人々を助けを上がっている。
8   ステーキってもんはね
9   これが聞こえてきた
10  なるほどねそうなんだやばいすげ えわ
11  殺菌得ながらを
12  じゃあ呼吸法やりましょう、呼吸、呼吸
13  カンタ : そこやれるの見たいと思ってるよ、みんな
14  すげーなんか色んなものがこう そうなんだそうそうばすごいね
15  前回は standard assets を使って 遊んでいました
16  を獲得しました
17  しかしながら本当の理由はそれ だけではないのです
18  病むなんですが
19  全体混ぜると これね混ぜたら数分蒸らした方がいいです
20  アプリはそういったことを解決して くれるアプリです
21  ご丁寧に
22  下に
23  合わせてかぶせれば...
24  そういう言い方で
25  朝食
26  流行ったものだそうですが
27  こうなります
28  次は釣りレベルの上限解放です。今度は何を釣らされるんだろうと思っていましたが、タマカイでした。
29  守りたい
30  だってさっきの人从众…

複数のモデルでPerplexityの値を取得

以下のコードでそれぞれのLLMのPerplexityの値を取得する

import json
import csv
import time
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

def perplexity(model, tokenizer, text) -> torch.Tensor:
    tokenized_input = tokenizer.encode(
        text, add_special_tokens=False, return_tensors="pt"
    ).to(model.device)

    with torch.inference_mode():
        output = model(tokenized_input, labels=tokenized_input)
        ppl = torch.exp(output.loss)

    return ppl.item()

models = [
    "stabilityai/StableBeluga-7B",
    "mistralai/Mistral-7B-Instruct-v0.2",
    "Rakuten/RakutenAI-7B-chat"
]

results = {}
csv_data = [["Text"] + [f"{model}_Perplexity" for model in models]]

with open("testData.txt", "r", encoding="utf-8") as f:
    lines = [line.strip() for line in f.readlines()[:30]]

for line in lines:
    line_results = {"text": line}
    csv_line = [line]

    for model_name in models:
        tokenizer = AutoTokenizer.from_pretrained(model_name)
        model = AutoModelForCausalLM.from_pretrained(
            model_name, device_map="cuda", torch_dtype=torch.float16
        )

        ppl = perplexity(model, tokenizer, line)

        line_results[model_name] = {
            "perplexity": ppl
        }
        csv_line.append(ppl)

        del model
        torch.cuda.empty_cache()

    results[line] = line_results

with open("perplexity_results5.json", "w", encoding="utf-8") as f:
    json.dump(results, f, ensure_ascii=False, indent=4)

with open("perplexity_results5.csv", "w", newline="", encoding="utf-8") as f:
    csv_writer = csv.writer(f)
    csv_writer.writerow(csv_data[0])
    for line in lines:
        csv_writer.writerow([line] + [results[line][model]["perplexity"] for model in models])

結果

Text stabilityai/StableBeluga-7B_Perplexity mistralai/Mistral-7B-Instruct-v0.2_Perplexity Rakuten/RakutenAI-7B-chat_Perplexity
それと僕が材料をお伝えした時にバニラエッセンスを入れたじゃないですか 13.036222457885742 30.592239379882812 77.44200134277344
1弦の5フレット、2弦の5フレット、 3弦の5フレット、2弦の7フレット、 4.010903358459473 8.111798286437988 6.279117107391357
けどもこれでえっと木スキル使うとさらに カウンターが1個貯まる 43.25908279418945 83.80355072021484 470.63653564453125
長い年月をかけて韓国人朝鮮人 と向き合ってきた中国人は韓国人 9.886605262756348 30.079328536987305 87.20085144042969
ごいハマり始めて 293.4146423339844 4317.986328125 334.7664794921875
50話 いらっしゃいませ♪ ヘラのグランプリ! 15.717564582824707 58.66378402709961 111.03834533691406
オムニテクでは人々を助けを上がっている。 65.81471252441406 90.47702026367188 1869.9520263671875
ステーキってもんはね 127.35417938232422 1428.76318359375 1153.15966796875
これが聞こえてきた 14.765314102172852 872.0487670898438 120.8353500366211
なるほどねそうなんだやばいすげ えわ 117.2963638305664 360.88482666015625 478.8385009765625
殺菌得ながらを 121.11297607421875 1618.6380615234375 3937.654052734375
じゃあ呼吸法やりましょう、呼吸、呼吸 9.24917221069336 33.77603530883789 262.35357666015625
カンタ : そこやれるの見たいと思ってるよ、みんな 51.29374694824219 86.22332000732422 313.9569091796875
すげーなんか色んなものがこう そうなんだそうそうばすごいね 37.839759826660156 103.7863540649414 135.54092407226562
前回は standard assets を使って 遊んでいました 33.08415985107422 90.7002182006836 162.7081298828125
を獲得しました 10.945358276367188 405.0987548828125 819.6907958984375
しかしながら本当の理由はそれ だけではないのです 10.608744621276855 28.476654052734375 130.30300903320312
病むなんですが 57.94710922241211 5614.7802734375 7005.65576171875
全体混ぜると これね混ぜたら数分蒸らした方がいいです 21.468355178833008 77.3314437866211 306.8896179199219
アプリはそういったことを解決して くれるアプリです 11.473381042480469 35.310543060302734 87.94023132324219
ご丁寧に 64.8609619140625 768.6679077148438 146.9370880126953
下に 8333.6044921875 385289856.0 118921.09375
合わせてかぶせれば... 79.0224838256836 315.1685485839844 1221.1976318359375
そういう言い方で 27.01752281188965 314.7711486816406 442.60284423828125
朝食 21129.865234375 302320000.0 658.495849609375
流行ったものだそうですが 33.65590286254883 241.5250701904297 1139.429443359375
こうなります 68.17607116699219 33799.25390625 943.4025268554688
次は釣りレベルの上限解放です。今度は何を釣らされるんだろうと思っていましたが、タマカイでした。 14.19534683227539 21.08135986328125 23.427536010742188
守りたい 164.52532958984375 41213.8125 217.5680389404297
だってさっきの人从众… 254.49359130859375 1318.85205078125 2268.48974609375

cl-tohoku/bert-base-japaneseを使って文章の自然さを判定する

開発環境

ライブラリのインストール

pip install torch transformers
pip install fugashi ipadic

データの準備

以下のようなデータを準備します

それと僕が材料をお伝えした時にバニラエッセンスを入れたじゃないですか
1弦の5フレット、2弦の5フレット、 3弦の5フレット、2弦の7フレット、
けどもこれでえっと木スキル使うとさらに カウンターが1個貯まる
長い年月をかけて韓国人朝鮮人 と向き合ってきた中国人は韓国人
ごいハマり始めて
50話 いらっしゃいませ♪ ヘラのグランプリ!
オムニテクでは人々を助けを上がっている。

文章の自然さの判定

from transformers import BertForMaskedLM, BertJapaneseTokenizer
import torch
import csv
import json

model_name = "cl-tohoku/bert-base-japanese"
tokenizer = BertJapaneseTokenizer.from_pretrained(model_name)
model = BertForMaskedLM.from_pretrained(model_name)

def tokenize_with_mask(text, tokenizer):
    tokens = tokenizer.tokenize(text)
    masked_tokens = []
    for i in range(len(tokens)):
        if tokens[i] not in ['[CLS]', '[SEP]']:
            masked_tokens.append(tokens[:i] + ['[MASK]'] + tokens[i+1:])
    return masked_tokens

def calculate_score(masked_tokens, tokenizer, model):
    scores = []
    for tokens in masked_tokens:
        input_ids = tokenizer.convert_tokens_to_ids(tokens)
        tensor_input = torch.tensor([input_ids])
        with torch.no_grad():
            outputs = model(tensor_input, labels=tensor_input)
            loss = outputs[0]
            scores.append(loss.item())
    return sum(scores) / len(scores)

with open('testData.txt', 'r', encoding='utf-8') as file:
    texts = file.readlines()

results = []
for text in texts[:100]: 
    text = text.strip()
    masked_tokens = tokenize_with_mask(text, tokenizer)
    score = calculate_score(masked_tokens, tokenizer, model)
    results.append({'text': text, 'score': score})

# CSVファイルに保存
with open('results.csv', 'w', encoding='utf-8', newline='') as csv_file:
    fieldnames = ['text', 'score']
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    writer.writeheader()
    for result in results:
        writer.writerow(result)

# JSONファイルに保存
with open('results.json', 'w', encoding='utf-8') as json_file:
    json.dump(results, json_file, ensure_ascii=False, indent=4)

結果は以下のようになります

文章の類似度にminineedleを使って類似度測定を行う

初めに

文章の類似度に minineedleを教えていただいたので触ってみます。ライブラリの内容を見る感じ タンパク質配列間などを記載があるので、生物系で使われているもの?なのかもしれません

github.com

(雑に書いたコードは)以下で試したコードを置いていますので、ご参考までに

github.com

開発環境

ライブラリのインストール

pip install minineedle
pip install miniseq

minineedleで使用できるアルゴリズムについて

minineedleでは以下の二つのアルゴリズムを使うことができます。

  • Needleman-Wunsch wiki
  • Smith-Waterman wiki

それぞれのアルゴリズムについて簡単な説明は以下です

NeedlemanWunschアルゴリズム: グローバルアラインメントを行うアルゴリズムです。 2つの配列の全体を比較し、最適なアラインメントを見つけます。 動的計画法を用いて、配列間の類似性を最大化するアラインメントを計算します。 ギャップを挿入することで、配列の長さを調整しながらアラインメントを行います。 配列の先頭から末尾までを比較するため、配列全体の類似性を評価するのに適しています。 SmithWatermanアルゴリズム: ローカルアラインメントを行うアルゴリズムです。 2つの配列の部分配列間の類似性を見つけるのに適しています。 配列内の最も類似した領域を特定します。 ギャップを挿入することで、部分配列間の類似性を最大化するアラインメントを計算します。 配列全体ではなく、部分的に類似した領域を見つけるのに適しています。

文章を判定するのには、Needleman-Wunsch の方が適してそうです

複数の文章で実行

以下のいくつかの文章で実際に試してみます

from minineedle import needle, smith, core

def perform_alignment(seq1, seq2):
    alignment = needle.NeedlemanWunsch(seq1, seq2)
    alignment.align()
    score = alignment.get_score()
    identity = alignment.get_identity()
    
    print("Alignment of SEQUENCE 1 and SEQUENCE 2:")
    print(alignment)
    print("Score:", score)
    print("Identity:", identity)
    print()

# Test case 1: Short English sentences
seq1 = "The cat sat on the mat"
seq2 = "The dog sat on the rug"
perform_alignment(seq1, seq2)

# Test case 2: Longer English sentences
seq1 = "I love to eat pizza and pasta for dinner"
seq2 = "I enjoy eating sushi and ramen for lunch"
perform_alignment(seq1, seq2)

# Test case 3: Short Japanese sentences (Hiragana)
seq1 = "わたしはりんごがすきです"
seq2 = "わたしはバナナがすきです"
perform_alignment(seq1, seq2)

# Test case 4: Longer Japanese sentences (Hiragana and Kanji)
seq1 = "今日はいい天気です。散歩に行きましょう"
seq2 = "明日は雨が降るかもしれません。傘を持って行きましょう"
perform_alignment(seq1, seq2)

# Test case 5: Mixed English and Japanese sentences (Hiragana, Katakana, and Kanji)
seq1 = "I love to eat 寿司 and 天ぷら"
seq2 = "私は寿司とテンプラが大好きです"
perform_alignment(seq1, seq2)

# Test case 6: Japanese tongue twister (Hiragana and Katakana)
seq1 = "あめがあめあめあめがふるあめふるふるかあめてふるあめ"
seq2 = "アメガアメアメアメガフルアメフルフルカアメテフルアメ"
perform_alignment(seq1, seq2)

# Test case 7: Japanese proverb (Hiragana and Kanji)
seq1 = "猿も木から落ちる"
seq2 = "さるもきからおちる"
perform_alignment(seq1, seq2)

結果が以下のようになります

Alignment of SEQUENCE 1 and SEQUENCE 2:
Alignment of SEQUENCE 1 and SEQUENCE 2:
        The cat sat on the mat
        The dog sat on the rug

Score: 10
Identity: 72.73

Alignment of SEQUENCE 1 and SEQUENCE 2:
Alignment of SEQUENCE 1 and SEQUENCE 2:
        I love to- eat--- pizza and pasta for dinner
        I ---enjoy eating sushi and ramen for -lunch

Score: -2
Identity: 47.73

Alignment of SEQUENCE 1 and SEQUENCE 2:
Alignment of SEQUENCE 1 and SEQUENCE 2:
        わたしはりんごがすきです
        わたしはバナナがすきです

Score: 6
Identity: 75.0

Alignment of SEQUENCE 1 and SEQUENCE 2:
Alignment of SEQUENCE 1 and SEQUENCE 2:
        今日は-----いい天気です。--散歩に行きましょう
        明日は雨が降るかもしれません。傘を持って行きましょう

Score: -8
Identity: 34.62

Alignment of SEQUENCE 1 and SEQUENCE 2:
Alignment of SEQUENCE 1 and SEQUENCE 2:
        I love to eat 寿司--- and 天ぷら
        ------------私は寿司とテンプラが大好きです

Score: -23
Identity: 7.41

Alignment of SEQUENCE 1 and SEQUENCE 2:
Alignment of SEQUENCE 1 and SEQUENCE 2:
        あめがあめあめあめがふるあめふるふるかあめてふるあめ
        アメガアメアメアメガフルアメフルフルカアメテフルアメ

Score: -26
Identity: 0.0

Alignment of SEQUENCE 1 and SEQUENCE 2:
Alignment of SEQUENCE 1 and SEQUENCE 2:
        -猿も木から落ちる
        さるもきからおちる

Score: 1
Identity: 55.56

espnet/yodasの音声データをmp3に変換してローカルに保存する

開発環境

  • Ubunts 22.02

ライブラリのインストール

pip install pydub
sudo apt-get install ffmpeg
pip install librosa soundfile

mp3に変換・保存

以下で.arrowで保存されているデータをmp3に変換して、保存します

import os
from datasets import load_dataset
from pydub import AudioSegment
import numpy as np

# データセットのロード
ds = load_dataset('espnet/yodas', 'ja000', trust_remote_code=True)

# 保存先のフォルダを指定
output_folder = "audio"

# 保存先のフォルダが存在しない場合は作成
os.makedirs(output_folder, exist_ok=True)

# データセットの音声データをmp3に変換して保存
for i, audio_data in enumerate(ds['train']):
    # 音声データを取得
    audio = audio_data['audio']
    
    # 音声データをバイト列に変換
    audio_bytes = audio['array'].tobytes()
    
    # AudioSegmentを使用して音声データを作成
    audio_segment = AudioSegment(
        data=audio_bytes,
        sample_width=2,  # 16-bit audio
        frame_rate=audio['sampling_rate'],
        channels=1  # Mono audio
    )
    
    # ファイル名を生成
    filename = f"{audio_data['utt_id']}.mp3"
    
    # 音声データをmp3形式で保存
    audio_segment.export(os.path.join(output_folder, filename), format="mp3")
    
    print("convert audio to mp3:",filename)

print("音声データの変換と保存が完了しました。")

Rustの形態素解析ライブラリのlinderaを動かす

初めに

Rustで動く辞書サイズが小さくなった形態素解析ライブラリが出ているみたいなので触ってみます

デモ

実行すると以下のような結果が返っています

開発環境

  • ubuntu22.04

環境構築

まずは Rustをインストールします

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

環境変数に追加します

source $HOME/.cargo/env

プロジェクトの作成

以下でプロジェクトを作成します

mkdir lindera-test
cd lindera-test

Cargo.toml ファイルの作成をします

[package]
name = "lindera-test"
version = "0.1.0"
edition = "2021"

[dependencies]
lindera-core = "0.24.0"
lindera-dictionary = "0.24.0"
lindera-tokenizer = { version = "0.24.0", features = ["ipadic"] }

以下のように src/main.rs でサンプルコードの作成をします

use lindera_core::{mode::Mode, LinderaResult};
use lindera_dictionary::{DictionaryConfig, DictionaryKind};
use lindera_tokenizer::tokenizer::{Tokenizer, TokenizerConfig};

fn main() -> LinderaResult<()> {
    let dictionary = DictionaryConfig {
        kind: Some(DictionaryKind::IPADIC),
        path: None,
    };

    let config = TokenizerConfig {
        dictionary,
        user_dictionary: None,
        mode: Mode::Normal,
    };

    // Tokenizerの作成
    let tokenizer = Tokenizer::from_config(config)?;

    // テキストのトークン化
    let tokens = tokenizer.tokenize("関西国際空港限定トートバッグ")?;

    // トークンの出力
    for token in tokens {
        println!("{}", token.text);
    }

    Ok(())
}

ビルドと実行

以下でビルドをします

cargo run --features=ipadic

また以下で実行できます

cargo run --features=ipadic

以下のように結果が出力されます

関西国際空港
限定
トートバッグ