OpenAIの最新モデル o4
先日,OpenAIの最新のモデルとしてo3 のほかにo4-miniが発表された.今回はo3と比較してその性能を試してみたい.o3の時に送ったプロンプトと同じものを使用して差をみてみる.
出力結果は下記.
Weasel Program を可能な限りリッチな表現を用いたコードで書いて.
その過程をアニメーションとして出力できるようにして.
# Weasel Program with Animation in Google Colab
# ===================================================
# 目標フレーズに向かって文字列を「進化」させる過程を、
# matplotlib の FuncAnimation でアニメーション表示します。
import random
import string
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
# Colab でアニメーションを埋め込む設定
plt.rcParams['animation.embed_limit'] = 2**128 # 大きめに設定
class WeaselProgram:
"""
Weasel Program:
- target: 目標フレーズ
- pop_size: 各世代の個体数
- mutation_rate: 1文字あたりの突然変異確率 (例: 0.05 は 5%)
- max_generations: 最大世代数
"""
def __init__(self,
target: str,
pop_size: int = 100,
mutation_rate: float = 0.05,
max_generations: int = 1000):
self.target = target
self.pop_size = pop_size
self.mutation_rate = mutation_rate
self.max_generations = max_generations
self.alphabet = string.ascii_uppercase + ' ' # 空白も扱う
def _random_individual(self) -> str:
"""ランダムな文字列個体を生成"""
return ''.join(random.choice(self.alphabet) for _ in self.target)
def _score(self, candidate: str) -> int:
"""目標フレーズとの一致文字数をスコアとする"""
return sum(1 for c, t in zip(candidate, self.target) if c == t)
def _mutate(self, parent: str) -> str:
"""突然変異を起こす(文字ごとに mutation_rate でランダム置換)"""
chars = []
for c in parent:
if random.random() < self.mutation_rate:
chars.append(random.choice(self.alphabet))
else:
chars.append(c)
return ''.join(chars)
def evolve(self) -> list:
"""
プログラムを実行して各世代のベスト個体を history として返す。
history[i] が i世代目の最良文字列。
"""
# 初期集団の生成
population = [self._random_individual() for _ in range(self.pop_size)]
history = []
for gen in range(self.max_generations):
# スコア順でソートし、上位10%を親に選出
scored = [(self._score(ind), ind) for ind in population]
scored.sort(reverse=True, key=lambda x: x[0])
best_score, best_ind = scored[0]
history.append(best_ind)
# 目標到達したら終了
if best_ind == self.target:
print(f"Reached target in generation {gen}!")
break
# 上位10%を親プールとし、新集団を生成
cutoff = max(1, int(self.pop_size * 0.1))
parents = [ind for _, ind in scored[:cutoff]]
# 各親から子を複数生成して新集団を構築
new_pop = []
for _ in range(self.pop_size):
parent = random.choice(parents)
child = self._mutate(parent)
new_pop.append(child)
population = new_pop
return history
# --- 実行部分 ---
if __name__ == "__main__":
# パラメータ設定
TARGET_PHRASE = "METHINKS IT IS LIKE A WEASEL"
POPULATION_SIZE = 200
MUTATION_RATE = 0.05
MAX_GENERATIONS = 200
# プログラム実行
wp = WeaselProgram(
target=TARGET_PHRASE,
pop_size=POPULATION_SIZE,
mutation_rate=MUTATION_RATE,
max_generations=MAX_GENERATIONS
)
history = wp.evolve() # 各世代のベスト文字列リスト
# --- アニメーション表示設定 ---
fig, ax = plt.subplots(figsize=(12, 2))
ax.axis('off')
# 文字ごとの x 座標
x_positions = np.arange(len(TARGET_PHRASE)) * 0.5
def update(frame: int):
ax.clear()
ax.axis('off')
candidate = history[frame]
# 各文字を色分け:一致は緑、不一致は黒
for idx, char in enumerate(candidate):
color = 'green' if char == TARGET_PHRASE[idx] else 'black'
ax.text(x_positions[idx], 0.5, char,
color=color,
fontsize=24,
fontfamily='monospace',
ha='center', va='center')
ax.set_title(f"Generation {frame + 1}/{len(history)}", fontsize=16)
anim = FuncAnimation(
fig,
update,
frames=len(history),
interval=200, # ミリ秒間隔
repeat=False
)
# Colab 上で表示
plt.close(fig) # 重複描画を防ぐ
display(HTML(anim.to_jshtml()))
するとこんな出力が返ってきた.
o4-miniの場合はもう少しプロントを工夫する必要があるかもしれない.
