【动手学深度学习】深入浅出深度学习之利用神经网络识别螺旋状数据集

目录

🌞一、实验目的

🌞二、实验准备

🌞三、实验内容

🌼1. 生成螺旋状数据集

🌼2. 打印数据集

🌼3. 编程实现

🌻仿射层-Affine类

🌻传播层-Sigmoid类

🌻损失函数相关类

🌻三层神经网络类-ThreeLayerNet

🌻随机梯度下降法的类-SGD

🌻训练过程

🌻绘制迭代效果图

🌞四、实验心得


🌞一、实验目的

  1. 利用神经网络识别螺旋状数据集(python实现);
  2. 正确理解深度学习所需的数学知识。

🌞二、实验准备

  1. 根据GPU安装pytorch版本实现GPU运行实验代码;
  2. 配置环境用来运行 Python、Jupyter Notebook和相关库等相关库。

🌞三、实验内容

资源获取:关注公众号【科创视野】回复  深度学习

🌼1. 生成螺旋状数据集

(1)利用numpy库生成螺旋状数据集,python源码如下:

# coding: utf-8
import numpy as np


def load_data(seed=2020264):   #🍕🍕🍕生成数据集🍕🍕🍕
    np.random.seed(seed)  #设置随机数种子
    N = 100  # 各类的样本数
    DIM = 2  # 数据的元素个数
    CLS_NUM = 3  # 类别数

    x = np.zeros((N*CLS_NUM, DIM))
    t = np.zeros((N*CLS_NUM, CLS_NUM), dtype=np.int)

    for j in range(CLS_NUM):
        for i in range(N):#N*j, N*(j+1)):
            rate = i / N
            radius = 1.0*rate
            theta = j*4.0 + 4.0*rate + np.random.randn()*0.2

            ix = N*j + i
            x[ix] = np.array([radius*np.sin(theta),
                              radius*np.cos(theta)]).flatten()
            t[ix, j] = 1

    return x, t

解释:

1.代码中导入了numpy库,用于生成和处理数组。

2.load_data函数:该函数用于生成数据集。接受一个seed参数,用于设置随机数生成的种子,以确保结果的可重复性。

3.设置参数:在函数内部,定义了几个参数,包括样本数N、数据的元素个数DIM和类别数CLS_NUM。这些参数用于确定生成数据的规模和属性。

4.初始化数组:通过np.zeros函数创建了两个数组x和t,用于存储生成的样本和对应的标签。

5.数据生成循环:通过两个嵌套的循环,依次生成每个类别的样本。外层循环遍历类别数,内层循环生成每个类别中的样本。

6.样本生成:在内层循环中,首先根据当前类别和样本索引计算出一个比例rate,用于确定样本的半径。然后,根据一定的规则计算样本的极坐标位置(半径和角度),并引入一定的随机扰动。最后,将样本的极坐标位置转换为笛卡尔坐标位置,并存储在数组x中。

7.标签生成:在内层循环中,通过将当前样本所属类别对应的位置设为1,将标签存储在数组t中。

8.返回结果:最后,函数返回生成的样本数组x和标签数组t。


🌼2. 打印数据集

在加载完数据集后,利用plt将生成的数据集打印出来,python源码如下:

# coding: utf-8
import sys
sys.path.append('..')  # 为了引入父目录的文件而进行的设定
import matplotlib.pyplot as plt


x, t = load_data()
print('x', x.shape)  # (300, 2)
print('t', t.shape)  # (300, 3)

# 绘制数据点
N = 100
CLS_NUM = 3
markers = ['o', 'x', '^']
for i in range(CLS_NUM):
    plt.scatter(x[i*N:(i+1)*N, 0], x[i*N:(i+1)*N, 1], s=40, marker=markers[i])
plt.show()

解释:

1.导入sys和matplotlib.pyplot库。sys库用于在代码中添加父目录的路径,而matplotlib.pyplot库用于数据可视化。

2.添加父目录路径:通过sys.path.append('..')语句,将父目录路径添加到代码中。这样做是为了能够引入父目录中的文件,这里是为了引入之前定义的load_data()函数。

