Py学习  »  Python

分步式讲解神经网络并带大家使用Python从头构建一个神经网络!

人工智能学习指南 • 1 月前 • 73 次点击  
人工智能做为一个交叉学科,基本可以和所有学科交叉做创新,但是对于其他领域的同学来说往往都不知道怎么去系统的学习这项技术,所以今天这篇文章将带大家从头开始在Python中编写一个神经网络。
不仅会提供逐步的操作指南,还将深入探讨神经网络背后的基础理论,不仅对大家理解神经网络非常有帮助还可以提升大家的问题解决能力和代码调试能力。

为了让大家可以更系统的学习人工智能(机器学习深度学习),小墨学长还为大家整理了一份60天入门人工智能(机器学习深度学习)的学习路线,从基础到进阶都包含在内,希望可以帮助到大家。

学习路线的资料都下载打包好了

大家可以添加小助手让她把学习路线的思维导图和相关资料一起发给你

 

线性与非线性

线性回归是机器学习领域的基础起点,但是它在有效捕捉和解释数据中的非线性关系方面存在局限性。
这种局限性源于线性回归模型的底层假设和结构,线性回归假设自变量与目标变量之间存在线性关系。
它试图拟合一条直线或超平面,以最好地表示变量之间的关系。
许多现实世界的现象展现出复杂的非线性模式和交互作用,这些无法仅通过简单的线性关系来准确建模。
线性回归在有效捕捉复杂的非线性关系方面力不从心,但神经网络在这方面表现出色。
神经网络通过以下三种重要方式增强了线性回归:
  1. 非线性变换:与线性回归不同,神经网络在线性变换之上应用非线性变换。这使得它们能够建模和捕捉数据中的复杂非线性模式。

  2. 多层结构:神经网络由多层组成,能够捕捉特征之间的交互和依赖关系。每一层都有助于提取输入数据的更高层次表示,从而实现更复杂的建模。

  3. 多个隐藏单元:在神经网络的每一层中,有多个隐藏单元。每个隐藏单元执行其独特的线性和非线性变换组合,从而在捕捉复杂关系和增强模型学习复杂模式的能力方面提供灵活性。


下面是神经网络背后的基本概念:

激活函数

我们使用激活函数来执行这些非线性变换,用非线性代替线性。
我们通过应用激活函数来修改线性函数y = wx + b,得到变换后的方程y = activation(wx + b)。

import numpy as np # 导入numpy库,用于数值计算import matplotlib.pyplot as plt # 导入matplotlib库,用于绘图
def plot_func(x, y, title): # 绘制激活函数的辅助函数 plt.plot(x, y) # 绘制x和y的曲线图 plt.title(title) # 设置图的标题 plt.xlabel('x') # 设置x轴标签 plt.ylabel('activation(x)') # 设置y轴标签 plt.grid(True) # 显示网格 plt.show() # 显示图形
x = np.linspace(-10, 10, 100) # 生成从-10到10的100个均匀分布的点

Sigmoid:Sigmoid激活函数是一种数学函数,将输入映射到0和1之间的值,提供一个平滑的S形曲线。

import numpy as np
def sigmoid(x): # 定义 sigmoid 激活函数,将输入映射到 0 和 1 之间 # 参数: # x: 输入值,可以是单个数值或 numpy 数组 # 返回: # sigmoid(x) 的值,即 1 / (1 + e^{-x}) return 1 / (1 + np.exp(-x))


ReLU(Rectified Linear Unit):ReLU激活函数是一种数学函数,如果输入为正则返回输入值,否则返回0,提供分段线性输出。

def relu(x): # 定义relu激活函数,将输入x中小于0的部分置为0,大于等于0的部分保持不变 # 这是常用的激活函数,能够引入非线性,并且计算效率高 # 参数: # x: 输入值,可以是单个数值或numpy数组 # 返回: # relu(x)的值,即np.maximum(0, x) return np.maximum(0, x)


Leaky ReLU:Leaky ReLU激活函数是ReLU函数的一种变体,允许负输入值有一个小的非零输出,防止信息被完全抑制。

def leaky_relu(x, alpha=0.1): # 定义Leaky ReLU激活函数,解决ReLU函数在负值区域梯度为0的问题 # 参数: # x: 输入值,可以是单个数值或numpy数组 # alpha: 控制负值区域的斜率,默认值为0.1 # 返回: # Leaky ReLU(x)的值,即np.maximum(alpha * x, x) return np.maximum(alpha * x, x)


Tanh:Tanh(双曲正切)激活函数是一种数学函数,将输入映射到-1和1之间的值,提供一个以0为中心的平滑S形曲线。

def tanh(x): # 定义双曲正切(tanh)激活函数,将输入值映射到 -1 和 1 之间 # 参数: # x: 输入值,可以是单个数值或numpy数组 # 返回: # tanh(x) 的值,即 (e^x - e^{-x}) / (e^x + e^{-x}) return np.tanh(x)


Softmax:Softmax激活函数是一种常用于多类分类任务的数学函数,它将一组实数值转换为多个类别的概率分布。

def softmax(x): # 定义softmax函数,将输入值转换为概率分布 # 参数: # x: 输入值,通常是一个numpy数组(如神经网络的输出层) # 返回: # softmax(x) 的值,即 exp(x) / sum(exp(x)),表示概率分布 exp_scores = np.exp(x) # 对输入值进行指数运算 return exp_scores / np.sum(exp_scores) # 归一化得到概率分布


在我们的实现中,我们将继续使用ReLU激活函数。

多层结构

当然,仅仅加入ReLU激活函数会极大地放大误差,这主要是因为对于任何小于零的输入,它都会产生相同的预测。
为了解决这个问题,我们在神经网络中引入多层结构。
例如,一个具有两层的神经网络可以用方程y^ = w2 * relu(w1 * x + b1) + b2来表示。

多个隐藏单元

一个名为prediction的lambda函数根据输入x计算线性预测,使用预定义的权重(w1)和偏置(b1)值。

prediction = lambda x, w1=.2, b=1.99: x * w1 + b

然后,我们对线性预测应用ReLU激活函数。

layer1_1 = np.maximum(0, prediction(x))plt.plot(x, layer1_1)


如果我们再添加一层会发生什么?

layer1_2 = np.maximum(0, prediction(x, .3, -2))plt.plot(x, layer1_1+layer1_2)


我们在输出中引入了非线性,让我们再添加一个层。

layer1_3 = np.maximum(0, prediction(x, .6, -2))plt.plot(x, layer1_1+layer1_2+layer1_3)


通过增加单元数量,我们观察到更明显的非线性关系的出现。随着我们调整权重,可以观察到关系中的相应变化。
让我们为两层结构绘制一个图。


计算输出

从上面的内容可以看出,一个组件的输出是另一个组件的输入。在这个过程中,我们使用矩阵乘法来计算输出。


假设我们有一个形状为2x1的输入矩阵。

前向传播

可以使用tsensor包来有效地可视化张量变量,通过增强错误信息并显示Python代码,TensorSensor提供了对张量变量形状的洞察。
它与TensorFlow、PyTorch、JAX、Numpy、Keras和fastai等流行库兼容。

from tsensor import explain as exp # 导入tsensor库,用于解释张量操作import numpy as np # 导入numpy库,用于数值计算
# 定义输入矩阵 x_input,形状为 5x1x_input = np.array([[10], [20], [-20], [-40], [-3]])
# 定义第一层的权重矩阵 l1_weights,形状为 1x2l1_weights = np.array([[.73, .2]])
# 定义第一层的偏置矩阵 l1_bias,形状为 1x2l1_bias = np.array([[4, 2]])
# 使用 tsensor 的 explain 上下文管理器解释张量操作with exp() as c: # 计算第一层的输出:l1_output = x_input @ l1_weights + l1_bias # @ 表示矩阵乘法,x_input 的形状为 5x1,l1_weights 的形状为 1x2 # 结果为 5x2 的矩阵,然后加上偏置 l1_bias l1_output = x_input @ l1_weights + l1_bias


我们对上述过程的输出应用一个激活函数。

l1_activated = relu(l1_output)

一个有用的指导原则是,权重矩阵的行数应与输入矩阵的列数相匹配,而权重矩阵的列数应与输出矩阵的列数相匹配。
因此,在第一层中,我们的权重矩阵是1x2,表示从1个输入特征过渡到2个输出特征。


本质上,这是在神经网络中进行预测的基本过程,它包括利用每层的权重矩阵和偏置矩阵,重复进行与权重矩阵的乘法运算,加入偏置,应用非线性,并对每一层重复这个过程。
要在层内添加更多单元,只需向权重矩阵添加更多列即可。

损失

现在,我们可以使用均方误差(或其他指标)来计算我们的输出与实际值之间的误差。

import numpy as np # 导入numpy库,用于数值计算
def calculate_mse(actual, predicted): # 计算均方误差(Mean Squared Error, MSE) # 参数: # actual: 实际值,形状为 (n, 1) 的numpy数组 # predicted: 预测值,形状为 (n, 1) 的numpy数组 # 返回: # 每个样本的平方误差,形状为 (n, 1) 的numpy数组 return (actual - predicted) ** 2
# 定义实际值数组 actual,形状为 5x1actual = np.array([[9], [13], [5], [-2], [-1]])
# 假设 output 是预测值数组,形状为 5x1# 计算均方误差并打印结果print(calculate_mse(actual, output))
"""输出结果:[[6.4000000e-03] # 第一个样本的平方误差 [9.2160000e-01] # 第二个样本的平方误差 [1.0000000e+00] # 第三个样本的平方误差 [3.6000000e+01] # 第四个样本的平方误差 [3.4386496e+01]] # 第五个样本的平方误差"""

在梯度下降过程中,确定损失函数的梯度(表示变化率)至关重要。
这个梯度指示了当我们修改输入值时,损失函数如何变化。

import numpy as np # 导入numpy库,用于数值计算
def gradient_mse(actual, predicted): # 计算均方误差(MSE)的梯度 # 参数: # actual: 实际值,形状为 (n, 1) 的numpy数组 # predicted: 预测值,形状为 (n, 1) 的numpy数组 # 返回: # 每个样本的MSE梯度,形状为 (n, 1) 的numpy数组 return predicted - actual
# 定义实际值数组 actual,形状为 5x1actual = np.array([[9], [13], [5], [-2], [-1]])
# 假设 output 是预测值数组,形状为 5x1# 计算MSE梯度并打印结果print(gradient_mse(actual, output))
"""输出结果:[[-0.08 ] # 第一个样本的MSE梯度 [-0.96 ] # 第二个样本的MSE梯度 [-1. ] # 第三个样本的MSE梯度 [ 6. ] # 第四个样本的MSE梯度 [ 5.864]] # 第五个样本的MSE梯度"""

这些信息可以指导我们对预测进行必要的调整,来有效地最小化误差。

反向传播

反向传播本质上逆转了前向传播,将梯度分配给网络的不同参数(如权重和偏置)。
这个梯度在利用梯度下降使网络能够学习方面发挥着关键作用。

前向传播
我们基本上逆转了这个过程来得到反向传播。
我们计算损失函数对每个参数的偏导数,输出层的梯度,即L2输出梯度,用于更新第二层中的权重。
在正向传播中,我们通过将第二层的输入和第一层的输出与L2输出梯度相乘来执行此更新。
偏置的更新则是通过对输出梯度的平均值进行计算来完成的。
接下来,我们将梯度乘以第二层的权重,传播到第一层。
接着让这个梯度通过ReLU函数,并利用它来更新第一层中的权重和偏置。

import numpy as np # 导入numpy库,用于数值计算from tsensor import explain as exp # 导入tsensor库,用于解释张量操作
# 计算输出层的梯度output_gradient = gradient_mse(actual, output) # 调用 gradient_mse 函数计算 MSE 梯度
# 使用 tsensor 的 explain 上下文管理器解释张量操作with exp(): # 计算第二层权重矩阵的梯度 # l1_activated.T @ output_gradient 表示 l1_activated 的转置与 output_gradient 的矩阵乘法 # l1_activated 是上一层的激活输出,形状为 (n, m) # output_gradient 是输出层的梯度,形状为 (n, 1) # 结果为第二层权重矩阵的梯度,形状为 (m, 1) l2_w_gradient = l1_activated.T @ output_gradient
# 打印第二层权重矩阵的梯度l2_w_gradient
"""输出结果:array([[-8.14616], # 第二层第一个权重的梯度 [ 2.1296 ]]) # 第二层第二个权重的梯度"""


