papermage
⚠️ 이 프로젝트는 EMNLP 2023을 위한 연구 프로토타입입니다. 다른 프로젝트 우선순위로 인해 정기적인 주기로 이슈를 다루거나 유지보수하기 어려울 수 있습니다. 현재 Dolma 프로젝트 배너 아래에서 관련 과학 논문 PDF 파싱 기능을 개발하고 있으니, 곧 새로운 릴리스가 있을지 주목해 주십시오. 감사합니다!
설치 (Setup)
conda create -n papermage python=3.11
conda activate papermage
소스에서 설치하는 경우:
pip install -e '.[dev,predictors,visualizers]'
PyPi에서 설치하는 경우:
pip install 'papermage[dev,predictors,visualizers]'
(명령줄 셸에 따라 따옴표를 추가하거나 제거해야 할 수 있습니다).
MacOSX를 사용하는 경우 다음 명령도 실행해야 합니다:
단위 테스트 (Unit testing)
가장 최근 실패한 테스트의 경우
python -m pytest --lf --no-cov -n0
특정 클래스의 특정 테스트 이름을 확인하는 경우
python -m pytest -k 'TestPDFPlumberParser' --no-cov -n0
빠른 시작 (Quick start)
1. PDF에서 처음으로 문서 생성하기
from papermage.recipes import CoreRecipe
recipe = CoreRecipe()
...
2. 출력 이해하기: Document 클래스
Document란 무엇일까요? 최소한 그것은 .symbols 레이어 아래에 저장된 일부 텍스트이며, 이는 단순히 <str>입니다. 예를 들면:
> doc.symbols
"PaperMage: A Unified Toolkit for Processing, Representing, and\nManipulating Visually-..."
하지만 이 라이브러리는 .symbols를 분할하는 여러 가지 다른 방법을 가지고 있을 때 정말 유용합니다. 예를 들어, 논문을 페이지(Pages)로 분할하고, 그 다음 각 페이지를 행(Rows)으로 분할하는 경우입니다:
for page in doc.pages:
print(f'
=== PAGE: {page.id} ===
')
for row in page.rows:
...
이것은 이 라이브러리의 두 가지 좋은 측면을 보여줍니다:
-
Document는 symbols의 다양한 세그멘테이션에 대한 이터러블(iterables)을 제공합니다. 옵션으로는 pages, tokens, rows, sentences, sections 등이 있습니다. 물론 모든 Parser가 모든 세그멘테이션을 제공하는 것은 아닙니다.
-
이러한 각 세그먼트(우리 라이브러리에서는 Entity 객체라고 부릅니다)는 다른 세그먼트 유형에 대해 인지하고 (접근할 수 있으며) 이를 활용할 수 있습니다. 예를 들어, 특정 Page와 교차하는 모든 Row를 얻으려면 page.rows를 호출할 수 있습니다. 또는 특정 Sentence와 교차하는 모든 Token을 얻으려면 sent.tokens를 호출할 수 있습니다. 혹은 특정 Sentence와 교차하는 Row(들)를 얻으려면 sent.rows를 호출할 수 있습니다. 이러한 인덱스는 Document가 생성될 때, 그리고 새로운 Entity 유형이 추가될 때마다 동적으로 구축됩니다. 극단적인 경우까지도, 해당 레이어들이 Document에 사용 가능하다면 다음과 같이 작성할 수 있습니다:
for page in doc.pages:
for sent in page.sentences:
for row in sent.rows:
...
사용 가능한 레이어는 다음을 통해 확인할 수 있습니다:
> doc.layers
['tokens',
'rows',
...
3. Entity의 교차 이해하기
Entity가 반드시 서로 완벽하게 중첩되는 것은 아니라는 점에 유의하십시오. 예를 들어, 다음 코드를 실행하면 어떻게 되는지 살펴보겠습니다:
for sent in doc.sentences:
for row in sent.rows:
print([token.text for token in row.tokens])
문장(sentence) 밖에 있는 Token도 여전히 출력될 수 있습니다. 이는 우리가 Sentence에서 그 Row들로 넘어갈 때, 해당 Sentence와 어떤 중첩이라도 가진 모든 Row를 찾기 때문입니다. Row는 문장의 경계를 넘어서 확장될 수 있으며, 따라서 해당 문장 밖에 있는 Token을 포함할 수도 있습니다.
이 라이브러리를 사용하는 핵심 측면은 이러한 다양한 레이어들이 어떻게 정의되었는지 이해하고, 그것들이 서로 어떻게 상호작용할지 예측하는 것입니다. 우리는 직관적인 결정을 내리려고 노력하지만, 사용자들에게 익숙해지도록 레이어를 실험해 보시기를 요청합니다.
4. Entity에는 무엇이 들어 있나요?
각 Entity 객체는 자신의 내용물과 위치에 대한 정보를 저장합니다:
-
.spans: List[Span], Span은 Document.symbols 내부의 포인터입니다 (즉, Span(start=0, end=5)는 symbols[0:5]에 해당합니다). 기본적으로 Entity를 반복하면 그 .spans를 반복하게 됩니다.
-
.boxes: List[Box], Box는 페이지 상의 직사각형 영역을 나타냅니다. 각 스팬(span)은 박스(Box)와 연결됩니다.
-
.metadata: Metadata, 해당 Entity에 대한 추가 메타데이터를 저장하기 위한 자유 형식의 딕셔너리 같은 객체입니다. 보통 이 필드는 비어 있습니다.
5. 나만의 Document는 어떻게 수동으로 생성할 수 있나요?
Document는 세 가지 유형의 도구인 Parsers, Rasterizers, 그리고 Predictors를 연결하여 만들어집니다.
-
Parsers는 PDF를 입력받아 .symbols와 다른 레이어들로 구성된 Document를 반환합니다. 우리가 사용하는 예시 도구는 PDFPlumber (MIT 라이선스)를 래핑한 것입니다.
-
Rasterizers는 PDF를 입력받아 페이지당 하나의 Image를 반환하며, 이는 Document.images에 추가됩니다. 우리가 사용하는 예시 도구는 PDF2Image (MIT 라이선스)입니다.
-
Predictors는 Document를 입력받아 새로운 세트의 Entity 객체를 계산하기 위해 어떤 연산을 적용하고, 이 객체들은 우리의 Document에 삽입될 수 있습니다. 이들은 모두 내부적으로 구축되었으며 간단한 휴리스틱(heuristics)이거나 완전한 머신러닝 모델일 수 있습니다.
6. 내 Document를 어떻게 저장할 수 있나요?
import json
with open('filename.json', 'w') as f_out:
json.dump(doc.to_json(), f_out, indent=4)
이는 다음과 유사한 내용을 생성합니다:
{
"symbols": "PaperMage: A Unified Toolkit for Processing, Representing, an...",
"entities": {
...
7. 내 Document를 어떻게 불러올 수 있나요?
이 방법들을 사용하여 다음과 같이 Document를 다시 재구성할 수 있습니다:
with open('filename.json') as f_in:
doc_dict = json.load(f_in)
doc = Document.from_json(doc_dict)
참고: 문서에 레이어를 추가하는 일반적인 패턴은 이전에 저장된 문서를 불러와서, 그 위에 추가 Predictors를 실행하고 결과를 저장하는 것입니다.
자세한 내용은 papermage/predictors/README.md를 참조하여 자체 데이터로 커스텀 예측기(predictor)를 학습할 수 있습니다.
더 많은 사용 패턴을 안내하는 노트북은 papermage/examples/quick_start_demo.ipynb에서 확인하실 수 있습니다.