例から学び、自分で間違いを直すAIを作る
例のデータを見て、予測が外れるたびに計算に使う数値を自分で直すプログラムを作ってみます。Pythonファイル1つで作れて、追加のライブラリや有料のAIサービスは必要ありません。この画面でそのまま実行することもできます。
学習するデータ
今回のモデルが学習するデータは次のとおりです。
| 入力 | 正解 |
|---|---|
| 1 | 2 |
| 2 | 4 |
| 3 | 6 |
| 4 | 8 |
私たちの目には「入力の2倍」という規則が見えます。プログラムにも、このデータを使ってその関係をさせましょう。学習が終わったら、学習に使っていない5と7を入れて予測を確かめます。
計算の枠組み — モデル
まず、プログラムに次のような計算の枠組み、つまりを決めてあげます。
予測値 = 入力 × w
w はプログラムがしながら変えていく数値です。このような値を、この場合はと呼びます。
最初は w = 0 から始めます。
入力 3 → 予測 0 → 正解は 6 → 差が大きい!
学習を繰り返して w が 2 に近づくと、次のようになります。
入力 3 → 予測は約 6 → 正解とほぼ同じ!
人は計算の枠組みと例のデータを用意し、プログラムはデータに合う w を見つけます。
コード — mini_ai.py
下のコードを mini_ai.py という名前で保存してください。この画面では[実行]を押すと、ブラウザの中のPythonがすぐに動かします。コードを書き換えて、もう一度実行してもかまいません。
[実行]を押すと、ブラウザ用のPythonを準備します。初回だけ約12MBをダウンロードします。
# 1. 学習データ: (入力, 正解)
data = [(1, 2), (2, 4), (3, 6), (4, 8)]
# 2. 最初は規則を知らない状態から始めます。
weight = 0.0
learning_rate = 0.01
# 3. 全データを見ながら100回学習します。
for step in range(100):
gradient = 0.0
for x, answer in data:
prediction = weight * x # 今の重みで予測
error = prediction - answer # 正解とどれだけ違うか
gradient += 2 * error * x # 修正する向きと大きさ
# 全データの結果を集めて、重みを少し修正します。
weight -= learning_rate * gradient / len(data)
if step + 1 in [1, 10, 50, 100]:
print(f"{step + 1}回目の学習: w = {weight:.4f}")
# 4. 学習に使っていない入力で予測します。
print(f"入力 5 の予測: {weight * 5:.4f}")
print(f"入力 7 の予測: {weight * 7:.4f}")
実行結果
[実行]を押すと、ここに結果が表示されます。
自分のパソコンで実行する
ファイルを保存したフォルダで、次のコマンドで実行します。
python3 mini_ai.py
実行結果
実際に実行して確かめた結果です。数値は小数点以下4桁まで表示しています。
1回目の学習: w = 0.3000 10回目の学習: w = 1.6063 50回目の学習: w = 1.9994 100回目の学習: w = 2.0000 入力 5 の予測: 10.0000 入力 7 の予測: 14.0000
最初は0だったが、を経て約2になりました。この重みを使って新しい入力の答えを計算することを、予測またはといいます。
コードで押さえたい3つのポイント
errorどれだけ外れたか- 予測値から正解を引いた値です。では、この誤差を2乗した値の平均が小さくなるようにを調整します。
gradient重みをどう変えるべきか- 誤差を減らすのに必要な修正の向きと大きさを計算します。この方法を勾配降下法といいます。2 * error * x は、このの2乗誤差を微分して得た式です。微分を完全に理解していなくても、まずは実験できます。
learning_rate一度にどれだけ変えるか- ここでは 0.01 です。小さすぎるとが遅くなり、大きすぎるとが大きく揺れたり、学習に失敗したりすることがあります。
自分で実験してみよう
1つずつ変えて、もう一度実行してみてください。[読み込んで実行]を押すと、変更したコードが上のエディタに入り、すぐに実行されます。
-
データを「3倍」の関係に変える
data = [(1, 3), (2, 6), (3, 9), (4, 12)]残りのコードはそのままにして実行してください。今度は重みが約3に学習されるかを確かめます。
確認した結果を見る
1回目の学習: w = 0.4500 10回目の学習: w = 2.4094 50回目の学習: w = 2.9991 100回目の学習: w = 3.0000 入力 5 の予測: 15.0000 入力 7 の予測: 21.0000
-
学習回数を減らす
for step in range(10):100回学習したときと比べて、予測がどれだけ不正確になるかを比べます。
確認した結果を見る
1回目の学習: w = 0.3000 10回目の学習: w = 1.6063 入力 5 の予測: 8.0313 入力 7 の予測: 11.2438
-
例から完璧な規則をなくしてみる
data = [(1, 2.1), (2, 3.9), (3, 6.2), (4, 7.8)]データが少しずつずれていても、全体としてよく合う重みを見つけられるかを見てみます。
確認した結果を見る
1回目の学習: w = 0.2985 10回目の学習: w = 1.5982 50回目の学習: w = 1.9894 100回目の学習: w = 1.9900 入力 5 の予測: 9.9500 入力 7 の予測: 13.9300
次の課題 — 入力 × w + b
このが表せるのは、入力 × w という形の比例関係だけです。たとえば 入力 × 2 + 3 をするには、モデルを 入力 × w + b に広げ、w と b の2つの数値を学習する必要があります。b はバイアスと呼びます。
上の実験を理解できたら、まずは自分でコードを書き換えてみてください。行き詰まったら、下の解答を開いてください。
解答コードを見る
学習データは 入力 × 2 + 3 で作った (1, 5), (2, 7), (3, 9), (4, 11) です。2つの数値を学習するので、学習率を 0.05 に上げて1000回学習します。
# 1. 学習データ: 入力 × 2 + 3 で作った (入力, 正解)
data = [(1, 5), (2, 7), (3, 9), (4, 11)]
# 2. 重み w とバイアス b をどちらも 0 から始めます。
weight = 0.0
bias = 0.0
learning_rate = 0.05
# 3. 全データを見ながら1000回学習します。
for step in range(1000):
grad_w = 0.0
grad_b = 0.0
for x, answer in data:
prediction = weight * x + bias # 今の w と b で予測
error = prediction - answer # 正解とどれだけ違うか
grad_w += 2 * error * x # w を変える向きと大きさ
grad_b += 2 * error # b を変える向きと大きさ
# w と b を一緒に少しずつ修正します。
weight -= learning_rate * grad_w / len(data)
bias -= learning_rate * grad_b / len(data)
if step + 1 in [1, 10, 100, 500, 1000]:
print(f"{step + 1}回目の学習: w = {weight:.4f}, b = {bias:.4f}")
# 4. 学習に使っていない入力で予測します。
print(f"入力 5 の予測: {weight * 5 + bias:.4f}")
print(f"入力 7 の予測: {weight * 7 + bias:.4f}")
1回目の学習: w = 2.2500, b = 0.8000 10回目の学習: w = 2.6082, b = 1.2119 100回目の学習: w = 2.1565, b = 2.5399 500回目の学習: w = 2.0004, b = 2.9989 1000回目の学習: w = 2.0000, b = 3.0000 入力 5 の予測: 13.0000 入力 7 の予測: 17.0000
w は最初 2 を超えますが、b が大きくなるにつれて 2 に戻り、最後は w = 2、b = 3 になります。