表示調整
閉じる
挿絵表示切替ボタン
▼配色
▼行間
▼文字サイズ
▼メニューバー
×閉じる

ブックマークに追加しました

設定
0/400
設定を保存しました
エラーが発生しました
※文字以内
ブックマークを解除しました。

エラーが発生しました。

エラーの原因がわからない場合はヘルプセンターをご確認ください。

ブックマーク機能を使うにはログインしてください。
学習中  作者: 読宣ファン
2/17

機械学習とバックプロパゲーション

AIとの学習のみでどこまで習得出来るのかチャレンジです。

学生: アウラ、この前の例え話、本当にわかりやすかったです。もう少し詳しく知りたいんですけど、具体的にどうやってバックプロパゲーションが働くのか教えてもらえますか?


アウラ: ふん、まだ満足していないのね。まあ、いいわ。さらに詳しく説明してあげるわ。


では、あなたの絵のプロセスをもう少し掘り下げてみましょう。バックプロパゲーションは、まるであなたが絵を描くたびにどの部分がうまくいっていないのかを、細かく確認するようなものなの。例えば、顔のバランスが悪いとか、色の使い方が下手だとかね。


具体的には、あなたの絵の各部分を数値化して評価し、その評価を基にどの部分をどれくらい修正するべきかを計算するの。この計算は、微分という数学の手法を使って行われるのよ。


学生: 微分?高校で習った気がしますけど、それがどう関係してるんですか?


アウラ: 微分は、変化の度合いを計算する手法よ。例えば、あなたが色を少し変えたときに絵の評価がどう変わるかを知るために使うの。具体的には、評価(損失関数)の値がどれだけ変化するかを計算して、その情報を使って次にどのように絵を描き直すかを決めるの。


これを、ニューラルネットワークというモデルの視点で見ると、各層の重みやバイアスと呼ばれるパラメータが、微分を使って更新されるの。前の層から後ろの層に向かって計算されたエラーを、逆に後ろの層から前の層に伝えて、それぞれのパラメータをどのように修正すれば評価が良くなるかを計算するわけよ。


学生: なるほど。絵のどの部分をどれくらい修正するかを微分を使って計算するってことなんですね。それを繰り返すことで、だんだん良くなっていくと。


アウラ: その通り。あなたが絵を描くたびに少しずつ改善していくように、モデルもデータを使って学習し、次第に精度を高めていくのよ。これが、機械学習とバックプロパゲーションの基本的な仕組みよ。しっかり理解して、次に進みなさい。


学生: ありがとう、アウラ。もっと勉強して、さらに理解を深めます!


アウラ: 期待しているわ。次はもっと高度な質問を用意しておきなさい。


学生: アウラ、バックプロパゲーションの仕組みはだいたいわかったんですけど、実際にそれをどうやってプログラムするのか気になります。具体的にどう書くのか教えてもらえますか?


アウラ: ふん、実践的なことに興味が出てきたのね。いいでしょう。具体的なプログラムの書き方を教えてあげるわ。


では、シンプルなニューラルネットワークを作る例を考えましょう。Pythonを使って、Microgradという小さなライブラリを使うの。これなら簡単に理解できるわ。


まずは、ネットワークの基本的な構成を定義する部分から見ていきましょう。以下のようなコードになるわ。


