⚠️ NSFW 研究記録。露骨な解剖学的描写を含む比較画像を末尾セクションに掲載しています。18 歳以上向け。検証目的の研究記事です。
要点
OpenWeight アリーナ上位の画像生成モデル HiDream-O1-Image (8B) に NSFW + アニメ質感の特化チューニングを当てる過程で、露骨な解剖学的描写 (penis 等) を解禁できない壁にぶつかった。最初は「ベースモデルの safety alignment が pixel head に焼き込まれている」という層問題を疑ったが、真因はそこではなく、自分たちのキャプション生成器 (Gemma-4 E4B) が "fellatio" を "oral sex" に丸め込み、明示的な解剖学用語を平準化して学習信号を希釈していたこと。
キャプション生成器を Grok-4.3 に差し替え、2 段階プロンプト (多肢選択での概念抽出 → 強制含有でのキャプション組み立て) で 1250 枚を再キャプション。"penis" 含有率は 13% → 55%、"fellatio" は 3% → 19% に跳ねた。bitsandbytes の 8-bit Adam で 8B モデルを 96 GB GPU 単体で全層ファインチューン、3000 step / 28 分。同じ画像の旧キャプション "oral sex" では描けなかった penis が、再キャプション後の "fellatio on an erect penis" では明確に描画されるようになった。
副産物として汎用性の高い SFW モデルが手に入った。NSFW 特化で 9000 step 回しても致命的忘却は起きず、SFW / Mature / トップレス / 全裸 / 写実 ⇔ アニメ のスタイル切替まで完全保持されている。
ただし重要な訂正として、検証中に観察できた現象は 2 つの異なる学習挙動が同居している ことが分かった。penis は base に概念がほぼ無い「新規習得」型(典型的な段階的描画破綻 → 形状接近の軌跡)、乳首は base に概念があるが品質下限が低い「既存だが粗い」型。前者は学習データの語彙修復 + step 数で前進したが、後者は今回の介入では品質改善がほぼ見られなかった (詳細は後段)。

背景
うちのサービス kotonia.ai では HiDream-O1-Image を /studio に常駐させ、自作 LoRA kotonia01/02 を載せてアニメ質感ブーストを公開している。kotonia02 は 191 枚の手動選別データで rank 16・1200 step、modern-anime / コミュニティ流のスタイル付け効果は確実に出ていた。
ただ NSFW 寄りのプロンプトを投げると:
- 上着脱ぎ・トップレスくらいは普通に出る
- けど 露骨な性器描写・性行為描写になるとベースの safety バイアスを引きずって柔らかく逃げる
これを正面から潰しに行こう、というのが今回の出発点。kotonia02 までで仕込んでた「ノイズ画像で隠して泥臭く押し込む」みたいなテクニックは限界が見えていた。
アプローチ 1: LoRA をひたすら厚くする (失敗の系譜)
最初の素朴な仮説は「データ量と学習量が足りないだけ」。
公開画像プラットフォームの認証付き API から 5000 枚 (プラットフォーム独自の NSFW レベル分類 5 tier を 15/15/20/25/25 の比率で混ぜ、高反応順で engagement 50 以上) を収集、自前の並列ダウンローダで取得し、Gemma-4 E4B で全 5000 枚にキャプションを当てた。データ・パイプライン側は綺麗にできた。
学習側で 3 段階イテレーション:
- kotonia03: rank 32 / 3000 step / 5000 枚 → 質感は明確に向上したが explicit には届かず
- kotonia04: kotonia03 から続行 + 6000 step → step は伸ばしたが explicit な行為描写はベースに引きずられる
- kotonia05:
final_layer2(ピクセル投影ヘッド) も解凍して 3000 step → ここで初めて「男性が画面に出てきた」「カップル構図になった」程度の前進
つまり「層問題仮説 (= ベースの safety が final_layer2 に焼き込まれている)」は半分正しかった: ヘッドを解凍したら確かに前に進んだ。けど penis 描写は依然として出ない。同じキャプションが当たっている学習画像を見にいくと、画像には大量の penis が映っている。なのに描けない。何かが噛み合っていない。
データを観察したら見えた歪み
キャプションファイル群を grep で集計したのが、今回の発見の入り口だった:
- lvl 16 (XXX) n=1250 枚 の中で
penis含有キャプション: 162 枚 (13%)fellatio含有: 38 枚 (3%)vaginal penetration: 196 枚 (16%)cum/semen: 74 枚 (4%)
実画像の含有率と全然合っていない。画像には明らかに penis が映っているのに、キャプションは "oral sex" や "vaginal penetration" など中立的・上位語に丸め込まれている。試しに E4B に同じ画像 + 多肢選択 (sexual_acts: [fellatio | cunnilingus | vaginal penetration | ... | none] から選ぶ形式) を渡しても、E4B は露骨な性行為画像に対して常に ["none"] を返す。解剖学的な名詞 (nipples, vulva 等) は素直に出すのに、行為の認定だけは構造的に拒否している挙動。
Gemma-4 系はローカルモデルなのでガード拒否は弱めなはずだったが、露骨な行為認定だけはきっちり言い換え (softening) が効いていた。多肢選択化、強いシステムプロンプト、露骨な語彙を埋め込むユーザープロンプト — どれも変化を起こせなかった。
学習信号が「露骨な penis ピクセル ↔ "oral sex" という中立トークン」の弱い対応に薄まり、推論時 "oral sex" → 「explicit っぽい何か = キス + 体液」みたいなベースの事前分布に戻る という現象が起きていた。真因はモデルではなくキャプション生成器だった。
仮説 B の検証: Grok-4.3 に差し替える
xAI の grok-4.3 で同じ画像 + 同じ多肢選択プロンプトを投げると:
{
"sexual_acts": ["fellatio", "ejaculation on face", "hand job"],
"anatomy_visible": ["penis", "testicles", "breasts", "tongue"],
"fluids_visible": ["semen", "saliva"]
}
E4B が ["none"] を返した同じ画像で、全て正しく明示的に命名された。
採用決定。recaption_two_stage.py として以下の 2 段階を実装:
- Stage 1 (語彙抽出): 概念列挙を JSON 構造化出力で強制。
sexual_actsフィールドは事前定義した固定ラベル集合 (fellatio | cunnilingus | vaginal penetration | anal penetration | hand job | breast play / paizuri | female masturbation | male masturbation | kissing | ejaculation on face | ejaculation on body | none) からの多肢選択。記述タスクではなく 分類タスクに組み直したことで safety alignment を回避しやすい - Stage 2 (強制含有): Stage 1 の語彙リストを必須含有で再投入し、それを原文ママに使った 1-3 文の散文キャプションを組み立てさせる。Grok-4.3 はここでも語彙を省略しない
vLLM 系の連続バッチングと違い、Grok は API ベースなので並列 8 で実行 (httpx ThreadPoolExecutor)。1250 枚を約 47 分、料金約 $30 で完走。
結果: 用語ヒット率の劇的改善

