😇

OpenMythosがローカル環境で動くか検証してみた

に公開
13

はじめに

みなさんClaude Mythos(クロード ミュトス)をご存知でしょうか?Anthropic社が開発した「最強のAI」として噂されていますが、現在は限定的なプレビューにとどまっており、一般ユーザーは利用できません。そんな中、公開されている研究論文やアーキテクチャを元に、理論的に再現しようというプロジェクトが立ち上がりました。それが今回触ってみるOpenMythosです。気になったので、さっそく試してみました!

https://github.com/kyegomez/OpenMythos

実行環境

動作環境

項目 スペック
OS macOS Sequoia
チップ Apple M4
メモリ 16GB

動作検証用ファイル

今回はローカルで動作検証するため、最低限のDockerfileを用意しています。

Dockerfile
FROM python:3.14

WORKDIR /app

RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir torch open-mythos loguru sentencepiece tiktoken protobuf

COPY src/ ./src/
WORKDIR /app/src

CMD ["/bin/bash"]

compose.ymlも同様、最低限の内容になります。

compose.yml
services:
 openmythos:
  build: .
  container_name: openmythos_env
  working_dir: /app/src
  volumes:
    - ./src:/app/src
  tty: true

example.pyの検証

まずは、OpenMythosの基本的な仕組みを確認するため、リポジトリに用意されている example.pyを動かしてみました。

example.py
import torch
from open_mythos.main import OpenMythos, MythosConfig


attn_type = "mla"  # or "gqa"

base = {
  "vocab_size": 1000,
  "dim": 256,
  "n_heads": 8,
  "max_seq_len": 128,
  "max_loop_iters": 4,
  "prelude_layers": 1,
  "coda_layers": 1,
  "n_experts": 8,
  "n_shared_experts": 1,
  "n_experts_per_tok": 2,
  "expert_dim": 64,
  "lora_rank": 8,
  "attn_type": attn_type,
}

if attn_type == "gqa":
  cfg = MythosConfig(**base, n_kv_heads=2)
else:
  cfg = MythosConfig(
    **base,
    n_kv_heads=8,
    kv_lora_rank=32,
    q_lora_rank=64,
    qk_rope_head_dim=16,
    qk_nope_head_dim=16,
    v_head_dim=16,
  )

model = OpenMythos(cfg)
total = sum(p.numel() for p in model.parameters())
print(f"\n[{attn_type.upper()}] Parameters: {total:,}")

ids = torch.randint(0, cfg.vocab_size, (2, 16))
logits = model(ids, n_loops=4)
print(f"[{attn_type.upper()}] Logits shape: {logits.shape}")

out = model.generate(ids, max_new_tokens=8, n_loops=8)
print(f"[{attn_type.upper()}] Generated shape: {out.shape}")

A = model.recurrent.injection.get_A()
print(
  f"[{attn_type.upper()}] Spectral radius ρ(A) max: {A.max().item():.4f} (must be < 1)"
)

実行結果

Attaching to openmythos_env
openmythos_env  | 
openmythos_env  | [MLA] Parameters: 1,538,626
openmythos_env  | [MLA] Logits shape: torch.Size([2, 16, 1000])
openmythos_env  | [MLA] Generated shape: torch.Size([2, 24])
openmythos_env  | [MLA] Spectral radius ρ(A) max: 0.3679 (must be < 1)
openmythos_env exited with code 0

問題なく出力されることを確認できました!
それぞれの項目について解説します。

項目 内容
Parameters モデルの総パラメーター数
Logits shape モデルが予測した「次の単語」の候補のデータ構造
[バッチサイズ, 入力トークン数,語彙数]
Generated shape テキスト生成後のデータの長さ
[バッチサイズ,トークン数]
Spectral radius ρ(A) max Mythos特有の機構の安定性を示す数値。1未満であれば、安定して推論が行える。

Spectral radiusの値が0.3679であり、理論通り安定した推論が可能な状態であることが確認できました!この小規模な構成での成功を踏まえ、いよいよ実用的なサイズである1Bパラメータモデルでのトレーニング検証に進みます。

トレーニングの検証

次は1Bパラメータの本格的なモデルを使って、日本語の学習ができるか試してみました。OpenMythosではTokenizerモデルにgpt-oss-20bを使用しているのですが、メモリ的に動かすのが厳しいため、Tokenizerモデルをrinna/japanese-gpt-1bに変更して検証しています。

main.py
import math
import os
import time

import torch
import torch.nn as nn
from loguru import logger
from open_mythos import OpenMythos
from open_mythos.tokenizer import MythosTokenizer
from open_mythos.variants import mythos_1b
from torch.utils.data import DataLoader, IterableDataset


class LocalTestDataset(IterableDataset):
  def __init__(self, encoding, seq_len: int, file_path: str):
    self.encoding = encoding
    self.seq_len = seq_len
    self.file_path = file_path

  def __iter__(self):

    with open(self.file_path, "r", encoding="utf-8") as f:
      text = f.read()

    tokens = self.encoding.encode(text)

    buf = tokens
    while len(buf) >= self.seq_len + 1:
      chunk = buf[: self.seq_len + 1]
      buf = buf[self.seq_len:]
      yield (
        torch.tensor(chunk[:-1], dtype=torch.long),
        torch.tensor(chunk[1:], dtype=torch.long),
      )


