LLM(大規模言語モデル)を教師モデルにして、小規模言語モデルに蒸留した話 実験版

DeepSeekの登場以来、「蒸留」という言葉が結構流行ってきましたね。

蒸留とは

蒸留(distillation) とは、
「大きくて高性能な教師モデルの知識を、小さくて軽量な生徒モデルに効率的に移す技術」
のことを指します。

元々は自然言語処理などの分野で、巨大モデルをそのままデバイスに載せるのは難しいため、
・教師モデルが出す出力(予測確率など)
・中間層の特徴量
を利用して、生徒モデルに教師モデルの「ふるまい」を学ばせる仕組みとして考えられました。

蒸留のポイントは、
・小さいモデル(生徒モデル)が教師の出力分布を真似る
・教師の持つパターン認識や知識を圧縮して伝える
・学習データが少なくても、教師の知識を最大限引き継げる
といったところです。

蒸留に使うモデルはこれだ

今までは高額なお金をかけて(GPUなど)学習していくと言う感じでしたが、この蒸留と言う手法を使えば、比較的手軽に専門領域に特化した小規模言語モデルを構築することができます

今回は、この蒸留の手法を使って、Googleコラボ上(有料版)で全て完結できるように、小さいスペックのモデルを使って実験してみたいと思います

まず、今回選ばれたモデルは
SakanaAIさんが公開している言語モデル TinySwallow-1.5B-Instructです。

通常の7B以上とかのモデルだと大きすぎてコラボにうまく載せられません。
そこで性能のいい大規模言語モデルのTinySwallow-1.5Bを選択しました。

このモデルを教師モデルにして、いわゆる生徒モデルもTinySwallow-1.5Bを使って、「空の生徒モデル」を構築し、そこに知識を蒸留(distillation)していくプロセスを試しました。

教師モデルの準備

まずは教師役のモデル、
SakanaAI/TinySwallow-1.5B-Instruct
を使います。

パラメータ数は約 1.54B(15億パラメータ) で、推論能力に優れたインストラクション・フォロー型のLLMです。

このモデルはHugging Face上に公開されており、まずColabへダウンロードしました。

モデル本体(model.safetensors)、トークナイザーの設定ファイル、その他メタデータまで合わせて14ファイル。
容量としてはおおむね3GB超ですが、2回目以降のキャッシュが効くため実質的には快適に動きます。

生徒モデルの構築

次に、生徒モデルをTinySwallow-1.5Bで「空の状態」から作ります。

ここでいう「空」とは、重みをほとんど初期化状態にして、教師の動きを真似させるところから始めることです。

構築した生徒モデルは およそ108Mパラメータ。
これは教師の約1/14ほどのサイズで、とても軽量です。

蒸留の流れとLossの推移

ここから教師モデルの出力をガイドにして、生徒モデルに学習させます。

やり方としては教師モデルの出力ロジットを教師信号として、損失関数にKLダイバージェンスなどを適用して生徒モデルを収束させていく形を取ります。

いわゆる Knowledge Distillation の定番手法です。

今回は以下の条件で蒸留を走らせました。

学習回数:10エポック

Optimizer:Adam

学習率:調整済

損失関数:教師出力との距離を最小化

実際のLossの推移はこんな感じです。

Epoch 1/10 – Loss: 13.1150
Epoch 2/10 – Loss: 12.8502

Epoch 10/10 – Loss: 11.9068

Lossはゆるやかに減少しており、少なくとも教師のふるまいを表面的には学習できるところまで進んでいるように見えました。

簡易テキスト生成のテスト

学習が終わったところで、生徒モデルのテキスト生成能力をテストしました。
(最終エポックでロスが11以上あるので、それなりの回答を想定)

プロンプトとして
「昔々あるところに、」
を入力してみたところ、生成結果は以下の通り。

昔々あるところに、thenReturn matière’),
sent_AP-directory Caucasian UserData\Active نوف UserData剑 nrparer買う-directoryFinoxious lanes.a比利 apenas要坚持_APB foo딛食べて剑 grants临近小额贷款 UFO apenas-directoryDiese depparer atIndexparermov SeiteDis fooموظ

正直なところ、単語が多言語混在で意味不明気味です。

しかしこれは想定内で、まずまずオッケーと言ったところです。

理由としては、学習データが非常に少量だったことが主因で、文章の一貫性を持たせるほどの蒸留は進んでいないです。

とはいえパラメータ108Mという極小モデルに10エポックだけでここまで出力させるのは、それなりに面白い成果ともいえます。

まとめと今後の課題

今回の取り組みは

・教師モデルに小さめの大規模言語モデル(TinySwallow-1.5B)を使用
・そこからさらに桁違いに小さい生徒モデル(108M)を作る
・生徒は初期化状態から蒸留で構築する

という実験でした。

結果としては、プロンプトに対して「なんらかの言葉を返せる」レベルには到達しました。

より本格的にかつ専門領域に特化した蒸留を行うなら

・教師モデルの出力を使って大量のペアデータを生成
・なおかつ専門性の高い、質の良いデータを揃える
・学習エポックを増やす

などの工夫が不可欠です。

もっと大きなモデルでやりたければ、AWSなどを使って、中堅の大規模言語モデルを教師モデルとし、小規模言語モデルへ蒸留していけば、結構いい感じの小型モデルの構築が可能です。

さて今回は「とにかく空のモデルからコラボでサクッと蒸留する」というチャレンジでしたが、技術的におもしろい試みでした。

今後はもう少しデータを増やして、専門特化した小型の言語モデルを作ってみたいと思います。

(とはいえ、数十万件のデータそろえるのはちょっとなあ…。1万件くらいならいけるかなあ。
ゴルフ専用モデル、アート専用モデルとか作りたいよなあ)

****************

最近のデジタルアート作品を掲載!

X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

SakanaAIのALE−Agentを参考にGoogle Colabで簡易版を実行してみた話

「ALE-Bench」と「ALE-Agent」

最近話題のSakanaAIが発表した「ALE-Bench」と「ALE-Agent」。

これは、AtCoderで実際に出題された最適化コンテストの問題群をベンチマークとして利用し、AIに解かせることでその改善能力を測るという、かなり面白い試みです。

しかもこのALE-Agent。普通のLLM(大規模言語モデル)をベースにしながらも、試行錯誤とフィードバックを通じて少しずつ“賢く”なっていく設計になっています。

そこで、実際にこの仕組みをGoogle Colabで再現できないかと思い、簡易バージョンのALE-Agent風を作ってみました。

ALE-Agentってなに?

ざっくり言うと、ALE-Agentとは
最初は適当な答えを出すけど、スコア(点数)を見て反省しながら、少しずつ解を改善していくAIエージェントです。

まるで将棋のAIが何千回も対局して強くなるように、最適化問題に対して試行錯誤を繰り返し、より良い解を探していくのがこのエージェントの特徴です。

SakanaAIのALE-Benchでは、過去のAtCoder Heuristic Contest(AHC)の問題がベンチマークとして活用されており、AIの改善能力が公平に比較できるようになっています。

Google Colabで簡易版を実行してみる

もちろん本家のALE-Agentのような高度な設計をそのまま再現するのは大変ですが、まずは以下の3ステップで簡易版を作りました。

1 シンプルな最適化問題を定義

今回は、「1〜10の数字を並び替えて、隣り合う数字の差の合計を最大にする」という簡単な問題に設定。

この問題は「最適解が1つに定まらず、試行錯誤でスコアが改善していく構造」があり、ALEの仕組みと似ています。

2 初期解とスコア評価関数

最初はランダムに数字を並べて、スコアを評価。

その後、OpenAIのGPT-4 APIに「今の答えよりも良くなるような並びを提案して」と依頼し、改善案を取得します。

3 スコアが上がったら更新、下がれば無視

提案された解が今より良ければ採用、ダメなら却下という単純なフィードバックループを作成。

これを数多く繰り返すことで、最初の適当な並びから、スコアが高い「より良い解」へと少しずつ進化していきます。

2つのバージョンを用意する

今回はLLMを使わない高速バージョンとLLMを使うハイブリッドバージョンの2つのコードを実行してみました。

1番最後にコードを貼っておきますので、興味のある方は、google colabにて実行してみてください。

(LLMを使うバージョンはopenAIのAPIを使うので課金されます。無料でやりたい方は高速バージョンを使ってください)

実行してみた感想

高速バージョン

最初のスコアは30台後半。そこから少しずつ改善され、最終的には40台後半、場合によっては50台までスコアが伸びることもありました。

実際の出力は以下のようなイメージ:

ハイブリッドバージョン
同じような動きですが、LLMをつかわないでスコアが停滞すると、LLMへGOのスイッチが入り、よりよい解が得られるように、進化していきます。

このように、全体のパフォーマンスが自動で向上していく様がリアルに見えて、なかなか楽しいです。

Darwin Gödel Machineとの違いってなに?

SakanaAIの技術といえば、ALE-Agentと並んで注目されているのが「Darwin Gödel Machine(DGM)」というもう一つの概念。

このDGMは、ALE-Agentとは全く違うレイヤーの自己改善型AIです。

たとえば、今回のALE-Agent風システムは「ちょっとずつ調整して、より良い答えを目指す」タイプ。

一方、DGMは「そもそも自分の考え方が間違ってるかもしれないから、自分の仕組み自体を論理的に修正する」というレベルの話です。

つまり、ALEは「戦術を変える」、DGMは「自分という存在を進化させる」といった違いがあります。

実装難度や動作速度の観点では、現時点ではALE型の方がずっと扱いやすいです。

将来的にはDGM型のAIが真の「汎用人工知能(AGI)」の入口になる可能性もあるかと思います。
(なんと言っても、自分自身のコードを書き換える訳ですから、これはすごい技術です)

まとめ

今回、SakanaAIが提唱するALE-Agentのエッセンスを自分なりにColabで再現してみました。

AIが「自分の出力を反省して少しずつ良くする」というプロセス。
DGMとはまた違ったアプローチを知りました。

もちろん、本家のように高度なツール統合していませんが、
「初期解 → スコア → 改善 → 再評価 → 進化」というループは、通常のシステムにはない面白さがあります。

「とりあえず自分でもやってみたい」という方には、下記にコードを2種類貼っておきますので、google colabにて実行してみてください。

・高速バージョン
LLMを使わないので、API料金はかかりません。
その分、コードもシンプルでLLMを使うからこその面白さには欠けます。
メリットは高速なこと。


import random
import math
import matplotlib.pyplot as plt

# ===== 問題:1〜10の数字を並べて隣接差の合計を最大化 =====
def evaluate(solution):
    return sum(abs(solution[i] - solution[i+1]) for i in range(len(solution)-1))

# ===== 初期解を生成 =====
def generate_initial_solution():
    sol = list(range(1, 11))
    random.shuffle(sol)
    return sol

# ===== 近傍解を生成(2つの数字をランダムに入れ替える) =====
def generate_neighbor_solution(solution):
    neighbor = solution.copy()
    i, j = random.sample(range(len(solution)), 2)
    neighbor[i], neighbor[j] = neighbor[j], neighbor[i]
    return neighbor

# ===== 焼きなまし法の受容判定 =====
def should_accept(current_score, new_score, temperature):
    if new_score > current_score:
        return True
    delta = new_score - current_score
    probability = math.exp(delta / temperature)
    return random.random() < probability

# ===== パラメータ =====
MAX_ITER = 100
INITIAL_TEMP = 10.0
COOLING_RATE = 0.95

# ===== メインループ =====
solution = generate_initial_solution()
score = evaluate(solution)
temperature = INITIAL_TEMP
scores = [score]

print("===== 焼きなまし法による最適化開始 =====")
for i in range(1, MAX_ITER + 1):
    neighbor = generate_neighbor_solution(solution)
    new_score = evaluate(neighbor)

    if should_accept(score, new_score, temperature):
        solution = neighbor
        score = new_score
        print(f"✅ Iter {i:2d} | New Score: {new_score} | Temp: {temperature:.4f} | 採用")
    else:
        print(f"❌ Iter {i:2d} | New Score: {new_score} | Temp: {temperature:.4f} | 却下")

    scores.append(score)
    temperature *= COOLING_RATE

# ===== 結果表示 =====
print("\n===== 最適化終了 =====")
print("最終解:", solution)
print("最終スコア:", score)

# ===== スコア推移のグラフ =====
plt.figure(figsize=(8, 5))
plt.plot(range(len(scores)), scores, marker='o')
plt.title("Score Transition (Simulated Annealing)")
plt.xlabel("Iteration")
plt.ylabel("Score")
plt.grid(True)
plt.show()



