굴러가는 분석가의 일상

RAG 성능을 좌지우지 하는 PARSING(파싱)의 한계점 본문

LLM/RAG

RAG 성능을 좌지우지 하는 PARSING(파싱)의 한계점

G3LU 2024. 11. 16. 22:45

본 게시물은 Florian June의 게시물을 참고하였습니다.

💡 PARSING 이란? 

AI를 연구하는 사람들은 일반적으로 특정 문제를 해결하기 위해 모델링을 수행하지만, 이러한 모델링의 성능은 데이터의 에 크게 좌우된다. 데이터의 품질이 높을수록 모델의 예측 정확도와 응답의 신뢰성이 높아지며, 반대로 데이터가 부정확하거나 부족하면 원하는 결과를 얻는건 불가능하다. 따라서 많은 연구자와 개발자들은 데이터를 수집하고 전처리하는 데 상당한 시간과 자원을 투자합니다.

 

RAG도 이와 마찬가지로 데이터의 중요성이 크게 부각이 된다. RAG를 효과적으로 적용하려면, 용도에 적합한 데이터를 수집하고, 이를 체계적으로 파싱(parsing) 및 구조화 하는 것이 상당히 중요하다. 이러한 작업은 단순히 데이터를 모으는 것에서 끝나지 않고, 모델이 효율적으로 검색하고 생성할 수 있도록 적합한 형식으로 가공하는 것 이다. 

 

RAG를 처음 접하는 사람은 단순하게 데이터를 불러 오면 파싱하는 것이 끝아닐까? 라는 생각을 하곤 한다. RAG에 사용되는 데이터 형식을 살펴보면 대부분 정형 데이터 보다 비정형 데이터가 월등히 많은 것을 알 수 있다. 


💡 PDF 파싱이 어려운 점 

비정형 문서인 PDF나 HWP는 회사에서 업무를 처리하거나 학교에서 보고서를 작성할 때 자주 사용된다. 이 중에서도 PDF는 비구조적 문서의 대표적인 예로, DOCX나 HTML처럼 <table>, <p>, <w:p>와 같은 논리적 태그를 사용하지 않고, 렌더링 구조를 기반으로 문서 내용을 정의된다. 즉, PDF는 "화면에 어떻게 보일 것인가"에 초점을 맞추고 있어, 페이지 전체의 레이아웃을 정확히 추출하고, 표, 제목, 단락, 차트, 이미지를 포함한 콘텐츠를 텍스트로 변환하는 것이 상당히 어렵다. 


💡 PDF 파싱의 한계

문서의 특성에 따라 각 섹션의 스타일과 내용들이 이미 사전에 정의되어 이에 따라 파싱하는 것을 의미한다. 하지만 PDF에는 다양한 레이아웃과 유형이 존재하기 때문에 사전에 규칙을 정의한다는 것은 사실상 불가능하여 일반화하기가 어렵다. LangChain(랭체인) 혹은 LlamaIndex(라마인덱스) 등 다양한 RAG 프레임워크에서 일반적으로 사용되는 PDF 파싱은 pypdf에 의해 수행된다. 예시를 통해 pypdf 성능을 한번 알아보도록 하겠다. 본 예시에서 사용된 PDF 문서는 거대 언어 모델의 발전에 크게 기여한 논문 "Attention Is All You Need"의 6번째 장을 활용하였다. 코드와 결과는 아래와 같다. 

# 코드 
import PyPDF2
filename = "1706.03762.pdf"
pdf_file = open(filename, 'rb')

reader = PyPDF2.PdfReader(pdf_file)

page_num = 5
page = reader.pages[page_num]
text = page.extract_text()

print('--------------------------------------------------')
print(text)

pdf_file.close()

# 결과 
Table 1: Maximum path lengths, per-layer complexity and minimum number of sequential operations
for different layer types. nis the sequence length, dis the representation dimension, kis the kernel
size of convolutions and rthe size of the neighborhood in restricted self-attention.
Layer Type Complexity per Layer Sequential Maximum Path Length
Operations
Self-Attention O(n2·d) O(1) O(1)
Recurrent O(n·d2) O(n) O(n)
Convolutional O(k·n·d2) O(1) O(logk(n))
Self-Attention (restricted) O(r·n·d) O(1) O(n/r)
3.5 Positional Encoding
Since our model contains no recurrence and no convolution, in order for the model to make use of the
order of the sequence, we must inject some information about the relative or absolute position of the
tokens in the sequence. To this end, we add "positional encodings" to the input embeddings at the
bottoms of the encoder and decoder stacks. The positional encodings have the same dimension dmodel
as the embeddings, so that the two can be summed. There are many choices of positional encodings,
learned and fixed [9].
In this work, we use sine and cosine functions of different frequencies:
PE(pos,2i)=sin(pos/100002i/d model)
PE(pos,2i+1)=cos(pos/100002i/d model)
where posis the position and iis the dimension. That is, each dimension of the positional encoding
corresponds to a sinusoid. The wavelengths form a geometric progression from 2πto10000 ·2π. We
chose this function because we hypothesized it would allow the model to easily learn to attend by
relative positions, since for any fixed offset k,PEpos+kcan be represented as a linear function of
PEpos.
...
...
...

 

결과를 한번 살펴보면 파싱이 어느정도 되었지만, 치명적인 문제점이 존재한다. Table 1을 보면  Layer Type에 따라 성능 차이를 보여주지만, 파싱된 결과는 성능 차이에 대해 어떠한 내용도 존재하지 않는다. 단순하게 텍스트를 긴 한 문장으로 나열한 것 이다. 즉, 파싱된 결과는 문서의 구조적 정보를 반영하지 않는 것이 가장 큰 문제점이다.