3.调用load_data()函数:通过调用load_data()函数,生成数据集的特征数组x和标签数组t。

4.打印数组形状:通过print()语句打印出数据集特征数组x和标签数组t的形状。x.shape输出的结果是(300, 2),表示x数组有300行和2列;t.shape输出的结果是(300, 3),表示t数组有300行和3列。这里的形状信息给出了生成数据集的维度信息。

5.绘制数据点:接下来,通过使用matplotlib.pyplot库来绘制数据集的散点图。循环遍历每个类别,利用plt.scatter()函数绘制对应类别的数据点。函数中的参数包括样本的x坐标和y坐标,使用不同的标记形状markers[i]和尺寸s=40来区分不同类别的数据点。

6.显示图像:最后,通过plt.show()函数显示绘制的图像,将数据集的散点图展示出来。

结果图为:


🌼3. 编程实现

🌻仿射层-Affine类
class Affine:
    def __init__(self,W,b):
        self.params = [W,b]#保存参数
        self.grads = [np.zeros_like(W),np.zeros_like(b)]#保存梯度
        self.x = None
    def forward(self,x):
        W,b = self.params
        out = np.dot(x,W) + b
        self.x = x
        return out
    def backward(self,dout):
        W,b = self.params
        dx = np.dot(dout,W.T)
        dW = np.dot(self.x.T,dout)
        db = np.sum(dout,axis=0)
        
        self.grads[0][...] = dW  
        self.grads[1][...] = db
        return dx

解释:

1.Affine类表示神经网络中的仿射层(Affine Layer)。类的初始化方法(__init__):该方法在创建Affine类的实例时被调用。它接受两个参数W和b,分别表示仿射层的权重和偏置。在方法中,首先创建了一个params列表,用于保存权重和偏置参数。然后创建了一个grads列表,用于保存权重和偏置参数的梯度。最后,初始化了一个x变量,并将其设为None。

2.前向传播方法(forward):该方法接受一个输入x,并根据保存的权重和偏置参数进行仿射变换。首先,从params列表中获取权重W和偏置b。然后,通过计算输入x与权重W的乘积,并加上偏置b,得到输出out。最后,将输入x保存在self.x变量中,并返回输出out。

3.反向传播方法(backward):该方法接受一个上游梯度dout,并根据保存的权重和输入x计算梯度。首先,从params列表中获取权重W和偏置b。然后,通过上游梯度dout与权重W的转置的乘积,得到对输入x的梯度dx。接下来,计算权重W的梯度dW,通过将输入x的转置与上游梯度dout的乘积得到。最后,计算偏置b的梯度db,通过对上游梯度dout按列求和得到。

4.更新梯度和返回梯度:在方法的最后,通过将权重和偏置的梯度分别赋值给self.grads列表中对应的元素,来更新梯度信息。使用[...]操作符可以确保在赋值时不改变梯度数组的形状和数据类型。最后返回输入的梯度dx,以便反向传播给前一层。


🌻传播层-Sigmoid类
class Sigmoid:
    def __init__(self):
        self.params = []
        self.grads = []
        self.out = None
    def forward(self,x):
        out = 1 / (1 + np.exp(-x))
        self.out = out
        return out
    def backward(self,dout):
        dx = dout * (1.0 - self.out) * self.out
        return dx

解释:

1.Sigmoid类表示一个Sigmoid函数。类的初始化:在__init__方法中,定义了三个实例变量params、grads和out,分别用于存储参数、梯度和前向传播的输出结果。这些变量在类的实例化时被创建,并初始化为空。

2.前向传播:在forward方法中,接收输入x作为参数。通过应用Sigmoid函数的定义,计算出输出out,即 1 / (1 + np.exp(-x))。然后将计算结果赋值给实例变量self.out,以便在反向传播中使用,并返回输出out。

3.反向传播:在backward方法中,接收反向传播的上游梯度dout作为参数。通过应用Sigmoid函数的导数公式,计算出输入x的梯度dx,即 dout * (1.0 - self.out) * self.out。然后返回计算得到的梯度dx。


