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: 今後の展望と課題 |