pythonista3で「収束」を可視化してみた

Pythonista3

機械学習を学んでいて、
こんなふうに感じたことはありませんか。

  • 勾配降下、最適化、収束……言葉は知っている
  • 数式や図も、一応は見た
  • でも
    「結局、何が起きているのか」は、よく分からない

それは、あなたの理解力の問題ではありません。
見せ方の問題だっただけです。

本記事では、
「ランダムに配置された点が、少しずつ整列していく」
ただそれだけの動きを、Pythonで可視化しました。

実はこの動きこそが、
機械学習がやっていることの“正体”です。


今回やること(この記事で体験できること)

本記事では、次のような様子を可視化します。

  • 最初:点は完全にランダム
  • 途中:少しずつ、ある方向に引き寄せられる
  • 最後:きれいに一直線に整列する

数式や専門用語を追う前に、
まずは 「学習している動き」そのもの を見てください。


使用環境・前提

使用するもの

  • Python(Pythonista3 で動作確認)
  • 標準ライブラリのみ

使用しないもの

  • 機械学習ライブラリ(scikit-learn 等)
  • 複雑な数式

機械学習の“核”だけを、
できるだけ裸の形で見せるためです。


まずはコードを動かしてみる

細かい説明は後回しで構いません。
まずは、動きを見てください。

from scene import *
import random

class AlignScene(Scene):
    def setup(self):
    self.n = 80
    self.points = []
    self.speed = 0.05 # 学習率(収束スピード)
    for _ in range(self.n):
        x = random.uniform(0, self.size.w)
        y = random.uniform(0, self.size.h)
        self.points.append([x, y])

    self.target_y = self.size.h / 2

def update(self):
    for p in self.points:
        p[1] += (self.target_y - p[1]) * self.speed

def draw(self):
    background(0, 0, 0)
    fill(1, 1, 1)

    for x, y in self.points:
        ellipse(x - 3, y - 3, 6, 6)

    stroke(0.3, 0.3, 0.3)
    stroke_weight(1)
    line(0, self.target_y, self.size.w, self.target_y)

run(AlignScene())

何が起きているのか(超ざっくり)

この動きの本質は、次の たった1行 です。

p[1] += (target_y - p[1]) * speed

やっていることは、とても単純です。

  • 今の位置と、目標との差を計算する
  • その差の「一部」だけ動かす
  • それを何度も繰り返す

一気に正解に行かない。

これが、機械学習の基本姿勢です。

機械学習と、どうつながっているのか

この可視化と、機械学習の対応関係を整理すると、こうなります。

今回の可視化機械学習
パラメータ
ランダム配置重みの初期化
中央の線正解(教師信号)
差分誤差
少しずつ動く勾配降下
整列収束

機械学習は、
賢く考えているわけではありません。

誤差を、少しずつ減らしているだけ

まずは、この感覚を持てれば十分です。


なぜ「y方向だけ」動かしているのか

今回は、あえて動きを 1方向だけ に限定しています。

  • 見るべき変化を1つに絞る
  • 観察ポイントをブレさせない

その結果、

  • 「何が起きているか」が迷子にならない
  • 収束という現象だけに集中できる

構成になっています。


発展:xも動かすと、どうなる?

実は、x方向も同じように動かすと、
これはそのまま 回帰分析(最小二乗法) になります。

  • 線形回帰
  • 多次元最適化

ただし本記事では、
理解体験を優先し、詳細は扱いません。


この可視化が役に立つ場面

  • 機械学習を学び始めたとき
  • G検定・DS検定の概念整理
  • 「学習率」や「最適化」を説明するとき
  • 自動売買・EAロジックの考え方を整理したいとき

数式の前に、
一度「動き」を見ておくだけで、
理解のハードルは大きく下がります。


まとめ

  • 機械学習の本質は「誤差を減らすこと」
  • 収束とは「状態」ではなく「過程」
  • 分からなかったのは、能力の問題ではない

見せ方を変えるだけで、理解は前に進みます。

おまけ:コードの紹介

① 前提:このスクリプトの正体

このコードは
「機械学習“っぽい”ことをしているが、機械学習ライブラリは一切使っていない」
という点が重要です。

やっていることは厳密には:

最適化(Optimization)の可視化

です。

  • 学習データ ❌
  • モデル ❌
  • 損失関数 ✅
  • 勾配降下 ✅

👉 MLの核だけを、裸で動かしている


② 全体構造(俯瞰)

