AI・機械学習
上級

ドメイン増分学習(ドメインゾウブンガクシュウ)

タスクIDを明示せずに複数の異なるドメインを順次学習する継続学習設定。モデルは推論時にどのドメインのデータか識別せずに全ドメインで高性能を維持することが求められる。

0 回閲覧
0 いいね
2026/6/6 更新
関連タグ
継続学習
ドメイン適応
増分学習
タスクフリー推論
LLM

ドメイン増分学習とは

ドメイン増分学習(Domain-Incremental Learning, Domain-IL)は、異なるデータ分布(ドメイン)から構成される複数のタスクを順次学習する継続学習の設定の一つ。タスク増分学習・クラス増分学習と並ぶ継続学習の基本3パラダイムの中で、最も実用的な設定とされる。

継続学習3設定の比較

設定1: タスク増分学習(Task-IL)
- 学習時: タスクA→B→C を順次学習
- 推論時: タスクID が明示される
- 難易度: 易(タスクIDで出力ヘッドを切り替え可能)
- 例: A=犬/猫分類, B=車/バイク分類(別ヘッド)

設定2: ドメイン増分学習(Domain-IL)★
- 学習時: ドメインA→B→C を順次学習
- 推論時: ドメインIDなし(どのドメインか不明)
- 難易度: 中(出力空間は同じ、入力分布が変化)
- 例: 医療→法律→金融テキストで同一の質問応答タスク

設定3: クラス増分学習(Class-IL)
- 学習時: クラス群を順次追加
- 推論時: 全クラスから識別(タスクIDなし)
- 難易度: 難(出力空間も拡大、全クラス混在で推論)
- 例: 10クラスずつ画像認識クラスを追加

LLMにおけるドメイン増分学習

定義

LLMのDomain-ILは以下の形式で定式化:

T = {D₁, D₂, ..., Dₙ}  (ドメインのシーケンス)
各Dᵢ = {(xᵢ, yᵢ)}: 入力xᵢと正解yᵢのペア
- 入力分布 P(xᵢ) が各ドメインで異なる
- タスク(出力形式)は共通
- 推論時: テスト入力xがどのドメインか不明

目標: 任意の入力xに対して最適な出力yを予測

実用シナリオ例

# 医療→法律→金融→技術 の順次ドメイン学習
domains = [
    {"name": "medical", "data": medical_corpus,
     "eval": medical_qa_benchmark},
    {"name": "legal", "data": legal_corpus,
     "eval": legal_qa_benchmark},
    {"name": "financial", "data": financial_corpus,
     "eval": financial_qa_benchmark},
    {"name": "tech", "data": tech_corpus,
     "eval": tech_qa_benchmark},
]

results = {}
for i, domain in enumerate(domains):
    print(f"\n=== ドメイン {i+1}: {domain['name']} ==="")
    
    # 新ドメインで継続事前学習
    train_on_domain(model, domain["data"])
    
    # 全ドメインで評価(Domain-ILの要件)
    for eval_domain in domains[:i+1]:
        score = evaluate(model, eval_domain["eval"])
        results[(i, eval_domain["name"])] = score
        print(f"  {eval_domain['name']}: {score:.3f}")

評価マトリクス(R matrix)

学習後 →         D1学習後  D2学習後  D3学習後  D4学習後
D1(医療)テスト:  0.85      0.71      0.62      0.58
D2(法律)テスト:  ---       0.82      0.74      0.69
D3(金融)テスト:  ---       ---       0.79      0.73
D4(技術)テスト:  ---       ---       ---       0.81

対角要素: 各ドメイン直後の性能(最高値)
左上三角: 後続学習による忘却の度合い

主要手法

1. リプレイベース(最も効果的)

class DomainILWithReplay:
    def __init__(self, model, buffer_size=1000):
        self.model = model
        self.memory_buffer = []
        self.buffer_size = buffer_size
    
    def learn_new_domain(self, new_data, new_domain_name):
        # リプレイバッファを構築/更新
        self._update_buffer(new_domain_name)
        
        # 新ドメイン + リプレイデータを混合
        replay_data = self._sample_from_buffer()
        mixed_data = ConcatDataset([new_data, replay_data])
        
        # 混合データで学習
        train(self.model, mixed_data)
        
        # 新ドメインの代表サンプルをバッファに追加
        new_samples = sample_representative(new_data, self.buffer_size)
        self.memory_buffer.extend(new_samples)
    
    def _sample_from_buffer(self):
        # 均等サンプリング(Reservoir Sampling)
        n = min(len(self.memory_buffer), self.buffer_size)
        return random.sample(self.memory_buffer, n)

2. 動的アーキテクチャ

# ドメイン検出 + ルーティング機構
class DomainRouter(nn.Module):
    def __init__(self, hidden_size, num_domains):
        super().__init__()
        # ドメイン識別器(テスト時も使用)
        self.domain_classifier = nn.Linear(hidden_size, num_domains)
        # ドメインごとのLoRAアダプタ
        self.domain_adapters = nn.ModuleList([
            LoRAAdapter(hidden_size) for _ in range(num_domains)
        ])
    
    def forward(self, x, hidden_states):
        # 入力から自動的にドメインを推定
        domain_logits = self.domain_classifier(hidden_states.mean(1))
        domain_weights = torch.softmax(domain_logits, dim=-1)
        
        # ソフトルーティング(全アダプタを重み付き加算)
        adapter_output = sum(
            w * adapter(x)
            for w, adapter in zip(
                domain_weights.unbind(-1), self.domain_adapters
            )
        )
        return adapter_output

3. プロンプトベース(LLM特有)

# ドメイン適応プロンプトを継続的に学習
class PromptPool:
    def __init__(self, num_prompts=100, prompt_length=10, embed_dim=768):
        # プロンプトプール: 学習可能なベクトルの集合
        self.pool = nn.Parameter(
            torch.randn(num_prompts, prompt_length, embed_dim)
        )
        self.prompt_key = nn.Parameter(
            torch.randn(num_prompts, embed_dim)
        )
    
    def retrieve_prompts(self, query, top_k=5):
        """入力に最も関連するプロンプトを検索"""
        similarity = F.cosine_similarity(
            query.unsqueeze(1),  # (B, 1, D)
            self.prompt_key.unsqueeze(0),  # (1, N, D)
            dim=-1
        )  # (B, N)
        top_indices = similarity.topk(top_k, dim=-1).indices
        return self.pool[top_indices]  # (B, top_k, L, D)

実用的なベンチマーク(2025年)

  • CIL-Benchmark: 5ドメイン(ニュース/医療/法律/金融/コード)のQAタスク
  • CLEVer: 言語理解の継続学習評価
  • TRACE: LLMの継続学習包括ベンチマーク

課題

  1. ドメイン境界の曖昧さ: 実際のデータは複数ドメインが混在
  2. ドメイン数の増加: ドメインが増えるほど忘却リスクが増大
  3. 評価コスト: 全ドメインのベンチマーク維持に計算コスト
  4. 分布シフトの定義: どこまでをドメイン変化と定義するかが曖昧
この記事について
カテゴリーAI・機械学習
難易度上級
作成日2026/6/6