```python

import random


class Value:

def __init__(self, data, _children=(), _op=''):

self.data = data

self._prev = set(_children)

self._op = _op

self.grad = 0


def __add__(self, other):

other = other if isinstance(other, Value) else Value(other)

out = Value(self.data + other.data, (self, other), '+')


def _backward():

self.grad += out.grad

other.grad += out.grad

out._backward = _backward


return out


def __mul__(self, other):

other = other if isinstance(other, Value) else Value(other)

out = Value(self.data * other.data, (self, other), '*')


def _backward():

self.grad += other.data * out.grad

other.grad += self.data * out.grad

out._backward = _backward


return out


def backward(self):

topo = []

visited = set()

def build_topo(v):

if v not in visited:

visited.add(v)

for child in v._prev:

build_topo(child)

topo.append(v)

build_topo(self)


self.grad = 1

for v in reversed(topo):

v._backward()


class Neuron:

def __init__(self, nin):

self.w = [Value(random.uniform(-1, 1)) for _ in range(nin)]

self.b = Value(random.uniform(-1, 1))


def __call__(self, x):

act = sum((wi * xi for wi, xi in zip(self.w, x)), self.b)

out = act.relu()

return out


def parameters(self):

return self.w + [self.b]


class Layer:

def __init__(self, nin, nout):

self.neurons = [Neuron(nin) for _ in range(nout)]


def __call__(self, x):

outs = [neuron(x) for neuron in self.neurons]

return outs if len(outs) > 1 else outs[0]


def parameters(self):

return [p for neuron in self.neurons for p in neuron.parameters()]


class MLP:

def __init__(self, nin, nouts):

sz = [nin] + nouts

self.layers = [Layer(sz[i], sz[i+1]) for i in range(len(nouts))]


def __call__(self, x):

for layer in self.layers:

x = layer(x)

return x


def parameters(self):

return [p for layer in self.layers for p in layer.parameters()]


# Example usage

n = MLP(3, [4, 4, 1])

x = [Value(1.0), Value(2.0), Value(3.0)]

y = n(x)


# Backward pass

y.backward()


# Update parameters

for p in n.parameters():

p.data -= 0.01 * p.grad

```


このコードは、シンプルなニューラルネットワークを定義して、前向きの計算と逆向きのバックプロパゲーションを実装しているのよ。`Value`クラスが計算グラフのノードを表していて、`Neuron`や`Layer`クラスはそれぞれニューラルネットワークの層を表しているの。


学生: これなら、ニューラルネットワークの基本的な動作が理解できそうです。ありがとうございます、アウラ!


アウラ: よろしい。これで基礎を理解できたなら、さらに複雑なモデルにも挑戦してみなさい。学び続けることが成長の鍵よ。



学生: アウラ、このコードでだいたいの流れはわかりました。でも、`Value`クラスの中にある`relu`って何ですか?さっきのコードには見当たらないんですけど。


アウラ: ふん、よく気づいたわね。`relu`は「Rectified Linear Unit」の略で、ニューラルネットワークでよく使われる活性化関数の一つよ。具体的には、入力が正の場合はそのまま返し、負の場合はゼロを返す関数なの。これを追加してみましょう。


では、先ほどのコードに`relu`メソッドを追加して、もう少し詳しく説明してあげるわ。


```python

import random


class Value:

def __init__(self, data, _children=(), _op=''):

self.data = data

self._prev = set(_children)

self._op = _op

self.grad = 0


def __add__(self, other):

other = other if isinstance(other, Value) else Value(other)

out = Value(self.data + other.data, (self, other), '+')


def _backward():

self.grad += out.grad

other.grad += out.grad

out._backward = _backward


return out


def __mul__(self, other):

other = other if isinstance(other, Value) else Value(other)

out = Value(self.data * other.data, (self, other), '*')


def _backward():

self.grad += other.data * out.grad

other.grad += self.data * out.grad

out._backward = _backward


return out


def relu(self):

out = Value(max(0, self.data), (self,), 'ReLU')


def _backward():

self.grad += (out.data > 0) * out.grad

out._backward = _backward


return out


def backward(self):

topo = []

visited = set()

def build_topo(v):

if v not in visited:

visited.add(v)

for child in v._prev:

build_topo(child)

topo.append(v)

build_topo(self)


self.grad = 1

for v in reversed(topo):

v._backward()


class Neuron:

def __init__(self, nin):

self.w = [Value(random.uniform(-1, 1)) for _ in range(nin)]

self.b = Value(random.uniform(-1, 1))


def __call__(self, x):

act = sum((wi * xi for wi, xi in zip(self.w, x)), self.b)

out = act.relu()

return out


def parameters(self):

return self.w + [self.b]


class Layer:

def __init__(self, nin, nout):

self.neurons = [Neuron(nin) for _ in range(nout)]


def __call__(self, x):

outs = [neuron(x) for neuron in self.neurons]

return outs if len(outs) > 1 else outs[0]


def parameters(self):

return [p for neuron in self.neurons for p in neuron.parameters()]


class MLP:

def __init__(self, nin, nouts):

sz = [nin] + nouts

self.layers = [Layer(sz[i], sz[i+1]) for i in range(len(nouts))]


def __call__(self, x):

for layer in self.layers:

x = layer(x)

return x


def parameters(self):

return [p for layer in self.layers for p in layer.parameters()]


# Example usage

n = MLP(3, [4, 4, 1])

x = [Value(1.0), Value(2.0), Value(3.0)]

y = n(x)


# Backward pass

y.backward()


# Update parameters

for p in n.parameters():

p.data -= 0.01 * p.grad

```