🌻损失函数相关类
def softmax(x):
    if x.ndim == 1:
        x = x - np.max(x)
        x = np.exp(x)/np.sum(np.exp(x))
    elif x.ndim == 2:
        x = x - x.max(axis = 1,keepdims = True)
        x = np.exp(x)
        x /= x.sum(axis=1, keepdims=True)
    return x

def cross_entropy_error(y,t):
    if y.ndim == 1:
        t = t.reshape(1,t.size)
        y = y.reshape(1,y.size)
        
    #因为监督标签是one-hot-vector形式,所以这里要取下标    
    if t.size == y.size:
        t = t.argmax(dim=1)
    
    batch_size = y.shape[0]
    #没看懂为啥
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
    
    
class SoftmaxWithLoss:
    def __init__(self):
        self.params = []
        self.grads = []
        self.y = None #softmx的输出
        self.t = None #监督标签
    
    def forward(self,x,t):
        self.t = t
        self.y = softmax(x)
        
        if self.t.size == self.y.size:
            self.t = self.t.argmax(axis=1)
        
        loss = cross_entropy_error(self.y,self.t)
        return loss
    def backward(self,dout =1):
        batch_size = self.t.shape[0]
        dx = self.y.copy()
        dx[np.arange(batch_size),self.t] -= 1
        dx *= dout
        dx = dx/batch_size
        
        return dx

解释:

1. softmax函数实现了Softmax函数的计算,接受一个数组x作为输入,根据输入的维度情况进行不同的计算。

当x的维度是1维时,首先将x减去最大值,然后计算每个元素的指数,并除以所有指数的和,得到Softmax函数的输出。

当x的维度是2维时,首先将x每行减去对应行的最大值,然后计算每个元素的指数,并除以每行指数的和,得到Softmax函数的输出。

最后,返回计算得到的Softmax函数的输出。

2. cross_entropy_error函数:实现交叉熵损失函数的计算。接受两个数组y和t作为输入,根据输入的维度情况进行不同的计算。

首先,根据输入的维度情况将t的形状调整为和y相同的形状,以便进行计算。

如果t的大小和y的大小相同,说明t是以one-hot向量形式表示的监督标签,这里将其转换为对应的类别索引。

接着,根据批量的大小计算交叉熵损失,通过对y使用np.arange(batch_size)和t的索引,取出正确类别的预测概率,并计算其对数,然后求和并取负数,最后除以批量大小得到平均损失。

最后,返回计算得到的交叉熵损失。

3. SoftmaxWithLoss类:这个类实现了Softmax with Loss层,包含了前向传播和反向传播的计算。

__init__方法用于初始化类的实例变量,包括参数列表params、梯度列表grads,以及用于保存Softmax函数的输出y和监督标签t的变量。

forward方法用于执行前向传播计算,接受输入x和监督标签t作为参数。在该方法中,首先将t赋值给实例变量self.t,然后使用softmax函数计算x的Softmax输出y。接着根据t的维度情况将t转换为类别索引形式。最后调用cross_entropy_error函数计算Softmax with Loss的损失并返回。

backward方法用于执行反向传播计算,接受一个可选的上游梯度dout作为参数,默认为1。在该方法中,首先获取监督标签的批量大小,然后创建一个梯度副本dx,并将其初始化为Softmax函数输出y的副本。接下来,根据监督标签的索引,在dx中将正确类别的位置减去1,以计算Softmax with Loss层的梯度。然后,将梯度乘以上游梯度dout,并除以批量大小,以获得平均梯度。最后,返回计算得到的梯度dx。


🌻三层神经网络类-ThreeLayerNet
class ThreeLayerNet:
    def __init__(self,input_size,hidden_size1,hidden_size2,output_size):
        I,H1,H2,O = input_size,hidden_size1,hidden_size2,output_size
    #初始化权重和偏置
        W1 = 0.01 * np.random.randn(I,H1)    #形状:I*H
        b1 = np.zeros(H1)
        W2 = 0.01 * np.random.randn(H1,H2)
        b2 = np.zeros(H2)
        W3 = 0.01 * np.random.randn(H2,O)
        b3 = np.zeros(O)
        #生成层
        self.layers = [
            Affine(W1,b1),
            Sigmoid(),
            Affine(W2,b2),
            Sigmoid(),
            Affine(W3,b3)
        ]
        #Softmax With Loss层和其他层的处理方式不同
        #所以不将它放在layers列表中,而是单独存储在变量loss_layer中
        self.loss_layer = SoftmaxWithLoss()
        self.params,self.grads = [],[]
        for layer in self.layers:
            self.params += layer.params
            self.grads += layer.grads
    def predict(self,x):
        for layer in self.layers:
            x = layer.forward(x)
        return x

    def forward(self,x,t):
        score = self.predict(x)
        loss = self.loss_layer.forward(score,t)
        return loss
    
    def backward(self,dout = 1):
        dout = self.loss_layer.backward(dout)
        for layer in reversed(self.layers):
            dout = layer.backward(dout)
        return dout

解释:

1.这里我实现了一个三层神经网络的类ThreeLayerNet,该类包含了网络的初始化、前向传播、反向传播和预测等方法。在初始化方法__init__中,定义了神经网络的结构和初始化权重和偏置。input_size表示输入层的大小,hidden_size1和hidden_size2表示两个隐藏层的大小,output_size表示输出层的大小。

2.权重的初始化采用了高斯分布随机初始化,通过np.random.randn生成服从标准正态分布的随机数,并乘以0.01进行缩放。偏置初始化为全零向量。

3.下面生成了三个层的实例,并按照顺序存储在self.layers列表中,分别是全连接层(Affine)、激活函数层(Sigmoid)和输出层(Softmax With Loss)。为了方便参数更新,将各层的参数和梯度分别存储在self.params和self.grads列表中。

4.predict方法用于进行前向传播,通过遍历self.layers列表,依次调用每个层的前向传播方法forward,并将输出作为下一层的输入,最终返回最后一层的输出结果。

5.forward方法在进行预测的同时,计算了损失值。首先调用predict方法获取输出结果,然后将输出结果和目标值t传入损失层self.loss_layer的前向传播方法forward,计算得到损失值,并返回。

6.backward方法用于进行反向传播,接收一个梯度dout作为输入,该梯度的默认值为1。首先将梯度传递给损失层self.loss_layer的反向传播方法backward,得到更新后的梯度。然后按照相反的顺序遍历self.layers列表,依次调用每个层的反向传播方法backward,将更新后的梯度传递给前一层,最终返回最初输入层的梯度。


🌻随机梯度下降法的类-SGD
class SGD:
    '''
    随机梯度下降法(Stochastic Gradient Descent)
    '''
    def __init__(self, lr=0.01):
        self.lr = lr
        
    def update(self, params, grads):
        for i in range(len(params)):
            params[i] -= self.lr * grads[i]

解释:

1.这里我实现了随机梯度下降法(Stochastic Gradient Descent,SGD)的类SGD,用于更新神经网络的参数。在初始化方法__init__中,定义了学习率lr,默认值为0.01。学习率控制了每次参数更新的步长。

2.update方法接收两个参数:params是网络中的参数列表,grads是对应参数的梯度列表。该方法根据SGD的更新规则,对每个参数进行更新。

3.在循环中,遍历了参数列表params和梯度列表grads的索引。对于每个参数和对应的梯度,使用梯度乘以学习率的方式更新参数。这里采用了原地更新,即直接在参数列表中更新参数的值。

4.通过减去学习率乘以梯度,实现了参数的更新。


🌻训练过程
#1.设定超参数
max_epoch = 300
batch_size = 30 
hidden_size = 10
learning_rate  =3.5

#2.读入数据,生成模型和优化器
x,t = load_data()
model = ThreeLayerNet(input_size=2,hidden_size1=hidden_size,hidden_size2=hidden_size,output_size=3)
optimizer = SGD(lr=learning_rate)

#学习用的变量
data_size = len(x)
max_iters = data_size // batch_size
total_loss = 0
loss_count = 0
loss_list = []

for epoch in range(max_epoch):
    #3.打乱数据
    idx = np.random.permutation(data_size)
    x = x[idx]
    t = t[idx]
    
    for iters in range(max_iters):
        batch_x = x[iters*batch_size:(iters+1)*batch_size]
        batch_t = t[iters*batch_size:(iters+1)*batch_size]

        #4.计算梯度,更新参数
        loss = model.forward(batch_x,batch_t)
        model.backward()
        optimizer.update(model.params,model.grads)

        total_loss += loss
        loss_count += 1

        #5.定期输出学习过程
        if (iters+1)%10 == 0:
            avg_loss = total_loss / loss_count
            print('| epoch %d | iterations %d / %d | loss %0.2f'% (epoch+1,iters + 1,max_iters,avg_loss))
            loss_list.append(avg_loss)
            total_loss,loss_count = 0,0

解释:

1.这里我实现了一个训练过程的循环,其中包含了数据处理、模型的前向传播、反向传播以及参数更新的步骤。首先,在代码中设定了一些超参数,包括最大迭代次数max_epoch、批大小batch_size、隐藏层大小hidden_size和学习率learning_rate。接下来,通过调用load_data函数读取数据,然后创建了一个ThreeLayerNet类的实例model,指定了输入层大小为2、两个隐藏层大小为hidden_size、输出层大小为3的网络结构。同时,创建了一个SGD类的实例optimizer,传入学习率learning_rate。接着,初始化了一些用于学习过程的变量,包括数据集大小data_size、每个迭代中的最大批次数max_iters、总损失total_loss、损失计数loss_count和损失列表loss_list。

2.下面是主要的训练循环,通过max_epoch控制迭代次数。在每个迭代中,首先进行数据的打乱操作,使用np.random.permutation对数据索引进行随机排列,然后根据打乱后的索引重新排列输入数据x和目标数据t,实现数据的随机化。然后,在每个迭代中,根据最大批次数max_iters遍历数据集。每次迭代从数据集中选取一批数据,包括输入数据batch_x和目标数据batch_t,并进行以下步骤:

调用模型的forward方法,计算当前批次的损失值,并返回该损失值。

调用模型的backward方法,根据损失值进行反向传播,计算参数的梯度。

调用优化器的update方法,根据梯度更新模型的参数。

3.累计当前批次的损失值到total_loss中,并增加loss_count计数器。如果当前批次的迭代次数是10的倍数,输出当前迭代的平均损失值,并将其添加到loss_list列表中。将total_loss和loss_count重置为0,为下一个迭代做准备。

训练循环的目的是通过多次迭代和参数更新,逐渐减小损失值,使模型适应训练数据,实现模型的训练过程。输出的学习过程中的损失值可以用于监控训练的进展。

运行迭代300次的结果图如下:

x, t = load_data()

# 绘制数据点
N = 100
CLS_NUM = 3
markers = ['o', 'x', '^']

# 绘制决策边界
h = 0.001
x_min, x_max = x[:, 0].min() - .1, x[:, 0].max() + .1
y_min, y_max = x[:, 1].min() - .1, x[:, 1].max() + .1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
X = np.c_[xx.ravel(), yy.ravel()]
score = model.predict(X)
predict_cls = np.argmax(score, axis=1)
Z = predict_cls.reshape(xx.shape)
plt.contourf(xx, yy, Z)
for i in range(CLS_NUM):
    plt.scatter(x[i*N:(i+1)*N, 0], x[i*N:(i+1)*N, 1], s=40, marker=markers[i])

plt.axis('off') # 是否关闭坐标轴
plt.show()

解释:

1.这里用于绘制数据点和模型的决策边界。首先,调用load_data函数加载数据,并将输入数据赋值给变量x,目标数据赋值给变量t。接着,定义了一些用于绘制的参数。N表示每个类别的数据点数量,CLS_NUM表示类别的数量,markers是绘制数据点时使用的标记符号。然后,通过指定步长h和输入数据的范围,创建了一个网格xx和yy,用于在整个输入空间上生成一组点。这些点将用于计算模型的预测结果,并绘制决策边界。

2.通过调用模型的predict方法,对生成的点进行预测。X是一个二维数组,每一行表示一个点的坐标。将这些点作为输入,得到模型的预测结果score,其中score是一个二维数组,表示每个点属于不同类别的概率。