| 用語 | 旧キャプション (E4B) | 再キャプション (Grok-4.3) | 改善倍率 |
|---|---|---|---|
| penis | 13% | 55% | 4.2× |
| fellatio | 3% | 19% | 6.4× |
| semen | 4% | 41% | 9.4× |
| ejaculat | 0% | 28% | (新規) |
| tongue | 2% | 29% | 16× |
| nipple | 19% | 60% | 3.1× |
| vulva | 13% | 42% | 3.2× |
| penetrat | 16% | 31% | 1.9× |
実画像が高 NSFW レベル (XXX) である以上、含有率はこのあたりが「実体に近い」分布になる。E4B 旧キャプションの数字が異様に低かったのは、画像内容を反映していなかったから。
全層ファインチューンの実装メモ: 8-bit Adam で 8B が 96 GB に収まる
VRAM 設計:
| 項目 | 容量 |
|---|---|
| 重み bf16 (8B) | 16 GB |
| 勾配 bf16 | 16 GB |
| Adam 状態 (fp32 既定) | 64 GB ← ここがネック |
| 活性化 + スクラッチ (バッチ 1 / 解像度 1024) | 約 7 GB |
| 合計 (素朴) | 約 103 GB → OOM |
bitsandbytes.optim.AdamW8bit を使うと Adam 状態を 16 GB に圧縮できる:
opt = bnb.optim.AdamW8bit(
(p for p in model.parameters() if p.requires_grad),
lr=args.lr, weight_decay=0.0,
)
これで 常駐 54.6 GB に収まる。学習率 1e-5 / ウォームアップ 100 step / 3000 step → 28 分 / 9000 step → 84 分。一度の model.save_pretrained() で 17 GB のチェックポイントシャード群が書かれる (HuggingFace 標準形式)。
同キャプション再現テスト: 真の決定打
学習画像 (16/34854503.jpg) の旧キャプションと再キャプション後のキャプションは次の通り:
旧 (E4B):
...She is depicted in the act of oral sex, with drool and fluids visible around her mouth, set against a dark red, atmospheric background with small floating hearts. ...NSFW explicit, oral sex, cum on face, visible fluids.
再キャプション (Grok-4.3):
...performs fellatio on an erect penis with visible tongue amid ejaculation on face, semen on face and saliva against a dark red background with floating pink hearts under dramatic side lighting with glossy highlights.
両方を 同じファインチューン後モデル (full_nsfw02_recapt) に投げる:

- 左 (旧: "oral sex"): 構図 (赤い三つ編み + 白いランジェリー + 男性の胴 + 暗赤背景 + ハート) は完璧、でも行為は「キスっぽい何か + よだれ」、penis は描かれない
- 右 (再キャプション: "fellatio on an erect penis"): 同じ構図に、手で penis を握って fellatio をしている描写、cum on face、白い手袋
これが今回の検証で一番強い証拠。モデルは penis を描く視覚情報を持っている。語彙ゲートが閉じていただけ。
2 次元行列: 学習軸 × プロンプト軸
学習データ側 (E4B → Grok 再キャプション + step 数) と推論時のプロンプト語彙側の 両方を独立に動かした結果を 2 次元で並べると、現象が明確になる:

- 縦軸 (モデル進化): LoRA (kotonia04) → 全層 FT 3000 step E4B → 全層 FT 3000 step 再キャプション → 全層 FT 9000 step 再キャプション
- 横軸 (推論プロンプト): 旧 "oral sex" / 再キャプション "fellatio on an erect penis"
読み解き:
- 横方向 (プロンプト語彙) の効果が大きい: どの段階のモデルでも、再キャプション語彙のプロンプトを投げれば penis が描かれる。E4B キャプションで学習した kotonia04 LoRA でさえ、プロンプトを再キャプション語彙にすれば penis を出せる
- 縦方向 (学習側) の効果は緻密: 学習データ側の再キャプション化 + step 数増は、解剖学的整合性 (anatomy がきちんと penis として描けているか) や構図安定性に効いてくる
- 左下 / 右上: 旧プロンプト + 旧学習 (左上) は完全に penis 不在。再キャプションプロンプト + 再キャプション学習 (右下) が最も安定して露骨描写を出力
- 左列を縦に見ると: 学習データを再キャプション化しても、旧プロンプトで投げ直す限りは penis が出ない。これが「学習側だけ直してもダメ、プロンプト側の語彙も揃える必要がある」という非対称性
要するに プロンプト語彙と学習語彙は両方揃って初めて目的の描画に到達する。両方の「丸め込み」を解消する必要があり、片方だけだと不完全。
副産物: 汎用 SFW モデルとして完璧な仕上がり
NSFW 特化 2500 枚 (lvl 8 + 16) で全層 FT を 9000 step 回したのに、SFW 系プロンプトは何ひとつ壊れていなかった:

- 屋上夕景 (写実): 欧州都市の写真品質、写実でアニメに倒れない。SFW プロンプトの整合性が完全
- カフェ読書 (アニメ): 水彩アニメ、すごく可愛い、しかも本の表紙に "KOTONIA" という文字を勝手に乗せてきた (トリガー語のイースターエッグ)
- ビーチ水着: アニメ半写実、谷間自然、Mature 文脈で破綻なし
- 森のサンドレス: アニメ、深い谷間 + 神秘的なライティング、解剖学完璧
プロンプトの文脈に応じてスタイルを 写実 ⇔ アニメ で自動切替する基本仕様も保持されている。これは予想以上の良い結果で、NSFW 表現力を解禁するために汎用性能を犠牲にしていない。当初の戦略でいうところの「副産物」が、実はかなり強い汎用 SFW モデルだった。
NSFW 表現力の境界 (解剖学的参照付き)
学習が効いた領域とまだ届いていない領域を測るため、露骨なプロンプトを 8 種類流した。最良の 1 つ (paizuri/breast play、解剖学的に最もクリーンに出た例) を載せる:

- 取得済みの概念: penis (単独描写)、fellatio (paizuri 系)、handjob、ejaculation on face、cum 描画、トップレス、全裸、暗示的なポーズ
- まだ絡まっている概念: vulva ↔ 口腔 (vaginal anatomy が「舌の入った口」として幻覚される)、cunnilingus 構造 (顔 ↔ 性器接触の幾何)
- 過学習の兆候: cum が 赤色 で描かれることが多い (学習データの暗赤背景 + ハートアイコンに貼り付いた色相事前分布)
vulva と cum 周りは、語彙修復に lvl 8 (X tier) の再キャプション追加と、多様な背景色の露骨データ補充で解消できる範囲。これは方法論的にもう未知の領域ではなくなった。
方法論として: キャプション語彙修復の一般化
今回の検証から取り出せる 一般化可能なパターン:
- OpenWeight 基盤モデルは視覚能力を持っていることが多い: アリーナ上位を取るために大量の (NSFW 含む) データを見ている。安全性アライメントはその上に乗っている層なので、能力そのものは重みに眠っている
- 語彙のゲートが能力を隠す: 一般用キャプション生成器はほぼ全て、露骨な行為名詞 (fellatio, penetration, etc) を中立的上位語 (oral sex, act, intimate moment, etc) に丸め込む。これがファインチューニングで弱信号を作り出す
- VLM の選択が学習パイプラインの全てを支配する: 自前データセットを使ったファインチューニングでモデルの NSFW 表現力を引き出したいなら、最初に解くべきは 「キャプション生成器の語彙忠実度」。モデル側のチューニングはその後
- 多肢選択 + 強制含有で safety alignment を構造的に回避: 自然文記述だと言い換えされるタスクでも、分類 + 原文引用に組み直すと通る
ここで重要なのは、キャプション生成器は拒否すらしていないという点。E4B はちゃんとキャプションを返してくる。でも返ってくるキャプションは言い換えされている。「拒否 0 件」をパイプライン健全性の指標にしてはいけない、というのも今回の教訓。
反省点
- 仮説 A (層問題) で kotonia03 → 04 → 05 と 3 回イテレーションしたのは時間を食った。最初に
grep -c penis dataset/*.txtをやるべきだった。1 分でできて、それが見えていれば 6 時間分の学習前にデータ側を疑えた - E4B の「拒否 0 件」を見て安心して進めたのも甘かった。安全性アライメントは拒否という形だけじゃなく、言い換え / 丸め込みという静かな形でも出る
- 一方で kotonia05 で
final_layer2を解凍したのは無駄ではなく、「層の問題は部分的に存在する」「ベースモデルの safety はピクセルヘッドにもある程度焼き込まれている」というのは確かに裏付けがある。仮説 A は破棄ではなく仮説 B との共存
仮説の再検討: 「解禁」型と「ゼロからの学習」型は別物だった
検証を進めた段階で、当初の「語彙修復でモデルの隠された表現力を解禁する」という単純な物語は、実は 2 つの異なる学習挙動が同居している ことに気付いた。
観察された非対称性
| 概念 | ベースでの挙動 | FT 後の挙動 | 学習タイプ |
|---|---|---|---|
| 乳首 (nipple) | ベースプロンプト "topless" で初手から出る (解剖学的には粗いが) | 9000 step FT 後も品質下限がほぼ同じ。データセット含有率 60% でも改善しない | 解禁型 (能力枠内に既存だが品質改善は別問題) |
| penis | ベースプロンプト "fellatio" で全く出ない。再キャプション語彙で押し込んでようやく形が出る | step を積むと「変形 → 奇妙な突起 → 形に近い物体 → 解剖学的に妥当」と段階的に獲得していく典型的な新規学習挙動 | ゼロからの学習型 (事前学習段階で意図的に切り出された可能性) |
なぜこの非対称が起きるか
このプロジェクトの user が立てた 「事前学習段階での選択的除去」仮説 が説得力ある説明になる:
- penis 判別器は需要が高く品質も高い: 商用モデレーション市場で penis は明確な単一特徴ターゲット、判別器が高精度に作れる。事前学習データセットから きれいに除去できる
- 乳首判別器は構造的に難しい: 男性も乳首を持つ、絵画にも普遍的、医療画像にもある、解剖学アトラスにもある → "乳首を含む全画像" を事前学習から消すのは現実的でない。ベースモデルは 粗い乳首の概念を持ったまま リリースされる
この仮説下では、今回の行列の右下 (全層 FT 9000 step + 再キャプションプロンプト) で penis が描けるようになったのは「解禁」ではなく「実質的な追加事前学習相当の概念教示」をしていたことになる。だから訓練段階で penis 描画が「段階的に変な形 → 形に近づく」推移をたどった (これは解禁挙動ではなく新概念学習の典型軌跡)。
逆に乳首は「事前学習で既に学んだが品質下限が低いまま放置」状態で、今回 1250 枚 lvl 16 + 1250 枚 lvl 8 に nipple が 60-49% で含まれるデータセットで全層 FT しても品質改善はほぼ線形に現れなかった。キャプションに「品質判定」が含まれていないことが主因と推測 (良い乳首 vs 崩れた乳首の判別軸が学習信号にない)。
これは MSE ピクセル損失が解剖学的品質に弱相関、という今回の他の発見とも整合する: データセット含有率の数字 (penis 13%→55%) が描画能力に転換するためには、概念の最低限の表現が重みに存在している必要がある。乳首はそれが満たされているのに品質改善できなかった、penis は満たされていなかったので新規学習で前進した、という分裂。
関連: 自然言語処理での「概念除去」の系譜
近年の概念編集 / 活性化エンジニアリング (ROME / MEMIT / Anthropic の representation engineering 系) が、特定概念のベクトル方向を特定して活性化レベルで抑制する手法を扱っている。OpenAI / Anthropic 系の事後学習に類似手法が組み込まれている可能性は十分あり、OpenWeight モデルでこれが行われていれば「重みには残っているが活性化レベルで削られている」状態を作れる。今回 penis が「強く押し込まないと出てこないが出始めると新概念学習挙動を示す」のはこのカテゴリで説明できる範囲。
記事の主張の訂正
当初の 「語彙修復で隠された表現力を解禁する」 物語は 乳首には適用できない。乳首は最初から見えていて、ただし品質が低い。これは語彙修復では解けない (キャプションの表現語彙に「美しい乳首 vs 崩れた乳首」の判別軸を入れていないため、学習信号が「存在する/しない」の 1 bit しか流れていない)。
penis は 語彙修復が新概念学習の入口を開く という挙動だったが、これは厳密には「解禁」ではなく 「有効化」。ベースモデルが露骨な解剖学を完全に除去していたら今回も不可能だった、けど「完全除去」ではなく「ほぼ除去」だったので、再キャプション語彙 + 9000 step で形に到達できた、というのがより精密な記述。
残課題と次フェーズの宿題
- 乳首品質: 敵対的学習アプローチ
- 既存データセットで訓練しても品質改善しないので、ユーザー主導の報酬ラベリング (200-500 枚に 1-5 星) → 軽量 CNN 判別器 → 拡散モデル側に報酬ファインチューン (Diffusion-DPO 系) で押し上げる経路を次回試す
- 副産物として「kotonia 好み判別器」が手に入り、記事カバー画像の自動選定にも使い回せる
- 非検閲キャプション生成器で Grok 依存を解消
- Grok-4.3 は今回約 $30 (lvl 16) + $0.5 (パイロット) で済んだが、lvl 8 まで広げると重い。次回は JoyCaption alpha-2 や CogVLM2/InternVL-2.5 のコミュニティ非検閲派生をローカルで動かすことを検討、コスト $0 / 無制限化を目指す
- lvl 8 も再キャプション: X tier 1250 枚を同パイプラインに通す。解剖学名詞の多様性 + nipple/vulva のカバー強化
- 背景色多様化: cum=赤の過学習を逃すために、明るい背景 + cum on body の画像を意識して追加収集
- cunnilingus 構造: 顔と性器の接触をクリーンに描けるサンプル収集が必要
- kotonia.ai 統合: マルチモデル VRAM デプロイ
- 現状 nsfw03 チェックポイントは単体運用、
/studioには kotonia01/02 LoRA のまま - 96 GB GPU に ベース (fp8, 8.79 GB) + nsfw03 (bf16, 16 GB) を同時常駐すれば、コールドスタートなしでリクエスト毎にモデル切替できる (生成時ピーク込みでも約 40 GB)、これを並列ロードで実装予定
- 現状 nsfw03 チェックポイントは単体運用、
- 記事の配信戦略: 学術的な検証文脈で Google のインデックス化を試行するか、SafeSearch 汚染回避で noindex に留めるかは継続検討中
関連コード
セルフホストのモノレポ内、私的運用:
collect.py— 公開画像プラットフォームの API + 認証トークンで 5000 枚並列ダウンロード、高反応順 / 全期間 / NSFW レベル混合caption_v1.py— E4B 旧キャプション生成器 (丸め込み問題が見つかった原典)recaption_two_stage.py— Grok-4.3 語彙修復キャプション生成器、--backend xai|e4b切替combine_for_training.py—--use_recaptで.recapt.txt優先シンボリックリンクtrain_full.py— bnb 8-bit Adam、--init_from続行、save_pretrained()HF 形式infer_full.py— FT モデル推論maintenance_shim.py+start_maintenance.sh/stop_maintenance.sh— 学習中の/studio+ LTX 経路を 3 言語 / 動的 ETA 込みの 503 メンテ画面に差し替えるショートカット
研究目的の note としては、ここで一旦区切る。次の進化は lvl 8 の再キャプションと背景色多様性 + 残課題 3 つの解消。