2024. 1. 3. 00:48ㆍDevelopers 공간 [Shorts]/Vision & Audio
<분류>
A. 수단
- OS/Platform/Tool : Linux, Kubernetes(k8s), Docker, AWS
- Package Manager : node.js, yarn, brew,
- Compiler/Transpillar : React, Nvcc, gcc/g++, Babel, Flutter
- Module Bundler : React, Webpack, Parcel
B. 언어
- C/C++, python, Javacsript, Typescript, Go-Lang, CUDA, Dart, HTML/CSS
C. 라이브러리 및 프레임워크 및 SDK
- OpenCV, OpenCL, FastAPI, PyTorch, Tensorflow, Nsight
1. What? (현상)
이번 글에서는 데이터를 정제하기 위해 형태소 분석기을 활용하거나 토크나이저(Tokenizer)를 활용해 tokenizer.model을 만들고 활용하는 내용을 정리하려고 합니다.
필요에 따라 위 두가지로 정제된 텍스트 데이터로 LM(Language Model)을 만들기도 합니다.
2. Why? (원인)
- X
3. How? (해결책)
이번에 작업할 과정은, 데이터를 먼저 준비한 뒤 아래와 같은 순서로 처리해보고자 합니다.
- 해당 데이터를 Cleaning
- MeCab을 활용해 형태소 분석
- sentencepiece 패키지를 활용해 tokenizer를 만들고 활용하기
순서대로 진행해보겠습니다.
0. 데이터 준비
먼저 데이터를 준비해야하는데, text로만 이루어진 text 파일을 만들어야 합니다.
하나의 예로 데이터는 AiHub의 "저음질 전화망 음성인식 데이터"(https://www.aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=realm&dataSetSn=571)를 받아서 처리할 때를 보고자합니다.
해당 데이터에서 text데이터들을 아래와 같은 코드를 통해 output.txt라는 파일로 모아보았습니다. 아래 내용 중 text_processing이라는 함수는 데이터에 따른 형식을 처리하기 위해 text를 전처리하는 방법으로, 편하신대로 만드셔도되지만 필자의 예시를 보시려면 이전 글(https://tkayyoo.tistory.com/162)을 참조하시면 됩니다.
import os
import glob
from tk_preprocessing import text_processing
INPUT_DATA_DIR="../007.저음질 전화망 음성인식 데이터/01.데이터/2.Validation"
OUTPUT_DATA_FILE = open("./output.txt", 'w')
txt_paths=[]
for depth_1 in glob.glob("{}/*".format(INPUT_DATA_DIR)):
if not os.path.isdir(depth_1) or depth_1.split("/")[-1] =="__MACOSX":
continue
for depth_2 in glob.glob("{}/**/D*/J*/S*/*.txt".format(depth_1), recursive=True):
if not os.path.isfile(depth_2):
continue
txt_paths.append(depth_2)
txt_paths_len = len(txt_paths)
for i, txt_path in enumerate(txt_paths):
print("Continuing??{}/{}".format(i+1, txt_paths_len), end='\r')
with open(txt_path, 'r') as f:
line = f.readline()
text, _, _ = text_processing(line)
OUTPUT_DATA_FILE.write(text+"\n")
OUTPUT_DATA_FILE.close()
이후에 이렇게 만들어진 output.txt파일을 간단한 검토 혹은 cleaning과정을 통해 step1_clean_test.ref라는 파일로 만들어주었습니다. 해당 cleaning 과정을 선택이기도 하기 때문에 step1_refine.py에 대해 참조하시려면 아래의 더보기를 누르시면 됩니다.
OUT_DIR="./OUTPUT"
OUT_FORM="test"
#STEP1 cleaning
from="./output.txt"
to="${OUT_DIR}/step1_clean_${OUT_FORM}.ref"
python3 step1_refine.py ${from} ${to}
-----------------------------------------------------------------
<일반적으로 사용하는 Text Data Cleaning 예시>
아래는 해당 데이터에 맞게 처리한 것이 아니라, 일반적으로 텍스트 데이터를 처리할 때 어떻게 하면 좋을지를 예로 보인 step1_refine.py입니다.
- strip()함수를 통해 공백을 지워줍니다.
- 데이터를 받아 한글(가~힣)을 제외하고 삭제해줍니다.
- 공백이 한번이상 반복되는 경우 공백을 한번 있는 것으로 바꿔줍니다.
import re,sys,os
with open(sys.argv[1], 'r', encoding='utf-8') as f:
with open(sys.argv[2], 'w', encoding='utf-8') as g:
for ln in f:
ln = re.sub(r'[^가-힣 ]', ' ', ln.strip())
ln = re.sub(r' +', ' ', ln)
print(ln.strip(), file=g)
----------------------------------------------------------------
위와 같이 처리해 만든 step1_clean_test.ref 파일 내용을 보면 아래와 같을 것입니다. 앞에 숫자 인덱스는 문장을 보기 쉽게 구분하기 위해 넣었습니다.
1. 학습지원센터입니다 무엇을 도와드릴까요
2. 예 예 뭐 쯤 여쭤볼라 그러는데요
3. 아무도 홈페이지에 아니 얘는 인강은 한 번도 안 해봤어요
4. 아 그건 아니시구요 저희가 뭐 예 잠시만요
5. 아 그럼 예비 고 일 관련으로 문의주신거 맞으시죠
6. 그 전용반이 있는 건 아니고 회원님이 이제 원하시는 강의를 수강하시면 되는 구조예요
...
1. 형태소 분석
이제 본격적으로 만들어진 step1_clean_test.ref 파일을 형태소 분석기 MeCab을 활용해 구분해보겠습니다. 한국어 형태소 분석기는 다양한 것들이 있는데 참조하시려면 아래 더보기를 눌러 참조하시면 됩니다.
------------------------------------------------------
<다양한 한글 형태소 분석기>
1. mecab-ko : 은전한닢 프로젝트는 검색에서 쓸만한 오픈소스 한국어 형태소 분석기를 만들기 위한 프로젝트입니다. Mecab은 최초에 일본어 형태소를 나누기 위해 만든 범용 형태소 분석기 엔진이며, mecab-ko는 같은 엔진을 활용해 한국어에도 활용하도록 진행한 “MeCab의 fork프로젝트”의 결과물인 c++기반의 한국어 형태소 분석기 엔진입니다.
- mecab은 CVF(Conditional Random Fields)를 활용해 말뭉치로부터 bigram모델을 학습하므로 형태소에서 다른 형태소로 이동시 이전 상태에 따라 결정됩니다. 따라서 일본어의 엔진을 그대로 한국에 사용할 수 있었습니다.
- seunjeon(슨전) : 역시나 은전한닢 프로젝트로 진행됐지만 JVM상에서돌아가는 한국어 형태소 분석기입니다. Java나 scala에서 사용시 편하게 사용할 수 있습니다.
- KoNLPY는 한국어 정보처리를 위한 상위 파이썬 패키지로, Hannanum(Java/Scala), Kkma(Java/Scala), Komoran(Java/Scala), Mecab-ko(C/C++), Twitter(OKT, Open Korean text)(Java,Scala)라는 Subpackaage의 형태소 분석기를 사용할 수 있습니다.
2. 노리(Nori) : 루씬(Lucene)은 Java기반의 고성능 정보 검색 라이브러리입니다. 이를 기반으로 방대한 양의 데이터를 검색하는 분석 엔진이 ElasticSearch입니다. 이런 ElasticSearch6.6버전부터 공식적으로 노리(Nori)라는 한글 형태소 분석기를 개발해 지원하기 시작했는데, 기존의 Kuromoji(구로모지)라는 ElasticSearch의 일본형태소 분석기를 활용해 구현했습니다.
- ElasticSearch에서는 아리랑(arirang), Twitter(OKT, Open Korean text), seunjeon(슨전) 형태소 분석기들을 활용할 수도 있습니다.
3. Pororo(뽀로로) : 카카오 브레인(Kakao Brain)에서 개발한 자연어 처리 라이브러리
4. Kiwi(Korean Itelligent Word Identifier) : c++기반으로 작성된 python 패키지.
5. Soynlp : Soynlp라는 한국어 자연어 처리 라이브러리의 LTokenizer가 있습니다.
------------------------------------------------------
시작하기에 앞서 MeCab을 설치해보겠습니다. 일반적인 설치 tutorial에서 제공하는 명령어로 실행을 하면 설치가 되지 않는 경우가 많아 직접 설치 파일을 가지고 설치하는 방식으로 진행합니다.
1. mecab-ko 설치
mecab-ko는 은전한닢 프로젝트의 한국어 형태소 분석기 엔진입니다. 최신버전 및 파일은 https://bitbucket.org/eunjeon/mecab-ko/downloads/ 에서 확인할 수 있으며, 파일을 받아 설치합니다.
wget https://bitbucket.org/eunjeon/mecab-ko/downloads/mecab-0.996-ko-0.9.2.tar.gz
tar xvf mecab-0.996-ko-0.9.2.tar.gz
cd mecab-0.996-ko-0.9.2
./configure
make check
make install
2. mecab-ko-dic 설치
21세기 세종 계획은 한국어 정보화 기반을 구축하기 위해 10년간 국비150억을 투자하고 매년 학자 300명이 참여한 국책사업입니다. 2007년에 종료되었지만, 2억 어절 규모의 말뭉치를 구축했으며 위에서 언급한 은전한닢 프로젝트에서 만든 mecab에서 형태소 분석을 수행하는데 필요한 한국어의 형태학적 모델을 담고 있는 파일들이 mecab-ko-dic입니다.
어떤 단어든지 viterbi 알고리즘을 활용해 효율적으로 검색할 수 있는 구조의 binary 사전형태를 가지고 있습니다. 위의 형태소분석기를 정리한 곳에서 언급한 Nori(재가공), mecab-ko, senjeon, 모두 이 사전을 활용합니다.
apt-get install automake
wget https://bitbucket.org/eunjeon/mecab-ko-dic/downloads/mecab-ko-dic-2.1.1-20180720.tar.gz
tar zxvf mecab-ko-dic-2.1.1-20180720.tar.gz
cd mecab-ko-dic-2.1.1-20180720
./autogen.sh
./configure
make
make install
3. mecab-python 설치
이제 mecab-ko관련 된 필요내용을 다 설치했으므로, 이를 활용한 실제 mecab 파이썬 패키지를 설치해줍니다.
# Method1
git clone https://bitbucket.org/eunjeon/mecab-python-0.996.git
cd mecab-python-0.996
python3 setup.py build
python3 setup.py install
# Method2
pip3 install mecab-python3
4. 기타 및 확인
아래 보여드릴 예시의 경우 직접적으로 konlpy를 활용하는 경우는 없지만, konlpy에 내장된 mecab을 활용하고 싶은 경우 설치해줍니다.
pip3 install konlpy
아래 명령어를 통해 확인합니다. 원래는 konlpy에 포함된 mecab을 설치하기 위해 사용하는 코드이지만 아마 잘 동작하지 않는 경우가 많아 결과를 확인하는 데만 사용했습니다.
bash <(curl -s https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh)
아래와 같은 결과가 나온다면 설치되었다고 보면 될 것같습니다.
mecab-ko is already installed
mecab-ko-dic is already installed
mecab-python is already installed
Done.
자 이제 MeCab을 활용해 step1_clean_test.ref 파일을 형태소 분석기를 통해 구분해보겠습니다. 아래는 step2_mecab.py라는 파일의 내용을 보였으며, tokenize()라는 함수를 만들었는데 형태소 분석 된 결과를 띄어쓰기로 구분할 것이기 때문에 실제로 있던 "띄어쓰기 공백"을 space_symbol로 바꿔줍니다. space_symbol은 ▃(+2583)를 활용했습니다.
import MeCab
import sys
TOKENIZER = MeCab.Tagger(f"—dicdir /usr/local/lib/mecab/dic/mecab-ko-dic")
def tokenize(text:str, space_symbol:str="▃"):
text = text.strip()
text_ptr = 0
tokenized = []
for mor in TOKENIZER.parse(text).split("\n"):
if "\t" in mor:
splitted = mor.split("\t")
token = splitted[0]
if text[text_ptr] ==" ":
while text[text_ptr] == " ":
text_ptr += 1
assert text[text_ptr] == token[0]
tokenized.append(space_symbol)
tokenized.append(token)
text_ptr += len(token)
return ' '.join((t for t in tokenized))
if __name__ == "__main__":
with open(sys.argv[1], 'r', encoding='utf-8') as f:
with open(sys.argv[2], 'w', encoding='utf-8') as g:
for ln in f:
if len(ln.strip()) >1:
print(tokenize(ln.strip()), file=g)
이제 아래와 같은 코드로 실행해보겠습니다.
#STEP2. mecab separating
from=$to
to="${OUT_DIR}/step2_mecab_${OUT_FORM}.mecab"
python3 step2_mecab.py ${from} ${to}
이렇게 만들어진 step2_mecab_test.mecab파일의 내용을 보면 아래와 같습니다. 앞에 숫자 인덱스는 문장을 보기 쉽게 구분하기 위해 넣었습니다.
1. 학습 지원 센터 입니다 ▃ 무엇 을 ▃ 도와 드릴까요
2. 예 ▃ 예 ▃ 뭐 ▃ 쯤 ▃ 여쭤 볼라 ▃ 그러 는데요
3. 아무 도 ▃ 홈페이지 에 ▃ 아니 ▃ 얘 는 ▃ 인강 은 ▃ 한 ▃ 번 도 ▃ 안 ▃ 해 봤 어요
4. 아 ▃ 그건 ▃ 아니 시 구요 ▃ 저희 가 ▃ 뭐 ▃ 예 ▃ 잠시 만 요
5. 아 ▃ 그럼 ▃ 예비 ▃ 고 ▃ 일 ▃ 관련 으로 ▃ 문 의 주 신 거 ▃ 맞 으시 죠
6. 그 ▃ 전 용반 이 ▃ 있 는 ▃ 건 ▃ 아니 고 ▃ 회원 님 이 ▃ 이제 ▃ 원 하 시 는 ▃ 강의 를 ▃ 수강 하 시 면 ▃ 되 는 ▃ 구조 예요
2. 토크나이저 활용하기
이번엔 Tokenizer(토크나이저)를 만들고 활용해보겠습니다. 필자는 sentencepiece(https://github.com/google/sentencepiece) 혹은 spe이라는 서브워드 토크나이징 알고리즘들을 내장한 패키지를 활용할 계획인데, 이외의 huggingface에서 제공하는 tokenizers라는 패키지도 존재합니다.
---------------------------------------------------------------------------
<Huggingface Tokenizers>
Huggingface의 Tokenizers(https://github.com/huggingface/tokenizers)에서도 다양한 토크나이저를 제공합니다.
먼저 설치방법은 아래와 같습니다.
pip3 install tokenizers==0.12.1
그중 BERT에서 활용한 워드피스 토크나이저(WordPiece Tokenizer, WPE)를 사용하는 코드는 아래와 같습니다.
import tokenizers
input_file = './OUTPUT/step2_mecab_test.mecab'
tokenizer = tokenizers.BertWordPieceTokenizer(lowercase=False)
tokenizer.train(input_file, vocab_size=5000)
tokenizer.save_model('./output')
---------------------------------------------------------------------------
먼저 설치하는 방법은 아래와 같습니다.
pip3 install sentencepiece python-abc
이제 학습 코드는 아래와 같습니다. NeMo 프레임워크에서 tokenize하는 코드 (https://github.com/NVIDIA/NeMo/blob/main/nemo/collections/common/tokenizers/sentencepiece_tokenizer.py)를 참조해 만들었습니다. model은 unigram, bpe, char, word 네가지를 제공합니다.
import sentencepiece as spm
input_file = './OUTPUT/step2_mecab_test.mecab'
vocab_size = 5000
prefix = 'callcenter'
model_type = 'unigram'
shuffle_input_sentence=True
cmd = (
f"--input={input_file} --model_prefix={prefix} "
f"--vocab_size={vocab_size} "
f"--model_type={model_type} "
f"--shuffle_input_sentence={shuffle_input_sentence} --hard_vocab_limit=false "
f"--character_coverage=1.0 "
)
cmd+="--split_by_unicode_script=false "
spm.SentencePieceTrainer.Train(cmd)
자 이제 학습하고 나면 실제 활용할 callcenter.model과 내용을 참조하기 위한 callcenter.vocab 두가지 파일이 만들어집니다. callcenter.vocab을 보면 아래와 같습니다. 기존의 MeCab의 결과로 띄어쓰기는 "형태소를 구분하는 기준" 이었는데, 이런 띄어쓰기를 다루기 위해 ▁(+2581)를 활용합니다.
<unk> 0
<s> 0
</s> 0
▁그 -0
▁네 -1
▁이 -2
▁아 -3
니다 -4
▁있 -5
▁어 -6
▁하 -7
......
자이제 만들어진 callcenter.model을 가지고 실제로 step2_mecab_test.mecab 파일을 토큰화 해보겠습니다. 실제 step3_sp.py파일은 아래와 같습니다.
import sentencepiece as spm
import sys
sp = spm.SentencePieceProcessor()
vocab_file = "callcenter.model"
sp.load(vocab_file)
with open(sys.argv[1], 'r', encoding='utf-8') as f:
with open(sys.argv[2], 'w', encoding='utf-8') as g:
for ln in f :
ln = sp.encode_as_pieces(ln.strip())
print((' '.join(ln)).strip(), file=g)
이를 아래와 같이 실행하겠습니다.
#STEP3. sentencepiece tokenizer
from=$to
to="${OUT_DIR}/step3_sp_${OUT_FORM}.spm"
python3 step3_sp.py ${from} ${to}
위 과정을 거친 step3_sp_test.spm파일을 살펴보면 아래와 같습니다. 앞에 숫자 인덱스는 문장을 보기 쉽게 구분하기 위해 넣었습니다.
1. ▁학습 ▁지원 ▁센터 ▁입니다 ▁ ▃ ▁무엇 ▁ 을 ▁ ▃ ▁도와 ▁드릴까요
2. ▁예 ▁ ▃ ▁예 ▁ ▃ ▁뭐 ▁ ▃ ▁ 쯤 ▁ ▃ ▁여쭤 ▁볼 라 ▁ ▃ ▁그러 ▁ 는데요
3. ▁아무 ▁도 ▁ ▃ ▁홈페이지 ▁에 ▁ ▃ ▁아니 ▁ ▃ ▁얘 ▁ 는 ▁ ▃ ▁인강 ▁은 ▁ ▃ ▁한 ▁ ▃ ▁번 ▁도 ▁ ▃ ▁안 ▁ ▃ ▁해 ▁봤 ▁어 요
4. ▁아 ▁ ▃ ▁그건 ▁ ▃ ▁아니 ▁시 ▁구 요 ▁ ▃ ▁저희 ▁가 ▁ ▃ ▁뭐 ▁ ▃ ▁예 ▁ ▃ ▁잠시 ▁만 ▁요
5. ▁아 ▁ ▃ ▁그럼 ▁ ▃ ▁예비 ▁ ▃ ▁고 ▁ ▃ ▁일 ▁ ▃ ▁관련 ▁ 으로 ▁ ▃ ▁문 ▁의 ▁주 ▁신 ▁거 ▁ ▃ ▁맞 ▁으 시 ▁ 죠
6. ▁그 ▁ ▃ ▁전 ▁용 반 ▁이 ▁ ▃ ▁있 ▁ 는 ▁ ▃ ▁건 ▁ ▃ ▁아니 ▁고 ▁ ▃ ▁회원 ▁ 님 ▁이 ▁ ▃ ▁이제 ▁ ▃ ▁원 ▁하 ▁시 ▁ 는 ▁ ▃ ▁강의 ▁ 를 ▁ ▃ ▁수강 ▁하 ▁시 ▁면 ▁ ▃ ▁되 ▁ 는 ▁ ▃ ▁구조 ▁예 요
이렇게 형태소 분석기와 토크나이저를 활용해 데이터를 준비해보았습니다. 이후에 활용하는 방법에 대해 참조하시려면 아래 더보기를 참조하시면 됩니다.
--------------------------------------------------------------------
<sentencepice 모듈 만들어 사용하기>
sentencepiece를 위와 같이 단순히 실행할 수도 있지만, class 모듈로 만들어 활용하는 경우의 예시를 남겨놓고자 합니다. 아래는 SentencepiecesTokenizer라는 class를 만들어 실제 활용해본 코드입니다.
path = 'callcenter.model'
tokenizer = SentencepiecesTokenizer(path)
vocab_list = tokenizer.sp.get_vocab()
# Check vocab list
for k in vocab_list.keys():
print("Check this first {}, {}".format(k, vocab_list[k]))
# Text to Ids
token_int = tokenizer.text2ids("▁주문 ▁ ▃ ▁배송 ▁에 ▁ ▃ ▁안 ▁ ▃ ▁써 ▁있 ▁ 는데 ▁ ▃ ▁원래 ▁ ▃ ▁안 ▁ ▃ ▁뜨 ▁ 는 ▁ ▃ ▁거 ▁예 요")
# Ids to Text
token_int = list(filter(lambda x: x!=0 and x!=1 and x!=2, token_int))
text = tokenizer.ids2text(token_int)
text = text.replace(' ','').replace('▃', ' ') # U+2583
print(text)
결과는 아래와 같습니다.
주문 배송에 안 써있는데 원래 안 뜨는 거예요
그럼 SentencepicesTokenizer은 어떻게 구현되었을까요? 아래와 같습니다. 참조하시길 바랍니다.
from abc import ABC
from pathlib import Path
from typing import Iterable, List, Union, Optional, Dict
import sentencepiece as spm
class SentencepiecesTokenizer(ABC):
def __init__(self, model: Union[Path,str], special_tokens: Optional[Union[Dict[str,str], List[str]]]=None):
self.model = str(model)
self.sp = spm.SentencePieceProcessor()
self.sp.load(self.model)
self.original_vocab_size= self.sp.get_piece_size()
self.vocab_size= self.sp.get_piece_size()
self.special_token_to_id = {}
self.id_to_special_token = {}
if special_tokens:
self.add_special_tokens(special_tokens)
vocabulary = {}
for i in range(self.vocab_size):
piece = self.ids2tokens([i])
piece = piece[0]
vocabulary[piece] = i+1
def get_vocab():
return vocabulary
self.sp.vocab_size = len(vocabulary)
self.sp.get_vocab = get_vocab
self.sp.all_special_tokens = self. special_token_to_id
#sentencepicesTokenizer(?쐍emo寃곌낵??
def add_special_tokens(self, special_tokens):
if isinstance(special_tokens, list):
for token in special_tokens:
if(self.sp.piece_to_id(token)==self.sp.unk_id() and token not in self.special_token_to_id):
self.special_token_to_id[token] = self.vocab_size
self.id_to_special_token[self.vocab_size] = token
self.vocab_size += 1
#ids <?붴붴?tokens <?붴붴? text
def token2id(self, token):
if token in self.special_token_to_id:
return self.special_token_to_id[token]
return self.sp.piece_to_id(token)
def ids2tokens(self, ids):
tokens = []
for id in ids:
if id>= self.original_vocab_size:
token.append(self.id_to_special_token[id])
else:
tokens.append(self.sp.id_to_piece(id))
return tokens
def tokens2ids(self, tokens:Union[str,List[str]]) -> Union[int,List[int]]:
if isinstance(tokens,str):
tokens = [tokens]
ids = []
for token in tokens:
ids.append(self.token2id(token))
return ids
def tokens2text(self, tokens:Iterable[str]) ->str:
return self.sp.DecodePieces(list(tokens))
def text2tokens(self, line:str)->List[str]:
return self.sp.EncodeAsPieces(line)
def ids2text(self, ids) -> str:
tokens = []
for id in ids:
if id >=self.original_vocab_size:
tokens.append(self.id_to_special_token[id])
else:
tokens.append(self.sp.id_to_piece(id))
return self.sp.DecodePieces(list(tokens))
def text2ids(self,line:str)->Union[int,List[int]]:
tokens = self.sp.EncodeAsPieces(line)
if isinstance(tokens,str):
tokens = [tokens]
ids = []
for token in tokens:
ids.append(self.token2id(token))
return ids
--------------------------------------------------------------------
추가적으로 이렇게 만든 데이터를 가지고 LM(Language Model)을 만들어볼 수도 있는데, 해당 링크(https://tkayyoo.tistory.com/165)를 참조하시기 바랍니다.
http://sosomemo.tistory.com/30
'Developers 공간 [Shorts] > Vision & Audio' 카테고리의 다른 글
[Audio] ASR에서 CER, WER 구현 및 측정해보기 (0) | 2024.02.09 |
---|---|
[NLP] KenLM으로 Language Model만들기 (1) | 2024.02.09 |
[Audio] Python 활용해 Audio 및 Text 데이터 Pre-processing (0) | 2024.01.14 |
[Audio] Python으로 VAD 구현하기 (0) | 2023.12.30 |
[NLP] 한글을 다양하게 조작해보기 (0) | 2023.11.12 |