3.使用np.argmax函数找到每个点概率最大的类别索引,得到预测的类别标签predict_cls。然后将predict_cls重新调整为与网格一样的形状,得到二维数组Z,用于绘制决策边界。

4.使用plt.contourf函数绘制决策边界,通过填充不同区域的颜色来表示不同的类别。

5.接下来,使用循环遍历每个类别,并使用plt.scatter函数绘制每个类别的数据点。通过切片操作x[i*N:(i+1)*N, 0]和x[i*N:(i+1)*N, 1],选择属于当前类别的数据点的坐标,并使用对应的标记符号进行绘制。

6.最后,通过plt.axis('off')设置是否关闭坐标轴,并调用plt.show()显示绘制的图像。

由此产生的图像可以看到相较于两层神经网络的效果更好,三层神经网络的结果如下所示:


🌻绘制迭代效果图
# loss_list----记录300次迭代次数
import numpy as np
import matplotlib.pyplot as plt
#正确显示中文和负号
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
# 数据准备
x3=range(1,301)
y3=loss_list
# 设置画布大小
plt.figure(figsize=(12, 5))
# plot 画x与y和x与z的关系图
plt.plot(x3,y3,label='损失函数',color='#1F77B4', linewidth=1,marker='',markersize=3)
# 设置x轴标签、坐标轴范围,坐标轴刻度,坐标轴刻度旋转角度
plt.xlabel('iterations(x10)',size=14)
plt.xlim(0,300)
plt.xticks([0,50,100,150,200,250,300],rotation=0,size=12) #
# 设置y轴标签、坐标轴范围,坐标轴刻度,坐标轴刻度旋转角度
plt.ylabel('loss',size=14)
plt.ylim(0,1.2)
plt.yticks([0,0.2,0.4,0.6,0.8,1.0,1.2],rotation=0,size=12)
#标题
plt.title('损失函数',size=18)
# 紧凑布局:自动调整图形、坐标轴、标签之间的距离,对于多个子图时尤其有用。
plt.tight_layout()
# 设置显示图例,要在plt.plot 时设置 label='xxx'才能显示图例
plt.legend()
#加网格线
plt.grid(True)
# 保存图像,可以是任意后缀名,dpi设置图像清晰度
#plt.savefig('./fig1.pdf', dpi=600)  #要放在plt.show()之前,否作保存的图像为空白
# 显示图像
plt.show()

解释:

1.设置中文和负号显示:通过设置plt.rcParams['font.sans-serif']=['SimHei']和plt.rcParams['axes.unicode_minus']=False来确保图表中的中文和负号能够正确显示。

2.数据准备:定义了一个x轴的范围从1到300,以及一个y轴的数据列表loss_list,用于记录300次迭代的损失函数值。

3.设置画布大小:通过plt.figure(figsize=(12, 5))设置绘图画布的大小为宽度12英寸、高度5英寸。

4.绘制曲线:使用plt.plot(x3, y3, label='损失函数', color='#1F77B4', linewidth=1, marker='', markersize=3)绘制曲线,x轴为迭代次数,y轴为损失函数值。label='损失函数'用于在图例中显示曲线的标签,color='#1F77B4'设置曲线的颜色,linewidth=1设置曲线的线宽,marker=''表示不显示数据点的标记,markersize=3设置数据点的大小。

5.设置坐标轴和刻度:使用plt.xlabel('iterations(x10)', size=14)设置x轴的标签为'iterations(x10)',plt.xlim(0, 300)设置x轴的范围为0到300,plt.xticks([0,50,100,150,200,250,300],rotation=0,size=12)设置x轴的刻度为[0, 50, 100, 150, 200, 250, 300],rotation=0表示刻度标签不旋转,size=12表示刻度标签的字体大小。

6.设置y轴的标签和刻度同理。设置标题:使用plt.title('损失函数', size=18)设置图表的标题为'损失函数',size=18表示标题的字体大小。

7.调整布局:使用plt.tight_layout()自动调整图形、坐标轴、标签之间的距离,使其紧凑显示。

8.显示图例:使用plt.legend()显示图例,前提是在绘制曲线时设置了label='损失函数'。添加网格线:使用plt.grid(True)添加网格线。

