神经网络

实验目的:

掌握全连接神经网络的搭建方法,能够自行推导BP算法,学会使用SGD方法优化神经网络。

实验内容:

① 自行下载公开数据集,将其划分为“训练集”和“测试集”两部分。

② 搭建全连接神经网络,利用SGD方法在训练集上对该网络进行优化。

③ 利用测试集对训练好的神经网络进行测试,输出测试准确率。

④ 将训练过程中的损失和分类准确率以图形方式输出。

⑤ 若测试准确率不理想,请尝试调整网络结构和学习率等。

⑥ 请大家不要借助第三方库来搭建并优化神经网络,采用原生Python是可以实现的。

⑦ 希望能够有自己的特色和创意!!!

初版

import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split

# 加载Wine数据集
wine = load_wine()
X, y = wine.data, wine.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 对特征数据进行归一化处理
X_train = (X_train - np.mean(X_train, axis=0)) / np.std(X_train, axis=0)
X_test = (X_test - np.mean(X_test, axis=0)) / np.std(X_test, axis=0)

# 初始化权重和偏置
np.random.seed(42)
w1 = np.random.randn(X_train.shape[1], 16)
b1 = np.zeros((1, 16))
w2 = np.random.randn(16, 3)
b2 = np.zeros((1, 3))

# 设置超参数
learning_rate = 0.01
num_epochs = 500

# 记录训练过程中的损失和分类准确率
losses, accuracies = [], []

# 训练神经网络
for epoch in range(num_epochs):
    # 前向传播
    hidden = np.maximum(0, np.dot(X_train, w1) + b1)
    scores = np.dot(hidden, w2) + b2

    # 计算softmax损失
    exp_scores = np.exp(scores)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    correct_probs = probs[range(len(X_train)), y_train]
    loss = -np.log(correct_probs).mean()

    # 计算分类准确率
    predicted_labels = np.argmax(scores, axis=1)
    accuracy = np.mean(predicted_labels == y_train)

    # 记录损失和准确率
    losses.append(loss)
    accuracies.append(accuracy)

    # 反向传播
    d_scores = probs
    d_scores[range(len(X_train)), y_train] -= 1
    d_scores /= len(X_train)

    d_w2 = np.dot(hidden.T, d_scores)
    d_b2 = np.sum(d_scores, axis=0, keepdims=True)

    d_hidden = np.dot(d_scores, w2.T)
    d_hidden[hidden <= 0] = 0

    d_w1 = np.dot(X_train.T, d_hidden)
    d_b1 = np.sum(d_hidden, axis=0, keepdims=True)

    # 更新权重和偏置
    w1 -= learning_rate * d_w1
    b1 -= learning_rate * d_b1
    w2 -= learning_rate * d_w2
    b2 -= learning_rate * d_b2

    if (epoch + 1) % 100 == 0:
        print(f"Epoch {epoch+1}/{num_epochs}: loss = {loss:.4f}, accuracy = {accuracy:.4f}")

# 测试神经网络
hidden = np.maximum(0, np.dot(X_test, w1) + b1)
scores = np.dot(hidden, w2) + b2
predicted_labels = np.argmax(scores, axis=1)
accuracy = np.mean(predicted_labels == y_test)
print(f"测试准确率: {accuracy:.4f}")

# 绘制损失和分类准确率曲线图
plt.figure()
plt.subplot(2, 1, 1)
plt.plot(range(num_epochs), losses)
plt.title('Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')

plt.subplot(2, 1, 2)
plt.plot(range(num_epochs), accuracies)
plt.title('Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')

plt.tight_layout()
plt.show()

中文版

import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split

# 加载Wine数据集
wine = load_wine()
X, y = wine.data, wine.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 对特征数据进行归一化处理
X_train = (X_train - np.mean(X_train, axis=0)) / np.std(X_train, axis=0)
X_test = (X_test - np.mean(X_test, axis=0)) / np.std(X_test, axis=0)

# 初始化权重和偏置
np.random.seed(42)
w1 = np.random.randn(X_train.shape[1], 16)
b1 = np.zeros((1, 16))
w2 = np.random.randn(16, 3)
b2 = np.zeros((1, 3))

# 设置超参数
learning_rate = 0.01
num_epochs = 500

# 记录训练过程中的损失和分类准确率
losses, accuracies = [], []

# 训练神经网络
for epoch in range(num_epochs):
    # 前向传播
    hidden = np.maximum(0, np.dot(X_train, w1) + b1)
    scores = np.dot(hidden, w2) + b2

    # 计算softmax损失
    exp_scores = np.exp(scores)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    correct_probs = probs[range(len(X_train)), y_train]
    loss = -np.log(correct_probs).mean()

    # 计算分类准确率
    predicted_labels = np.argmax(scores, axis=1)
    accuracy = np.mean(predicted_labels == y_train)

    # 记录损失和准确率
    losses.append(loss)
    accuracies.append(accuracy)

    # 反向传播
    d_scores = probs
    d_scores[range(len(X_train)), y_train] -= 1
    d_scores /= len(X_train)

    d_w2 = np.dot(hidden.T, d_scores)
    d_b2 = np.sum(d_scores, axis=0, keepdims=True)

    d_hidden = np.dot(d_scores, w2.T)
    d_hidden[hidden <= 0] = 0

    d_w1 = np.dot(X_train.T, d_hidden)
    d_b1 = np.sum(d_hidden, axis=0, keepdims=True)

    # 更新权重和偏置
    w1 -= learning_rate * d_w1
    b1 -= learning_rate * d_b1
    w2 -= learning_rate * d_w2
    b2 -= learning_rate * d_b2

    if (epoch + 1) % 100 == 0:
        print(f"迭代次数 {epoch+1}/{num_epochs}: 损失 = {loss:.4f}, 分类准确率 = {accuracy:.4f}")

# 测试神经网络
hidden = np.maximum(0, np.dot(X_test, w1) + b1)
scores = np.dot(hidden, w2) + b2
predicted_labels = np.argmax(scores, axis=1)
accuracy = np.mean(predicted_labels == y_test)
print(f"测试准确率: {accuracy:.4f}")

# 中文显示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

# 绘制损失和分类准确率曲线图
plt.figure()
plt.subplot(2, 1, 1)
plt.plot(range(num_epochs), losses)
plt.title('损失')
plt.xlabel('迭代次数')
plt.ylabel('损失')

plt.subplot(2, 1, 2)
plt.plot(range(num_epochs), accuracies)
plt.title('分类准确率')
plt.xlabel('迭代次数')
plt.ylabel('准确率')

plt.tight_layout()
plt.show()