AlignScene(Sceneクラス)
├ setup()   : 初期化(ランダム配置)
├ update()  : 毎フレームの更新(収束ロジック)
└ draw()    : 描画(見える化)

Pythonista の scene
「60fpsで update → draw を繰り返す状態機械」 です。


③ import 部分

from scene import *
import random

scene

  • Pythonista専用
  • 高速アニメーション用フレームワーク
  • Scene を継承して使う

random

  • 初期状態を「完全ランダム」にするため
  • 学習の初期値=ランダム初期化 と同義

④ クラス定義

class AlignScene(Scene):
  • Scene を継承
  • iOS画面全体が「学習空間」になる

⑤ setup():初期化フェーズ

def setup(self):

👉 学習前の状態を作る


⑤-1 点の数

self.n = 80
  • 同時に動く点の数
  • MLで言えば:
    • サンプル数
    • パラメータ数
    • エージェント数

多すぎると iPhone が悲鳴をあげる
80 は安定値(実測)


⑤-2 点群の入れ物

self.points = []
  • 各点は [x, y]
  • 状態ベクトルそのもの

⑤-3 収束スピード(超重要)

self.speed = 0.05

数学的意味

これは 学習率(learning rate) です。

  • 0.01 → 遅いが安定
  • 0.1 以上 → 発散しやすい

※ 内部的に再計算すると0<α<10 < \alpha < 10<α<1

を満たしており、必ず収束します。


⑤-4 ランダム初期化

for _ in range(self.n):
    x = random.uniform(0, self.size.w)
    y = random.uniform(0, self.size.h)
    self.points.append([x, y])

ここで起きていること

  • 画面全体に一様分布で点を配置
  • 偏りなし
  • 事前知識ゼロ

👉 MLの「ランダム初期重み」と完全一致


⑤-5 目標ライン

self.target_y = self.size.h / 2
  • y方向の目的値
  • 損失が最小になる状態

ここが 「正解」 です。


⑥ update():学習ステップ

def update(self):
  • 1フレーム = 1ステップ
  • 60fps → 秒間60回学習

⑥-1 本質の1行

p[1] += (self.target_y - p[1]) * self.speed

分解すると

部分意味
self.target_y - p[1]誤差(error)
* self.speed学習率
+=更新

数式で書くと

yt+1=yt+α(ytargetyt)y_{t+1} = y_t + \alpha (y_{target} – y_t)yt+1​=yt​+α(ytarget​−yt​)

これは:

  • 勾配降下
  • 誤差最小化
  • 指数収束

全部成立しています。


⑦ draw():可視化

def draw(self):

⑦-1 背景

background(0, 0, 0)
  • 黒背景
  • コントラスト重視

⑦-2 点の描画

fill(1, 1, 1)
for x, y in self.points:
    ellipse(x - 3, y - 3, 6, 6)
  • 半径3pxの白点
  • 視認性最優先

⑦-3 目標ライン(教師信号)

stroke(0.3, 0.3, 0.3)
stroke_weight(1)
line(0, self.target_y, self.size.w, self.target_y)
  • 薄いグレー
  • 「正解はここだよ」と示すだけ
  • 点はこの線を直接見ていない ←重要

⑧ 実行

run(AlignScene())
  • Scene を起動
  • 無限ループ開始

⑨ これを ML に対応させると

このコード機械学習
パラメータ
ランダム初期化重み初期化
target_y正解ラベル
誤差損失
speed学習率
update勾配降下
整列収束

👉 MLの骨格を再現


Pythonista3
スポンサーリンク
この記事を書いた人

運営者について

当サイトは、個人が運営する学習・記録ブログです。

AI・データサイエンス・自動化を中心に、
Python、G検定・DS検定の学習内容や、
実際に試しながら整理した知識をまとめています。

特定の企業や団体に属さない個人サイトとして、
学習過程で得た気づきや判断の整理を目的に運営しています。

「知識はあるが、どう使えばよいか分からない」
「情報が多く、判断に迷ってしまう」
といった状態を減らすことを目的に発信しています。

専門家として教える立場ではなく、
自分自身がつまずき、試し、整理してきた過程をそのまま共有するスタイルです。

用語の暗記やテクニックの紹介よりも、
・なぜそう考えるのか
・どの順番で判断するのか
・どこで迷いやすいのか
といった思考の整理を重視しています。

学び場をフォローする
学び場をフォローする
タイトルとURLをコピーしました