Skip to content

ericsson-kuma/IR

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESG-SASB Matching System | ESG-SASB 匹配系統

English | 中文


English

📌 Project Overview

This project implements a Retrieval-Augmented Generation (RAG) system for matching ESG (Environmental, Social, and Governance) report segments to SASB (Sustainability Accounting Standards Board) metrics. Given a page from an ESG report and a corresponding SASB standard, the system identifies relevant text regions and predicts their bounding boxes along with the matching SASB metric codes.

🎯 Task Definition

  • Input: ESG report PDF page + SASB report (metric definitions)
  • Output: Predicted bounding boxes and corresponding SASB metric codes
  • Evaluation Metric: F1 Score (IoU threshold = 0.5)
  • Goal: F1 > 0.2

📁 Project Structure

IR/
├── main.py                           # 🚀 Main entry point (end-to-end pipeline)
├── config.py                         # ⚙️ Configuration management
├── data/
│   ├── train.json                    # Training data (151 samples)
│   ├── test.json                     # Test data (72 samples)
│   ├── train_solution.csv            # Ground truth labels
│   ├── reports/                      # ESG report PDFs (15 companies)
│   ├── sasb/                         # SASB standard PDFs & markdown (7 industries)
│   └── processed/
│       ├── esg_segments_v2.jsonl     # Extracted ESG segments (OCR)
│       ├── esg_segments_v4.jsonl     # Extracted ESG segments (PyMuPDF)
│       ├── sasb_metrics.json         # Parsed SASB metrics
│       └── sasb_metrics_translated.json
├── scripts/
│   ├── 01_build_esg_segments_v2.py   # Extract ESG segments from PDFs
│   ├── 02_build_sasb_metrics.py      # Parse SASB metrics from markdown
│   ├── 03_make_train_solution_csv.py # Generate solution CSV
│   ├── 04_rag_baseline_infer_v64_selective_merge.py  # Standalone inference
│   ├── ensemble_union.py             # 🎯 Ensemble: union multiple predictions
│   ├── score.py                      # Evaluation script
│   └── analyze_*.py                  # Analysis scripts
├── results/                          # Inference results & submissions
│   ├── test_full_union.csv           # ⭐ Best submission (Private=0.2000)
│   ├── test_v64_selective_merge_gemini3.csv  # Gemini3 predictions
│   ├── test_deepseek_th060_llm8.csv  # DeepSeek predictions
│   └── test_gemma3_th060_llm8.csv    # Gemma3 predictions
├── FINAL_SUMMARY.md                  # 📊 Experiment summary
└── README.md

🔧 Requirements

# Python 3.8+
pip install torch transformers sentence-transformers numpy pandas tqdm openai

# Optional: For Gemini API support
pip install google-generativeai

Required Models:

  • BAAI/bge-m3 - Bi-encoder for semantic retrieval
  • BAAI/bge-reranker-v2-m3 - Cross-encoder for reranking (optional but recommended)

LLM Options (choose one):

  • Ollama (default): Remote/Local LLM server (e.g., minimax-m2:cloud, qwen3:8b)
  • Gemini API: Google's Gemini (gemini-2.5-pro)

🚀 Quick Start

Option 1: Using Main Pipeline (Recommended)

The easiest way to run the system is using main.py:

cd IR

# Run full pipeline (preprocess + inference + evaluate)
python main.py --mode train --full

# Run only inference on test set
python main.py --mode test

# Run only preprocessing
python main.py --preprocess

# Run only evaluation
python main.py --evaluate results/train_v64_selective_merge.csv

# Show current configuration
python main.py --show-config

# Override parameters
python main.py --mode train --score-threshold 0.55 --llm-threshold 8

# Use Gemini API instead of Ollama
export GEMINI_API_KEY="your-api-key-here"
python main.py --mode train --llm-provider gemini

Option 2: Step-by-Step Execution

Step 1: Data Preprocessing

1.1 Extract ESG Segments