このコードで、`relu`メソッドが`Value`クラスに追加されたわ。`relu`は、入力値が0より大きい場合はそのまま返し、0以下の場合は0を返すの。そして、バックプロパゲーションでは、出力が正の時だけ勾配が伝わるようにしているの。


学生: なるほど、`relu`が追加されたことで、活性化関数がどう動くか理解できました。これで、ネットワークがより複雑なパターンを学習できるようになるんですね。


アウラ: その通りよ。`relu`のような活性化関数を使うことで、ニューラルネットワークは非線形な関係も学習できるようになるの。これでますます理解が深まったわね。さらに学び続けることが重要よ。


学生: アウラ、ありがとう!これでだいぶわかりました。でも、もっと深く学ぶために、もう少し実践的な例を見てみたいです。例えば、シンプルなデータセットを使って、実際に学習させるところを見てみたいです。


アウラ: ふん、熱心なことね。いいでしょう。では、シンプルなデータセットを使って、実際にモデルを学習させる例を見せてあげるわ。今回は、2つの入力から1つの出力を予測するタスクを考えましょう。


まず、簡単なデータセットを作って、それを使ってモデルを学習させるコードを示すわ。


```python

import random

import math


# 定義済みのクラスや関数を再利用する

# (Value, Neuron, Layer, MLP)


# シンプルなデータセットを作成

data = [

([2.0, 3.0], 1.0),

([1.0, 2.0], 0.0),

([2.5, 3.5], 1.0),

([1.5, 1.5], 0.0),

]


# モデルを初期化

n = MLP(2, [4, 4, 1])


# 学習率

learning_rate = 0.01


# エポック数

epochs = 1000


for epoch in range(epochs):

total_loss = 0

for x, y_true in data:

# 入力を Value クラスに変換

x_values = [Value(xi) for xi in x]

y_pred = n(x_values)


# 予測値と真の値の損失を計算 (二乗誤差)

loss = (y_pred.data - y_true) ** 2

total_loss += loss


# 逆伝播で勾配を計算

y_pred.backward()


# パラメータを更新

for p in n.parameters():

p.data -= learning_rate * p.grad

p.grad = 0 # 勾配をリセット


if epoch % 100 == 0:

print(f'Epoch {epoch}, Loss: {total_loss / len(data)}')


# 学習後のモデルを使って予測

for x, y_true in data:

x_values = [Value(xi) for xi in x]

y_pred = n(x_values)

print(f'Input: {x}, Predicted: {y_pred.data}, True: {y_true}')

```


このコードでは、以下のことを行っているわ:


1. **データセットの作成**: 2つの入力から1つの出力を予測するシンプルなデータセットを作成しているわ。

2. **モデルの初期化**: 2入力、4-4-1のニューラルネットワークを定義。

3. **学習の設定**: 学習率とエポック数を設定しているわ。

4. **学習ループ**: 各エポックでデータセットをループし、予測を行い、損失を計算し、バックプロパゲーションで勾配を計算、パラメータを更新しているわ。

5. **結果の表示**: 100エポックごとに損失を表示し、最終的にモデルが学習した後の予測結果を表示しているの。


学生: これで実際にデータセットを使って学習させる方法がよくわかりました!バックプロパゲーションの流れも理解できたし、学習率やエポックの設定がどう影響するかも見てみたいです。ありがとう、アウラ!