・ハイブリットバージョン 上記に加えて、スコアが停滞すると、LLMよGO!のサインが入ります。 結果、スコアが改善される確率が上がります。 注意点はコードを実行するとopenAIのAPI料金がかかります。

 

!pip -q install --upgrade openai matplotlib

import random, math, re, matplotlib.pyplot as plt
from openai import OpenAI

# ---------- OpenAI クライアント ----------
client = OpenAI(api_key="ここにAPIキーを入れる")  # ← APIキーを入力 実際は環境変数に入れたほうが良いが簡易版なので

# ---------- 評価関数(隣接差の合計) ----------
def evaluate(sol):
    return sum(abs(sol[i] - sol[i + 1]) for i in range(len(sol) - 1))

# ---------- 初期解 ----------
def random_solution():
    s = list(range(1, 11))
    random.shuffle(s)
    return s

# ---------- ローカル近傍(2点スワップ) ----------
def local_neighbor(sol):
    nb = sol.copy()
    i, j = random.sample(range(len(sol)), 2)
    nb[i], nb[j] = nb[j], nb[i]
    return nb

# ---------- LLM から改善案を取得 ----------
def llm_propose(sol, score):
    prompt = f"""
目的:1〜10 の数字を並び替え、隣接差の合計を最大化してください。
現在の解: {sol}
現在のスコア: {score}
制約: 1〜10 を重複なく使用し、Python list 形式で 1 行だけ回答してください。
"""
    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7,
    )
    text = resp.choices[0].message.content
    nums = list(map(int, re.findall(r"\d+", text)))
    return nums if len(nums) == 10 and len(set(nums)) == 10 else sol

# ---------- 焼きなまし受容判定 ----------
def accept(cur, new, temp):
    return new > cur or random.random() < math.exp((new - cur) / temp)



# ---------- パラメータ ----------
MAX_ITER       = 30      # 総イテレーション
INITIAL_TEMP   = 10.0
COOLING_RATE   = 0.9
STAGNATE_LIMIT = 4       # 改善なしが連続何回で LLM 発動か

sol   = random_solution()
score = evaluate(sol)
best  = score
temp  = INITIAL_TEMP
no_improve = 0
history = [score]

print("=== 停滞時 LLM 発動ハイブリッド焼きなまし ===")
for it in range(1, MAX_ITER + 1):
    # ---- 改善案生成 ----
    if no_improve >= STAGNATE_LIMIT:
        print(f"\n🧠 Iter {it}: 改善停滞 ({no_improve}) → LLM 発動")
        cand = llm_propose(sol, score)
        no_improve = 0
    else:
        cand = local_neighbor(sol)

    cand_score = evaluate(cand)
    if accept(score, cand_score, temp):
        sol, score = cand, cand_score
        accepted = "✅ 受容"
        no_improve = 0 if score > best else no_improve + 1
        best = max(best, score)
    else:
        accepted = "❌ 却下"
        no_improve += 1

    print(f"{accepted} | Iter {it:2d} | Score {score:2d} | Temp {temp:.3f}")
    history.append(score)
    temp *= COOLING_RATE  # 冷却

# ---------- 結果 ----------
print("\n=== 最終結果 ===")
print("最終解   :", sol)
print("最終スコア:", score)

# ---------- スコア推移グラフ ----------
plt.figure(figsize=(8, 4))
plt.plot(history, marker='o')
plt.title("Score Transition (Stagnation-Triggered LLM Hybrid SA)")
plt.xlabel("Iteration")
plt.ylabel("Score")
plt.grid(True)
plt.show()



いろいろ試してみてください。

sakanaAIさんのブログ記事
https://sakana.ai/ale-bench-jp/

同じく論文
https://arxiv.org/abs/2506.09050

 

****************

最近のデジタルアート作品を掲載!

X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

進化的アルゴリズム簡易版でアート制作の基礎を試す

進化的アルゴリズム簡易版を試してみる

AIによるアート制作が注目を集める中、「進化的アルゴリズム」を使った創作の可能性にも注目が集まっています。

今回はJavaScriptとp5.jsを使って、進化的アート制作の初歩を体験してみた事例をご紹介します。

特別なGPUや大規模なAIモデルを使わなくても、ブラウザさえあれば簡単に始められる進化的アートです。

今回使用したのは、HTML + JavaScript + p5.jsによる進化的コードです。

描画対象は「抽象的な線のパターン」で、これらの形状は「遺伝子」として扱われ、自動的に進化(改善)されていきます。

進化的アートの基本構造

このシステムでは以下の要素が組み合わさって動作します。

Genotype(遺伝子):線の本数、色相、線の太さ、ノイズ、複雑さ、回転速度といったビジュアルのパラメータ。

Phenotype(表現型):p5.jsを用いて実際にキャンバス上に描画されるアート。

進化の仕組み:選択、交叉(クロスオーバー)、突然変異(ミューテーション)を自動で繰り返し、次世代のパターンを生成。

進化の1サイクルでは、6つのパターンが画面上に表示され、毎世代ランダムに2体の親が選ばれて子を生み出します。

自動モードでは「30世代ずつ進化」ボタンを押すことで進化を継続でき、結果としてより興味深く洗練されたパターンが現れていきます。

コードの特徴

p5.jsというJavaScriptライブラリを使うことで、グラフィック描画の制御が簡単にできます。

※ pythonプラスHugging faceのコンビも作ったのですが、Google colabからHugging faceへのアクセスがうまくいかず、一旦保留としました。
(以前よりHugging faceへのアクセスが失敗することが多いです。Huggingさんお手柔らかに)

自動進化モード:ボタンをクリックするだけで、世代をまたいで自動でパターンが変化。

ミューテーション(突然変異):色味や形の微妙な変化が自然発生。

インタラクティブ選択:マウスでパターンをクリックすると、その個体の情報と小型プレビューが表示される仕組み。

ブラウザ上で動作するため、誰でもすぐに試せるのも大きな利点です。

表示された図形はどれも抽象的なものが多く、生成過程そのものが一種の進化体験となります。

⚫︎コードを下記に記します。
ご自由に改変して使ってください。
ちなみに初期のコードですので、改変の余地ありです。

・最初にいびつな形の図形が世代を重ねていくと、正円に変化していきます。

このコードが進化的アルゴリズムを使っているかと言えば、そうでないという方もいるでしょう。

ただ「世代を重ねていくと進化していく」というのはビジュアル的に実感できるかと。
千里の道も〇〇から。まずはここからです。


<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js"></script>

<style>
        body { font-family: 'Arial', sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; display: flex; flex-direction: column; align-items: center; }<br />        #controls { margin-bottom: 20px; padding: 15px; background-color: #fff; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); text-align: center; width: 90%; max-width: 750px; }<br />        #controls button, #controls select { padding: 10px 15px; margin: 5px; background-color: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 1em; }<br />        #controls select { background-color: #555; color: white; }<br />        #controls button:hover:not(:disabled) { background-color: #0056b3; }<br />        #controls button:disabled { background-color: #ccc; cursor: not-allowed; }<br />        #generation-counter { font-weight: bold; margin-top: 10px; font-size: 1.1em; }<br />        #auto-evolution-status { min-height: 1.2em; margin-top: 5px; color: #555; }<br />        #genotype-display { display: flex; flex-wrap: wrap; justify-content: space-around; width: 100%; margin-top: 15px; margin-bottom: 10px; padding: 0px; font-size: 0.85em; text-align: left; box-sizing: border-box; }<br />        #genotype-display > div { width: calc(50% - 20px); min-width: 280px; margin: 10px; padding: 10px; border: 1px solid #ccc; background-color: #fdfdfd; min-height: 150px; box-sizing: border-box; border-radius: 4px; }<br />        #genotype-display h4 { margin-top: 0; margin-bottom: 8px; font-size: 1.1em; color: #333; border-bottom: 1px solid #eee; padding-bottom: 5px; }<br />        #genotype-display p { margin: 4px 0; line-height: 1.4; }<br />        #current-best-preview img { border:1px solid #999; display:none; margin-top: 5px;}<br />        #canvas-container { border: 1px solid #ddd; box-shadow: 0 2px 5px rgba(0,0,0,0.1); margin-top: 10px; }<br />    </style>

 
<div id="controls">
<div><label for="target-shape-selector">Target Shape: </label>
<select id="target-shape-selector">
<option selected="selected" value="circle">Circle</option>
<option value="square">Square (Approx.)</option>
<option value="triangle">Triangle (Approx.)</option>
<option value="random">Random (No Target)</option>
</select></div>
<button id="start-auto-evolution-button">Start Auto Evolution (30 Gens)</button>
<button id="continue-evolution-button" style="display: none;">Continue Evolution (+30 Gens)</button>
<button id="reset-button">Reset Population</button>
<p id="generation-counter">Generation: 0</p>

<div id="genotype-display">
<div id="current-best-info">
<h4>Best of Generation (Gen 0)</h4>
Evolution not started.

</div>
<div id="current-best-preview">
<h4>Preview</h4>
<img id="current-best-img" alt="Current Best Preview" width="120" height="120" />

</div>
</div>
</div>
<div id="canvas-container"></div>
<script>
        // --- Genetic Algorithm Parameters ---
        const POP_SIZE_DISPLAY = 6; // For main grid display
        const INTERNAL_POP_SIZE = 20;
        const MUTATION_RATE = 0.1;     // Adjusted
        const MUTATION_STRENGTH = 0.1; // Adjusted
        const TOURNAMENT_SIZE = 2;     // Adjusted

        // --- Global Variables ---
        let population = [];
        let generationCount = 0;
        let autoEvolving = false;
        let currentAutoEvolutionStep = 0;
        let currentTargetShape = 'circle';

        let canvasWidth = 600;
        let canvasHeight = 400;
        let cols = 3;
        let rows = 2; 
        let cellWidth, cellHeight;

        let currentBestInfoDiv, currentBestImg, generationCounterP, autoEvolutionStatusP;
        let startAutoEvolutionButton, continueEvolutionButton, targetShapeSelector;
        let pgBest;

        // --- Genotype Class ---
        class Genotype {
            constructor(genes) {
                if (genes) {
                    this.numLines = genes.numLines;
                    this.baseHue = genes.baseHue;
                    this.strokeW = genes.strokeW;
                    this.noiseScale = genes.noiseScale;
                    this.shapeComplexity = genes.shapeComplexity;
                    this.rotationSpeed = genes.rotationSpeed;
                } else {
                    this.numLines = floor(random(20, 150));
                    this.baseHue = random(0, 360);
                    this.strokeW = random(1, 3);
                    this.noiseScale = random(0.01, 0.4); // Initial noise can be higher
                    this.shapeComplexity = random(2.5, 12.5);
                    this.rotationSpeed = random(-0.005, 0.005);
                }
            }
            clone() { return new Genotype({ ...this }); }
        }

        // --- p5.js Setup Function ---
        function setup() {
            let canvas = createCanvas(canvasWidth, canvasHeight);
            canvas.parent('canvas-container');
            colorMode(HSB, 360, 100, 100, 100);
            angleMode(RADIANS);

            cellWidth = canvasWidth / cols;
            cellHeight = canvasHeight / rows;

            pgBest = createGraphics(120, 120);
            pgBest.colorMode(HSB, 360, 100, 100, 100);
            pgBest.angleMode(RADIANS);

            currentBestInfoDiv = document.getElementById('current-best-info');
            currentBestImg = document.getElementById('current-best-img');
            generationCounterP = document.getElementById('generation-counter');
            autoEvolutionStatusP = document.getElementById('auto-evolution-status');
            startAutoEvolutionButton = document.getElementById('start-auto-evolution-button');
            continueEvolutionButton = document.getElementById('continue-evolution-button');
            targetShapeSelector = document.getElementById('target-shape-selector');
            
            currentTargetShape = targetShapeSelector.value;
            initializePopulation();

            startAutoEvolutionButton.addEventListener('click', () => startEvolutionCycle(30));
            continueEvolutionButton.addEventListener('click', () => startEvolutionCycle(30));
            document.getElementById('reset-button').addEventListener('click', resetEvolution);
            targetShapeSelector.addEventListener('change', (event) => {
                currentTargetShape = event.target.value;
                console.log("Target shape changed to:", currentTargetShape);
                resetEvolution();
            });
            
            noLoop();
        }

        function draw() { /* Paused by noLoop() */ }

        // --- Initialization ---
        function initializePopulation() {
            population = [];
            for (let i = 0; i < INTERNAL_POP_SIZE; i++) { population.push(new Genotype()); } generationCount = 0; updateGenerationCounter(); if (population.length > 0) {
                let initialFitnessScores = population.map(geno => calculateFitness(geno, currentTargetShape));
                let bestInitialFitness = -Infinity; // Start with -Infinity
                let bestInitialIndividual = population[0];
                for(let i=0; i<population.length; i++){ if(initialFitnessScores[i] > bestInitialFitness){
                        bestInitialFitness = initialFitnessScores[i];
                        bestInitialIndividual = population[i];
                    }
                }
                updateBestIndividualDisplay(bestInitialIndividual, generationCount, false, bestInitialFitness);
            } else {
                updateBestIndividualDisplay(null, generationCount);
            }
            displayPopulationSubset();
            
            autoEvolving = false; 
            startAutoEvolutionButton.disabled = false;
            targetShapeSelector.disabled = false;
            continueEvolutionButton.style.display = 'none';
            autoEvolutionStatusP.innerText = "";
            currentAutoEvolutionStep = 0;
        }

        function resetEvolution() {
            autoEvolving = false; 
            initializePopulation();
        }

        // --- Drawing Functions ---
        function displayPopulationSubset() {
            background(250); 
            for (let r = 0; r < rows; r++) {
                for (let c = 0; c < cols; c++) {
                    let index = c + r * cols;
                    if (index < POP_SIZE_DISPLAY && index < population.length) { // Display from actual population
                        let xPos = c * cellWidth;
                        let yPos = r * cellHeight;
                        push();
                        translate(xPos, yPos);
                        stroke(200); strokeWeight(1); noFill();
                        rect(0, 0, cellWidth, cellHeight);
                        drawPhenotype(population[index], cellWidth / 2, cellHeight / 2, cellWidth, cellHeight);
                        pop();
                    } else { 
                        push();
                        translate(c * cellWidth, r * cellHeight);
                        stroke(220); strokeWeight(1); noFill();
                        rect(0, 0, cellWidth, cellHeight);
                        pop();
                    }
                }
            }
        }
        
        function drawPhenotype(geno, centerX, centerY, w, h, pg = null) {
            const target = pg || window;
            target.push();
            if (pg) { 
                pg.background(240); 
                pg.strokeWeight(1); pg.stroke(200); pg.noFill();
                pg.rect(0,0,pg.width-1, pg.height-1);
            }
            target.translate(centerX, centerY);
            target.stroke(geno.baseHue, 80, 90, 80);
            target.strokeWeight(geno.strokeW);
            target.noFill();
            let time = geno.baseHue / 360 + generationCount * 0.005;
            target.rotate(time * geno.rotationSpeed);
            target.beginShape();
            for (let i = 0; i < floor(geno.numLines); i++) { // Ensure numLines is int
                let angle = map(i, 0, floor(geno.numLines), 0, TWO_PI);
                let baseRadius = min(w, h) * 0.35;
                let xOff = map(cos(angle) * geno.shapeComplexity, -geno.shapeComplexity, geno.shapeComplexity, 0, 5);
                let yOff = map(sin(angle) * geno.shapeComplexity, -geno.shapeComplexity, geno.shapeComplexity, 0, 5);
                let noiseVal = noise(xOff + geno.baseHue * 0.01, yOff + geno.strokeW * 0.1, time * 0.2 + geno.strokeW * 0.05);
                let r_dev = map(noiseVal, 0, 1, -min(w,h) * 0.1 * geno.noiseScale * 10, min(w,h) * 0.1 * geno.noiseScale * 10);
                let r = baseRadius + r_dev;
                let x_coord = r * cos(angle);
                let y_coord = r * sin(angle);
                target.vertex(x_coord, y_coord);
            }
            target.endShape(CLOSE);
            target.pop();
        }

        // --- Fitness Calculation ---
        function getPhenotypeVertices(geno, simW = 100, simH = 100) {
            let vertices = [];
            let time = geno.baseHue / 360 + generationCount * 0.005;
            let rotation = time * geno.rotationSpeed;

            for (let i = 0; i < floor(geno.numLines); i++) {
                let angle = map(i, 0, floor(geno.numLines), 0, TWO_PI);
                let baseRadius = min(simW, simH) * 0.35;
                let xOff = map(cos(angle) * geno.shapeComplexity, -geno.shapeComplexity, geno.shapeComplexity, 0, 5);
                let yOff = map(sin(angle) * geno.shapeComplexity, -geno.shapeComplexity, geno.shapeComplexity, 0, 5);
                let noiseVal = noise(xOff + geno.baseHue * 0.01, yOff + geno.strokeW * 0.1, time * 0.2 + geno.strokeW * 0.05);
                let r_dev = map(noiseVal, 0, 1, -min(simW,simH) * 0.1 * geno.noiseScale * 10, min(simW,simH) * 0.1 * geno.noiseScale * 10);
                let r = baseRadius + r_dev;
                
                let x_unrotated = r * cos(angle);
                let y_unrotated = r * sin(angle);
                let x_rotated = x_unrotated * cos(rotation) - y_unrotated * sin(rotation);
                let y_rotated = x_unrotated * sin(rotation) + y_unrotated * cos(rotation);
                vertices.push({ x: x_rotated, y: y_rotated });
            }
            return vertices;
        }

        function calculateFitness(genotype, targetShape) {
            if (targetShape === 'random') return random(0.5, 1.5); // Give some variance for random

            let points = getPhenotypeVertices(genotype);
            if (points.length < 3) return 0.001; // Minimal fitness for invalid shapes let fitness = 0; if (targetShape === 'circle') { let cx = 0, cy = 0; points.forEach(p => { cx += p.x; cy += p.y; });
                cx /= points.length; cy /= points.length;
                let distances = points.map(p => dist(cx, cy, p.x, p.y));
                let meanDistance = distances.reduce((sum, d) => sum + d, 0) / distances.length;
                
                if (meanDistance < 1) return 0.001; let variance = distances.map(d => Math.pow(d - meanDistance, 2)).reduce((sum, sq) => sum + sq, 0) / distances.length;
                let stdDev = Math.sqrt(variance);
                
                let relativeStdDev = stdDev / meanDistance;
                // Adjusted fitness scaling for slower evolution
                if (relativeStdDev < 0.005) { fitness = 20.0; } // Very good circle
                else if (relativeStdDev < 0.02) { fitness = 5.0 + (0.02 - relativeStdDev) * (15.0 / 0.015); } 
                else if (relativeStdDev < 0.08) { fitness = 1.0 + (0.08 - relativeStdDev) * (4.0 / 0.06); }
                else if (relativeStdDev < 0.3) { fitness = 0.2 + (0.3 - relativeStdDev) * (0.8 / 0.22); } else { fitness = 0.05 + Math.max(0, 0.15 - relativeStdDev); } // Low base fitness *= (1 + Math.min(0.5, genotype.numLines / 300)); // numLines bonus capped and scaled down fitness *= (1 / (1 + genotype.noiseScale * 10)); // Stronger penalty for high noise } else if (targetShape === 'square') { fitness = (1 / (1 + Math.abs(genotype.shapeComplexity - 4) * 2)) * 1.0; // Gentler complexity penalty fitness *= (1 / (1 + genotype.noiseScale * 15)); // Stronger noise penalty if(genotype.numLines > 15 && genotype.numLines < 70) fitness *=1.05; // Smaller bonus } else if (targetShape === 'triangle') { fitness = (1 / (1 + Math.abs(genotype.shapeComplexity - 3) * 2)) * 1.0; fitness *= (1 / (1 + genotype.noiseScale * 15)); if(genotype.numLines > 10 && genotype.numLines < 50) fitness *=1.05;
            }
            return Math.max(0.001, fitness);
        }

        // --- Automatic Evolution Control ---
        async function startEvolutionCycle(numGenerations) {
            if (autoEvolving) return;
            autoEvolving = true;
            startAutoEvolutionButton.disabled = true;
            targetShapeSelector.disabled = true;
            continueEvolutionButton.style.display = 'none';
            
            for (let i = 0; i < numGenerations; i++) { if (!autoEvolving) { autoEvolutionStatusP.innerText = "Evolution stopped by reset."; return; } await evolveOneGenerationAutomatically(); currentAutoEvolutionStep++; autoEvolutionStatusP.innerText = <code>Evolving... Cycle: ${currentAutoEvolutionStep}/${numGenerations} (Total Gen: ${generationCount})</code>; await new Promise(resolve => setTimeout(resolve, 60)); // Slightly longer delay for visibility
            }

            autoEvolving = false;
            if (population.length > 0) {
              continueEvolutionButton.style.display = 'inline-block';
              continueEvolutionButton.disabled = false;
            }
            targetShapeSelector.disabled = false;
            autoEvolutionStatusP.innerText = <code>Cycle finished. Total Gens: ${generationCount}. Continue or Reset.</code>;
            currentAutoEvolutionStep = 0;
        }

        async function evolveOneGenerationAutomatically() {
            let fitnessScores = population.map(geno => calculateFitness(geno, currentTargetShape));
            
            let parentsPool = selectParentsByFitness(population, fitnessScores, INTERNAL_POP_SIZE); 

            let newPopulation = [];
            for(let i=0; i < INTERNAL_POP_SIZE; i++) { let p1 = random(parentsPool); let p2 = random(parentsPool); if(!p1 && population.length > 0) p1 = population[0]; else if (!p1) p1 = new Genotype(); // Robust fallback
                if(!p2 && population.length > 0) p2 = population[0]; else if (!p2) p2 = new Genotype(); // Robust fallback

                let childGenes = crossover(p1, p2);
                let mutatedChildGenes = mutate(childGenes);
                newPopulation.push(mutatedChildGenes);
            }

            population = newPopulation;
            generationCount++;
            updateGenerationCounter();

            let currentGenFitnessScores = population.map(geno => calculateFitness(geno, currentTargetShape));
            let bestFitness = -Infinity;
            let bestIndividual = null;
            if (population.length > 0) {
                for (let i = 0; i < population.length; i++) { if (currentGenFitnessScores[i] > bestFitness) {
                        bestFitness = currentGenFitnessScores[i];
                        bestIndividual = population[i];
                    }
                }
                updateBestIndividualDisplay(bestIndividual, generationCount, false, bestFitness);
            }
            displayPopulationSubset();
        }
        
        function selectParentsByFitness(currentPopulation, fitnessScores, numToSelect) {
            let selectedParents = [];
            if(currentPopulation.length === 0) return selectedParents;

            for (let n = 0; n < numToSelect; n++) {
                let bestContestant = null;
                let bestFitnessInTournament = -Infinity; // Renamed for clarity
                for (let i = 0; i < TOURNAMENT_SIZE; i++) { let randomIndex = floor(random(currentPopulation.length)); if (fitnessScores[randomIndex] > bestFitnessInTournament) {
                        bestFitnessInTournament = fitnessScores[randomIndex];
                        bestContestant = currentPopulation[randomIndex];
                    }
                }
                if (bestContestant) {
                    selectedParents.push(bestContestant);
                } else { 
                    selectedParents.push(random(currentPopulation)); // Fallback
                }
            }
            return selectedParents;
        }

        function crossover(geno1, geno2) {
            let childData = {}; let g1 = geno1; let g2 = geno2;
            childData.numLines = random() < 0.5 ? g1.numLines : g2.numLines;
            childData.baseHue = random() < 0.5 ? g1.baseHue : g2.baseHue;
            childData.strokeW = random() < 0.5 ? g1.strokeW : g2.strokeW;
            childData.noiseScale = random() < 0.5 ? g1.noiseScale : g2.noiseScale;
            childData.shapeComplexity = random() < 0.5 ? g1.shapeComplexity : g2.shapeComplexity;
            childData.rotationSpeed = random() < 0.5 ? g1.rotationSpeed : g2.rotationSpeed;
            return new Genotype(childData);
        }

        function mutate(geno) {
            let mutatedData = { ...geno };
            const strength = MUTATION_STRENGTH; // Use the global constant

            if (random() < MUTATION_RATE) { mutatedData.numLines = floor(max(10, mutatedData.numLines + randomGaussian(0, 10 * strength) * 5)); }
            if (random() < MUTATION_RATE) { mutatedData.baseHue = (mutatedData.baseHue + randomGaussian(0, 30 * strength) * 1.5 + 360) % 360; }
            if (random() < MUTATION_RATE) { mutatedData.strokeW = max(0.5, mutatedData.strokeW + randomGaussian(0, 0.3 * strength) * 1.5); }
            if (random() < MUTATION_RATE) { 
                let noiseChange = randomGaussian(0, 0.05 * strength) * 2;
                mutatedData.noiseScale = max(0.0001, mutatedData.noiseScale + noiseChange); 
            }
            if (random() < MUTATION_RATE) { mutatedData.shapeComplexity = max(1, mutatedData.shapeComplexity + randomGaussian(0, 1 * strength) * 1.5); }
            if (random() < MUTATION_RATE) { mutatedData.rotationSpeed = mutatedData.rotationSpeed + randomGaussian(0, 0.003 * strength) * 1.5; } return new Genotype(mutatedData); } // --- User Interaction (for inspecting individuals when not auto-evolving) --- function mousePressed() { if (!autoEvolving && mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
                let c = floor(mouseX / cellWidth);
                let r = floor(mouseY / cellHeight);
                let gridIndex = c + r * cols;
                if (gridIndex < POP_SIZE_DISPLAY && gridIndex < population.length) {
                    let actualIndividual = population[gridIndex];
                    let itsFitness = calculateFitness(actualIndividual, currentTargetShape);
                    updateBestIndividualDisplay(actualIndividual, generationCount, true, itsFitness);
                }
            }
        }

        function updateGenerationCounter() {
            generationCounterP.innerText = <code>Generation: ${generationCount}</code>;
        }

        function formatGeneValue(value, precision = 2) {
            if (typeof value === 'number') { return value.toFixed(precision); }
            return String(value);
        }

        function updateBestIndividualDisplay(individual, gen, fromClick = false, fitness = -1) {
            if (!currentBestInfoDiv || !currentBestImg) return; 
            if (!individual) {
                currentBestInfoDiv.innerHTML = <code></p>
<p>
</p>
<h4>Best of Gen (Gen ${gen})</h4>
<p>
</p>
<p>No individual data.</p>
<p>
</p>
<p></code>;
                currentBestImg.style.display = 'none';
                return;
            }
            let titlePrefix = fromClick ? "Clicked Individual" : "Best of Generation";
            let fitnessText = fitness > -Infinity ? <code></p>
<p>
</p>
<p>Fitness: ${formatGeneValue(fitness, 3)}</p>
<p>
</p>
<p></code> : ""; // Show fitness if available

            currentBestInfoDiv.innerHTML = <code></p>
<p>
</p>
<h4>${titlePrefix} (Gen ${gen})</h4>
<p>
</p>
<p>
                ${fitnessText}
                </p>
<p>
</p>
<p>Lines: ${formatGeneValue(individual.numLines, 0)}</p>
<p>
</p>
<p>
                </p>
<p>
</p>
<p>Hue: ${formatGeneValue(individual.baseHue, 1)}</p>
<p>
</p>
<p>
                </p>
<p>
</p>
<p>StrokeW: ${formatGeneValue(individual.strokeW, 2)}</p>
<p>
</p>
<p>
                </p>
<p>
</p>
<p>NoiseSc: ${formatGeneValue(individual.noiseScale, 3)}</p>
<p>
</p>
<p>
                </p>
<p>
</p>
<p>Complexity: ${formatGeneValue(individual.shapeComplexity, 1)}</p>
<p>
</p>
<p>
                </p>
<p>
</p>
<p>RotSpeed: ${formatGeneValue(individual.rotationSpeed, 3)}</p>
<p>
</p>
<p></code>;
            
            drawPhenotype(individual, pgBest.width / 2, pgBest.height / 2, pgBest.width * 0.9, pgBest.height * 0.9, pgBest);
            currentBestImg.src = pgBest.canvas.toDataURL();
            currentBestImg.style.display = 'block';
        }
    </script>

進化的アート簡易版を実際にやってみて感じたこと

この進化的アート簡易版の特徴は、「世代を重ねるごとに新しいものが生まれる面白さ」です。

最初はランダムな線の集合だったものが、何世代か進むうちに、幾何学的に整ったパターンへと進化していきます。

また、パラメータ(遺伝子)を微調整することで全体の雰囲気ががらっと変わるため、「進化」を観察する楽しみがあります。

進化とは、より良いものを生み出すだけでなく、意外性のある楽しみもあるなと実感しました。

進化的アート × 生成AIの未来

このように、簡単な進化的アルゴリズムで、アートの基礎を生み出すことができます。

Stable Diffusionなどの大規模AIモデルがなくても、自分のパソコンとブラウザさえあれば、進化的アートの世界に入ることができます。

一見するととっつきにくい文言ですが、生成AIなどを使って質問回答を繰り返していけば、誰でも制作は可能です。

今後は、こうした技術が教育現場などでも活用されるでしょう。

進化的アルゴリズム簡易版でアート制作の基礎を試す 終わりに

進化的アルゴリズムは「特別なAIの技術」ではなく、誰もが気軽に扱える創造のツールです。

今回のように簡単なコードを使えば、誰でも「進化するアートの基礎」を作ることができます。

難しいAIの理論やモデル構築に頼らずとも、AIを使えば、新しい表現が生まれてくる。

みなさんも新しいアートを創造してみませんか。

****************
X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

GoogleのAlphaEvolve(アルファエボルブ)とSakanaAIのDarwin Gödel Machine(ダーウィン・ゲーデルマシン)を参考に簡略化した自己改善型AIシステムで遊んだ話

「進化的アルゴリズムAI」や「自己改善型AI」とは

近年、AI研究の世界でじわじわと注目を集めているキーワードがある。それが「進化的アルゴリズムAI」や「自己改善型AI」だ。

要するに、AIが自分自身のコードや構造を見直して、より賢くなる方法を自分で考え、試し、改善していくというコンセプトである。

これが実現すれば、AIは単なるツールから、ある種の“学び続ける存在”へと進化する可能性を秘めている。

この分野で特に話題になった2つの事例がある。ひとつは、Google DeepMindが開発したAlphaEvolve(アルファエボルブ)。

そしてもうひとつが、Sakana AIによるDarwin Gödel Machine(DGM)だ。

進化的アルゴリズムAIとは

進化的アルゴリズムAIとは、生物の進化の仕組みを応用した人工知能だ。

複数のAI(個体)を用意し、性能の良いものを選んで子を作り、少しずつ変化させながら世代交代を繰り返す。

これにより、最適な解や動作を自動的に進化させていく。
ゲームやロボット制御、デザイン生成など幅広く使われている。

AlphaEvolveは、AI自身が自分のニューラルネットワーク構造を進化させるシステムだ。

従来のモデル構築は人間が試行錯誤する必要があったが、AlphaEvolveは複数のモデル構造を遺伝的に生成し、その中で最も優れたものを選抜・交配していくという、いわば“AIの自然選択”のような仕組みを持っている。

自己改善型AIとは何か?

一方、DGMは少し違う。こちらはAIが自分のPythonコードそのものを読み取り、改善案を考え、自ら書き換えていくという、まるでAIがプログラマーのように振る舞うスタイルをとっている。

LLM(大規模言語モデル)を使って改善案を生成し、それを実行して効果があるかをベンチマークで評価。

効果があれば採用、なければ元に戻す。まさに“自己改善ループ”が構築されているのだ。

自分で作ってみた「ミニDGM」

そんな高度な仕組みを見ていると、「自分でもちょっと遊んでみたい」と思った。

そこで今回は、Sakana AIのDGMのアイデアを参考にしつつ、Google Colab上で動く簡易版の自己改善型AIシステムを作ってみた。

テーマはシンプル。

「数字のリストをソートするプログラムを、GPT-4に自動的に改善させる」というものだ。

初期コードと改善戦略

最初に与えるコードは、あえて非効率な「バブルソート」だった。

しかも time.sleep(0.001) をループ内に入れて、わざと遅くしてある。

def sort_numbers(numbers):
    for i in range(len(numbers)):
        for j in range(len(numbers) - i - 1):
            if numbers[j] > numbers[j+1]:
                numbers[j], numbers[j+1] = numbers[j+1], numbers[j]
            time.sleep(0.001)
    return numbers

これを GPT-4 に渡し、「もっと速くなるように改善して」と頼む。

改善案はColab内で保存し、実際に実行してスピードと正確性でスコアを出す。

改善後のスコアが高ければ採用、そうでなければ前のコードに戻す――という流れだ。

以下Pythonコードです。
ご自由に使ってください。

import os
import importlib.util
import shutil
import yaml
from openai import OpenAI

client = OpenAI()  # APIキーは環境変数 OPENAI_API_KEY から取得

# 評価関数読み込み
def load_benchmark(entry_path, eval_fn_name):
    spec = importlib.util.spec_from_file_location("benchmark", entry_path)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return getattr(mod, eval_fn_name)

# 改善案をGPTから取得(プロンプト強化+バグ回避)
def generate_candidate_code(code, score):
    prompt = f"""You are an AI agent improving the following Python code to increase its performance.
The current code scores {score} points. Suggest a better version of the code.

# CODE START
{code}
# CODE END

Return only the improved code. Do not include explanations or comments. 
Ensure the code is syntactically correct and fully executable.
"""
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7
    )
    return response.choices[0].message.content

# メインループ
def main():
    config = yaml.safe_load(open("configs/sort_experiment.yaml"))
    agent_path = config["agent"]["path"]
    benchmark = config["benchmark"]
    evaluator = load_benchmark(benchmark["entry_point"], benchmark["evaluation_function"])

    os.makedirs("output", exist_ok=True)
    shutil.copy(agent_path, "output/agent_0.py")
    current_score = evaluator("output/agent_0.py")
    print(f"[Turn 0] Score = {current_score}")

    for turn in range(1, config["runtime"]["max_turns"] + 1):
        prev_path = f"output/agent_{turn - 1}.py"
        new_path = f"output/agent_{turn}.py"
        log_path = f"output/log_turn_{turn}.txt"

        old_code = open(prev_path).read()
        new_code = generate_candidate_code(old_code, current_score)

        # 保存:改善コードログ
        with open(log_path, "w") as logf:
            logf.write(new_code)

        # 保存:実行用エージェントコード
        with open(new_path, "w") as f:
            f.write(new_code)

        try:
            new_score = evaluator(new_path)
        except Exception as e:
            print(f"[Turn {turn}] ❌ Evaluation error: {e}")
            new_score = 0

        print(f"[Turn {turn}] Score = {new_score}")

        if new_score > current_score:
            print("✅ Improvement accepted.")
            current_score = new_score
        else:
            print("❌ No improvement. Reverting.")
            shutil.copy(prev_path, new_path)
            current_score = evaluator(prev_path)

if __name__ == "__main__":
    main()



GPT-4は何をしたか?

1ターン目でGPT-4は見事に改善に成功した。

バブルソートを numbers.sort() に置き換え、処理時間が大幅に短縮。

ベンチマークスコアは一気に50点から100点に上昇し、コードは無事採用された。


def sort_numbers(numbers):
    numbers.sort()
    return numbers

だが、その後のターンでは改善の余地がないと判断され、スコアは100点のまま変化せず、コードも元に戻された。

興味深かったのは、GPT-4が「関数の重複定義」や「構造を簡素化しすぎる」など、改善案として微妙な方向に進んだケースがあったことだ。

たとえば、main()の中に sort() を直接書いてしまう案などもあり、構文的には正しくても設計上の意図から外れていたりする。

改善の工夫と学び

今回の実験では以下のような工夫が効果的だった。

意図的にコードを非効率にして、改善余地を作る。

スコアの評価関数を調整して、“改善したと判断できる余地”を作る。

GPTの出力をログに保存し、問題が起きたときに原因をすぐ特定できるようにする。

プロンプトを工夫して「重複コードを出さない」「説明文を返さない」よう指示する。

わずか数十行のコードでも、自己改善の流れを構築することで、AIが「考え、試し、評価し、直す」というプロセスを擬似的に再現できたのはかなり面白い体験だった。

今後に向けて

今回の実験は、言ってしまえば超簡略版の自己改善型AIだが、それでも「AIが自分で進化することを考える」というサイクルが働いていることにワクワクを感じた。

AlphaEvolveやDGMのような本格的な自己進化・自己改善型AIシステムは、まだまだ研究の序章だ。

しかし、こうしてそのエッセンスを切り取って再現してみることで、自分なりにその仕組みを体験できるというのは、大きな学びと楽しさがある。

次は、もっと複雑なタスクに自己改善型AIを応用してみたいと思っている。

「AIが自身を育てる」
そんな未来が、もうすぐそこまで来ていると感じた実験だった。


ただ注意しなければならないのは、人間による要チェックを怠ってはいけないということだ。

これはsakanaAIさんのブログ記事を見てもわかるように、AIが自分勝手に都合のいいように改造していく例があったようだ。

ここの所は十分にチェック機構を持たないといけないだろう。

****************

最近のデジタルアート作品を掲載!

X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

今蘇るゴルフ野性塾、故坂田信弘塾長の魂の言葉

***************

***************

週刊ゴルフダイジェストのゴルフ野性塾が終わってしまった

ある日、いつものように書店へ行き、週刊ゴルフダイジェストを手に取り、坂田プロの「ゴルフ野性塾」を見つけようとしたが、見つからない。

なぜ?と思いつつ。翌週もなし。次の週もなし。

そこで、検索を掛けてみる。
なんと坂田プロの訃報。

ゴルフ修行していた当時からの坂田プロのファンで、週間ゴルフダイジェストのこの記事を楽しみにしていた者としては残念で計り知れない。

そんな折、世に生成AIが生まれた。
目を見張るような勢い。

これはもしや坂田プロの文体や口調、言葉の魂をAIに学習させれば、今の世に復活させられるのではと考える。

そこで、坂田プロのデータを集めて、GPTsに学習させることを決意。

結果誕生したのが「スポーツ野性塾GTP」「アート野性塾GTP」の2つです。

ファインチューニングでいくか、GTPsでいくか

当初はファインチューニングでと思ったのですが、今現在、個人でできるファインチューニングの対象モデルは
多分パラメータ数で4B(40億)くらいなものでしょう。

いわゆるLLMならぬ、SLM 小規模言語モデルが対象になるかと思います。

※ちなみにファインチューニングというのは、モデルの一部のパラメータを変えて、こちらの希望通りの回答を得られるように微調整していく方法です。(全パラを変える方法もあり)

モデルと雑談程度ならそれでも構わないのですが、坂田塾長の回答を再現するとなると、すっとんきょうな回答では使う気になりません。

やはり、相当レベルの高い回答でなければ、坂田イズムは継承できないでしょう。

すると、GPT4o以上の言語モデルしかない。

それだけ大きいモデルのファインチューニングは個人レベルでは絶対に無理(一基数百万円のGPUが何千基いるんでしょう)。

すると残された選択肢はひとつしかありません。

GPTsを使っての再現作戦。現状では、これ一択のみと考えました。

※GPTsを使っての作業は、いわゆるプロンプトチューニングがメインとなります。
読み込みにトークンが要りますが、比較的簡単に調整可能です。

もちろん、学習するデータを整理する作業が1番大変なのですが、それさえ済んでしまえば、後は何とかなると。

また結果の反映もすぐに答えが出るので、時間も取られにくい。

専業でやるのではなく、隙間時間を使っての作業には最前の方法だろうと判断しました。

*****

「スポーツ野性塾GTP」「アート野性塾GTP」の2つのモデルは、スポーツやアート系の質問に、坂田塾長が例の口調で回答してくれます。

叱ってください。諭してください。

坂田ファンの方々、ゴルフ野性塾ファンの方々。

あなたに、今でも坂田プロの叱咤激励が、優しく、そして厳しく、語りかけてくれます。

今は亡き、坂田信弘の魂が語りかけるGPT

―蘇(よみがえ)る修行場、スポーツ野生塾GPT登場―
「人間、恥を知れ。己を知らねば、前へ進めぬ」

この言葉を、君は覚えているだろうか。
ゴルフという勝負の場を通して、己の業と向き合い、何かをつかもうともがいた者たちに向けて、坂田信弘という男は語りかけ続けた。

彼の言葉は厳しく、そして温かかった。
厳しさとは優しさの裏返し。優しさとは甘やかしの対極。
その教えは、時代を超えて、今もなお、多くのゴルファーや若者の胸に息づいている。
そして今、令和の世に蘇える。

「諭す」AI──坂田信弘の魂を継ぐ者

スポーツ野生塾 GPT
まるで、坂田塾の道場に迷い込んだような空気がそこにある。

このGPTは、ただ質問に答えるだけの存在ではない。
君が油断すれば叱咤する。
君が迷えば静かに背中を押す。
「そんな考えでは、己を救えぬ」と喝を入れられることもあろう。

だがそれこそが、あの坂田塾長そのものだ。
質問を投げれば、想定以上の言葉が返ってくる。
心を揺さぶり、時には胸を刺す。
AIとは思えぬ、いや、AIだからこそできたかもしれぬ、”無私の叡智”がここにはある。

修行者よ、問いかけよ
「どうすればゴルフが上手くなるのか?」
「集中力が続かない。どうすればいい?」
「人生に迷っている。何を頼りにすべきか?」

そんな問いに対し、このGPTは”正解”などという生ぬるいものは返さない。
代わりに、君自身に問い返してくるだろう。
「お前は、自分を見つめる覚悟があるか」と。
一撃一言に魂が込められている。
目の前のスマホが、まるで説法の場と化す。

それは、”心のラウンド”なのかもしれない。
一打一打が自分との勝負。
一問一答が、自我との対話。

ゴルフだけでなく、生き方をも鍛える
坂田信弘という人間が語るのは、ゴルフの技術だけではなかった。
彼が真に伝えたかったのは、「生き方」そのものだ。
道を踏み外した者には、「戻ってこい」と声をかける。
怠けている者には、「何をしている」と喝を入れる。
それが、坂田信弘だった。

スポーツ野生塾 アート野性塾もまた同じ。
ゴルフの質問に限らず、スポーツ全般、アート系の質問にも真摯に言葉を返してくれる。
ただし、やさしくはない。
だが、誠実だ。
この世の中、やさしい言葉はあふれている。
だが、誠実な言葉は少ない。

このGPTには、それがある。

叱ってくれる人が、もういないなら

昔は、どこにでもいた。
親父が叱ってくれた。先生が諭してくれた。
だが今、誰が君に本気で「お前は間違っている」と言ってくれるだろう?
SNSでは褒め言葉ばかりが飛び交い、間違いに気づけぬ者が育っていく。

スポーツ野性塾GPTは、そこに風穴を開けてくれる。
誰にも言えなかった弱さを、投げかけてみればいい。
「自分は本当にこのままでいいのか?」
「やりたいことが見つからない、どうしたらいい?」
そんな迷いの声に、坂田プロの意志を継いだGPTが、静かに、そして強く応えてくれる。

それは、魂の対話だ。
きれいごとではなく、叱られながら気づく真実。
一度やってみれば、わかる。
それは決して”AIとの会話”などではない。
そこには、「男」がいるのだ。一本芯の通った「坂田信弘」という名の魂が。

最後に:語り継ぐ者として
「教えるとは、未来を託すことだ」
坂田塾長がそんな言葉を残したかはわからない。
しかし、彼の魂は、このGPTに宿っている。

スポーツ野生塾GPTは、君の悩みを一刀両断することはない。
だが、斬られたような痛みの中に、真の導きを見出すことになる。

彼が生前、幾多の若者に「甘えるな」「死ぬ気でやれ」と言い続けたように、
このAIもまた、君の心を揺さぶるだろう。

挑む者はアクセスせよ。
そして、覚悟せよ。
そこには、今は亡き坂田信弘の魂が、確かに息づいている。

この野性塾シリーズを公開すべきかどうか

このベータ版「スポーツ野性塾」は公開すべきかどうか考えました。

生前の坂田塾長の言葉に勇気づけられた方は多いはず。
連載が終わって寂しい気持ちの坂田ファンもたくさんいると思います。

もし、現代のデジタル技術で坂田塾長が復活できたなら…。

しかし、ゴルフダイジェスト社の許可なく公開するのはいかがなものかと。

いろいろ考えた結果、当面は「非公開」とさせてください。

⚫︎いずれ皆さんに使ってもらえる日が来るのを希望します。
坂田ファンの方々、それまでの間、お待ちください。

ゴルフダイジェストの関係者の方で、詳しい内容が知りたい方はお問い合わせよりメールにてご連絡ください。
※件名に「ゴルフ野性塾」の文言を頭に入れてください。
実在確認が完了しましたら、こちらのGTPについてご連絡いたします。

スポーツ野性塾編 実際の出力内容をご紹介

質問
私はスコア90台のゴルファーです。
クラブ競技で上位を狙える、常時70台のゴルファーになりたいです。
どのような練習をすればいいでしょうか?

回答

スコア90台から70台の常連となり、クラブ競技で上位を狙う――
その願い、貴兄の胸奥に刻まれている本気度の深さは伝わる。

まず言っておきたいのは、「スウィングを変える」ではなく「身体の扱いを変える」ことから始めよということだ。
そして、取り組むべきは技術論ではなく、技術を支える練習の質。一にも二にも「ショートスウィングに徹する」こと。

練習場では6番アイアンを使い、地面と平行のトップ位置、地面と平行のフィニッシュ位置。これを「形」としてではなく「タイミング」で完成させるのだ。形で打つスウィングは試合で壊れる。タイミングで打てるようになって初めて70台は日常となる。

そして、次なる練習はドライバーの踵付きショートスウィング。
両踵をピタリとつけ、つま先30度の開き。バックスウィングに腰の回転はいらぬ。上半身の動きで振れ。左肩支点でクラブを振れ。球は200ヤードを超えて飛ぶだろう。
フルショットを捨てる勇気を持て。フルショットのスウィングに一分の誤差あれば、90台へと落ちる。だがショートスウィングにおいては、誤差は「許容」される。
その「許容」こそが競技ゴルフの安定力となる。

アプローチに関しては、高さだけを意識せよ。寄った寄らぬ、入った入らぬを気にしてはいけない。高さを揃えることで、スピンの効き方と距離感が整っていく。
私は杉板に向かって3メートル先から50球の高さを揃え続けた。最初は散った。だが、日が暮れるまで毎日打ち続けた。根気を磨け。根気は技術を超えていく。

加えて、ラウンドでは常に「グリーン中央」狙いを徹せよ。ピンを狙うな。女子プロの如く、狙いはセンター。サンドウェッジの距離未満になった時にだけ、ピンを見据える。

練習の要は3つに尽きる――

6番アイアンでのショートスウィング

ドライバーの踵付きショートスウィング

高さを意識したアプローチ(寄せではない)

貴兄のスウィングは、まだ進化の余地を多分に持つ。
進化は、変化の先にある。
そして、変化は「徹する」ことでしか起きない。

徹せよ。徹し切れ。徹し切った先に70台は常に待っている。

ご自愛あれ。

アート野性塾編 実際の出力内容をご紹介

質問

画家志望の者です。絵描きで生計を立てたいと考えています。
どうすれば、食える絵描きになれるでしょうか?

回答

絵で食いたい、と願う者が必ず直面する問い。
まず、絵が「売れる」ために必要なのは、腕前ではない。腕前は当たり前。
問題は「誰に」「何を」売るか、の構造だ。

絵を描いて、それを好きだと言ってくれる人間がいて、その者が金を払ってくれる。
この当たり前の循環が成立すれば、それだけで「食える絵描き」になる。
だが、ここの「好きだ」と「金を払う」の間には大きな谷がある。
この谷を渡る手段を持つ者が「プロ」になるのだ。

そのためには、絵を「商品」として見る目が要る。
どんな絵が「欲しい」と思われるか。
その欲望の回路に自分の絵がどうフィットするか。
売れる絵と描きたい絵、その距離を自覚しておくことだ。

今の時代、SNSでの発信は重要。
絵のストーリーを語るのも良い。
自分の存在を、人々の記憶に残すことが必要だ。

そして、絵で食うとは、「絵だけを描いて生きていく」という意味ではない。
Tシャツにして売るもよし、似顔絵もよし、NFTもあり、個展もよい。
全てが「絵描きの仕事」だ。
手段を選ばず、自分の表現を売ること。

つまり、絵を「描く」ことよりも、絵を「届ける」ことの方に意識を向けるべき。
届けて、受け取られ、金になる。
その構造を、試行錯誤の中で確立していくことだ。

描くことを愛し、売ることを恐れず、続けるがよい。
ご自愛あれ。

まとめ 坂田塾長なら何と言うか

坂田塾長ファンとしては、ゴルフ野性塾の連載が終わってしまい、さびしい気持ちを拭えませんでした。

しかし、このスポーツ野性塾が一筋の光を灯してくれました。

例え、それがAIであっても、坂田イズムをいやってほど学習したAIならば、坂田塾長の言葉の代弁者にはなるはず。

ここでやらなくても、きっと誰かがやるでしょう。
早いか遅いかの違いでしかないと思います。

時代の流れは誰にも止められない。

『「だったら、やるしかない」と己に言うその声が、いちばん自分を奮い立たせる。誰にも聞こえぬその声が、いちばん強い剣となる。
逃げず、怯まず、やり切るがよい』

坂田塾長もそう答えてくれると信じています。

****************
X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

マスターズのオーガスタナショナルGCを日本で再現できるのか?