Extract text segments from ESG report PDFs:

cd IR
python scripts/01_build_esg_segments_v2.py

This reads content_list.json files (from OCR tools like MinerU) and outputs data/processed/esg_segments_v2.jsonl.

1.2 Parse SASB Metrics

Parse SASB standard documents to extract metrics:

python scripts/02_build_sasb_metrics.py

This reads SASB markdown files from data/sasb/ and outputs data/processed/sasb_metrics.json.

1.3 Generate Solution CSV (Optional)

python scripts/03_make_train_solution_csv.py

Step 2: Run Inference

Training Set:

python scripts/04_rag_baseline_infer_v64_selective_merge.py --mode train

Test Set:

python scripts/04_rag_baseline_infer_v64_selective_merge.py --mode test

Results will be saved to results/train_v64_selective_merge.csv or results/test_v64_selective_merge.csv.

Step 3: Evaluate

python scripts/score.py data/train_solution.csv results/train_v64_selective_merge.csv

Output example:

F1 Score: 0.1618

🔬 Technical Pipeline

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  1. Segment      │     │  2. Bi-encoder   │     │  3. BM25         │
│     Extraction   │ ──► │     Retrieval    │ ──► │     Hybrid       │
│  (OCR/PyMuPDF)   │     │  (bge-m3)        │     │     Search       │
└──────────────────┘     └──────────────────┘     └──────────────────┘
                                                           │
                                                           ▼
                         ┌──────────────────┐     ┌──────────────────┐
                         │  4. Cross-Encoder│     │  5. LLM          │
                         │     Reranking    │ ──► │     Scoring      │
                         │ (bge-reranker)   │     │  (Top-3 only)    │
                         └──────────────────┘     └──────────────────┘
                                                           │
                                                           ▼
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  8. Output       │     │  7. BBox         │     │  6. Candidate    │
│     Results      │ ◄── │     Merging      │ ◄── │     Selection    │
│  (CSV format)    │     │  (Selective)     │     │  (LLM score ≥7)  │
└──────────────────┘     └──────────────────┘     └──────────────────┘

Key Components:

  1. Segment Extraction: Extract text segments with bounding boxes from ESG PDFs
  2. Bi-encoder Retrieval: Use bge-m3 to compute semantic similarity
  3. BM25 Hybrid Search: Combine lexical and semantic matching
  4. Cross-Encoder Reranking (NEW): Use bge-reranker-v2-m3 to filter candidates before LLM
  5. LLM Scoring: Use LLM to score relevance (1-10) on Top-3 candidates only
  6. Selective BBox Merging: Intelligently merge adjacent segments
  7. Output: Generate predictions in CSV format

⚙️ Key Parameters

All parameters are centralized in config.py for easy tuning:

Parameter Value Description
score_threshold 0.52 Bi-encoder similarity threshold
confidence_threshold 7 LLM score threshold (1-10)
use_reranker True Enable cross-encoder reranking
reranker_top_k 5 Keep top-K candidates after reranking
top_k_candidates_per_metric 3 Max segments per metric sent to LLM
horizontal_spread_threshold 200 Pixels threshold for bbox merging
max_merged_ratio 0.50 Maximum merged bbox size (% of page)
bm25_boost_value 0.03 BM25 score boost

Configuration Files:

  • config.py - All configurable parameters (paths, models, thresholds)
  • Modify config.py directly or use command-line overrides with main.py

📊 Performance | 效能表現

Version Train F1 Test Public Test Private Strategy
v22 0.1006 - - Bi-encoder only
v35 0.1127 - - + LLM reranking
v55 0.1387 - - + BM25 hybrid
v64 0.1618 0.1904 0.1250 + Selective merge (Gemini3)
Ensemble - 0.1923 0.2000 Multi-model union

🎯 Best Result: Ensemble Strategy

The best performing submission was achieved using multi-model ensemble:

# Generate predictions from multiple LLMs
python main.py --mode test --llm-provider gemini  # Gemini3 Pro
python main.py --mode test --llm-model deepseek-r1:14b  # DeepSeek R1
python main.py --mode test --llm-model gemma3:12b --llm-threshold 8  # Gemma3

# Combine predictions using union strategy
python scripts/ensemble_union.py \
    results/test_v64_selective_merge_gemini3.csv \
    results/test_deepseek_th060_llm8.csv \
    results/test_gemma3_th060_llm8.csv \
    --output results/test_full_union.csv --stats

Ensemble Union Script Usage:

# Basic usage
python scripts/ensemble_union.py file1.csv file2.csv --output union.csv

# With statistics
python scripts/ensemble_union.py file1.csv file2.csv file3.csv --output union.csv --stats

# Priority: first file's prediction takes precedence
python scripts/ensemble_union.py \
    results/gemini3_predictions.csv \
    results/deepseek_predictions.csv \
    --output results/ensemble.csv

📝 Data Format

Input (train.json):

{
  "id": "003",
  "page": 169,
  "label": ["78.14,238.71,482.26,349.60:TC-SC-320a.1"],
  "company": "tsmc",
  "esg_report": "TSMC_台積電.pdf",
  "sasb_report": "SASB-TC-SC.pdf"
}

Output (CSV):

ID,TARGET
003,78.14,238.71,482.26,349.60:TC-SC-320a.1
004,NONE

📚 References


中文

📌 專案概述

本專案實作了一個 檢索增強生成 (RAG) 系統,用於將 ESG(環境、社會、治理)報告段落匹配到 SASB(可持續會計準則委員會)指標。給定 ESG 報告的特定頁面和對應的 SASB 標準,系統會識別相關文字區域,並預測其邊界框 (bounding box) 及對應的 SASB 指標代碼。

🎯 任務定義

  • 輸入:ESG 報告 PDF 頁面 + SASB 報告(指標定義)
  • 輸出:預測的邊界框和對應的 SASB 指標代碼
  • 評估指標:F1 Score(IoU 閾值 = 0.5)
  • 目標:F1 > 0.2

📁 專案結構

IR/
├── main.py                           # 🚀 主程式入口(端到端流程)
├── config.py                         # ⚙️ 配置管理
├── data/
│   ├── train.json                    # 訓練資料(151 筆)
│   ├── test.json                     # 測試資料(72 筆)
│   ├── train_solution.csv            # 標準答案
│   ├── reports/                      # ESG 報告 PDF(15 家公司)
│   ├── sasb/                         # SASB 標準 PDF 和 markdown(7 個產業)
│   └── processed/
│       ├── esg_segments_v2.jsonl     # 提取的 ESG 段落(OCR 版本)
│       ├── esg_segments_v4.jsonl     # 提取的 ESG 段落(PyMuPDF 版本)
│       ├── sasb_metrics.json         # 解析的 SASB 指標
│       └── sasb_metrics_translated.json
├── scripts/
│   ├── 01_build_esg_segments_v2.py   # 從 PDF 提取 ESG 段落
│   ├── 02_build_sasb_metrics.py      # 從 markdown 解析 SASB 指標
│   ├── 03_make_train_solution_csv.py # 產生答案 CSV
│   ├── 04_rag_baseline_infer_v64_selective_merge.py  # 獨立推理腳本
│   ├── ensemble_union.py             # 🎯 Ensemble:合併多模型預測
│   ├── score.py                      # 評分腳本
│   └── analyze_*.py                  # 分析腳本
├── results/                          # 推理結果與提交檔案
│   ├── test_full_union.csv           # ⭐ 最佳提交 (Private=0.2000)
│   ├── test_v64_selective_merge_gemini3.csv  # Gemini3 預測
│   ├── test_deepseek_th060_llm8.csv  # DeepSeek 預測
│   └── test_gemma3_th060_llm8.csv    # Gemma3 預測
├── FINAL_SUMMARY.md                  # 📊 實驗總結
└── README.md

