RAG Project

[RAG Project] GlobalMacro QA chatbot - Data Preprocessing - audio파일 (3)

hibyeys 2024. 9. 10. 22:28

2024.09.10 - [RAG Project] - [RAG Project] GlobalMacro QA chatbot - Data Preprocessing - md 파일 (2)

 

[RAG Project] GlobalMacro QA chatbot - Data Preprocessing - md 파일 (2)

2024.09.09 - [RAG Project] - [RAG Project] GlobalMacro QA chatbot - 데이터 크롤링(1) [RAG Project] GlobalMacro QA chatbot - 데이터 크롤링(1)2024.08.20 - [RAG Project] - [RAG Project] GlobalMacro QA chatbot - 개요(0) [RAG Project] GlobalMacr

hibyeys.tistory.com

지난 포스팅에 이어서 이번에는 Audio 파일 프로세싱 과정을 적어보겠다.

데이터 유형

  1. MD (마크다운) 파일
  2. Audio 파일
  3. 표 형식의 각종 지표 (csv or xlsx)

Audio 파일을 RAG에 넣기 위해서는 아래와 같은 과정을 거쳤다.

STT (speech to text) -> Sentence Correction -> Summary -> Chunking -> Metadata Tag

 

1. STT (Speech To Text)

STT는 현재 가장 많이 쓰이는 whisper 모델을 사용하였다. (https://huggingface.co/openai/whisper-large-v3)

 

openai/whisper-large-v3 · Hugging Face

Whisper Whisper is a state-of-the-art model for automatic speech recognition (ASR) and speech translation, proposed in the paper Robust Speech Recognition via Large-Scale Weak Supervision by Alec Radford et al. from OpenAI. Trained on >5M hours of labeled

huggingface.co

※ 여담 : 필자는 맥북 m1 pro 와 3090 데스크탑을 가지고 있어서 mps 와 cuda 둘다 테스트해보았는데 그냥 마음 편하게 cuda 를 쓰고 맥북에서 쓸일이 있을 때는 openai whisper api를 사용하기로 했다. (속도가 10배 정도 차이가 난다)

 

1.1 직면한 문제 

  • 결과물들을 확인하면 중간중간에 원하는 단어가 아니거나 (ex. 하워드 막스 -> 하우드 마스) 글자가 중복해서 찍히는 경우 (안녕 -> 안녕안녕안녕) 같은 부정확한 문장들이 보였다.
  • 원본 오디오 파일과 비교했을 때 가끔 뒷부분에 문장이 통째로 변환이 안된 것들이 있었다.

위에 문제들을 해결하기 위해 긴 오디오 파일들을 잘른뒤 STT를 수행한뒤 붙이는 과정을 수행했고 텍스트를 교정하는 파트 (Sentence Correction) 를 추가하여 문제를 해결했다. (그래도 가끔 튀는 문장들이 있었는데 그런것들은 어쩔 수 없이 사람이 직접 교정하는 수 밖에없을 것 같다.)

 * whisper 모델 자체내에서도 오디오를 분할하는 로직이 있있는데 오디오파일을 잘랐다고 문장이 skip 되는 문제가 해결된게 잘 이해가 안갔다.

 

 

2. Sentence Correction

위의 STT의 오류를 해결하고 나중에 문장을 분할할 때를 대비해 문장의 단락을 나누기위해 Sentence Correction 파트를 추가해 주었다. 

# Sentence Correction Prompt (.yaml)
prompt: |
  """
    “다음 텍스트는 STT(음성 인식)에서 추출한 긴 텍스트입니다. 문맥을 고려해 자연스럽게 단락을 나누고, STT가 잘못된 부분이 있다면 이를 교정하세요. 텍스트 내용은 변경하지 않고 가능한 한 원래 의미를 유지해주세요.”

    1.	텍스트를 읽고 문맥 흐름을 파악하세요.
    2.	각 주제 또는 아이디어가 전환되는 지점에서 적절하게 단락을 나누세요.
    3.	STT 오류로 인해 의미가 불분명하거나 이상한 부분을 문맥에 맞게 수정하세요.
    4.	수정한 부분은 부드럽게 이어질 수 있도록 하세요.
    5.  원문에 누락되는 내용이 없도록 하세요.

    {docs}
  """

 

2.1 직면한 문제

이 과정을 통해 배우게 된 것은 gpt-4o-mini의 input limit token 이 128k 이고 output limit token이 16,384 이라는 것이다.

처음 몇개의 문서를 테스트 했을 때, 이상하게 문장들이 요약되는 현상이 있어서 프롬프트의 문제인가 싶어서 여러 삽질을 했지만

결론적으로 input token이 (20,000 정도) output limit token 수 보다 커서 압축되서 나오는 것이었다.

그래서 아래와 같이 CharactorTextSpliiter를 이용해 문장을 분할한뒤 LLM 에 전달하였다.

 

3. Summary

요약 파트는 시간과 비용을 가장 많이 소비한 파트이다. 처음에 몇개의 샘플로 요약을 진행했을 때, 단순하게 파일을 집어넣고 요약해 달라고했다 (이걸 Stuff 방식이라고 하더라). 그런데 결과물이 너무 좋지 않아 Summary Task 에 대한 검색을 실시 했다.

예상대로 하나의 중요한 Task 로서 많은 연구가 이뤄지고 있었다.

(요약 방법에 대한 자세한 내용은 나중에 따로 정리해 두고 일단 langchain에서 제공하는 Summarization task 노트북을 링크로 걸어 두겠다)

 

서치한 내용을 토대로 내가 선택한 방법은 Map - Refine 방식에서 Map 부분에 Chain of Density prompting(논문링크)를 적용한 것이다. chain of density prompting 에 대해 간단히 설명하자면 "주어진 주제에 대해 점진적으로 더 상세하고 밀도 높은 내용을 생성" 하게 해주는 기법이다.

 

Chain of Density prompting 과정:

  1. 주제에 대해 간단한 요약으로 시작
  2. Entity를 도출하여 missing Entities를 전달하여 이전 버전을 개선하고 세부 정보를 추가
  3. 위의 과정을 여러 번 반복하여 내용의 밀도와 품질을 높임 (논문에서는 5번을 제시)

3.1 Test

먼저 Sentence Correction까지 마친 문서 하나를 가지고 테스트를 진행하였다. (사전에 내용을 숙지한채로 요약을 평가하였다)

내가 고려해야할 사항은 크게 세 가지 였다. 

  1. Chain of Density prompting을 할 때, 나에게 맞게 어떻게 optimize를 할 것인가?
  2. Map Summary를 진행할때 chunk_size 와 overlap 파라미터를 어떻게 줄 것인가?
  3. 한 문서를 요약하는데 시간이 얼마나 소요되는가?

테스트 하기전 우연히 chain of density prompt에 Knowledge Graph prompt를 결합해서 사용하는 영상을 보았다

꽤 괜찮은 방법이라 생각해서 Vanilla CoD와 Knowledge Graph를 추가한 것을 비교해 보았다.

둘다 괜찮은 퀄리티의 요약본을 만들었지만 Knowledge Graph를 추가한 쪽 문장이 뭔가 매끄럽지 않았다.

그래서 문장을 교정해주는 프롬프트를 추가해서 테스트 해보았는데 훨씬 매끄러운 요약본이 나왔다.

자세히 살펴보니 Vanilla CoD 보다 핵심문장들이 더 잘들어 있다고 판단해서 Knowledge Graph를 추가한 프롬프트를 사용하기로 했다.

Knowledge Graph prompt
문장 교정 prompt

 

그 다음으로  Map Summary 단계의 Chunk_size 를 테스트 했는데 확실히 size가 작을 수록 좋은 품질의 요약본이 나왔다.

하지만 소요되는 시간이 너무 길었다. (Chunk_size = 500일 때, 1시간이 소요)

그래서 500을 하한선으로 잡고 500 ~ 1000 사이를 테스트 해보다가 Chunk_size = 700 , 30분 소요에서 합의를 보았다.

또한 Semantic chunker (텍스트를 의미론적 유사성에 기반하여 분할하는 고급 텍스트 분할 기법) 도 테스트 해보았는데,

2시간이 소요되는 반면 이전 테스트와 퀄리티 차이가 크게 느껴지지 않아서 배제했다.

※ AutoRAG를 통해 정량적인 평가 (G-Eval 등) 도 진행해보려 했으나 테스트셋을 만드는 과정이 복잡하여 시간관계상 생략하였다.

3.2 직면한 문제

전반적으로 만족할 만한 요약본을 받을 수 있었으나 몇가지 아쉬운 부분들이 있었다.

  1. 문단의 순서가 이상한 부분이 있다 (한참전에 나와야 할 문단이 저 뒤에 있다)
  2. 가끔 요약된 문장이 기존의 의미와 다른 의미로 요약된게 있다.
  3. 교정을 거친 단어라도 발화자의 발음으로 인해 잘못된 단어들이 있다. ex) TED -> TD

위의 문제들은 결국 직접 수정해 주는 수 밖에 없었다. 하지만 방대한 양을 일일이 읽어가며 바꿀 수는 없어서

Retrieve에 걸렸을 때, 문장을 한번 체크해보고 이상한 것을 수정해 나가는 방식을 채택해서 넘어갔다.

 

4. chunking

다음으로 잘 만들어진 요약본을 chunking 해서 Document 로 만드는 과정을 수행했다.

위의 요약을 위한 chunking과는 다르게 의미적으로 분리해야하기에 어떻게 해야할지 고민이 많았다.

크게 고민해봐야 내가 할 수 있는 방법은 3 가지 정도였다.

  1. 직접 소제목을 달면서 주제별로 나누는 방법
  2. LLM 에 전달하여 나누어 달라고 하는 방법
  3. Semantic Chunker를 이용하는 방법

첫번째 방법은 최후의 보루로 놔두기 위해 배제하고 나머지 두 가지를 실험해보았다.

 

먼저 LLM 에 전달하여 나누는 것을 테스트했는데 문단을 너무 잘게 쪼개서 소제목을 붙이고 내용 소실도 심해서

context를 전달하기에는 많이 부족해 보였다. 프롬프트를 개선해도 크게 나아지지 않아 3번으로 넘어갔다.

 

