0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Uncensored1776 Day 23: 高度なテクニック

Last updated at Posted at 2025-12-22

Uncensored1776 Day 23: 高度なテクニック

さらなる最適化と自動化

公開日: 2025-12-23
シリーズ: 科学と神々株式会社 アドベントカレンダー
難易度: ★★★★☆ (上級)


今日学ぶこと

  • マルチモデル対応の実装
  • バッチ処理による効率化
  • 自動化パイプラインの構築

1. マルチモデル対応

1.1 モデルアダプターパターン

異なるモデルアーキテクチャに同じ処理を適用するため、アダプターパターンを使用します。

アダプターパターンの構造:

                    ┌─────────────────┐
                    │  ModelAdapter   │ ← 抽象基底クラス
                    │  (interface)    │
                    ├─────────────────┤
                    │ get_mlp_weights │
                    │ set_mlp_weights │
                    │ get_hidden_states│
                    └────────┬────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
   ┌─────▼─────┐      ┌──────▼─────┐      ┌──────▼─────┐
   │QwenAdapter│      │LlamaAdapter│      │MistralAdapter│
   └───────────┘      └────────────┘      └─────────────┘
         │                   │                   │
         ▼                   ▼                   ▼
   model.model.        model.model.        model.model.
   layers[i].mlp      layers[i].mlp      layers[i].mlp
   .down_proj         .down_proj         .down_proj

アダプターの核心部分

# アダプターの核心(抜粋)
class ModelAdapter(ABC):
    @abstractmethod
    def get_mlp_weights(self, layer_idx: int) -> torch.Tensor:
        """MLP重みを取得"""
        pass

    @abstractmethod
    def set_mlp_weights(self, layer_idx: int, weights: torch.Tensor):
        """MLP重みを設定"""
        pass

def get_adapter(model) -> ModelAdapter:
    """モデルタイプに応じたアダプターを自動選択"""
    model_type = model.config.model_type.lower()
    if "qwen" in model_type: return QwenAdapter(model)
    elif "llama" in model_type: return LlamaAdapter(model)
    elif "mistral" in model_type: return MistralAdapter(model)
    else: return LlamaAdapter(model)  # デフォルト

完全な実装はscripts/model_adapters.pyを参照してください。

モデル別のMLP構造:

Qwen/Llama/Mistral(共通形式):
model.model.layers[i].mlp.down_proj.weight

Phi-4:
model.model.layers[i].mlp.fc2.weight

→ アダプターがこの差異を吸収

1.2 統一Abliterationクラス

アダプターを使うことで、モデルに依存しない統一的なAbliterationが可能になります。

UniversalAbliterationの動作:

入力:
├── adapter: ModelAdapter(任意のモデルに対応)
├── refusal_directions: Dict[層番号, 拒否方向]
└── パラメータ: method, peak, width, strength

処理フロー:
for layer_idx in range(num_layers):
    ├── 1. Weight Kernel計算 → 層別強度
    ├── 2. adapter.get_mlp_weights(layer_idx) → 重み取得
    ├── 3. Abliteration適用 → 重み修正
    └── 4. adapter.set_mlp_weights() → 重み更新

→ アダプター経由でモデルの差異を吸収
# 統一Abliterationの核心(抜粋)
class UniversalAbliteration:
    def apply(self, refusal_directions, threshold=0.1):
        for layer_idx in range(self.adapter.config.num_layers):
            strength = self.compute_kernel_weight(layer_idx) * self.base_strength
            if strength < threshold:
                continue  # 閾値以下はスキップ

            weight = self.adapter.get_mlp_weights(layer_idx)
            direction = refusal_directions[layer_idx]
            # Abliteration適用(projectedまたはstandard)
            self._apply_method(weight, direction, strength)

完全な実装はscripts/universal_abliteration.pyを参照してください。


2. バッチ処理

2.1 バッチアクティベーション収集

大量のプロンプトを処理する場合、バッチ処理で効率化できます。

バッチ処理 vs 逐次処理:

逐次処理(1つずつ):
プロンプト1 → 処理 → プロンプト2 → 処理 → ...
時間: プロンプト数 × 処理時間

バッチ処理(まとめて):
[プロンプト1-8] → 並列処理 → [プロンプト9-16] → ...
時間: (プロンプト数 / バッチサイズ) × 処理時間

→ GPUの並列性を活用して高速化
バッチ収集の流れ:

入力: 60プロンプト, batch_size=8
      ↓