🔧 環境需求

# Python 3.8+
pip install torch transformers sentence-transformers numpy pandas tqdm openai

# 可選:支援 Gemini API
pip install google-generativeai

必要模型:

  • BAAI/bge-m3 - 用於語義檢索的 Bi-encoder
  • BAAI/bge-reranker-v2-m3 - 用於重排序的 Cross-encoder(可選但推薦)

LLM 選項(選擇其一):

  • Ollama(預設):遠端/本地 LLM 服務(如 minimax-m2:cloudqwen3:8b
  • Gemini API:Google 的 Gemini(gemini-2.5-pro

🚀 快速開始

方法一:使用主程式 (推薦)

最簡單的方式是使用 main.py

cd IR

# 執行完整流程(預處理 + 推理 + 評估)
python main.py --mode train --full

# 僅在測試集上執行推理
python main.py --mode test

# 僅執行預處理
python main.py --preprocess

# 僅執行評估
python main.py --evaluate results/train_v64_selective_merge.csv

# 顯示當前配置
python main.py --show-config

# 覆蓋參數
python main.py --mode train --score-threshold 0.55 --llm-threshold 8

# 使用 Gemini API(而非 Ollama)
export GEMINI_API_KEY="your-api-key-here"
python main.py --mode train --llm-provider gemini

方法二:分步驟執行

步驟 1:資料預處理

1.1 提取 ESG 段落

從 ESG 報告 PDF 中提取文字段落:

cd IR
python scripts/01_build_esg_segments_v2.py

這會讀取 content_list.json 檔案(由 MinerU 等 OCR 工具產生),並輸出 data/processed/esg_segments_v2.jsonl

1.2 解析 SASB 指標

解析 SASB 標準文件以提取指標:

python scripts/02_build_sasb_metrics.py

這會讀取 data/sasb/ 中的 SASB markdown 檔案,並輸出 data/processed/sasb_metrics.json

1.3 產生答案 CSV(可選)

python scripts/03_make_train_solution_csv.py

步驟 2:執行推理

訓練集:

python scripts/04_rag_baseline_infer_v64_selective_merge.py --mode train

測試集:

python scripts/04_rag_baseline_infer_v64_selective_merge.py --mode test

結果將儲存至 results/train_v64_selective_merge.csvresults/test_v64_selective_merge.csv

步驟 3:評估

python scripts/score.py data/train_solution.csv results/train_v64_selective_merge.csv

輸出範例:

F1 Score: 0.1618

🔬 技術流程

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  1. 段落提取      │     │  2. Bi-encoder   │     │  3. BM25         │
│  (OCR/PyMuPDF)   │ ──► │     檢索         │ ──► │     混合搜尋      │
│                  │     │  (bge-m3)        │     │                  │
└──────────────────┘     └──────────────────┘     └──────────────────┘
                                                           │
                                                           ▼
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  6. 輸出結果      │     │  5. Bbox         │     │  4. LLM          │
│  (CSV 格式)      │ ◄── │     合併         │ ◄── │     重排序        │
│                  │     │  (選擇性合併)     │     │  (Qwen2.5-7B)    │
└──────────────────┘     └──────────────────┘     └──────────────────┘

關鍵組件:

  1. 段落提取:從 ESG PDF 中提取帶有邊界框的文字段落
  2. Bi-encoder 檢索:使用 bge-m3 計算語義相似度
  3. BM25 混合搜尋:結合詞彙匹配和語義匹配
  4. Cross-Encoder 重排序(新增):使用 bge-reranker-v2-m3 在 LLM 前過濾候選
  5. LLM 評分:僅對 Top-3 候選進行評分(1-10 分)
  6. 選擇性 Bbox 合併:智慧合併相鄰段落
  7. 輸出:產生 CSV 格式的預測結果

⚙️ 關鍵參數

所有參數都集中在 config.py 中,方便調整:

參數 數值 說明
score_threshold 0.52 Bi-encoder 相似度閾值
confidence_threshold 7 LLM 分數閾值(1-10)
use_reranker True 啟用 Cross-encoder 重排序
reranker_top_k 5 Reranker 後保留的候選數
top_k_candidates_per_metric 3 每個指標最多送幾個給 LLM
horizontal_spread_threshold 200 Bbox 合併的像素閾值
max_merged_ratio 0.50 合併後 bbox 最大尺寸(頁面百分比)
bm25_boost_value 0.03 BM25 分數加成

配置檔案:

  • config.py - 所有可配置參數(路徑、模型、閾值)
  • 可直接修改 config.py 或使用 main.py 的命令列參數覆蓋

📊 效能表現

版本 Train F1 Test Public Test Private 策略
v22 0.1006 - - 僅 Bi-encoder
v35 0.1127 - - + LLM 重排序
v55 0.1387 - - + BM25 混合
v64 0.1618 0.1904 0.1250 + 選擇性合併 (Gemini3)
Ensemble - 0.1923 0.2000 多模型聯集

🎯 最佳結果:Ensemble 策略

最佳提交成績是透過 多模型 Ensemble 達成的:

# 從多個 LLM 產生預測
python main.py --mode test --llm-provider gemini  # Gemini3 Pro
python main.py --mode test --llm-model deepseek-r1:14b  # DeepSeek R1
python main.py --mode test --llm-model gemma3:12b --llm-threshold 8  # Gemma3

# 使用 union 策略合併預測
python scripts/ensemble_union.py \
    results/test_v64_selective_merge_gemini3.csv \
    results/test_deepseek_th060_llm8.csv \
    results/test_gemma3_th060_llm8.csv \
    --output results/test_full_union.csv --stats

Ensemble Union 腳本使用方式:

# 基本使用
python scripts/ensemble_union.py file1.csv file2.csv --output union.csv

# 顯示統計資訊
python scripts/ensemble_union.py file1.csv file2.csv file3.csv --output union.csv --stats

# 優先順序:第一個檔案的預測優先
python scripts/ensemble_union.py \
    results/gemini3_predictions.csv \
    results/deepseek_predictions.csv \
    --output results/ensemble.csv

📝 資料格式

輸入(train.json):

{
  "id": "003",
  "page": 169,
  "label": ["78.14,238.71,482.26,349.60:TC-SC-320a.1"],
  "company": "tsmc",
  "esg_report": "TSMC_台積電.pdf",
  "sasb_report": "SASB-TC-SC.pdf"
}

輸出(CSV):

ID,TARGET
003,78.14,238.71,482.26,349.60:TC-SC-320a.1
004,NONE

🔍 SASB 指標代碼說明

代碼前綴 產業
TC-SC 半導體 (Semiconductors)
TC-HW 硬體 (Hardware)
FN-CB 商業銀行 (Commercial Banks)
EM-RM 石油與天然氣精煉 (Oil & Gas Refining)
HC-BP 生物製藥 (Biotechnology & Pharmaceuticals)
HC-MS 醫療設備 (Medical Equipment & Supplies)
IF-GU 天然氣公用事業 (Gas Utilities)

🐛 常見問題

Q1:模型載入失敗?

# 確保有足夠的 GPU 記憶體(建議 16GB+)
# 或修改腳本使用 CPU

Q2:找不到 content_list.json?

# 需要先用 MinerU 等 OCR 工具處理 PDF
# 或使用 PyMuPDF 版本的 segment 提取腳本

Q3:如何調整閾值?

# 在 04_rag_baseline_infer_v64_selective_merge.py 中修改:
SCORE_THRESHOLD = 0.52          # 提高會減少誤報,降低會減少漏報
LLM_CONFIDENCE_THRESHOLD = 7    # 提高會更嚴格

📚 參考資料


License

MIT License

Author

IRIE Final Project - Fall 2024

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors