当前位置: 首页 > news >正文

全连接神经网络(前馈神经网络)

一、全连接神经网络介绍

在多层神经网络中, 第 N 层的每个神经元都分别与第 N-1 层的神经元相互连接。

1、神经元

这个神经元接收的输入信号为向量(x_1,x_2,x_3,x_4,x_5) , 向量(w_1,w_2,w_3,w_4,w_5)为输入向量的组合权重, b 为偏置项, 是一个标量。

神经元的作用是对输入向量进行加权求和, 并加上偏置项 b, 最后经过激活函数f 变换产生输出y = f\left(\sum_{i=1}^{5} w_i x_i + b\right)   ===>  y = f(w^Tx+b)

2、网络结构

在分类问题中, 神经网络一般有多层:

  • 第一层为输入层, 对应输入向量, 神经元的数量等于特征向量的维数, 输入层不对数据进行处理, 只是将输入向量送入下一层中进行计算。
  • 中间层为隐含层, 可能有多个。
  • 最后是输出层, 神经元的数量等于要分类的类别数, 输出层的输出值被用来做分类预测

  • 第一层是输入层,对应的输入向量为(x_1,x_2,x_3) , 有 3 个神经元, 输入层不对数据做任何处理, 直接原样送入下一层。
  • 中间层有 4 个神经元, 接收的数据为 (x_1,x_2,x_3), 输出向量为 (y_1,y_2,y_3,y_4)
  • 第三层为输出层, 接收的数据为向量(y_1,y_2,y_3,y_4) , 输出向量为(z_1,z_2)

神经网络通过激活函数而具有非线性, 通过调整权重形成不同的映射函数。现实应用中要拟合的函数一般是非线性的, 线性函数无论怎样复合最终还是线性函数, 因此, 必须使用非线性激活函数。

3、正向传播算法

算法公式:u^{(l)} = W^{(l)} z^{(l-1)} + b^{(l)}z^{(l)} = f(u^{(l)})

假设神经网络有 m 层, 正向传播算法的流程为:

 二、反向传播算法

1、理解

假设神经网络有 n_l 层, 第 l 层的神经元个数为 s_l。 第 l 层从第 l - 1 层接收的输入向量为 z^{(l-1)}, 第 l 层的权重矩阵为 w^{(l)}, 偏置向量为b^{(l)}, 输出向量为 z^{(l)}。 该层的输出可以写成如下形式:

(已有推导结论: \nabla_{W} L = \left(\nabla_{u^{(l)}} L\right) {z^{(l-1)}}^T\nabla_{​{z^{(l-1)}}} L = W^T\left(\nabla_{u^{(l)}} L\right) )

损失函数对权重和偏置的梯度:

发现\nabla_{W} L\nabla_{b^{(l)}} L中都存在\nabla_{u^{(l)}} L,因此定义误差项为:

即得到\delta^{(l)}递推公式为:

通过递推公式知\delta^{(l)}\delta^{(l+1)}计算得到,因此需要从后往前计算,当\delta^{(l)}计算出来时\nabla_{W} L\nabla_{b^{(l)}} L也可计算出来,这就称为反向传播

2、迭代流程

均按照一个样本迭代,若有m个样本,公式要除以m,以求平均梯度

  1. 正向传播, 利用当前权重和偏置值, 计算每一层的输出值--确定z^{(l-1)}
  2. 计算输出层的误差项 \delta^{(n_l)}
  3. 反向传播, 计算隐藏层各层的误差项:

    ⊙ 表示元素乘法,前边表示矩阵乘法
  4. 计算损失函数对权重和偏置的梯度:
  5. 用梯度下降法更新权重和梯度:


    如果采用所有样本进行迭代, 根据单个样本损失函数的梯度计算总梯度, 然后求均值即可。

3、常见激活函数

根据上边公式:\delta^{(l)} = (W^{(l+1)})^T \cdot (\delta^{(l+1)}) \odot f'(u^{(l)})

f'(u^{(l)})是激活函数的导数,因此若激活函数倒数好计算,误差项计算就会容易。

下面是几种常用的激活函数及它们的导数:

三、构建神经网络模型的基本步骤

四、线性回归神经网络结构

线性回归模型可以认为是神经网络模型的一种极简特例, 是一个神经元,其只有加权和、没有非线性变换。

4.1 数据处理

1、数据导入

从本地文件或 URL 中读取数据。

data_list = pd.read_csv(filepath)

2、数据归一化处理

使用Z-Score 归一化

data_list = (data_list - data_list.mean()) / data_list.std()

3、数据集划分

将数据集划分成训练集和测试集, 其中训练集用于确定模型的参数, 测试集用于评判模型的效果。

train_size = int(len(data_list) * ratio)
# 生成一个随机排列的整数数组
random_indices = np.random.permutation(len(data_list))
# 使用随机排列的索引列表重新设定 DataFrame 的行顺序
data_list = data_list.iloc[random_indices]
trainset = data_list[:train_size]