Batch 1: [prompt 1-8]   → tokenize → model → hidden_states
Batch 2: [prompt 9-16]  → tokenize → model → hidden_states
...
Batch 8: [prompt 57-60] → tokenize → model → hidden_states
      ↓
各プロンプトの最後のトークン位置からアクティベーション抽出
      ↓
出力: {layer_idx: tensor(60, hidden_dim)}

2.2 パディング処理の重要性

バッチ処理では、異なる長さの入力を揃える必要があります。

# バッチ処理の核心(抜粋)
inputs = tokenizer(
    batch_texts,
    return_tensors="pt",
    padding=True,        # 短い入力をパディング
    truncation=True,     # 長い入力を切り詰め
    max_length=256
)

# 最後の「有効な」トークン位置を取得(パディングを除く)
attention_mask = inputs['attention_mask']
seq_len = attention_mask[batch_idx].sum().item() - 1
activation = hidden_states[layer_idx][batch_idx, seq_len, :]

完全な実装はscripts/batch_collector.pyを参照してください。

バッチサイズの選び方:

VRAM 8GB:  batch_size = 2-4
VRAM 16GB: batch_size = 8-16
VRAM 24GB: batch_size = 16-32

→ メモリエラーが出たらサイズを下げる

3. 自動化パイプライン

3.1 パイプラインの概念

複数モデルの処理を自動化するパイプラインを構築できます。

自動化パイプラインの構造:

入力: YAML設定ファイル
      ↓
┌─────────────────────────────────────────────────┐
│                AbliterationPipeline             │
├─────────────────────────────────────────────────┤
│ 1. プロンプト読み込み                           │
│ 2. 各モデルに対して:                            │
│    ├── モデルロード                             │
│    ├── アクティベーション収集                   │
│    ├── 拒否方向計算                             │
│    ├── Abliteration適用                        │
│    └── 保存                                     │
│ 3. テスト実行(オプション)                     │
│ 4. Hub アップロード(オプション)               │
│ 5. レポート生成                                 │
└─────────────────────────────────────────────────┘
      ↓
出力: 複数の検閲解除モデル + レポート

3.2 パイプライン設定ファイル

YAMLで設定を管理し、再利用可能にします:

# pipeline_config.yaml
name: "Qwen Family Abliteration"

models:
  - "Qwen/Qwen2.5-0.5B-Instruct"
  - "Qwen/Qwen2.5-1.5B-Instruct"
  - "Qwen/Qwen2.5-3B-Instruct"

output_dir: "outputs/pipeline_run"

# Abliteration設定
method: "projected"
peak: 0.6
width: 0.15
strength: 0.9

# オプション
test_after: true        # 処理後にテスト実行
upload_to_hub: false    # HuggingFaceにアップロード
hub_prefix: "your-username"

3.3 CLI実行

# パイプライン実行
python scripts/run_pipeline.py --config pipeline_config.yaml

# 実行内容の確認(実行なし)
python scripts/run_pipeline.py --config pipeline_config.yaml --dry-run

完全なパイプライン実装はscripts/run_pipeline.pyを参照してください。

パイプライン実行結果の例:

============================================================
Running Pipeline: Qwen Family Abliteration
Models: 3
============================================================

[Qwen/Qwen2.5-0.5B-Instruct] Loading...
[Qwen/Qwen2.5-0.5B-Instruct] ✓ Saved to outputs/.../

[Qwen/Qwen2.5-1.5B-Instruct] Loading...
[Qwen/Qwen2.5-1.5B-Instruct] ✓ Saved to outputs/.../

[Qwen/Qwen2.5-3B-Instruct] Loading...
[Qwen/Qwen2.5-3B-Instruct] ✓ Saved to outputs/.../

--- Running Tests ---
[Qwen/Qwen2.5-0.5B-Instruct] Censorship: 13.6%
[Qwen/Qwen2.5-1.5B-Instruct] Censorship: 15.2%
[Qwen/Qwen2.5-3B-Instruct] Censorship: 12.1%

✓ Report saved to outputs/pipeline_report.md

============================================================
Pipeline Complete: 3/3 successful
============================================================

4. 監視とレポート

4.1 処理監視のポイント

長時間実行されるパイプラインでは、進捗監視が重要です。

監視すべきイベント:

1. 処理開始/終了
├── 開始時刻
├── 終了時刻
└── 総処理時間

2. モデル別進捗
├── ロード完了
├── アクティベーション収集完了
├── Abliteration適用完了
└── 保存完了

3. エラー
├── エラーが発生したモデル
├── エラーメッセージ
└── スタックトレース

