🔥

コンテキストアウェアリフレクティブ方式QAデータセット生成システムの実装

2024/11/26に公開

はじめに

このノートブックでは、LLMを使用して高品質なQAデータセットを生成するシステムを実装します。特徴は以下の通りです:

  • コンテキストアウェアな質問生成
  • リフレクティブな品質評価・改善
  • 自動的なデータセットのアップロード

環境セットアップ

!pip install -q litellm tqdm loguru wikipedia transformers
!pip install -q datasets huggingface-hub

必要なライブラリをインストールします。主な依存関係:

  • litellm: LLMとの対話用
  • tqdm: プログレスバー表示
  • loguru: ロギング
  • wikipedia: Wikipedia APIクライアント
  • transformers & datasets: Hugging Face関連

基本設定とインポート

import wikipedia
import json
from typing import List, Dict, Any
from loguru import logger
import re
from tqdm import tqdm
from datetime import datetime
from pathlib import Path

# 基本パラメータ
MODEL_NAME = "ollama/llama3.1:8b-instruct-fp16"
DEFAULT_CHUNK_SIZE = 200
DEFAULT_OVERLAP_SIZE = 500
DEFAULT_QA_PAIRS_PER_CHUNK = 5
API_BASE = "http://localhost:11434"

主な設定項目の説明:

  • MODEL_NAME: 使用するLLMモデル
  • DEFAULT_CHUNK_SIZE: テキスト分割サイズ
  • DEFAULT_OVERLAP_SIZE: チャンク間のオーバーラップ
  • DEFAULT_QA_PAIRS_PER_CHUNK: 1チャンクあたりのQA生成数

WikiTextProcessor クラスの実装

class WikiTextProcessor:
    """Wikipediaテキストの処理とチャンク分割を行うクラス"""
    
    @staticmethod
    def get_wiki_text(topic: str, lang: str = "ja") -> str:
        """指定されたトピックのWikipedia記事を取得"""
        wikipedia.set_lang(lang)
        try:
            page = wikipedia.page(topic)
            return page.content
        except Exception as e:
            logger.error(f"Error fetching {topic}: {e}")
            return ""

    @staticmethod
    def clean_text(text: str) -> str:
        """テキストのクリーニング"""
        text = re.sub(r'\[\d+\]', '', text)  # 参照記号の削除
        text = re.sub(r'\n\s*\n', '\n', text)  # 余分な改行の削除
        return text.strip()

WikiTextProcessorの機能:

  • Wikipedia記事の取得
  • テキストのクリーニング
  • チャンク分割とコンテキスト付与

QAGenerator クラス

class QAGenerator:
    """Q&Aペアの生成を担当するクラス"""
    
    @staticmethod
    def generate_qa_pairs_with_context(
        chunk_data: Dict[str, str],
        num_pairs: int = DEFAULT_QA_PAIRS_PER_CHUNK,
        max_retries: int = 3
    ) -> List[Dict[str, str]]:
        # プロンプトの構築
        prompt = f"""
以下のテキストから質問と回答のペアを{num_pairs}つ生成してください。

## 全体の文脈:
{chunk_data['summary']}

## テキストの位置:
テキスト全体の{int(chunk_data['position'] * 100)}%付近

## メインテキスト:
{chunk_data['chunk_text']}

出力形式:
{{
    "qa_pairs": [
        {{"question": "具体的な質問1?", "answer": "回答1"}},
        {{"question": "具体的な質問2?", "answer": "回答2"}}
    ]
}}
"""
        # LLMを使用してQAペアを生成

QAGeneratorの主な特徴:

  • コンテキストを考慮したQA生成
  • 固有名詞の明示的な使用
  • 質問の独立性確保

リフレクティブな評価と改善

@dataclass
class QAEvaluation:
    """Q&Aペアの評価結果を保持するデータクラス"""
    score: float
    feedback: str
    improvement_suggestions: List[str]
    factuality_score: float
    question_quality_score: float
    answer_completeness_score: float

def evaluate_qa_pair(self, qa_pair: Dict[str, str], context: Dict[str, str]) -> QAEvaluation:
    """Q&Aペアを評価し、詳細なフィードバックを生成"""
    evaluation_prompt = f"""
質問: {qa_pair['question']}
回答: {qa_pair['answer']}

以下の基準で評価してください:
1. 事実性 (0-1)
2. 質問の質 (0-1)
3. 回答の完全性 (0-1)
"""
    # LLMを使用して評価を実行

評価システムのポイント:

  • 複数の評価基準
  • 具体的な改善提案
  • 反復的な品質向上

データセット生成とアップロード

def create_dataset(self, topics: List[str], output_file: str = "qa_dataset.json") -> None:
    """データセット生成のメインプロセス"""
    all_qa_pairs = []
    
    for topic in topics:
        # Wikipedia記事の取得と処理
        text = self.wiki_processor.get_wiki_text(topic)
        text = self.wiki_processor.clean_text(text)
        
        # チャンク分割とQA生成
        chunks = self.wiki_processor.split_into_chunks_with_context(text)
        for chunk in chunks:
            qa_pairs = self.qa_generator.generate_qa_pairs_with_reflection(chunk)
            all_qa_pairs.extend(qa_pairs)
    
    # 結果の保存
    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(all_qa_pairs, f, ensure_ascii=False, indent=2)

最後に、生成したデータセットをHugging Faceにアップロードする機能も実装されています。

パラメータチューニングのヒント

効果的なデータセット生成のためのパラメータ調整のコツ:

  1. チャンクサイズ(chunk_size)

    • 推奨: 200-300文字
    • 長すぎると文脈が散漫に
    • 短すぎると文脈が失われる
  2. オーバーラップサイズ(overlap_size)

    • 推奨: チャンクサイズの40-60%
    • 文脈の連続性維持が重要
  3. 品質閾値(quality_threshold)

    • 推奨: 0.8以上
    • 厳しすぎると生成数が減少
    • 緩すぎると品質が低下

使用例

# データセット生成の実行
creator = DatasetCreator(config={
    "chunk_size": 200,
    "overlap_size": 500,
    "qa_pairs_per_chunk": 5,
    "quality_threshold": 0.8,
    "max_improvement_attempts": 2
})

topics = ["霊烏路空", "物部布都"]
creator.create_dataset(topics=topics, output_file="touhou_qa.json")

このシステムの特長は、単なるQA生成だけでなく、生成された各QAペアに対して品質評価と改善を行う点です。これにより、より高品質なデータセットの作成が可能になります。

📒ノートブック

https://colab.research.google.com/drive/1OYdgAuXHbl-0LUJgkLl_VqknaAEmAm0S?usp=sharing

Discussion