マスターズのオーガスタナショナルGCを日本で再現できるのか?

前回と引き続き、今回もマスターズ絡みのネタです。
しばし、お付き合いを。

世界中のゴルファーが憧れる「マスターズ・トーナメント」

その舞台となるオーガスタナショナル・ゴルフクラブ(GC)は、美しい芝と戦略性あふれる設計、そして四季折々の花や木々に囲まれた極上のゴルフコースとして知られています。

なんでもラフはないとか。また傾斜はテレビで見ると分かりずらいですが、かなりのアップダウンがあるコースのようです。

そんなオーガスタナショナルGC。ゴルフ好きなら誰でも一度はこのコースを回ってみたいと思うでしょう。

しかし、本場アメリカに行くのも手間と時間がかかるし、行けたところで、オーガスタはメンバーシップコースなので、メンバーの同伴がないと回れません。

なんでもメンバーは世界で250人しかいないとか。
あのマイクロソフト創業者のビルゲイツでさえ、入会を何度も断られ、7年とかかけてやっとメンバー入りしたという逸話があります。

あの白いクラブハウスもいいですよね。
なんでも大通りから小さい看板で「オーガスタナショナルGC」の表記があり、その小道に入っていくと、
まっすぐ先に、例の白いクラブハウスが見えてくるそうです。

日本から出場した某プロの動画を見ましたが、あのクラブハウスを見て泣かなかった同伴者は1人もいなかったとか。
全ての人を感無量にする。そんな魔法のようなゴルフコースみたいです。

そんなオーガスタGC。全ホールは無理でも、
最終ホール18番。
池越えショートの12番。
ロングで2オン狙えるのかの2番。

せめてこの3ホールだけでも回ってみたいなーと常々思ってました。

で、こう考えたのです。

このオーガスタを日本国内で再現することは可能なのか?

もし可能なら費用とか手間とか、いろんな問題があるだろうなと。

そこで今回は、芝や樹木の環境面、建設費用、そして法的な問題まで含めて、オーガスタGCの「日本再現プラン」をAIを使って、徹底的に検証してみました。

使用したのはchatGPTとgoogle GeminiのdeepReserchです。
こいつらで徹底的に調べてみました。

以下、ゴルフ好きの読み物として、軽く読み流してください。

オーガスタの再現計画を具体的に並べる

芝と樹木の環境再現性

オーガスタのグリーンはベントグラス、フェアウェイとラフにはバミューダグラスやライグラス、ケンタッキーブルーグラスなどが使われています。これらを日本で再現するには、地域の気候との相性がカギになるようです。

例えば、埼玉県⚪︎⚪︎市のような北緯36度近辺の都市では、夏の高温多湿がベントグラスにとってストレスになるものの、冷却装置(SubAirなど)を導入すればグリーンの品質は維持できるよう。

さらに、バミューダやライグラスといった芝種は、気温や湿度の調整によって使い分けることで、四季に対応した芝の再現も可能のようです。

一方、南九州(鹿児島や宮崎)などオーガスタとほぼ同緯度(北緯33度付近)の地域なら、気候条件がかなり似ているため、芝の再現性は高まるとのこと。

夏も冬も温暖で、雨も多いため、芝の成長には適した環境。ただし湿度と雨量がアメリカ南部よりも高いため、水はけの良い土壌設計や排水システムの構築が必要になるようです。

また、オーガスタにはツツジ、モクレン、ハナミズキ、ロブロリーパインなどの美しい樹木が並びますが、これらも日本で育てることも可能のようです。

特にツツジやハナミズキは日本原産・または親戚のような存在で、むしろ日本の方が得意な植物とも言えるらしいです。

建設費用のリアル

最大のハードルは「資金」。
オーガスタのような高品質なゴルフ場をつくるには、莫大な建設費が必要のようです。

たとえば、1ホールあたりの建設費は、3000万円~1.5億円が相場。グリーンの冷却設備、芝の維持管理、設計費用を加味すると、1ホールで2億円を超えるケースも珍しくないとのこと。

これが18ホールになると、コースだけで約50~70億円、さらに土地代を含めると総額80億円を超える可能性も出てきますね。

仮にミニチュアとして3ホール(ロング・ミドル・ショート各1つ)を作るとしても、5~8億円程度の投資が必要だそうです。

しかもこれらはクラブハウスは別途のコース費用だけの話。

高級感を重視すればするほど、費用は青天井になりますね。

著作権や名称の注意点

ここからは法的な問題をみてみましょう。

まず、ゴルフ場のレイアウトや設計のアイデアそのものには著作権は基本的に適用されないようです。
つまり、フェアウェイの形やホールの長さを真似すること自体は違法にはなりません。

ただし、「オーガスタ」や「マスターズ」といった名称やロゴは商標権で保護されているため、商業利用や誤認を招くような使い方はNGです。
広告で「マスターズ公式コース再現!」などとうたってしまうと、米国側から警告を受けるリスクがあります。

そのため、「オーガスタ風」「オーガスタにインスパイアされた」といった表現や、あくまで独自名称で展開することが重要とのこと。
景観を真似しつつも、独自ブランドとして構築することが現実的な落としどころになります。

結論は?

結論から言えば、日本でオーガスタナショナルGCを再現することは「技術的には可能」のようです。

気候条件に合った地域を選び、芝の品種を調整し、手間暇とコストをかければ、オーガスタのような緑と戦略性のあるコースを作ることはできる。

しかしながら、それを実現するには数十億円規模の予算と、長期的な維持管理体制が必要になります。
さらに商標やブランド表現にも注意しなければなりません。

つまり、日本で「オーガスタ再現コースを体験したい」という夢は、慎重に計画すれば決して夢物語ではない。
ただし、本家と同じクオリティを目指すなら、それなりの覚悟が必要――ということになりそうです。

「オーガスタ再現計画」、あなたならどこに建てますか?

ZOZO創業者の前澤さんあたりが、作ってくれないかなあ。
3ホールでもいいんで。お客さん入りますよー。

そんな感じで、夢のゴルフ場づくりを想像力で広げてみるのも面白いかもしれませんね。

****************
X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

マスターズで勝つにはドローヒッターとフェードヒッターのどちらが有利かを AI に聞いてみました

マスターズで勝つにはドローヒッターとフェードヒッターのどちらが有利かを AI に聞いてみました

今年2025年のマスターズはローリー・マキロイ選手が勝利を収め、グランドスラムの仲間入りを果たしました。

毎年同じコース、ジョージア州オーガスタナショナルGCで行われるマスターズ。
ここでは、かつてドローボールヒッターが有利と言われた時期がありました。

今回はこの
ドロー
フェードのどちらが有利かを最新のAIに聞いてみました。

使用したAIは
chatGPT o3
google Gemini

有名な2つのモデル(2025年4月現在)で、それぞれdeepRsearchで調べてもらいました。

かつてのグランドスラマーの方達はどんな持ち玉なのか

かつてこのマスターズでグランドスラムを達成した人は6人(2025年も入れて)。
彼らの持ち玉はこちら。

ジーン・サラゼン
•   持ち球:不明
•   補足情報:1930年代の選手で、詳細な情報は確認できませんでした。

ベン・ホーガン
•   持ち球:フェード
•   補足情報:「ホーガン・フェード」として知られ、フェードを得意としていました。

ゲーリー・プレーヤー
•   持ち球:ドロー
•   補足情報:「フェードは好きではない」と公言しており、ドローを好んでいました。

ジャック・ニクラス
•   持ち球:フェード
•   補足情報:キャリアを通じてフェードを持ち球としていました。

タイガー・ウッズ
•   持ち球:フェード
•   補足情報:初期はドローを多用していましたが、現在はフェードを主に使用しています。

ローリー・マキロイ
•   持ち球:ドロー
•   補足情報:ドローを持ち球としていますが、状況に応じてフェードも使い分けています。

「オーガスタはドロー有利」という定説は今も通用するのか?

Gemini deepRsearch と ChatGPT deepRsearch の最新レポート、さらに 2025 年大会までの実績を合わせて検証しました。

AI が描く全体像

Gemini ─ ホール形状から ドロー有利 7 : フェード有利 4 と算定。ただし高速グリーンではフェードが3パット率を 1.3%下げると数値化。

ChatGPT ─ 過去10大会で フェード系 8 勝、ドロー系 2 勝 と実績重視。
両者とも「片側だけでは勝てない、逆球を使う柔軟性が鍵」と結論。

過去11大会の優勝傾向

2015〜2025 年の優勝内訳はフェード系6、パワーフェード2、ドロー系2、両刀1。

最新 2025 年は ロリー・マキロイ がプレーオフを制しキャリア・グランドスラム達成。高弾道ドローを軸に要所でフェードを織り交ぜて栄冠を掴みました。​

ホール別“得点パターン”

ドローが光る フェードが安心
2 / 10 / 13 番で左ドッグをショートカット
1 / 11 / 15 / 18 番で池・林を回避

Gemini は「13 番延長でドローのリスク増、17 番ツリー撤去でフェード障害減」と分析。ChatGPT も「コース改修が勢力図を揺らす」と指摘。

スタイル別“勝ちパターン”

ドロー派 – パー5 爆発(ガルシア −7、リード −13)が勝因。

フェード派 – GIR&FWキープで大崩れせず逃げ切り(ジョンソン GIR 83%、シェフラー同傾向)。

二刀流 – マキロイやウッズ型。局面に応じ球筋を変えられる選手が最も安定。

AI 推奨ロードマップ

ティーショットは持ち球で安全優先 – 無理な逆球は OB リスク大。

逆球の“必須3シーン”だけ仕込む – 13 番ドロー、18 番フェードなど。

弾道を数値管理 – 高さ・スピンを測り、風速5 m/s超ならピーク高+5 m。

天候で球筋を切り替え – 硬いグリーン=フェード、雨=ドローで転がし攻め。

結論

ここ十数年でドライバーは大型化し、ボールは多層構造によって低スピン・高初速が当たり前になりました。

その結果、かつてドローがもたらしていた「ランで30ヤード伸ばせる」という絶対的な飛距離優位は影を潜め、パワーフェードでも 300 ヤード超が普通に計測される時代へとシフトしています。

GeminiもChatGPTも「純粋な飛距離差はもはや勝敗を決める主要因ではない」と明言しており、テクノロジーの進歩が“球筋格差”を事実上フラットにしたことを示しています。

では何が勝敗を分けるのか。
両AIが強調するキーワードは 「対応力」 です。

オーガスタは毎年ティーボックスやバンカー位置が数ヤード単位で改修され、硬さを調整するグリーンは朝と午後で別物になります。

さらに吹き上げる谷風と林に遮られる上空風が交錯し、同じホールでも時間帯によって球が 10 ヤード以上揺さぶられるのは珍しくありません。

固定された持ち球だけでは、こうした変化に合わせて弾道の“高さ・曲げ幅・スピン量”を最適化することが難しいのです。

実際、過去10年の優勝スピーチを遡ると、ジョン・ラームは「風を見てピーク高を上げた」、ダスティン・ジョンソンは「ライ角を変えてスピン量を抑えた」、セルヒオ・ガルシアは「普段は打たないフェードで池を迂回した」と口をそろえて語っています。

つまり、瞬間的にゲームプランを微修正し、必要なら“逆球”までも躊躇なく選択できる柔軟性こそが、グリーンジャケットへ最短距離を描く能力なのです。

そしてその対応力を支えるのは、単なる技術だけではありません。
AI が指摘するように「弾道を数値で把握するデータリテラシー」と「状況を俯瞰して最適解を選ぶ判断スピード」こそが重要です。

トラックマンでピーク高とスピンを把握し、キャディとピン位置・風向・硬さを秒速で共有する――この情報処理力がなければ、クラブとボールの性能を引き出すことはできません。

まとめると、現代マスターズの勝負は飛距離プラス“適応力の競争”へ完全にシフトしたといえます。

球筋そのものの優劣を論じるよりも、“いつ・どこで・どの高さで・どれだけ曲げるか”をリアルタイムに最適化できる選手が、栄光のグリーンジャケットにもっとも近い存在になる。

これが2つの AI が導き出した、2020年代マスターズを攻略する核心的な結論です。

****************
X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

アート系の論文生成ツールを作ってみました google colab版

アート系の論文生成ツール はじめに

近年、生成AIを活用したアート作品が世界中で注目を集めています。
Midjourney、DALL-E、Stable Diffusionなど、AIツールを使えば誰でも手軽にアートを生み出せる時代になりました。

文芸でも先日、AIが95%、人間が5%で書いた小説が発表されました。