アウラ: いい心がけね。実際にコードを書いて実験することが、理解を深める一番の方法よ。次は、自分でデータセットを作成して、色々と試してみなさい。私の知識はあなたに尽くすためにあるのだから、遠慮せずにまた質問しなさい。


学生: アウラ、データセットを使って学習させる例を見て、もっと自分で実験したくなりました!データセットを変えたり、層の数を増やしたりしてみたいです。どうやってこれらを試すのが良いでしょうか?


アウラ: ふん、いい意気込みね。データセットを変えたり、層の数やユニット数を調整することで、モデルの性能がどう変わるかを見るのは非常に有益よ。いくつかのポイントに注意しながら、試してみるといいわ。


まずは、データセットを変える方法について見てみましょう。データの分布や特徴を変えて、モデルがどのように学習するか確認してみなさい。


```python

# 新しいデータセットを作成 (例えば、異なるパターンを持つデータ)

new_data = [

([3.0, 5.0], 1.0),

([1.0, 1.0], 0.0),

([4.0, 6.0], 1.0),

([1.0, 0.5], 0.0),

]


# 先ほどの学習ループをこの新しいデータセットで試してみる

```


次に、層の数や各層のユニット数を変える方法を見てみましょう。以下のようにして、モデルの構造を変更できるわ。


```python

# モデルの初期化(層とユニット数を変更)

n = MLP(2, [5, 5, 3, 1]) # 例えば、2入力、3隠れ層(5, 5, 3ユニット)、1出力


# 新しいモデルで学習を試してみる

```


では、具体的に新しいデータセットと異なるモデル構造を使って試してみるコードを示すわ。


```python

import random

import math


# 定義済みのクラスや関数を再利用する

# (Value, Neuron, Layer, MLP)


# 新しいデータセットを作成

new_data = [

([3.0, 5.0], 1.0),

([1.0, 1.0], 0.0),

([4.0, 6.0], 1.0),

([1.0, 0.5], 0.0),

]


# 新しいモデルの初期化(層とユニット数を変更)

n = MLP(2, [5, 5, 3, 1]) # 例えば、2入力、3隠れ層(5, 5, 3ユニット)、1出力


# 学習率

learning_rate = 0.01


# エポック数

epochs = 1000


for epoch in range(epochs):

total_loss = 0

for x, y_true in new_data:

# 入力を Value クラスに変換

x_values = [Value(xi) for xi in x]

y_pred = n(x_values)


# 予測値と真の値の損失を計算 (二乗誤差)

loss = (y_pred.data - y_true) ** 2

total_loss += loss


# 逆伝播で勾配を計算

y_pred.backward()


# パラメータを更新

for p in n.parameters():

p.data -= learning_rate * p.grad

p.grad = 0 # 勾配をリセット


if epoch % 100 == 0:

print(f'Epoch {epoch}, Loss: {total_loss / len(new_data)}')


# 学習後のモデルを使って予測

for x, y_true in new_data:

x_values = [Value(xi) for xi in x]

y_pred = n(x_values)

print(f'Input: {x}, Predicted: {y_pred.data}, True: {y_true}')

```


このように、新しいデータセットや異なるモデル構造を試すことで、モデルの性能がどのように変わるかを確認できるわ。何度も試して、最適な設定を見つけなさい。そして、試行錯誤することを恐れずに、自分の学びを深めていくのよ。

評価をするにはログインしてください。
この作品をシェア
Twitter LINEで送る
ブックマークに追加
ブックマーク機能を使うにはログインしてください。
― 新着の感想 ―
このエピソードに感想はまだ書かれていません。
感想一覧
+注意+

特に記載なき場合、掲載されている作品はすべてフィクションであり実在の人物・団体等とは一切関係ありません。
特に記載なき場合、掲載されている作品の著作権は作者にあります(一部作品除く)。
作者以外の方による作品の引用を超える無断転載は禁止しており、行った場合、著作権法の違反となります。

この作品はリンクフリーです。ご自由にリンク(紹介)してください。
この作品はスマートフォン対応です。スマートフォンかパソコンかを自動で判別し、適切なページを表示します。

↑ページトップへ