我们取5x2的l1_activated矩阵(现在是2x5,即正向传播中第一层的输出)的转置,并将其与5x1的输出梯度相乘,得到一个2x1的矩阵。
这个矩阵给出了我们w2矩阵中每个值的梯度。
提供的图示展示了在正向传播中,输入是如何通过权重相乘来生成输出的。
显然,每个权重都与多个输入相关联,并且每个权重都与多个输入和多个输出相连。
我们将第一层的输出进行转置,并乘以输出梯度,以获得权重梯度。

l2_w_gradient =  l1_activated.T @ output_gradient

为了确保通过权重连接到输出的每个输入都乘以相应的输出梯度,我们转置第一层输出矩阵(作为第二层的输入)。
通过将输出梯度与层的输入相乘,我们可以确定对权重所需的调整。这种关系源于偏导数链式法则的应用。


应用偏导数链式法则,我们计算损失对第二个权重矩阵的偏导数。
这涉及将损失对x和w2乘积的偏导数(相对于w2)相乘。解这个方程可以让我们确定权重矩阵的适当值。
接下来,我们计算偏置的导数。

with exp(): # 计算第二层偏置的梯度 # np.mean(output_gradient, axis=0) 表示对 output_gradient 沿着第0轴(样本维度)求均值 # output_gradient 是输出层的梯度,形状为 (n, 1) # 结果为第二层偏置的梯度,形状为 (1,) l2_b_gradient = np.mean(output_gradient, axis=0)
# 打印第二层偏置的梯度l2_b_gradient
"""输出结果:array([1.9648]) # 第二层偏置的梯度"""


为了更新第二层的权重和偏置,我们从当前w和b的值中减去梯度(乘以学习率)。
学习率有助于防止更新过大,这可能会使我们远离具有最低误差的最优解。

# 设置学习率lr = 1e-4 # 学习率,用于控制参数更新的步长
with exp(): # 更新偏置值 l2_bias = l2_bias - l2_b_gradient * lr # 使用梯度下降法更新第二层偏置 # 更新权重值 l2_weights = l2_weights - l2_w_gradient * lr # 使用梯度下降法更新第二层权重
# 打印更新后的权重值l2_weights
"""输出结果:array([[0.40171069], # 更新后的第二层第一个权重 [0.09955278]]) # 更新后的第二层第二个权重"""

我们更新l2偏置和l2权重。


第一层梯度
接下来,我们计算第一层的梯度,第一层的输出是通过将输入与相应的权重相乘得到的,从而产生第二层的输出。
为了确定损失相对于第一层输出的梯度,我们反向进行正向传播,即将输出梯度与第二层的权重相乘。

with exp(): # 计算第一层激活输出的梯度 # output_gradient @ l2_weights.T 表示 output_gradient 与 l2_weights 的转置的矩阵乘法 # output_gradient 是输出层的梯度,形状为 (n, 1) # l2_weights.T 是第二层权重的转置,形状为 (1, m) # 结果为第一层激活输出的梯度,形状为 (n, m) l1_activated_gradient = output_gradient @ l2_weights.T
# 打印第一层激活输出的梯度l1_activated_gradient
"""输出结果:array([[-0.03213686, -0.00796422], # 第一个样本的第一层激活输出梯度 [-0.38564227, -0.09557067], # 第二个样本的第一层激活输出梯度 [-0.40171069, -0.09955278], # 第三个样本的第一层激活输出梯度 [ 2.41026416, 0.5973167 ], # 第四个样本的第一层激活输出梯度 [ 2.35563151, 0.58377753]]) # 第五个样本的第一层激活输出梯度"""

接着,我们计算第一层权重和偏置的梯度,首先,我们需要将梯度通过ReLU非线性函数进行传播,所以我们考虑ReLU函数的导数。
在我们的案例中,斜率为0或1,所以ReLU函数的导数为0或1。

with exp(): # 计算第一层输出的梯度 # l1_activated_gradient * np.heaviside(l1_output, 0) 表示将第一层激活输出的梯度与 ReLU 的导数相乘 # np.heaviside(l1_output, 0) 是 ReLU 的导数,当 l1_output > 0 时为 1,否则为 0 # 结果为第一层输出的梯度,形状为 (n, m) l1_output_gradient = l1_activated_gradient * np.heaviside(l1_output, 0)
# 打印第一层输出的梯度l1_output_gradient
"""输出结果:array([[-0.03213686, -0.00796422], # 第一个样本的第一层输出梯度 [-0.38564227, -0.09557067], # 第二个样本的第一层输出梯度 [-0. , -0. ], # 第三个样本的第一层输出梯度(ReLU 导数为 0) [ 0. , 0. ], # 第四个样本的第一层输出梯度(ReLU 导数为 0) [ 2.35563151, 0.58377753]]) # 第五个样本的第一层输出梯度"""