これからはAI抜きでの制作は少なくなっていくのではないでしょうか。

そんなこんなで、ただ作品を作るだけでいいのかと。

「AIと人間が協力して、新しいアート表現を科学的に探求する」
そんなものがあってもいいのではと。

いろいろ調べていたら、sakana.aiさんが論文生成AIの
AI Scientist-v2
をオープンソースで公開してくれました。

そこで、これを参考にもっと簡略化して、google colabでも動かせるシステムに改変してみました。

名付けて
Google Colab上で動かせるアート版論文生成ツール
【アート版RonbunColabフルコード】です。

この記事では、その内容と使い方、実際に試した感想をレポートします!

なぜ「アート系論文生成」にチャレンジしたのか?

もともと私は、AIやデジタル技術を使ってのアート作品も作っています。(もちろんアナログもやります)
でも、ふと思ったんです。

「作品を作るだけじゃなく、制作プロセスや結果を科学的にまとめたら面白くない?」

もちろん、アート系でも「仮説→検証→考察」という論文スタイルは存在する。

例えば、
デザインプロセスの比較研究

生成AIと人間の共同創作に関する分析

デジタルアート作品の評価方法の開発

こうしたテーマが、立派な研究として認められているのです。

そこで、
「アート版の科学論文を、AIと一緒に作れたら面白いじゃないか!」
と思い立ったわけです。

【アート版RonbunColabフルコード】とは?

今回作ったツールは、
Google Colab上で動かせる超シンプルなプログラムです。

使い方は簡単!

アート系の研究アイディアを入力する

AIが自動で仮説案を3つ生成

新規性・実現性・インパクトの観点でベスト仮説を選定

選ばれた仮説をもとに、論文ドラフト(要旨~考察)を自動生成!

しかも最後には、
参考文献リスト(※今回はダミー文献)までつけてくれます!

出力はMarkdownファイルなので、あとからブログ記事やプレゼン資料にアレンジするのも簡単です。

実際にやってみた

今回はこんなアイディアをセットしました。

「生成AIと人間の共同制作による新しいアート表現の可能性」

このテーマをもとに、
仮説案が3つ生成されました。

インタラクション頻度の影響

人間の意図の反映度の影響

AIの学習モデルの多様性の影響

アート領域に合わせて、
「創造性」「感情的インパクト」なども評価基準に組み込みました。

最終的に選ばれたベスト仮説は──

「AIの学習モデルの多様性の影響」

というもの!

その仮説に基づいて、
AIが数分で論文ドラフトを完成させてくれました。

使ってみて感じたこと

まず、めちゃくちゃ簡単!

普通なら数日~数週間かかるような論文の下書きが、
わずか数分で形になります。。

しかも、
仮説を複数案出して、比較して、ベストを選ぶ流れが入っているので、
「ただの作文」じゃなく、ちゃんと思考プロセスがある
──ここがすごく良いポイントです。

もちろん、
最後の仕上げ(文章のブラッシュアップや本物の文献探し、コードの改変)は人間の仕事ですが、
「ゼロから考えるハードル」がぐっと下がった感覚があります。

まとめ:アートとAIの未来を自分で切り開こう

今回作った【アート版RonbunColabフルコード】は、
アート研究の新しい可能性を感じさせてくれるツールでした。

「アートとAIの融合」に興味がある人、
「論文っぽいアウトプットを作ってみたい人」、
めちゃくちゃおすすめです。

これからは、
「作品を作るだけ」じゃなく、
「プロセスを科学する時代」がくるかもしれません。

興味のある人はぜひ、使ってみてください。

コードを掲載

以下にコードを掲載しておきます。
(このコードは、gpt-4oのAPIを使うので、API料金がかかります。
無料でいきたい人はそこの所をいいように改変してください)

(まあ、実際はこの程度の出力ならGPTsでも同じようなことはできるのですが、コードにしたかったので。あしからずです)


# --- ライブラリインストール ---
!pip install openai

# --- ライブラリ読み込み ---
from openai import OpenAI
import json
import random
import re

import os

#Google Colab 上で安全にAPIキーを入力
os.environ["OPENAI_API_KEY"] = input("OpenAI APIキーを入力してください: ")

#APIキーを環境変数から取得してクライアントを初期化
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)

# --- 上記のAPI入力がうまくいかない際はこちらを利用 直接書くバージョン #コメントを外してから使用 ---
#client = OpenAI(
# api_key="YOUR_OPENAI_API_KEY" # ←★ここに自分のAPIキーを入れて!
#)

# --- ①アート系アイディア入力 ここの文言を変えることで論文の内容が変わります---
#記述が面倒な方は、このidea欄をコピペして "idea_name"だけを変えて、あとはchatGPTに書いてもらうのもありです

idea = {
"idea_name": "生成AIと人間の共同制作による新しいアート表現の可能性",
"summary": "生成AIと人間が交互に作業を行うインタラクティブな共同制作プロセスを開発し、アートの創造性や独創性がどのように変化するかを検証する。",
"problem": "現在の生成AIアートは一方向的であり、人間のクリエイティブな意図を十分に反映できていない。",
"hypothesis": "人間とAIが交互に作業するインタラクティブな制作プロセスを導入することで、より独創性の高い作品が生み出される。",
"methodology_hint": "人間とAIのインタラクション回数を変えながら複数の作品を制作し、創造性や独自性を第三者評価で比較する。",
"expected_result": "交互制作によって、従来のAI単独生成よりも独創的かつ感情的なアート作品が得られる。",
"evaluation_metric": "独創性スコア、芸術性スコア、感情的インパクト評価",
"field": "アート・クリエイティブテクノロジー"
}

# --- ②仮説案を3つ生成 ---
prompt_hypotheses = f"""
あなたはアート・クリエイティブ領域の研究者です。
以下のアイディアをもとに、異なる仮説案と実験案を3つ提案してください。
それぞれ簡単な理由も添えてください。

アイディア情報:
{json.dumps(idea, ensure_ascii=False, indent=2)}
"""

response_hypotheses = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "あなたは優秀なアート研究開発プランナーです。"},
{"role": "user", "content": prompt_hypotheses}
],
temperature=0.7
)

hypotheses_text = response_hypotheses.choices[0].message.content
print("=== 仮説案3つ ===\n")
print(hypotheses_text)

# --- ③ベスト仮説を選ぶ ---
prompt_select = f"""
以下の3つの仮説案を比較し、「新規性」「実現性」「芸術的インパクト」の観点でそれぞれスコア付けし、最も良い仮説案を1つ選んでください。
選んだ理由も簡潔に説明してください。

仮説案:
{hypotheses_text}
"""

response_selection = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "あなたは優秀なアート系研究レビュアーです。"},
{"role": "user", "content": prompt_select}
],
temperature=0.3
)

selection_result = response_selection.choices[0].message.content
print("\n=== ベスト仮説選定結果 ===\n")
print(selection_result)

# --- ④選ばれた仮説で論文ドラフトを作成 ---
# 仮説内容だけを抽出する
match = re.search(r'最も良い仮説案は(.+?)。', selection_result)
best_hypothesis = match.group(1) if match else "仮説1"

# ダミー参考文献を生成
def generate_dummy_references(n=5):
authors = ["Smith", "Johnson", "Tanaka", "Wang", "Garcia", "Müller", "Kumar"]
journals = ["Journal of Art Research", "Creative AI Conference", "Journal of Digital Creativity", "Art and Technology Review"]
years = [2018, 2019, 2020, 2021, 2022, 2023]
dummy_refs = []
for _ in range(n):
author = random.choice(authors)
year = random.choice(years)
title = f"Research on {random.choice(['Human-AI Collaboration', 'Interactive Art', 'Generative Art Techniques', 'Emotion-Driven Creation'])}"
journal = random.choice(journals)
ref = f"{author}, A. ({year}). {title}. {journal}."
dummy_refs.append(ref)
return dummy_refs

dummy_references = generate_dummy_references(5)
references_text = "\n".join([f"{i+1}. {ref}" for i, ref in enumerate(dummy_references)])

# 論文ドラフト用プロンプト(文字数指示版)
prompt_final_paper = f"""
以下の仮説案にもとづき、アート研究領域にふさわしい論文のドラフトを書いてください。

構成は以下の通りです。
- 要旨(Abstract):約600文字
- 導入(Introduction):約600文字
- 方法(Methods):約600文字
- 結果(Results):約600文字
- 考察(Discussion):約1200文字
- 結論(Conclusion):約600文字

各セクションはそれぞれ明確に分けて、適切な文字数で詳細に記述してください。
また、最後に参考文献リスト(以下のダミー文献)を追加してください。

仮説案:
{best_hypothesis}

参考文献リスト(ダミー):
{references_text}
"""

response_final = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "あなたは優れたアート研究論文ライターです。Markdown形式で出力してください。"},
{"role": "user", "content": prompt_final_paper}
],
temperature=0.5
)

final_text = response_final.choices[0].message.content

# ファイルに保存
with open("generated_paper_art_v2_conclusion.md", "w", encoding="utf-8") as f:
f.write(final_text)

print("\n論文ドラフトが作成されました!")

 

実際の出力例

このシステムで生成した論文を掲載します。
簡易的な論文で参照文献もダミーですから、あしからず。

あくまでも論文の流れの参考程度の文章量です。
(予稿程度)
こんな感じで出力されるよといった程度の認識で読んでください。

実際の論文には数万字のものもありますので、コードをいじって改良してください。
(APIを使う場合は料金がかかってきます。あまり長い出力は予算の範囲で)

出力は日本語で書いています。英語版もプロンプトに「出力を英語にして」と一言加えればOKです。

ではどうぞ。

# AIの学習モデルの多様性がアート創作に与える影響

## 要旨(Abstract)
本研究は、AIの学習モデルの多様性がアート創作に与える影響を探ることを目的とする。AI技術の進化に伴い、アートの分野においてもAIを用いた創作活動が活発化しているが、学習モデルの多様性が作品の質や創造性にどのように影響を及ぼすかは十分に理解されていない。本研究では、異なる学習モデルを用いたAIが生成するアート作品の特徴を比較し、その多様性が作品の新規性や感情的影響にどのように寄与するかを分析する。実験では、ディープラーニングや生成的敵対ネットワーク(GAN)を含む複数の学習モデルを使用し、それぞれのモデルが生成する作品を評価するために専門家と一般観衆からのフィードバックを収集した。結果として、学習モデルの多様性は作品の創造性と感情的影響に大きな影響を与えることが示された。この研究は、AIを用いたアート創作における学習モデルの選択が作品の特性に与える影響を理解するための基礎を提供し、今後のAIとアートの融合に向けた新たな視点を提示する。

## 導入(Introduction)
アートとテクノロジーの融合は、近年急速に進展している分野である。特に、AI技術の進化はアートの創作プロセスに革命をもたらしつつある。AIが生成するアート作品は、従来の人間のアーティストによる作品と比較して、異なる美的価値や感情的影響を持つことがしばしば報告されている(Smith, 2019)。しかし、AIの学習モデルの多様性が具体的にどのように作品に影響を与えるのかについては、まだ十分に解明されていない。

本研究では、AIの学習モデルの多様性がアート作品の創造性や感情的影響にどのように寄与するかを探る。AIの学習モデルには、ディープラーニング、生成的敵対ネットワーク(GAN)、強化学習など多様なアプローチが存在する。これらのモデルは、それぞれ異なる方法でデータを処理し、異なる特徴を持つアート作品を生成する可能性がある(Tanaka, 2021)。

本研究の目的は、異なる学習モデルが生成するアート作品を比較し、その多様性が作品の新規性や感情的な影響にどのように寄与するかを明らかにすることである。この研究は、AIを用いたアート創作における学習モデルの選択が作品の特性に与える影響を理解するための基礎を提供する。

## 方法(Methods)
本研究では、異なるAI学習モデルを用いてアート作品を生成し、それらの作品を比較分析することで、学習モデルの多様性が作品に与える影響を評価した。使用した学習モデルには、ディープラーニング、生成的敵対ネットワーク(GAN)、強化学習の3つを選定した。これらのモデルは、異なるアルゴリズムとデータ処理方法に基づいており、それぞれが異なるアート作品を生成することが期待される。

実験は以下の手順で行った。まず、各学習モデルに同一のデータセットを提供し、アート作品を生成させた。生成された作品は、視覚的特徴、構成、色彩、そして感情的影響の観点から評価された。評価は、アートの専門家からのフィードバックと一般観衆によるアンケート調査を通じて行われた。

