- 通过神经网络对鸢尾花进行预测
- 在训练中使用前向传播进行预预测,接着计算误差,结合误差进行反向传播更新各个位置上的权重
from dataclasses import dataclass, field
import pandas as pd
from sklearn.datasets import load_iris
import numpy as np
from sklearn.model_selection import train_test_split
ds = load_iris(as_frame=True, return_X_y=True)
data = ds[0].iloc[:100, :]
target = ds[1][:100]
def sigmoid(x):
return 1 / (1 + np.exp(-1 * x))
def sigmoid_derivative(x):
return x * (1 - x)
@dataclass
class Neuron:
weights: list[float] = field(default_factory=lambda: [])
bias: float = 0.0
N: float = 0.0
M: float = 0.0
def compute(self, inputs):
self.N = np.dot(self.weights, inputs) + self.bias
self.M = sigmoid(self.N)
return self.M
@dataclass
class MyNeuronNetwork:
HL1: Neuron = field(init=False)
HL2: Neuron = field(init=False)
HL3: Neuron = field(init=False)
O1: Neuron = field(init=False)
def __post_init__(self):
self.HL1 = Neuron()
self.HL1.weights = np.random.dirichlet(np.ones(4))
self.HL1.bias = np.random.normal()
self.HL2 = Neuron()
self.HL2.weights = np.random.dirichlet(np.ones(4))
self.HL2.bias = np.random.normal()
self.HL3 = Neuron()
self.HL3.weights = np.random.dirichlet(np.ones(4))
self.HL3.bias = np.random.normal()
self.O1 = Neuron()
self.O1.weights = np.random.dirichlet(np.ones(3))
self.O1.bias = np.random.normal()
def compute(self, inputs):
m1 = self.HL1.compute(inputs)
m2 = self.HL2.compute(inputs)
m3 = self.HL3.compute(inputs)
output = self.O1.compute([m1, m2, m3])
return output
def train(self, data: pd.DataFrame, target: pd.Series, learning_rate=0.1, epochs=100):
for epoch in range(epochs):
total_error = 0
for idx, row in data.iterrows():
m1 = self.HL1.compute(row)
m2 = self.HL2.compute(row)
m3 = self.HL3.compute(row)
prediction = self.O1.compute([m1, m2, m3])
error = target[idx] - prediction
total_error += error ** 2
delta_output = error * sigmoid_derivative(prediction)
delta_hl1 = delta_output * self.O1.weights[0] * sigmoid_derivative(m1)
delta_hl2 = delta_output * self.O1.weights[1] * sigmoid_derivative(m2)
delta_hl3 = delta_output * self.O1.weights[2] * sigmoid_derivative(m3)
self.O1.weights[0] += learning_rate * delta_output * m1
self.O1.weights[1] += learning_rate * delta_output * m2
self.O1.weights[2] += learning_rate * delta_output * m3
self.O1.bias += learning_rate * delta_output
for i in range(len(row)):
self.HL1.weights[i] += learning_rate * delta_hl1 * row[i]
self.HL2.weights[i] += learning_rate * delta_hl2 * row[i]
self.HL3.weights[i] += learning_rate * delta_hl3 * row[i]
self.HL1.bias += learning_rate * delta_hl1
self.HL2.bias += learning_rate * delta_hl2
self.HL3.bias += learning_rate * delta_hl3
if (epoch + 1) % 10 == 0:
print(f"Epoch {epoch + 1}, Total Error: {total_error}")
def predict(self, data: pd.DataFrame):
results = []
for idx, row in enumerate(data.values):
pred = self.compute(row)
results.append(round(pred))
return results
def main():
ds = load_iris(as_frame=True, return_X_y=True)
data = ds[0].iloc[:100, :]
target = ds[1][:100]
X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=42)
nn = MyNeuronNetwork()
nn.train(X_train, y_train)
results = nn.predict(X_test)
df = pd.DataFrame()
df["预测值"] = results
df["实际值"] = y_test.values
print(df)
if __name__ == "__main__":
main()