现在,我们计算第一层的梯度。

# 反向传播# 计算第一层权重的梯度# input.T @ l1_output_gradient 表示输入矩阵的转置与第一层输出梯度的矩阵乘法# input.T 的形状为 (m, n),l1_output_gradient 的形状为 (n, p)# 结果为第一层权重的梯度,形状为 (m, p)l1_w_gradient = input.T @ l1_output_gradient
# 计算第一层偏置的梯度# np.mean(l1_output_gradient, axis=0) 表示对第一层输出梯度沿着第0轴(样本维度)求均值# 结果为第一层偏置的梯度,形状为 (p,)l1_b_gradient = np.mean(l1_output_gradient, axis=0)
# 梯度下降更新参数# 更新第一层权重:新权重 = 旧权重 - 权重梯度 × 学习率l1_weights -= l1_w_gradient * lr
# 更新第一层偏置:新偏置 = 旧偏置 - 偏置梯度 × 学习率l1_bias -= l1_b_gradient * lr

在上一步中,我们计算了第一层的梯度,并使用它们来更新权重和偏置值。
实质上,我们通过两层进行了反向传播,并在每一层中应用了梯度下降。

训练
以下是我们采用的算法:
  1. 通过网络执行正向传播并获得输出。

  2. 使用mse_grad函数计算网络输出的梯度。

  3. 对网络中的每一层:

    确定非线性输出前的梯度(如果层包含非线性)。

    计算权重的梯度。

    计算偏置的梯度。

    确定该层输入的梯度。

  4. 利用梯度下降法更新网络参数。

(注:为了简化,我们将第4步合并到了第3步中。然而,重要的是要理解反向传播对应于第3步,而梯度下降对应于第4步。通过将这两步分开,我们可以更方便地使用不同的梯度下降变体,如Adam或RMSProp,来更新权重。第3步和第4步通常被称为神经网络的反向传播。)
反向传播和梯度下降是训练神经网络中较为复杂的方面,从概念上讲,反向传播涉及反转网络的正向传播过程,以确定最小化误差的最有效方法。
这包括将损失的梯度从一层传播到另一层,并在传播过程中应用链式法则。