4、数据形状变换

如果读取的数据维数与我们的模型输入的输入维数不一致, 我们就需要进行数据形状的变换

X_train = X_train.values
y_train = trainset["MEDV"]
y_train = y_train.values.reshape(-1, 1) #1维变2维,-1表示自动计算行数,1表示列数
X_test = testset.drop("MEDV", axis=1)
X_test = X_test.values
y_test = testset["MEDV"]
y_test = y_test.values.reshape(-1, 1)

4.2 模型设计

如果将输入特征和输出预测值均以向量表示, 输入特征x有 13 个分量,y有 1 个分量, 那么参数权重的形状是 13× 1:W = \begin{bmatrix} w_1 & w_2 & w_3 & \cdots & w_{13} \end{bmatrix}

class Network(object):def __init__(self, num_of_weights):# 随机产生 w 的初始值# 为了保持程序每次运行结果的一致性, 此处设置固定的随机数种子np.random.seed(0)self.w = np.random.randn(num_of_weights, 1) #数学中向量数据是按列存储的self.b = 0def forward(self, x):z = np.dot(x, self.w) + self.breturn z

4.3 训练配置

通过损失函数平衡模型的好坏

    def loss(self, z, y):error = z - ycost = error * errorcost = np.mean(cost)return cost

    4.4 训练过程

    使用梯度下降法寻找最优W和b

    def gradient(self, x, y):z = self.forward(x)gradient_w = (z - y) * x #(z - y)是m*1  x是m*ngradient_w = np.mean(gradient_w, axis=0) #批量梯度下降,对各个样本取得权重求均值gradient_w = gradient_w[:, np.newaxis] #变成列向量gradient_b = (z - y)gradient_b = np.mean(gradient_b)return gradient_w, gradient_bdef update(self, gradient_w, gradient_b, alpha=0.01):self.w = self.w - alpha * gradient_wself.b = self.b - alpha * gradient_b

    训练模型

    def train(self, x, y, iterations=100, alpha=0.01):losses = []for i in range(iterations):z = self.forward(x)L = self.loss(z, y)gradient_w, gradient_b = self.gradient(x, y)self.update(gradient_w, gradient_b, alpha)losses.append(L)if (i + 1) % 10 == 0:print('iter {}, loss {}'.format(i, L))return losses

    调用函数进行模型训练

    # 创建网络
    net = Network(13)
    num_iterations = 1000
    # 启动训练
    losses = net.train(X_train, y_train, iterations=num_iterations,
    alpha=0.01)
    # 画出损失函数的变化趋势
    plot_x = np.arange(num_iterations)
    plot_y = np.array(losses)
    plt.plot(plot_x, plot_y)
    plt.show()

    4.5 模型保存

    将训练好的模型保存用于后续的预测过程。 当需要进行预测时使用训练好的模型进行预测。

    # 模型保存
    params = {"w": net.w.tolist(),"b": net.b
    } #将参数保存到文件
    with open('params.json', 'w') as f:json.dump(params, f, indent=4)# 使用模型进行预测
    net = Network(13)
    with open('params.json', 'r') as f:params = json.load(f)net.w = np.array(params["w"])
    net.b = params["b"]z = net.forward(X_test)

    绘制图像

    # 绘制预测值与真实值的关系图
    x = np.arange(len(y_test))
    fig, ax = plt.subplots()
    ax.plot(x, z, label='predic', color='red')
    ax.plot(x, y_test, label='label', color='blue')
    ax.legend()
    plt.show()

     完整代码

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import json
    import random
    # pip install pandas matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple# 1.数据处理
    # 载入数据集
    def loadData(filepath):""":param filepath: csv:return: X, y"""data_list = pd.read_csv(filepath)# 使用Z-score对数据进行归一化处理data_list = (data_list - data_list.mean()) / data_list.std()return data_listdata_list = loadData('housing.csv')# 划分训练集与测试集
    def splitData(data_list, ratio):train_size = int(len(data_list) * ratio)# 生成一个随机排列的整数数组random_indices = np.random.permutation(len(data_list))# 使用随机排列的索引列表重新设定 DataFrame 的行顺序data_list = data_list.iloc[random_indices]trainset = data_list[:train_size]testset = data_list[train_size:]X_train = trainset.drop("MEDV", axis=1)X_train = X_train.valuesy_train = trainset["MEDV"]y_train = y_train.values.reshape(-1, 1)X_test = testset.drop("MEDV", axis=1)X_test = X_test.valuesy_test = testset["MEDV"]y_test = y_test.values.reshape(-1, 1)return X_train, X_test, y_train, y_testX_train, X_test, y_train, y_test = splitData(data_list, 0.8)class Network(object):def __init__(self, num_of_weights):# 随机产生w的初始值# 为了保持程序每次运行结果的一致性,此处设置固定的随机数种子np.random.seed(0)self.w = np.random.randn(num_of_weights, 1)self.b = 0.def forward(self, x):z = np.dot(x, self.w) + self.breturn zdef loss(self, z, y):error = z - ynum_samples = error.shape[0]cost = error * errorcost = np.sum(cost) / num_samplesreturn costdef gradient(self, x, y):z = self.forward(x)gradient_w = (z - y) * xgradient_w = np.mean(gradient_w, axis=0)gradient_w = gradient_w[:, np.newaxis]gradient_b = (z - y)gradient_b = np.mean(gradient_b)return gradient_w, gradient_bdef update(self, gradient_w, gradient_b, alpha=0.01):self.w = self.w - alpha * gradient_wself.b = self.b - alpha * gradient_bdef train(self, x, y, iterations=100, alpha=0.01):losses = []for i in range(iterations):z = self.forward(x)L = self.loss(z, y)gradient_w, gradient_b = self.gradient(x, y)self.update(gradient_w, gradient_b, alpha)losses.append(L)if (i + 1) % 10 == 0:print('iter {}, loss {}'.format(i, L))return lossesdef SGD_train(self, x, y, num_epochs, batch_size=64, alpha=0.01):indices = list(range(len(x)))random.shuffle(indices)  # 打乱数据索引,以便随机选择样本losses = []for epoch_id in range(num_epochs):# 在每轮迭代开始之前,将训练数据的顺序随机打乱random.shuffle(indices)  # 打乱数据索引,以便随机选择样本# 将训练数据进行拆分,每个mini_batch包含batch_size条的数据loss = 0for start in range(0, len(x), batch_size):end = min(start + batch_size, len(x))batch_indices = indices[start:end]X_batch = x[batch_indices]y_batch = y[batch_indices]a = self.forward(X_batch)L = self.loss(a, y_batch)loss += Lgradient_w, gradient_b = self.gradient(X_batch, y_batch)self.update(gradient_w, gradient_b, alpha)print('Epoch {} / iter {}, loss = {}'.format(epoch_id, start+1, L))losses.append(loss)return losses# 创建网络
    net = Network(13)
    num_iterations = 1000
    # 启动训练
    losses = net.train(X_train, y_train, iterations=num_iterations, alpha=0.01)
    # losses = net.SGD_train(X_train, y_train, num_epochs=num_iterations, batch_size=64, alpha=0.01)# 画出损失函数的变化趋势
    plot_x = np.arange(num_iterations)
    plot_y = np.array(losses)
    plt.plot(plot_x, plot_y)
    plt.show()# 模型保存
    params = {"w": net.w.tolist(),"b": net.b
    }# 将参数保存到文件
    with open('params.json', 'w') as f:json.dump(params, f, indent=4)# 使用模型进行预测
    net = Network(13)
    with open('params.json', 'r') as f:params = json.load(f)net.w = np.array(params["w"])
    net.b = params["b"]z = net.forward(X_test)# 绘制预测值与真实值的关系图
    x = np.arange(len(y_test))
    fig, ax = plt.subplots()
    ax.plot(x, z, label='predic', color='red')
    ax.plot(x, y_test, label='label', color='blue')
    ax.legend()
    plt.show()

     五、全连接神经网络实现手写数字识别代码

    1、手写数字识别原理

    计算机存储数据的最小单位是 bit, 它只有 0 和 1 两种二进制状态, 所以任何数据在计算机中都是以 0 和 1 组成的一堆数字。 那如何让计算机认出图片中的数字是几呢? 灰度图像是一种只包含灰度级别而不包含彩色信息的图像, 灰度级别通常被分为 256 个等级, 即从全黑(灰度值 0) 到全白(灰度值 255), 使用 8位二进制数可以表示从 0 到 255 的 256 个不同的数值, 因此用一个 8 位二进制数表示一个像素。 如下图所示把 0 以外的点连接起来就能看出图片中的是数字 4。

    2、MINST 数据集

    MNIST 数据集是美国国家标准与技术研究院收集整理的大型手写数字数据库,包含 60,000 个示例的训练集以及 10,000 个示例的测试集。 其中的图像的尺寸为 28*28。 采样数据显示如下:

    MNIST 图像文件有一个特定的文件头, 其中包含一些元数据, 这个文件头由 16 字节组成, 它们分别表示:

    • magic_number: 一个魔数, 用于标识文件格式。 对于图像文件, 这个值通常是 0x00000803;
    • num_images: 文件中的图像数量;
    • num_rows: 每张图像的行数(即高度);
    • num_cols: 每张图像的列数(即宽度)。

    3、代码实现

    3.1 方法概括

    使用一个 3 层的全连接神经网络实现手写数字识别, 输入层神经原个数为 784(也就是图片的像素数 28× 28), 隐藏层的神经元个数为 128, 输出层的神经元个数为 10(数字从 0~9 的个数)。 隐藏层的激活函数使用 ReLU, 输出层的激活函数为 softmax。 分别使用批量梯度下降法和随机梯度下降法进行参数优化。

    3.2 数据处理

    # 读取MNIST数据集
    train_images = idx2numpy.convert_from_file('./MNIST/raw/train-images-idx3-ubyte')
    train_labels = idx2numpy.convert_from_file('./MNIST/raw/train-labels-idx1-ubyte')
    test_images = idx2numpy.convert_from_file('./MNIST/raw/t10k-images-idx3-ubyte')
    test_labels = idx2numpy.convert_from_file('./MNIST/raw/t10k-labels-idx1-ubyte')# 将图像数据转换为一维向量,并归一化
    X_train = train_images.reshape(train_images.shape[0], -1) / 255.0
    X_test = test_images.reshape(test_images.shape[0], -1) / 255.0# 将标签进行one-hot编码
    num_classes = 10
    y_train = np.eye(num_classes)[train_labels]
    y_test = np.eye(num_classes)[test_labels]

    one-hot讲解

     3.3 模型设计

    反向传播初始误差项跟所选损失函数有关

    • 使用均方误差(MSE)损失函数对应初始误差项 :

      a^{(L)} 是输出层的激活值,y 是真实标签
    • 使用交叉熵损失函数对应初始误差项 :

      y 是真实标签的one-hot编码
    class NeuralNetwork:def __init__(self, input_size, hidden_size, output_size):self.input_size = input_sizeself.hidden_size = hidden_sizeself.output_size = output_size# 初始化权重self.W1 = np.random.randn(self.input_size, self.hidden_size)self.b1 = np.zeros((1, self.hidden_size))self.W2 = np.random.randn(self.hidden_size, self.output_size)self.b2 = np.zeros((1, self.output_size))def forward(self, X):# 前向传播self.z1 = np.dot(X, self.W1) + self.b1self.a1 = np.maximum(0, self.z1)  # ReLU激活函数self.z2 = np.dot(self.a1, self.W2) + self.b2exp_scores = np.exp(self.z2)    # softmaxself.probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)return self.probsdef backward(self, X, y, learning_rate=0.01):# 反向传播m = X.shape[0]delta3 = self.probs - ydW2 = np.dot(self.a1.T, delta3) / mdb2 = np.sum(delta3, axis=0, keepdims=True) / mdelta2 = np.dot(delta3, self.W2.T) * (self.a1 > 0) #(self.a1 > 0)表示Relu激活函数求导结果,要么是0要么是1dW1 = np.dot(X.T, delta2) / mdb1 = np.sum(delta2, axis=0, keepdims=True) / m# 更新权重self.W1 -= learning_rate * dW1self.b1 -= learning_rate * db1self.W2 -= learning_rate * dW2self.b2 -= learning_rate * db2

    3.4 定义损失函数

    • 在回归问题中常用均方误差作为损失函数;
    • 在分类问题中常用采用交叉熵(Cross-Entropy) 作为损失函数。
        def calculate_loss(self, X, y):# 计算softmax交叉熵损失log_probs = -np.log(self.probs[range(X.shape[0]), np.argmax(y, axis=1)])return np.mean(log_probs)
    常用损失函数

    3.5 训练过程

    # 梯度下降法训练def train(self, X, y, num_epochs=1000, learning_rate=0.01):for epoch in range(num_epochs):# 前向传播和反向传播probs = self.forward(X)self.backward(X, y, learning_rate)loss = self.calculate_loss(X, y)print(f"Epoch {epoch}, Loss: {loss}")# 随机梯度下降法训练def train_SGD(self, X, y, num_epochs=1000, learning_rate=0.01, batch_size=64):  # 增加了batch_size参数indices = list(range(len(X)))random.shuffle(indices)  # 打乱数据索引,以便随机选择样本for epoch in range(num_epochs):# 使用随机顺序遍历数据集for start in range(0, len(X), batch_size):end = min(start + batch_size, len(X))batch_indices = indices[start:end]X_batch = X[batch_indices]y_batch = y[batch_indices]# 前向传播和反向传播probs = self.forward(X_batch)self.backward(X_batch, y_batch, learning_rate)if (start // batch_size) % 100 == 0:loss = self.calculate_loss(X_batch, y_batch)print(f"Epoch [{epoch + 1}/{num_epochs}], step {start + 1}/{len(X)}, Loss: {loss}")
    随机梯度下降算法
    • 梯度下降法计算一步梯度需要对所有样本进行计算
    • 随机梯度下降法(SGD)每次迭代都不使用整个数据集, 而是只选择小批量随机训练样本来计算梯度并更新模型参数。核心概念如下:
      1)minibatch: 每次迭代时抽取出来的一批数据被称为一个 minibatch。
      2)batch_size: 每个 minibatch 所包含的样本数目称为 batch_size。
      3)Epoch: 当程序迭代的时候, 按 minibatch 逐渐抽取出样本, 当把整个数据集都遍历到了的时候, 则完成了一轮训练, 也叫一个 Epoch(轮次)。 启动训练时,可以将训练的轮数 num_epochs 和 batch_size 作为参数传入。

    随机梯度下降算法的过程如下: 



     

    3.6 模型保存

    # 模型保存
    params = {"W1": nn.W1.tolist(),"b1": nn.b1.tolist(),"W2": nn.W2.tolist(),"b2": nn.b2.tolist()
    }
    # 将参数保存到文件
    with open('fcn_params.json', 'w') as f:json.dump(params, f, indent=4)

    4、手动实现代码(完整版)

    import numpy as np
    import idx2numpy  # 用于读取MNIST数据集
    from sklearn.metrics import accuracy_score
    import random
    import json
    import matplotlib.pyplot as plt# 读取MNIST数据集
    train_images = idx2numpy.convert_from_file('./MNIST/raw/train-images-idx3-ubyte')
    train_labels = idx2numpy.convert_from_file('./MNIST/raw/train-labels-idx1-ubyte')
    test_images = idx2numpy.convert_from_file('./MNIST/raw/t10k-images-idx3-ubyte')
    test_labels = idx2numpy.convert_from_file('./MNIST/raw/t10k-labels-idx1-ubyte')# num_images_to_display = 5
    # # for i in range(num_images_to_display):
    # #     plt.imshow(train_images[i], cmap='gray')
    # #     plt.title(f"Label: {train_labels[i]}")
    # #     plt.axis('off')
    # #     plt.show()# 将图像数据转换为一维向量,并归一化
    #第二个维度 -1 表示将所有剩余的维度(即 height 和 width)展平成一维。因此,每个图像将被转换为一个长度为 height * width 的一维数组。
    X_train = train_images.reshape(train_images.shape[0], -1) / 255.0
    X_test = test_images.reshape(test_images.shape[0], -1) / 255.0# 将标签进行one-hot编码
    num_classes = 10
    y_train = np.eye(num_classes)[train_labels]
    y_test = np.eye(num_classes)[test_labels]class NeuralNetwork:def __init__(self, input_size, hidden_size, output_size):self.input_size = input_sizeself.hidden_size = hidden_sizeself.output_size = output_size# 初始化权重self.W1 = np.random.randn(self.input_size, self.hidden_size)self.b1 = np.zeros((1, self.hidden_size))self.W2 = np.random.randn(self.hidden_size, self.output_size)self.b2 = np.zeros((1, self.output_size))def forward(self, X):# 前向传播self.z1 = np.dot(X, self.W1) + self.b1self.a1 = np.maximum(0, self.z1)  # ReLU激活函数self.z2 = np.dot(self.a1, self.W2) + self.b2exp_scores = np.exp(self.z2)    # softmaxself.probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)return self.probsdef backward(self, X, y, learning_rate=0.01):# 反向传播m = X.shape[0]delta3 = self.probs - ydW2 = np.dot(self.a1.T, delta3) / mdb2 = np.sum(delta3, axis=0, keepdims=True) / mdelta2 = np.dot(delta3, self.W2.T) * (self.a1 > 0) #(self.a1 > 0)表示Relu激活函数求导结果,要么是0要么是1dW1 = np.dot(X.T, delta2) / mdb1 = np.sum(delta2, axis=0, keepdims=True) / m# 更新权重self.W1 -= learning_rate * dW1self.b1 -= learning_rate * db1self.W2 -= learning_rate * dW2self.b2 -= learning_rate * db2def calculate_loss(self, X, y):# 计算softmax交叉熵损失log_probs = -np.log(self.probs[range(X.shape[0]), np.argmax(y, axis=1)])return np.mean(log_probs)# 梯度下降法训练def train(self, X, y, num_epochs=1000, learning_rate=0.01):for epoch in range(num_epochs):# 前向传播和反向传播probs = self.forward(X)self.backward(X, y, learning_rate)loss = self.calculate_loss(X, y)print(f"Epoch {epoch}, Loss: {loss}")# 随机梯度下降法训练def train_SGD(self, X, y, num_epochs=1000, learning_rate=0.01, batch_size=64):  # 增加了batch_size参数indices = list(range(len(X)))random.shuffle(indices)  # 打乱数据索引,以便随机选择样本for epoch in range(num_epochs):# 使用随机顺序遍历数据集for start in range(0, len(X), batch_size):end = min(start + batch_size, len(X))batch_indices = indices[start:end]X_batch = X[batch_indices]y_batch = y[batch_indices]# 前向传播和反向传播probs = self.forward(X_batch)self.backward(X_batch, y_batch, learning_rate)if (start // batch_size) % 100 == 0:loss = self.calculate_loss(X_batch, y_batch)print(f"Epoch [{epoch + 1}/{num_epochs}], step {start + 1}/{len(X)}, Loss: {loss}")# 定义网络结构和参数
    input_size = 784  # 28*28像素
    hidden_size = 128
    output_size = 10
    batch_size = 64# 创建神经网络实例
    nn = NeuralNetwork(input_size, hidden_size, output_size)# 训练模型
    nn.train_SGD(X_train, y_train, num_epochs=1, learning_rate=0.01, batch_size=batch_size)
    # nn.train(X_train, y_train, num_epochs=1, learning_rate=0.01)# 模型保存
    params = {"W1": nn.W1.tolist(),"b1": nn.b1.tolist(),"W2": nn.W2.tolist(),"b2": nn.b2.tolist()
    }
    # 将参数保存到文件
    with open('fcn_params.json', 'w') as f:json.dump(params, f, indent=4)# 使用模型进行预测
    nn = NeuralNetwork(input_size, hidden_size, output_size)
    with open('fcn_params.json', 'r') as f:params = json.load(f)nn.W1 = np.array(params["W1"])
    nn.b1 = np.array(params["b1"])
    nn.W2 = np.array(params["W2"])
    nn.b2 = np.array(params["b2"])# 预测并评估模型
    test_predictions = np.argmax(nn.forward(X_test), axis=1)test_accuracy = accuracy_score(np.argmax(y_test, axis=1), test_predictions)print(f"Test Accuracy: {test_accuracy:.4f}")

    5、pytorch实现代码(完整版)

    # python --version     3.8.10
    # PyTorch --version   2.3.1
    # torchvision --version 0.18.1
    import torch
    import torch.nn as nn
    import torch.optim as optim
    from torchvision import datasets, transforms# 定义超参数
    input_size = 784  # 28x28
    hidden_size = 128
    num_classes = 10
    num_epochs = 1
    batch_size = 64
    learning_rate = 0.001# 加载和预处理数据
    train_dataset = datasets.MNIST(root='./', train=True, transform=transforms.ToTensor(), download=False)
    test_dataset = datasets.MNIST(root='./', train=False, transform=transforms.ToTensor(), download=False)
    train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
    test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)# 定义全连接神经网络
    class NeuralNet(nn.Module):def __init__(self, input_size, hidden_size, num_classes):super(NeuralNet, self).__init__()self.fc1 = nn.Linear(input_size, hidden_size)self.relu = nn.ReLU()self.fc2 = nn.Linear(hidden_size, num_classes)def forward(self, x):out = self.fc1(x)out = self.relu(out)out = self.fc2(out)return out# 训练模型
    def train(model, train_loader, optimizer, criterion, num_epochs):for epoch in range(num_epochs):for i, (images, labels) in enumerate(train_loader):# 前向传播outputs = model.forward(images.reshape(-1, 28 * 28))loss = criterion(outputs, labels)# 反向传播和优化optimizer.zero_grad()loss.backward()optimizer.step()if i % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Step [{i + 1}/{len(train_loader)}], Loss: {loss.item()}')# 测试模型
    def predict(model, test_loader):model.eval()  # 设置为评估模式correct = 0total = 0with torch.no_grad():for images, labels in test_loader:outputs = model.forward(images.reshape(-1, 28 * 28))_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print(f'Accuracy of the network on the 10000 test images: {100 * correct / total} %')model = NeuralNet(input_size, hidden_size, num_classes)
    # 定义损失函数和优化器
    criterion = nn.CrossEntropyLoss()
    # optim.Adam
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)  # SGD
    # 训练模型
    train(model, train_loader, optimizer, criterion, num_epochs=num_epochs)# 保存模型
    torch.save(model.state_dict(), 'fcn_state_dict.pth')# 加载模型
    model.load_state_dict(torch.load('fcn_state_dict.pth'))# 测试模型
    predict(model, test_loader)

    相关文章:

    全连接神经网络(前馈神经网络)

    一、全连接神经网络介绍 在多层神经网络中, 第 N 层的每个神经元都分别与第 N-1 层的神经元相互连接。 1、神经元 这个神经元接收的输入信号为向量 , 向量为输入向量的组合权重, 为偏置项, 是一个标量。 神经元的作用是对输入向…...

    【llm对话系统】什么是 LLM?大语言模型新手入门指南

    什么是 LLM?大语言模型新手入门指南 大家好!欢迎来到 LLM 的奇妙世界!如果你对人工智能 (AI) 的最新进展,特别是那些能像人类一样阅读、写作甚至进行对话的 AI 感兴趣,那么你来对地方了。这篇文章将带你认识 LLM 的基…...

    【Linux】互斥锁、基于阻塞队列、环形队列的生产消费模型、单例线程池

    ⭐️个人主页:小羊 ⭐️所属专栏:Linux 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 1、互斥锁2、生产消费模型2.1 阻塞队列2.2 环形队列 3、单例线程池4、线程安全和重入问题 1、互斥锁 临界资源:多线程…...

    【学术会议征稿】第五届能源、电力与先进热力系统学术会议(EPATS 2025)

    能源、电力与先进热力系统设计是指结合物理理论、工程技术和计算机模拟,对能源转换、利用和传输过程进行设计的学科领域。它涵盖了从能源的生产到最终的利用整个流程,旨在提高能源利用效率,减少能源消耗和环境污染。 重要信息 官网&#xf…...

    ES6 类语法:JavaScript 的现代化面向对象编程

    Hi,我是布兰妮甜 !ECMAScript 2015,通常被称为 ES6 或 ES2015,是 JavaScript 语言的一次重大更新。它引入了许多新特性,其中最引人注目的就是类(class)语法。尽管 JavaScript 一直以来都支持基于…...

    Sprintboot原理

    配置优先级 Springboot中支持的三种配置文件: application.propertiesapplication.ymlapplication.yaml java系统属性:-Dxxxxxx 命令行参数:-xxxxxx 优先级:命令行参数>java系统属性>application.properties>applicat…...

    OpenHarmony 5.0.2 Release来了!

    版本概述 OpenHarmony 5.0.2 Release版本对标准系统的能力进行持续完善,以快速迭代的方式推出API 14,相比5.0.1 Release版本,重点做出了如下特性新增或增强: 进一步增强ArkUI、图形图像的能力,提供更多组件的高级属性…...

    Qt 控件与布局管理

    1. Qt 控件的父子继承关系 在 Qt 中,继承自 QWidget 的类,通常会在构造函数中接收一个 parent 参数。 这个参数用于指定当前空间的父控件,从而建立控件间的父子关系。 当一个控件被设置为另一控件的子控件时,它会自动成为该父控…...

    使用小尺寸的图像进行逐像素语义分割训练,出现样本不均衡训练效果问题

    在使用小尺寸图像进行逐像素语义分割训练时,确实可能出现样本不均衡问题,且这种问题可能比大尺寸图像更显著。 1. 小尺寸图像如何加剧样本不均衡? (1) 局部裁剪导致类别分布偏差 问题:遥感图像中某些类别(如道路、建…...

    0.91英寸OLED显示屏一种具有小尺寸、高分辨率、低功耗特性的显示器件

    0.91英寸OLED显示屏是一种具有小尺寸、高分辨率、低功耗特性的显示器件。以下是对0.91英寸OLED显示屏的详细介绍: 一、基本参数 尺寸:0.91英寸分辨率:通常为128x32像素,意味着显示屏上有128列和32行的像素点,总共409…...

    读书笔记--分布式服务架构对比及优势

    本篇是在上一篇的基础上,主要对共享服务平台建设所依赖的分布式服务架构进行学习,主要记录和思考如下,供大家学习参考。随着企业各业务数字化转型工作的推进,之前在传统的单一系统(或单体应用)模式中&#…...

    HTML5 新的 Input 类型详解

    HTML5 引入了许多新的输入类型,极大地增强了表单的功能和用户体验。这些新的输入类型不仅提供了更好的输入控制,还支持内置的验证功能,减少了开发者手动编写验证逻辑的工作量。本文将全面介绍 HTML5 中新增的输入类型,并结合代码示…...

    ESP32-CAM实验集(WebServer)

    WebServer 效果图 已连接 web端 platformio.ini ; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library stor…...

    Case逢无意难休——深度解析JAVA中case穿透问题

    Case逢无意难休——深度解析JAVA中case穿透问题~ 不作溢美之词,不作浮夸文章,此文与功名进取毫不相关也!与大家共勉!! 更多文章:个人主页 系列文章:JAVA专栏 欢迎各位大佬来访哦~互三必回&#…...

    Golang笔记——常用库context和runtime

    大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Golang的常用库context和runtime,包括库的基本概念和基本函数的使用等。 文章目录 contextcontext 包的基本概念主要类型和函数1. **…...

    2000-2020年各省第二产业增加值占GDP比重数据

    2000-2020年各省第二产业增加值占GDP比重数据 1、时间:2000-2020年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区名称、年份、第二产业增加值占GDP比重 4、范围:31省 5、指标解释:第二产业增加值占GDP比重…...

    unity商店插件A* Pathfinding Project如何判断一个点是否在导航网格上?

    需要使用NavGraph.IsPointOnNavmesh(Vector3 point) 如果点位于导航网的可步行部分,则为真。 如果一个点在可步行导航网表面之上或之下,在任何距离,如果它不在更近的不可步行节点之上 / 之下,则认为它在导航网上。 使用方法 Ast…...

    Day24-【13003】短文,数据结构与算法开篇,什么是数据元素?数据结构有哪些类型?什么是抽象类型?

    文章目录 13003数据结构与算法全书框架考试题型的分值分布如何? 本次内容概述绪论第一节概览什么是数据、数据元素,数据项,数据项的值?什么是数据结构?分哪两种集合形式(逻辑和存储)&#xff1f…...

    富文本 tinyMCE Vue2 组件使用简易教程

    参考官方教程 TinyMCE Vue.js integration technical reference Vue2 项目需要使用 tinyMCE Vue2 组件(tinymce/tinymce-vue)的第 3 版 安装组件 npm install --save "tinymce/tinymce-vue^3" 编写组件调用 <template><Editorref"editor"v-m…...

    强化学习在自动驾驶中的实现与挑战

    强化学习在自动驾驶中的实现与挑战 自动驾驶技术作为当今人工智能领域的前沿之一,正通过各种方式改变我们的出行方式。而强化学习(Reinforcement Learning, RL),作为机器学习的一大分支,在自动驾驶的实现中扮演了至关重要的角色。它通过模仿人类驾驶员的决策过程,为车辆…...

    记录 | MaxKB创建本地AI智能问答系统

    目录 前言一、重建MaxKBStep1 复制路径Step2 删除MaxKBStep3 创建数据存储文件夹Step4 重建 二、创建知识库Step1 新建知识库Step2 下载测试所用的txtStep3 上传本地文档Step4 选择模型补充智谱的API Key如何获取 Step5 查看是否成功 三、创建应用Step1 新建应用Step2 配置AI助…...

    特种作业操作之低压电工考试真题

    1.下面&#xff08; &#xff09;属于顺磁性材料。 A. 铜 B. 水 C. 空气 答案&#xff1a;C 2.事故照明一般采用&#xff08; &#xff09;。 A. 日光灯 B. 白炽灯 C. 压汞灯 答案&#xff1a;B 3.人体同时接触带电设备或线路中的两相导体时&#xff0c;电流从一相通过人体流…...

    [免费]基于Python的Django博客系统【论文+源码+SQL脚本】

    大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的基于Python的Django博客系统&#xff0c;分享下哈。 项目视频演示 【免费】基于Python的Django博客系统 Python毕业设计_哔哩哔哩_bilibili 项目介绍 随着互联网技术的飞速发展&#xff0c;信息的传播与…...

    Cannot resolve symbol ‘XXX‘ Maven 依赖问题的解决过程

    一、问题描述 在使用 Maven 管理项目依赖时&#xff0c;遇到了一个棘手的问题。具体表现为&#xff1a;在 pom.xml 文件中导入了所需的依赖&#xff0c;并且在 IDE 中导入语句没有显示为红色&#xff08;表示 IDE 没有提示依赖缺失&#xff09;&#xff0c;但是在实际使用这些依…...

    我们需要有哪些知识体系,知识体系里面要有什么哪些内容?

    01、管理知识体系的学习知识体系 主要内容&#xff1a; 1、知识管理框架的外部借鉴、和自身知识体系的搭建&#xff1b; 2、学习能力、思维逻辑能力等的塑造&#xff1b; 3、知识管理工具的使用&#xff1b; 4、学习资料的导入和查找资料的渠道&#xff1b; 5、深层关键的…...

    什么是vue.js组件开发,我们需要做哪些准备工作?

    Vue.js 是一个非常流行的前端框架,用于构建用户界面。组件开发是 Vue.js 的核心概念之一,通过将界面拆分为独立的组件,可以提高代码的可维护性和复用性。以下是一个详细的 Vue.js 组件开发指南,包括基础概念、开发流程和代码示例。 一、Vue.js 组件开发基础 1. 组件的基本…...

    网络工程师 (3)指令系统基础

    一、寻址方式 &#xff08;一&#xff09;指令寻址 顺序寻址&#xff1a;通过程序计数器&#xff08;PC&#xff09;加1&#xff0c;自动形成下一条指令的地址。这是计算机中最基本、最常用的寻址方式。 跳跃寻址&#xff1a;通过转移类指令直接或间接给出下一条指令的地址。跳…...

    第4章 神经网络【1】——损失函数

    4.1.从数据中学习 实际的神经网络中&#xff0c;参数的数量成千上万&#xff0c;因此&#xff0c;需要由数据自动决定权重参数的值。 4.1.1.数据驱动 数据是机器学习的核心。 我们的目标是要提取出特征量&#xff0c;特征量指的是从输入数据/图像中提取出的本质的数 …...

    【Python】第五弹---深入理解函数:从基础到进阶的全面解析

    ✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】【Python】 目录 1、函数 1.1、函数是什么 1.2、语法格式 1.3、函数参数 1.4、函数返回值 1.5、变量作用域 1.6、函数…...

    【MQ】如何保证消息队列的高性能?

    零拷贝 Kafka 使用到了 mmap 和 sendfile 的方式来实现零拷贝。分别对应 Java 的 MappedByteBuffer 和 FileChannel.transferTo 顺序写磁盘 Kafka 采用顺序写文件的方式来提高磁盘写入性能。顺序写文件&#xff0c;基本减少了磁盘寻道和旋转的次数完成一次磁盘 IO&#xff0…...