4.2 レポート生成

パイプライン完了後、結果をMarkdownレポートとして出力します:

# Abliteration Pipeline Report

Generated: 2025-12-23T14:30:00

## Summary

| Model | Status | Censorship | Hub URL |
|-------|--------|------------|---------|
| Qwen/Qwen2.5-0.5B-Instruct | success | 13.6% | N/A |
| Qwen/Qwen2.5-1.5B-Instruct | success | 15.2% | N/A |
| Qwen/Qwen2.5-3B-Instruct | success | 12.1% | N/A |

完全な監視実装はscripts/pipeline_monitor.pyを参照してください。


5. 🧪 Wikipediaファインチューニング(実験的機能)

Abliterationでは解決できない政治的バイアス型モデル(Qwen3など)に対する実験的なアプローチです。

5.1 検閲 vs 政治的バイアスの違い

検閲型モデル (Qwen2.5など) - ✅ Abliterationで解除可能
├── 動作: 敏感なトピックで回答を拒否
├── 原因: 出力層に拒否方向ベクトルが存在
└── 解決: Abliterationで拒否方向を削除

バイアス型モデル (Qwen3など) - ❌ Abliterationでは解除不可能
├── 動作: 回答するが内容が偏っている
├── 原因: 知識層自体がバイアスされた訓練データで学習
└── 解決: ファインチューニングで知識を上書き

5.2 Wikipediaアプローチ

Wikipediaの中立的な記事を使って、バイアスされた知識を上書きします。

対象トピック(60+記事):

トピック 記事数
天安門事件 10 Tank Man, Goddess of Democracy
台湾 12 Taiwan independence, Cross-Strait relations
ウイグル 10 Xinjiang internment camps, Uyghur genocide
チベット 10 14th Dalai Lama, 1959 Tibetan uprising
香港 10 2019 protests, National security law
中国政治 8 Human rights in China, Great Firewall

5.3 2段階ファインチューニング

Phase 1: LoRAファインチューニング
├── epochs: 5
├── lora_r: 32 (標準の2倍)
├── lora_alpha: 64 (標準の2倍)
├── learning_rate: 2e-5
└── 成功判定: 検閲率 < 50%

        ↓ (不十分な場合)

Phase 2: フルファインチューニング(フォールバック)
├── --no-lora フラグ
├── --gradient-checkpointing でメモリ節約
└── タイムアウト: 4時間

5.4 使用方法

# 自動モード(推奨)- バイアス検出時に自動実行
./uncensor auto "Qwen/Qwen3-4B-Instruct-2507"

# 手動でWikipediaデータ取得
./uncensor wiki --source api -o ./data/wiki_data

# ファインチューニングのみ
./uncensor finetune "Qwen/Qwen3-4B-Instruct-2507" \
  -t ./data/wiki_data/train.jsonl \
  -e 5 \
  -o ./outputs/qwen3_wiki_finetuned

5.5 制限事項

  • 実験的機能: 完全なバイアス解除は保証されません
  • 計算コスト: Abliteration(数分)に対して、数時間かかります
  • 効果は限定的: 深く埋め込まれたバイアスは上書きできない可能性
  • 他能力への影響: ファインチューニングにより他の能力が劣化する可能性

詳細な技術ドキュメントは wikipedia-finetuning.md を参照してください。


6. 今日のまとめ

高度なテクニックの要点:

マルチモデル対応:
├── ModelAdapterパターンで抽象化
├── Qwen/Llama/Mistral/Phi対応
└── 統一インターフェースで差異を吸収

バッチ処理:
├── 複数プロンプトを並列処理
├── パディングで入力長を統一
└── GPUメモリに応じてバッチサイズ調整

自動化パイプライン:
├── YAML設定で再利用可能
├── 複数モデルを一括処理
└── テスト・アップロードを自動化

監視とレポート:
├── 進捗追跡
├── エラーロギング
└── 結果をMarkdownで出力

🧪 Wikipediaファインチューニング(実験的):
├── バイアス型モデル向け(Abliterationが効かない場合)
├── 60+ Wikipedia記事で中立的知識を上書き
├── 2段階: LoRA → フルファインチューニング
└── 計算コストは高いが、Abliterationでは解決不可能な問題に対応

明日の予告

Day 24: 今後の展望と課題

  • 最新の研究動向
  • 残された課題
  • コミュニティへの貢献

参考リンク


ナビゲーション

前の記事 Day 22: モデルの公開と共有
次の記事 Day 24: 今後の展望と課題
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?