AI手帖

XORはなぜ一本の直線で分けられない? 隠れ層と非線形変換をPythonで試す

XORは、2つの入力が異なるときだけ1を返す判定です。その4点を学習させると、今回のパーセプトロンは2/4点、隠れ層8ユニットの多層ネットは4/4点で正解しました。

さらに、隠れ層の数を変えずに非線形変換を外すと、正解は2/4点に戻りました。学習した4点への予測を比べながら、層を重ねることと、途中で非線形に変換することの役割を確かめます。

この記事の流れ

XORの4点を一本の直線で分けてみる

XORは、2つの入力が異なるときに1、同じときに0を返す判定です。入力を座標にすると、[0, 0]と[1, 1]が0、[0, 1]と[1, 0]が1になり、同じ答えの2点が対角に並びます。

XORは対角の点が同じクラス
XORの4つの入力と正解。

パーセプトロンは、入力に重みを掛けて足し、バイアスを加えた値がしきい値を超えるかどうかで判定します。入力が2つなら、計算は w1 × x1 + w2 × x2 + b。この判定の境界は一本の直線になります。

学習では、予測を間違えたときに重みを更新します。ただし、更新によって動かせるのは、この直線の位置や傾きです。

NumPyとscikit-learnを読み込んだ準備セルの後で、次のコードを実行します。4点をすべて学習に使い、その同じ4点への予測を確かめます。入力の順序と正解の並びにも注目してください。

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=float)
y = np.array([0, 1, 1, 0])

model = Perceptron(
    max_iter=1000, tol=None, random_state=42, shuffle=False
)
model.fit(X, y)
print(model.predict(X))

この設定での出力は [0, 0, 0, 0] となり、正解は2/4点でした。これは random_state=42、shuffle=False などを指定した今回の出力です。パーセプトロンが必ずすべて0を返す、という意味ではありません。

線形判定は4点を分けられなかった
XORの4点に対するパーセプトロンの出力。

4点の配置を見ると、直線の向きを変えても、対角の2点だけを片側へまとめられません。入力をこの2つの値のまま使い、一本の直線で判定する限り、XORの4点をすべて正しく分けることはできません。

たとえば「x1 + x2が0.5より大きければ1」という判定なら3/4点は当たりますが、[1, 1]を間違えます。今回の2/4点という出力と、直線では全点を分けられないという限界は、区別して読みます。

この限界は、学習回数を増やすだけでは解消しません。そこで、入力から判定までの間に、別の表現へ変換する層を加えます。

隠れ層8ユニットとtanhを加える

入力と出力の間に、8ユニットの隠れ層を置きます。各ユニットは入力を重み付きで足し、tanh という非線形な関数に通して、次の判定へ渡します。図は接続の構成を示したもので、線の太さが学習した重みを表すわけではありません。

隠れ層で入力を非線形に変換する
XORに使った、隠れ層8ユニットのネットワーク構成。(概念図)

tanh は値を−1から1の範囲へ変換する、直線では表せない関数です。この変換を途中に挟むことで、元の入力に対する一本の直線とは異なる境界を表現できます。

入力の X と正解の y は、先ほどの4点をそのまま使います。モデルを多層パーセプトロンの MLPClassifier に替え、次の設定で学習させました。

model = MLPClassifier(
    hidden_layer_sizes=(8,), activation="tanh", solver="lbfgs",
    max_iter=2000, random_state=42, tol=1e-8, alpha=0.0001
)
model.fit(X, y)
print(model.predict(X))

出力は [0, 1, 1, 0] となり、学習した4点すべてで正解と一致しました。

同じ4点が、すべて正解になった
学習したXORの4点に対する多層ネットの出力。

ここで確認したのは、用意した4点そのものへの適合です。未知の入力に対する性能や、別の課題でも多層ネットの方がよいかどうかは、この結果からは分かりません。

非線形変換を外すとどうなるか

隠れ層のユニット数を8のままにして、activation だけを tanh から identity に替えてみます。identity は、受け取った値をそのまま返す関数です。ほかのMLPの引数は同じにそろえ、最初から学習し直しました。

結果は次のとおりです。各配列の順序は、冒頭の入力4点と対応しています。

モデル4点への予測正解数
パーセプトロン[0, 0, 0, 0]2/4
MLP・tanh[0, 1, 1, 0]4/4
MLP・identity[1, 1, 0, 0]2/4

identity では、隠れ層があっても正解は2/4点でした。途中で行うのが重み付きの足し算だけなら、何段重ねても、一段の重み付きの足し算にまとめられます。そのため、この構成でも判定の境界は一本の直線になり、XORを分ける限界が残ります。

モデル内部の重みを学習するときは、出力の誤りを減らす方向を求めます。誤差逆伝播は、各重みに対する損失の勾配を計算する方法です。今回指定した lbfgs は、その勾配を使って重みを調整する準ニュートン法の一種です。

誤りから、内部の重みを調整する
予測の誤りから勾配を求め、重みを更新する流れ。(概念図)

Pythonで同じ4点を確かめる

手元で試す場合は、ノートブックの「依存ライブラリ → 共通準備 → XOR → 結果を保存」の順に実行してください。Attentionのセルは飛ばせます。

ノートブックを使わない場合は、下のZIPを展開し、python -m pip install -r requirements.txt でライブラリを準備してから、python run-foundations.py --out foundation-results-local.json を実行すると、XORとAttentionの両方の結果を保存できます。APIキーや学習済みLLMは使いません。初回のライブラリ取得には通信が必要です。

記事の数値は2026年10月20日JSTにサーバーCPUで実行した結果です。環境はPython 3.11.2、NumPy 2.4.6、SciPy 1.16.2、scikit-learn 1.7.2。ColabやGPUで取得した記録ではありません。

設定を変えて試すときは、まず activation だけを変更し、4点それぞれの予測を比べてみてください。正解数だけでなく、どの入力への答えが変わったかを見ると、今回の比較を追いやすくなります。

計算と実装を確認した公式資料

確認日:2026年10月20日。本文の数値は、教材用の入力と記載したライブラリの版で実行した結果です。現在の資料にある既定値や、未知データ・実モデルの性能を示すものではありません。