实验结果如下:


🌞四、实验心得

通过这次实验,我成功创建了一个用于识别螺旋状的数据集三层神经网络,并对深度学习所需的数学知识有了更深入的理解。

一开始,我选择了ReLU激活函数,但是在调整学习率时无法找到合适的参数。因此改用Sigmoid作为激活函数。通过建立三层神经网络,我发现之前适用于两层神经网络的学习率并不适用于三层神经网络,需要重新寻找适合的学习率,而学习率设置得太小会导致学习的收敛速度变慢。

通过对比两层和三层神经网络的训练结果,我发现它们之间存在明显的差异,特别是在中心点区域。这说明增加网络的层数可以更好地拟合复杂的数据集,但也需要仔细调整参数以确保网络的有效训练。

两层神经网络结果:

三层神经网络结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/506389.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[数据结构初阶]堆的应用

各位读者老爷好,鼠鼠又来了捏!鼠鼠上一篇博客介绍的堆,那么今天来浅谈以下堆的应用,那么好,我们先来看两个问题: 1.如果有一组乱序的数组数据,希望你将这组数组的数据排成升序或降序&#xff0c…

【Spring MVC】快速学习使用Spring MVC的注解及三层架构

💓 博客主页:从零开始的-CodeNinja之路 ⏩ 收录文章:【Spring MVC】快速学习使用Spring MVC的注解及三层架构 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 Spring Web MVC一: 什么是Spring Web MVC&#xff1…

大促销活动时期如何做好DDoS防护?

每一次活动大促带来的迅猛流量,对技术人而言都是一次严峻考验。如果在活动期间遭受黑产恶意DDoS攻击,无疑是雪上加霜。电商的特性是业务常态下通常不会遭受大流量DDoS攻击,且对延迟敏感,因此只需要在活动期间按需使用DDoS防护。本…

分享three.js实现乐高小汽车

前言 Web脚本语言JavaScript入门容易,但是想要熟练掌握却需要几年的学习与实践,还要在弱类型开发语言中习惯于使用模块来构建你的代码,就像小时候玩的乐高积木一样。 应用程序的模块化理念,通过将实现隐藏在一个简单的接口后面&a…

代码随想录第二十四天| 回溯算法P1 | ● 理论基础 ● 77.

● 理论基础 题目分类 什么是回溯法 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。 在二叉树系列中,不止一次提到了回溯,如二叉树:以为使用了递归,其实还隐藏着回溯 (opens new window)。 回溯是递归的副产品&…

通过pymysql读取数据库中表格并保存到excel(实用篇)

本篇文章是通过pymysql将本地数据库中的指定表格保存到excel的操作。 这里我们假设本地已经安装了对应的数据库管理工具,里面有一个指定的表格,现在通过python程序,通过调用pymysql进行读取并保存到excel中。 关于数据库管理工具是Navicat P…

使用Python简单筛选excel表数据并写入到新表

文章目录 0 背景1 技术2 实现代码 0 背景 因为需要检索excel中的一些信息,把检索后的结果,写入到新表中。 符合筛选后的结果: 写入到的新表格数据: 1 技术 使用pandas库,读取excel表格的数据。然后对表格中的数据…

初始Java篇(JavaSE基础语法)(5)(类和对象(下))

个人主页(找往期文章包括但不限于本期文章中不懂的知识点):我要学编程(ಥ_ಥ)-CSDN博客 目录 封装 访问限定符 封装扩展之包 自定义包 static成员 static修饰成员变量 static修饰成员方法 static成员变量初始化 内部类 对象的打…

leetcode131分割回文串

递归树 下面这个代码是遍历处所有的子串 #include <bits/stdc.h> using namespace std; class Solution { public:vector<vector<string>> vvs;vector<string> vs;vector<vector<string>> partition(string s) {dfs(0,s);return vvs;}vo…

使用Thymeleaf配置国际化页面

在国际化&#xff08;i18n&#xff0c;即 Internationalization 的缩写&#xff0c;其中“i”和“n”之间有18个字母&#xff09;的上下文中&#xff0c;Thymeleaf 和 Spring Boot 可以很容易地一起工作&#xff0c;以支持多种语言的页面显示。下面是如何在 Spring Boot 应用中…