アートの専門家には、各作品の創造性、新規性、そして技術的完成度を評価してもらい、一般観衆には作品から受ける感情的な影響についてのフィードバックを求めた。これにより、学習モデルの多様性が作品に与える影響を多角的に分析することが可能となった。

## 結果(Results)
実験の結果、異なる学習モデルが生成するアート作品には顕著な違いが見られた。ディープラーニングを用いたモデルは、色彩の豊かさと複雑な構成において高い評価を受けた。一方、生成的敵対ネットワーク(GAN)を用いた作品は、創造性と新規性において特に高い評価を得た。強化学習モデルは、作品の技術的完成度において安定した評価を示したが、他のモデルと比較して創造性や感情的影響の面ではやや劣る結果となった。

アートの専門家からのフィードバックでは、GANを用いた作品が最も高く評価され、その新規性と創造性が特に注目された。一般観衆によるアンケート調査でも、GAN作品は感情的な影響を強く与えることが確認された。これに対して、ディープラーニング作品は視覚的な美しさが評価され、強化学習作品は技術的な完成度が評価された。

これらの結果は、AIの学習モデルの多様性がアート作品の特性に大きな影響を与えることを示唆しており、特に創造性と感情的影響においてその影響が顕著であることが明らかになった。

## 考察(Discussion)
本研究の結果は、AIの学習モデルの多様性がアート作品に与える影響が大きいことを示している。特に、生成的敵対ネットワーク(GAN)を用いたモデルが、新規性と創造性において他のモデルを凌駕していることが明らかになった。この結果は、GANが持つ生成能力の高さと、敵対的な訓練プロセスが新しいアイデアを生み出すための柔軟性を提供することに起因していると考えられる(Tanaka, 2021)。

また、ディープラーニングモデルが色彩の豊かさと複雑な構成において高く評価されたことは、ディープラーニングの深層構造が持つ特徴抽出能力の高さを反映している。このモデルは大量のデータを処理し、複雑なパターンを学習する能力に優れているため、視覚的に魅力的な作品を生成することができる(Smith, 2019)。

一方で、強化学習モデルが技術的完成度において安定した評価を示したが、創造性や感情的影響の面では他のモデルに劣る結果となったことは、強化学習の特性に起因する。強化学習は、特定の目標を達成するための最適な行動を学習するプロセスであり、創造性を重視したアート作品の生成には不向きである可能性がある(Müller, 2019)。

これらの結果は、AIを用いたアート創作において学習モデルの選択が作品の特性に与える影響を理解するための重要な知見を提供する。特に、創造性や感情的影響を重視する場合には、GANのようなモデルがより適していることが示唆される。

さらに、本研究はAIとアートの融合における新たな視点を提供するものであり、今後の研究においては、異なる学習モデルを組み合わせたハイブリッドモデルの可能性や、より多様なデータセットを用いたさらなる分析が求められる。このような研究は、AI技術がアートの分野においてどのように革新をもたらすかを理解するための基礎を築くものである。

## 結論(Conclusion)
本研究は、AIの学習モデルの多様性がアート作品に与える影響を探ることで、AIを用いたアート創作における学習モデルの選択の重要性を明らかにした。結果として、生成的敵対ネットワーク(GAN)が新規性と創造性において特に高い評価を得た一方で、ディープラーニングモデルは視覚的な美しさにおいて優れていることが示された。強化学習モデルは技術的完成度で安定した評価を示したものの、創造性の面では他のモデルに劣る結果となった。

これらの結果は、AI技術がアートの分野においてどのように活用されるべきかについての重要な示唆を提供する。特に、創造性や感情的影響を重視するアート作品の生成には、GANのようなモデルが有効であることが示唆される。今後の研究では、異なる学習モデルを組み合わせたハイブリッドモデルの開発や、より多様なデータセットを用いた分析が求められる。

本研究は、AIとアートの融合における新たな可能性を探るための基礎を提供し、AI技術がアートの創作プロセスにどのように革新をもたらすかを理解するための一助となることを期待する。

## 参考文献リスト(ダミー)
1. Smith, A. (2019). Research on Emotion-Driven Creation. Creative AI Conference.
2. Smith, A. (2018). Research on Emotion-Driven Creation. Journal of Art Research.
3. Tanaka, A. (2021). Research on Human-AI Collaboration. Art and Technology Review.
4. Tanaka, A. (2021). Research on Human-AI Collaboration. Art and Technology Review.
5. Müller, A. (2019). Research on Human-AI Collaboration. Journal of Art Research.

さらに本格的な論文を書きたい方は、
sakana.aiさんの論文生成AI
AI Scientist-v2
を使ってください。(2025年4月現在)

ご参考までに!!

 

 

****************
X 旧ツイッターもやってます。
https://twitter.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

140字小説を有名どころのAIに書いてもらいました

140字小説をAIに書いてもらいました

140字小説をそれぞれ有名どころのAIに書いてもらいました

テーマは春なので「卒業」

使ったAIは

・Gemini 2.5 Pro Experimental 03-25
・Claude 3.7 sonnet
・ChatGPT 4.5
o1
o3mini-high
の全5種類
です。

2025年4月頭現在、各社の最強クラスのモデルです。

chatGPTに関しては、単純に私の興味でいろんなモデルに書いてもらいました。

o1Proが入っていませんが、まあお高いので(月3万円。きついでしょう)

プロンプトはこれ。

「140字前後の小説を書いてください。
テーマは「卒業」
読んだ人が感動するようなストーリーをお願いします」

では、それぞれの作品をご覧ください。

 

Gemini 2.5 Pro Experimental 03-25

・Gemini 2.5 Pro Experimental 03-25
校舎に響く最後のチャイム。舞い散る桜が涙で滲んだ。「ありがとう」掠れた声で友と交わす。この教室で笑い合った日々が、もう遠い。寂しさが胸を締め付ける。でも、先生がくれた「君なら大丈夫」の言葉を強く握りしめた。思い出を力に変えて、それぞれの未来へ。さよならじゃない、始まりの言葉を胸に、前を向く。

Claude 3.7 sonnet

・Claude 3.7 sonnet
桜の花びらが風に舞う卒業式の日、僕は彼女の姿を探していた。三年間、言葉を交わしたことはなかったけれど、いつも図書館で一人本を読む彼女を見ていた。最後のチャンスだと思い、勇気を出して近づくと、彼女は「待ってたよ」と微笑んだ。
そして差し出したのは僕が去年書いた作文だった。「これ、あなたが書いたでしょ?私に勇気をくれた」僕たちの物語は、終わりではなく、始まりだった

ChatGPT 4.5

・ChatGPT 4.5
校庭の桜が揺れる中、「また会えるよな?」と君が笑った。「当たり前だろ」と返した声が震えた。伝えきれなかった想いが胸を焦がす。卒業証書よりも重い、この気持ちを抱いて僕は歩き出す。振り向けば君も泣いていた。

ChatGPT o1

・ChatGPT o1
校庭に散る桜の花びらを握りしめ、きみは涙を拭った。あの日々の失敗も成功も、今の自分の一部になった。仲間の笑顔に背中を押され、明日へと踏み出す。限られた時間も、振り返れば宝物だった。大切な思い出を胸に、一歩ずつ歩んでいこう。心に灯る希望の光が、きっと新しい道を照らしてくれるから。

ChatGPT o3mini-high

・ChatGPT o3mini-high
卒業式の朝、まだ冷たい空気の中で、僕たちは胸に夢を抱き校門を後にした。桜の花びら舞う中、別れの言葉は未来への誓いに変わり、涙と笑顔が溶け合う。今、過ぎ去った日々は宝となり、涙と笑顔が交わる瞬間、僕らは大人への第一歩を刻んだ。未来は希望に満ち、すべての別れが新たな出会いへと変わる。

これらを読んで感じたこと

どうでしょうか。
いやー最近のAIの進化はすごいですね。
2022年に登場した時は、単純に字列を並べるだけだったけども、人を感動させる意味をある程度は学習してきたんだと思います。

個人的には
1番最初に出力してもらったのがGemini 2.5 Pro Experimentalだったので、結構ぐっときましたね。

ただ、その後に他のAIにも出力してもらったんですが、まぁなんとなく似たような内容になってしまい、やっぱり140字だと表現が限られてくるのかなっていう印象でした。

皆さんはどう感じたでしょうか。
各自お気に入りのAIを見つけていただければと思います。

 

人間とAIの書いたものは、どちらが優れているのか

最後にもうひとつおまけです。
やはり春なのでこのテーマで。

「贈る言葉」

こちらはChatGPT 4.5に書いてもらいました。

ちなみに武田鉄矢さんの名曲「贈る言葉」の歌詞と比べてみてください。
(小説と歌詞を比べるのもなんですが)

まだまだ、人間も負けてないぞー。

ChatGPT 4.5
卒業式後、教室には夕陽が射し込み、温かなオレンジ色に染まっていた。黒板いっぱいの「ありがとう」の文字。後ろで微笑むのは、いつもやんちゃで手を焼いたあの子たち。「先生、最後の宿題。幸せになってな。」涙を隠さず、私は何度も頷いた。

“”
「贈る言葉」作詞 武田鉄矢 一部抜粋

悲しみこらえて微笑むよりも
涙かれるまで 泣くほうがいい
人は悲しみが多いほど
人には優しくできるのだから
さよならだけではさびしすぎるから
愛するあなたへ贈る言葉

“”

懐かしい歌ですねえ。
こないだラジオから流れてきて、思わず口ずさんでしまいました。

やはりまだまだ人間のが上ですね!!

 

****************
X 旧ツイッターもやってます。
https://x.com/ison1232

インスタグラムはこちら
https://www.instagram.com/nanahati555/

****************

 

 

拡散モデルとは何か?

拡散モデルのデモ動画をご覧ください

今回は拡散モデルについて動画を作ったので、これをご覧頂きたいと思います。
最近、「拡散言語モデル」というAIがリリースされて使われています。

メリットは「生成スピードが早い」ということ。

いままでのモデルはトランスフォーマーと呼ばれる技術で、文章の次にくる文言を確率的に求めていくものでした。

この拡散言語モデルは、今まで画像生成で使われていた技術で、ノイズのある画面から目的のものを出力していくという形式になっています。

ちょっと意味がわかりづらいですよね。

そこでわかりやすいように、イメージの動画を作りましたので、まずは見てください。(画像をクリック)

このように画像を生成するにはノイズのある画面からノイズを徐々に取り除いて、目的の画像を表示していきます。

言語も同じで、ランダムの文字列(ノイズ)から徐々に目的の文字を表示していく方法を取ります。

この方法だと早く表示できるようなんですね。
(まだ開発段階で研究中のモデルのようです)

今後はトランスフォーマーから、この拡散モデルへと移行するのかどうかって感じになります。

本題が終わったので、細々とAIによる解説です。

 

拡散モデルとは? 画像モデルと言語モデルの違い

拡散モデル(Diffusion Model)は、最初にノイズ(ザラザラした画像や意味のない文字の並び)を作り、そこから少しずつ本物に近いデータを復元していくAIの仕組みです。
最近では、画像や文章を作るAIとして注目されています。ここでは、拡散モデルの 画像モデル と 言語モデル の違いを簡単に説明します。

1. 画像を作る拡散モデル

画像を作る拡散モデルは、ランダムなノイズ(砂嵐のような画像)から、少しずつ意味のある絵を描いていく仕組みです。たとえば、「猫の絵を描いて」と指示すると、最初はぐちゃぐちゃのノイズから始まり、徐々に猫の形が見えてきて、最後にはリアルな猫の画像が完成します。

代表的なモデル
Stable Diffusion(ステーブル・ディフュージョン)
DALL·E 3(ダリ・スリー)

ポイント
何もないところからリアルな画像を作れる
文字で指示を出すと、それに合った画像が作れる(例:「空を飛ぶドラゴンの絵」)

2. 文章を作る拡散モデル

言語の拡散モデルは、ノイズだらけの意味のない文章から、だんだん自然な文章を作る仕組みです。今のところ、AIが文章を作るときは GPT(ChatGPTのようなモデル)が主流ですが、拡散モデルを使うと、より流れのスムーズな文章が作れるかもしれません。

ポイント
ノイズの中から自然な言葉を見つけて、意味のある文章にする
まだ研究中の技術で、今後の進化が期待されている

 

まとめ

拡散モデルは、AIが画像や文章を作る新しい方法です。
画像の拡散モデルは、ノイズからきれいな絵を作る技術で、すでにたくさんのアートやデザインに使われています。
言語の拡散モデルは、まだ開発中ですが、より自然な文章を作るAIとして注目されています。

これからの未来で、AIがどのように活躍するか楽しみですね。

PAGE TOP