사실 Semantic Chunk는 이전에 요약하는데 사용했을 때, 시간이 많이 걸리는 것을 보고 좀 꺼려하고 있었다.

하지만 그건 다른 chain들도 함께 작동하고 있어서 그런것이었지, 실제로는 한 요약본에 1분정도 밖에 걸리지 않았다.

결국 Semantic Chunker 를 사용하기로 하고 어떤 프레임워크에서 어떤 임베딩 모델을 사용할지 테스트 하였다.

Semantic Router 설명

Semantic_router 라는 패키지와 (openai embedding 사용) langchain의 Semantic chunker (upstage embedding 사용)를 비교하였는데 위에 설명해도 확실히 chunking이 빠르게 수행되었다. 하지만 openai를 사용한 semantic_router는 너무 잘게 쪼개져서 context 전달이 잘 안될것 같았다. 반면에 upstage를 사용한 sematic chunker는 적절한 크기로 잘려있고 주제도 잘 구분되 있었지만 중간중간에 의미없이 짧은 문장들이 몇개 보였다. (글자 수로 filtering해서 저장하지 않는 함수를 짜 두었다) 

 

결론적으로 upstage embedding model을 사용한 semantic chunker를 사용하여 문장을 분리하였다.

※ 여러 벤치마크 점수를 봐도 한글 embedding에는 upstage가 Top인 것 같다

 

 

5. MetaData Tag

metadata는 이전 포스팅에서 수행한 과정을 그대로 수행했다. (이전 포스팅을 참고)