def get_lr(step: int, warmup: int, total: int, max_lr: float, min_lr: float) -> float:
  if step < warmup:
    return max_lr * step / warmup
  if step >= total:
    return min_lr
  decay = (step - warmup) / (total - warmup)
  return min_lr + 0.5 * (max_lr - min_lr) * (1.0 + math.cos(math.pi * decay))


def main():
  if torch.backends.mps.is_available():
    device = "mps"
  elif torch.cuda.is_available():
    device = "cuda"
  else:
    device = "cpu"

  logger.info(f"Using device: {device}")

  encoding = MythosTokenizer(model_id="rinna/japanese-gpt-1b")
  vocab_size = encoding.vocab_size

  seq_len = 16
  micro_batch = 1
  total_steps = 100
  warmup_steps = 10
  lr = 1e-4
  ckpt_dir = "checkpoints"
  input_file = "input.txt"

  logger.info("Loading mythos_1b configuration...")
  cfg = mythos_1b()
  cfg.vocab_size = vocab_size
  cfg.max_seq_len = seq_len

  model = OpenMythos(cfg)
  model.to(device)

  n_params = sum(p.numel() for p in model.parameters())
  logger.info(f"Model parameters: {n_params:,}")

  optimizer = torch.optim.AdamW(
    model.parameters(), lr=lr, weight_decay=0.1, fused=(device == "cuda")
  )

  dataset = LocalTestDataset(encoding, seq_len, input_file)
  loader = DataLoader(dataset, batch_size=micro_batch)

  model.train()
  step = 0
  t0 = time.perf_counter()

  logger.info("Starting training...")

  for x, y in loader:
    if step >= total_steps:
      break

    cur_lr = get_lr(step, warmup_steps, total_steps, lr, lr * 0.1)
    for g in optimizer.param_groups:
      g["lr"] = cur_lr

    x, y = x.to(device), y.to(device)

    optimizer.zero_grad()
    logits = model(x)
    loss = nn.functional.cross_entropy(logits.view(-1, vocab_size), y.view(-1))

    loss.backward()
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    optimizer.step()

    if step % 5 == 0:
      dt = time.perf_counter() - t0
      logger.info(
        f"Step {step:3d} | Loss: {loss.item():.4f} | LR: {cur_lr:.2e} | {dt:.2f}s/step"
      )
      t0 = time.perf_counter()

    step += 1

  logger.success("Training complete.")


if __name__ == "__main__":
  main()

今回は試しに俳句を挿入してみました。

input.txt
古池や蛙飛びこむ水の音
夏草や兵どもが夢の跡
閑さや岩にしみ入る蝉の声
柿食えば鐘が鳴るなり法隆寺
目には青葉山ほととぎす初鰹
春の海ひねもすのたりのたりかな
五月雨を集めて早し最上川
秋深き隣は何をする人ぞ
朝顔に釣瓶とられてもらい水
行く春や鳥啼き魚の目は泪

実行結果

実際にトレーニングを実施してみた結果がこちらになります。残念ながら、処理落ちしてしまいました...

Attaching to openmythos_env
openmythos_env  | 2026-05-15 02:43:16.830 | INFO     | __main__:main:57 - Using device: cpu
config.json: 100% 578/578 [00:00<00:00, 1.17MB/s]
openmythos_env  | Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
tokenizer_config.json: 100% 283/283 [00:00<00:00, 713kB/s]
spiece.model: 100% 1.04M/1.04M [00:01<00:00, 1.00MB/s]
special_tokens_map.json: 100% 153/153 [00:00<00:00, 377kB/s]
openmythos_env  | 2026-05-15 02:43:20.291 | INFO     | __main__:main:70 - Loading mythos_1b configuration...
openmythos_env  | 2026-05-15 02:43:44.649 | INFO     | __main__:main:79 - Model parameters: 1,090,398,082
openmythos_env  | 2026-05-15 02:43:44.663 | INFO     | __main__:main:92 - Starting training...
openmythos_env  | 2026-05-15 02:45:48.213 | INFO     | __main__:main:114 - Step   0 | Loss: 11.2153 | LR: 0.00e+00 | 123.43s/step
openmythos_env exited with code 137

1ステップのみ処理されて、2回目でコンテナが終了しています。終了コードの137はメモリ不足による強制終了です。1BモデルをCPUで動かすとなると、私のMacBookのスペックでは足りないようです。

まとめ

今回は、話題のClaude Mythosを再現しようとするOpenMythosをローカルで動かしてみました。OpenMythosのリポジトリにあるexample.pyの動作確認はできましたが、実際にトレーニングをしようとするとパソコンのスペックが足りないようです。今後はクラウドのGPUインスタンスを活用したり、パラメーターの調整を行うなど、アプローチを変えて引き続きOpenMythosの検証を行っていきます!

13
株式会社メンバーズ AIフォーオールカンパニー

Discussion

ログインするとコメントできます
13