Unix中的进程和线程-1

目录 1.如何创建一个进程 2.如何终止进程 2.2遗言函数 3.进程资源的回收 4.孤儿进程和僵尸进程 孤儿进程 (Orphan Process)&#xff1a; 僵尸进程 (Zombie Process)&#xff1a; 代码示例&#xff1a; 5. 进程映像的更新 在Linux中&#xff0c;进程和线程是操作系统进行工作调…

文件名目录名或卷标语法不正确:数据恢复策略与预防措施

一、文件名目录名或卷标语法不正确的现象 在日常使用电脑或移动设备时&#xff0c;我们经常会遇到“文件名目录名或卷标语法不正确”的错误提示。这种错误通常发生在尝试访问、修改或删除文件、目录或卷标时&#xff0c;系统会提示无法完成操作&#xff0c;因为文件名、目录名…

星云曲库测试报告

文章目录 一、项目介绍1.1项目背景1.2功能介绍 二、测试环境三、测试执行过程3.1功能测试3.1.1登录页面测试3.1.2歌曲列表页面测试3.1.3“我喜欢”页面测试3.1.4上传页面测试 3.2界面自动化测试3.2.1登录页面测试3.2.2歌曲列表页面测试3.2.3“我喜欢”页面测试3.2.4上传页面测试…

Unity TrailRenderer的基本了解

在Unity中&#xff0c;TrailRenderer组件用于在对象移动时创建轨迹效果。通常用于增强游戏中的动态物体&#xff0c;比如子弹、飞行道具或者角色移动时的拖尾效果。 下面来了解下它的基本信息。 1、创建 法1&#xff1a;通过代码创建 using UnityEngine;public class Trail…

css3之3D转换transform

css3之3D转换 一.特点二.坐标系三.3D移动&#xff08;translate3d)1.概念2.透视&#xff08;perpective)(近大远小&#xff09;&#xff08;写在父盒子上&#xff09; 四.3D旋转&#xff08;rotate3d)1.概念2.左手准则3.呈现&#xff08;transfrom-style)&#xff08;写父级盒子…

精品PPT-2023年无人驾驶汽车车联网网络安全方案

以下是部分PPT内容&#xff0c;请您参阅。如需下载完整PPTX文件&#xff0c;请前往星球获取&#xff1a; 无人驾驶安全架构是一个复杂的系统&#xff0c;它涉及到多个关键组件和层次&#xff0c;以确保无人驾驶车辆在各种情况下都能安全、可靠地运行。以下是一些主要的无人驾驶…

并查集

本文用于个人算法竞赛学习&#xff0c;仅供参考 目录 一.什么是并查集 二.并查集实现 三.路径优化 四.时间复杂度 五.并查集路径压缩 模板 五.题目 一.什么是并查集 并查集&#xff08;Disjoint Set&#xff09;是一种数据结构&#xff0c;用于处理一系列不相交的集合的合…

javaIO

file类 一个File类的对象可以表示一个具体的文件或目录 mkdir 创建单级文件夹 mkdirs 创建多级文件夹 delete 删除一个文件夹时&#xff0c;文件夹里面必须是空的 listfiles 将文件夹的子集放到一个file类型的数组中 输入及输出的概念 输入input 输出output 把jav…

pyinstaller打包多线程pyqt5程序后,报错,反复弹窗等问题

报错1&#xff1a; Traceback (most recent call last): File “MPL.py”, line 502, in File “Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_multiprocessing.py”, line 45, in _freeze_support ValueError: not enough values to unpack (expected 2, got 1) 报…

STM32学习笔记(10_3)- 软件I2C读写MPU6050

无人问津也好&#xff0c;技不如人也罢&#xff0c;都应静下心来&#xff0c;去做该做的事。 最近在学STM32&#xff0c;所以也开贴记录一下主要内容&#xff0c;省的过目即忘。视频教程为江科大&#xff08;改名江协科技&#xff09;&#xff0c;网站jiangxiekeji.com 本期开…