代码
在以下部分,我们将上述所有主题整合到了一个名为“Neural”的类中。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom sklearn.model_selection import train_test_splitfrom sklearn.preprocessing import StandardScalerfrom sklearn.metrics import mean_squared_errorfrom statistics import meanfrom typing import Dict, List, Tuple
np.random.seed(42)
class Neural: def __init__(self, layers: List[int], epochs: int, learning_rate: float = 0.001, batch_size: int=32, validation_split: float = 0.2, verbose: int=1): # 初始化神经网络 self._layer_structure: List[int] = layers # 网络结构(每层的神经元数量) self._batch_size: int = batch_size # 批大小 self._epochs: int = epochs # 训练轮数 self._learning_rate: float = learning_rate # 学习率 self._validation_split: float = validation_split # 验证集比例 self._verbose: int = verbose # 是否打印训练信息 self._losses: Dict[str, float] = {"train": [], "validation": []} # 记录损失 self._is_fit: bool = False # 模型是否已训练 self.__layers = None # 存储网络层参数 def fit(self, X: np.ndarray, y: np.ndarray) -> None: # 划分训练集和验证集 X, X_val, y, y_val = train_test_split(X, y, test_size=self._validation_split, random_state=42) # 初始化网络层参数 self.__layers = self.__init_layers() for epoch in range(self._epochs): epoch_losses = [] for i in range(1, len(self.__layers)): # 前向传播 x_batch = X[i:(i+self._batch_size)] y_batch = y[i:(i+self._batch_size)] pred, hidden = self.__forward(x_batch) # 计算损失 loss = self.__calculate_loss(y_batch, pred) epoch_losses.append(np.mean(loss ** 2)) # 反向传播 self.__backward(hidden, loss) # 计算验证集损失 valid_preds, _ = self.__forward(X_val) train_loss = mean(epoch_losses) valid_loss = np.mean(self.__calculate_mse(valid_preds,y_val)) # 记录损失 self._losses["train"].append(train_loss) self._losses["validation"].append(valid_loss) # 打印训练信息 if self._verbose: print(f"Epoch: {epoch} Train MSE: {train_loss} Valid MSE: {valid_loss}") self._is_fit = True return def predict(self, X: np.ndarray) -> np.ndarray: # 预测 if self._is_fit == False: raise Exception("Model has not been trained yet.") pred, hidden = self.__forward(X) return pred def plot_learning (self) -> None: # 绘制训练损失和验证损失曲线 plt.plot(self._losses["train"],label="loss") plt.plot(self._losses["validation"],label="validation") plt.legend() def __init_layers(self) -> List[np.ndarray]: # 初始化网络层参数 layers = [] for i in range(1, len(self._layer_structure)): layers.append([ np.random.rand(self._layer_structure[i-1], self._layer_structure[i]) / 5 - .1, # 权重 np.ones((1,self._layer_structure[i])) # 偏置 ]) return layers def __forward(self, batch: np.ndarray) -> Tuple[np.ndarray, List[np.ndarray]]: # 前向传播 hidden = [batch.copy()] for i in range(len(self.__layers)): batch = np.matmul(batch, self.__layers[i][0]) + self.__layers[i][1] # 线性变换 if i < len(self.__layers) - 1: batch = np.maximum(batch, 0) # ReLU 激活函数 # 保存隐藏层输出,用于反向传播 hidden.append(batch.copy()) return batch, hidden def __calculate_loss(self,actual: np.ndarray, predicted: np.ndarray) -> np.ndarray: # 计算损失(MSE 的梯度) "mse" return predicted - actual def __calculate_mse(self, actual: np.ndarray, predicted: np.ndarray) -> np.ndarray: # 计算均方误差(MSE) return (actual - predicted) ** 2 def __backward(self, hidden: List[np.ndarray], grad: np.ndarray) -> None: # 反向传播 for i in range(len(self.__layers)-1, -1, -1): if i != len(self.__layers) - 1: grad = np.multiply(grad, np.heaviside(hidden[i+1], 0)) # ReLU 的导数 w_grad = hidden[i].T @ grad # 权重梯度 b_grad = np.mean(grad, axis=0) # 偏置梯度 self.__layers[i][0] -= w_grad * self._learning_rate # 更新权重 self.__layers[i][1] -= b_grad * self._learning_rate # 更新偏置 grad = grad @ self.__layers[i][0].T # 计算前一层的梯度 return

接下来,我们生成一些虚拟数据来测试“Neural”类。

def generate_data():    # 定义特征之间的相关性系数    corr_a = 0.8  # 特征 a 与目标值的相关性    corr_b = 0.4  # 特征 b 与目标值的相关性    corr_c = -0.2  # 特征 c 与目标值的相关性        # 生成独立特征    a = np.random.normal(0, 1, size=100000)  # 特征 a,服从标准正态分布    b = np.random.normal(0, 1, size=100000)  # 特征 b,服从标准正态分布    c = np.random.normal(0, 1, size=100000)  # 特征 c,服从标准正态分布    d = np.random.randint(0, 4, size=100000)  # 特征 d,取值为 0 到 3 的整数    e = np.random.binomial(1, 0.5, size=100000)  # 特征 e,取值为 0 或 1 的二项分布        # 生成目标特征,基于独立特征的线性组合    target = 50 + corr_a*a + corr_b*b + corr_c*c + d*10 + 20*e + np.random.normal(0, 10, size=100000)    # 目标值的计算公式:50 + 0.8*a + 0.4*b - 0.2*c + 10*d + 20*e + 噪声        # 创建包含所有特征的 DataFrame    df = pd.DataFrame({'a': a, 'b': b, 'c': c, 'd': d, 'e': e, 'target': target})    return df

以下是客户端代码:
# 生成数据集df = generate_data()
# 分离特征和目标值X = df.drop('target', axis=1) # 特征矩阵,去掉目标列y = df['target'] # 目标值
# 标准化特征scaler = StandardScaler()X = scaler.fit_transform(X) # 对特征进行标准化处理
# 划分训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)y_train = y_train.to_numpy().reshape(-1,1) # 将训练目标值转换为 numpy 数组并调整形状y_test = y_test.to_numpy().reshape(-1,1) # 将测试目标值转换为 numpy 数组并调整形状
# 定义网络结构layer_structure = [X_train.shape[1],10,10,1] # 输入层、两个隐藏层(每层10个神经元)、输出层# 初始化神经网络nn = Neural(layer_structure, 20, 1e-5, 64, 0.2, 1) # 网络结构、训练轮数、学习率、批大小、验证集比例、是否打印信息
# 训练模型nn.fit(X_train, y_train)
# 使用训练好的模型进行预测y_pred = nn.predict(X_test)
# 绘制训练和验证损失曲线nn.plot_learning()
# 计算测试集的均方误差print("Test error: ",mean_squared_error(y_test, y_pred))
"""输出结果:Epoch: 0 Train MSE: 6066.584227303851 Valid MSE: 5630.972575612107Epoch: 1 Train MSE: 5870.45827241517 Valid MSE: 5384.024826048717Epoch: 2 Train MSE: 5584.489636840577 Valid MSE: 4993.952466830458Epoch: 3 Train MSE: 5127.64238543267 Valid MSE: 4376.563641292963Epoch: 4 Train MSE: 4408.550555767417 Valid MSE: 3470.967255214888Epoch: 5 Train MSE: 3370.6165240733935 Valid MSE: 2333.4365011529103Epoch: 6 Train MSE: 2112.702666917853 Valid MSE: 1245.1547720938968Epoch: 7 Train MSE: 1001.3618108374816 Valid MSE: 565.5834115291266Epoch: 8 Train MSE: 396.9514096548994 Valid MSE: 298.31216370120575Epoch: 9 Train MSE: 198.29006090703072 Valid MSE: 204.83294115572235Epoch: 10 Train MSE: 139.2931182121901 Valid MSE: 162.0341771457693Epoch: 11 Train MSE: 113.971621253487 Valid MSE: 138.35491897074462Epoch: 12 Train MSE: 100.19734344395454 Valid MSE: 124.60170156400542 Epoch: 13 Train MSE: 92.35069581444299 Valid MSE: 116.55999261926036Epoch: 14 Train MSE: 87.88890529435344 Valid MSE: 111.85169154584908Epoch: 15 Train MSE: 85.37162170152865 Valid MSE: 109.08001681897412Epoch: 16 Train MSE: 83.96135084225956 Valid MSE: 107.42929147368837Epoch: 17 Train MSE: 83.17564386183105 Valid MSE: 106.42800615549532Epoch: 18 Train MSE: 82.73977092210092 Valid MSE: 105.80581167903857Epoch: 19 Train MSE: 82.49876360284046 Valid MSE: 105.40815905002043Test error: 105.40244085384184"""

以及学习曲线图:

我们已逐步探索了如何使用Python从零开始构建一个神经网络。
本文提供了一个精简而简单的实现方案,可以帮助大家了解神经网络架构的基础知识。

另外我们打磨了一套基于数据与模型方法的 AI科研入门学习方案(已经迭代过5次),对于ai来说,任何专业,要处理的都只是实验数据,所以我们根据实验数据将课程分为了三种方向的针对性课程,包含时序、图结构、影像三大实验室,我们会根据你的数据类型来帮助你选择合适的实验室,根据规划好的路线学习 只需 5 个月左右(很多同学通过学习已经发表了 sci 二区及以下、ei会议等级别论文)如果需要发高区也有其他形式。

人工智能系统班学习路线

大家感兴趣可以直接添加小助手微信:ai0808q  通过后回复咨询既可!


大家想自学的我还给大家准备了一些机器学习、深度学习、神经网络资料大家可以看看以下文章(文章中提到的资料都打包好了,都可以直接添加小助手获取)

<


 人工智能资料分享 



>








零基础学习路线(点击图片即可跳转)











深度学习中文教程书(点击图片即可跳转)


神经网络学习资料(点击图片即可跳转)


大家觉得这篇文章有帮助的话记得分享给你的死党闺蜜、同学、朋友、老师、敌蜜!

B站:AI秃秃学长小墨



关注小墨

获取最新AI技能+最肝AI干货

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/177670
 
73 次点击