用 Python 从零开始创建神经网络(三):添加层级(Adding Layers)

news2024/11/26 10:44:44

添加层级(Adding Layers)

  • 引言
  • 1. Training Data
  • 2. Dense Layer Class

引言

我们构建的神经网络变得越来越受人尊敬,但目前我们只有一层。当神经网络具有两层或更多隐藏层时,它们变成了“深度”网络。目前我们只有一层,实际上是一个输出层。为什么我们想要两层或更多隐藏层的原因将在后面的章节中变得明显。目前,我们没有隐藏层。隐藏层不是输入层或输出层;作为科学家,你看到的数据是输入到输入层的数据以及来自输出层的结果数据。这些端点之间的层具有我们不一定处理的值,因此得名“隐藏”。不过,别让这个名字让你认为你不能访问这些值。你通常会使用它们来诊断问题或改进你的神经网络。为了探索这个概念,让我们给这个神经网络增加另一层,并且,现在,让我们假设我们将要拥有的这两层是隐藏层,我们还没有编写我们的输出层。

在我们添加另一层之前,让我们思考一下即将到来的内容。对于第一层,我们可以看到我们有一个包含4个特征的输入:


在这里插入图片描述

将包含 4 个特征的输入层转化为包含 3 个神经元的隐藏层。


样本(特征集数据)通过输入传递,输入本身不会以任何方式改变它,传递到我们的第一个隐藏层,我们可以看到这一层有3组权重,每组包含4个值。

这3组独特的权重集与它们各自的神经元相关联。因此,由于我们有3组权重,这第一个隐藏层就有3个神经元。每个神经元都有一组独特的权重,我们有4个(因为这一层有4个输入),这就是为什么我们的初始权重有一个形状为 ( 3 , 4 ) (3,4) (3,4) 的原因。

现在,我们希望增加另一层。为此,我们必须确保该层的预期输入与前一层的输出匹配。我们通过设置每层有多少组权重和偏差来设定层中的神经元数量。前一层对当前层的权重集的影响是每个权重集需要有每个输入的单独权重。这意味着前一层的每个神经元(或如果我们谈论输入的话,每个特征)都有一个独特的权重。前一层有3组权重和3个偏差,所以我们知道它有3个神经元。这意味着,对于下一层,我们可以有尽可能多的权重集(因为这是这个新层将拥有的神经元数量),但这些权重集中的每一个都必须有3个独立的权重。

为了创建这个新层,我们将复制并粘贴我们的权重和偏差到 weights2 和 biases2,并将它们的值改为新的假设集。这里有一个例子:

import numpy as np

inputs = [[1, 2, 3, 2.5],
          [2., 5., -1., 2],
          [-1.5, 2.7, 3.3, -0.8]]

weights = [[0.2, 0.8, -0.5, 1],
           [0.5, -0.91, 0.26, -0.5],
           [-0.26, -0.27, 0.17, 0.87]]
biases = [2, 3, 0.5]

weights2 = [[0.1, -0.14, 0.5],
            [-0.5, 0.12, -0.33],
            [-0.44, 0.73, -0.13]]
biases2 = [-1, 2, -0.5]

接下来,我们将调用输出 layer1_ouputs

layer1_outputs = np.dot(inputs, np.array(weights).T) + biases
print("layer1_outputs:", layer1_outputs)
>>>
layer1_outputs: [[ 4.8    1.21   2.385]
				 [ 8.9   -1.81   0.2  ]
				 [ 1.41   1.051  0.026]]

正如之前所述,层的输入要么是来自您正在训练的实际数据集的输入,要么是来自前一层的输出。这就是为什么我们定义了两个版本的权重和偏差,但只有一个输入的原因 —— 因为第二层的输入将是前一层的输出:

layer2_outputs = np.dot(layer1_outputs, np.array(weights2).T) + biases2
print("layer2_outputs:", layer2_outputs)
>>>
layer2_outputs: [[ 0.5031  -1.04185 -2.03875]
				 [ 0.2434  -2.7332  -5.7633 ]
				 [-0.99314  1.41254 -0.35655]]

完整:

import numpy as np

inputs = [[1, 2, 3, 2.5],
          [2., 5., -1., 2],
          [-1.5, 2.7, 3.3, -0.8]]

weights = [[0.2, 0.8, -0.5, 1],
           [0.5, -0.91, 0.26, -0.5],
           [-0.26, -0.27, 0.17, 0.87]]
biases = [2, 3, 0.5]

weights2 = [[0.1, -0.14, 0.5],
            [-0.5, 0.12, -0.33],
            [-0.44, 0.73, -0.13]]
biases2 = [-1, 2, -0.5]

layer1_outputs = np.dot(inputs, np.array(weights).T) + biases
print("layer1_outputs:", layer1_outputs)

layer2_outputs = np.dot(layer1_outputs, np.array(weights2).T) + biases2
print("layer2_outputs:", layer2_outputs)

此时,我们的神经网络可以直观地表示为:
在这里插入图片描述


1. Training Data

训练数据


接下来,我们将使用一个可以创建非线性数据的函数,而不是手工输入随机数据。什么叫非线性数据?线性数据可以用直线拟合或表示。


在这里插入图片描述

可用直线(绿线)表示(拟合)的数据(橙色点)示例


非线性数据无法用直线很好地表示:


在这里插入图片描述

直线拟合不理想的数据(橙色点)示例。


如果你要绘制形式为 ( x , y ) (x, y) (x,y) 的数据点,其中 y = f ( x ) y = f(x) y=f(x),并且看起来像是一条具有明显趋势或斜率的线,那么很可能,这些是线性数据!线性数据可以非常容易地被比神经网络简单得多的机器学习模型近似。其他机器学习算法不容易近似的是非线性数据集。为了简化这一点,我们创建了一个可以通过 pip 安装的Python包,名为 nnfs:

pip3 install nnfs

nnfs 软件包包含一些函数,我们可以用它们来创建数据。例如:

from nnfs.datasets import spiral_data

螺旋数据(spiral_data)函数是从 https://cs231n.github.io/neural-networks-case-study/ 上稍加修改的,它是本主题的一个很好的补充资源。


通常你不会为你的神经网络从函数生成训练数据。你会有一个实际的数据集。这种方式生成数据集纯粹是为了目前阶段的便利性。我们还将使用这个包来确保每个人的重复性,使用 nnfs.init(),在导入NumPy之后:

import numpy as np
import nnfs

nnfs.init()

nnfs.init()执行三件事:它将随机种子设置为0(默认情况下),创建一个 float32 数据类型的默认值,并覆盖NumPy的原始点积函数。所有这些都是为了确保后续操作的可重复结果。

spiral_data函数允许我们创建一个数据集,可以有我们想要的任意多的类别。该函数有参数可以选择类别数和每个类别中点/观测的数量,来生成结果中的非线性数据集。例如:

import numpy as np
import nnfs
from nnfs.datasets import spiral_data
import matplotlib.pyplot as plt

nnfs.init()

X, y = spiral_data(samples=100, classes=3)

plt.scatter(X[:,0], X[:,1])
plt.show()

在这里插入图片描述

未着色的螺旋数据集


如果从中心开始追踪,就可以分别确定所有 3 个类别,但对于机器学习分类器来说,这是一个非常具有挑战性的问题。在图表中添加颜色可以让这一点更加清晰:

import numpy as np
import nnfs
from nnfs.datasets import spiral_data
import matplotlib.pyplot as plt

nnfs.init()

X, y = spiral_data(samples=100, classes=3)

plt.scatter(X[:,0], X[:,1])
plt.show()

plt.scatter(X[:, 0], X[:, 1], c=y, cmap='brg')
plt.show()

在这里插入图片描述

在这里插入图片描述

按类别着色的螺旋数据集


请记住,神经网络不会意识到颜色的差异,因为数据没有类别编码。这只是作为对读者的一种指导。在上述数据中,每个点都是特征,其坐标是构成数据集的样本。该点的 “分类 ”与它属于哪种螺旋有关,如上图中的蓝色、绿色或红色。然后,这些颜色将被分配一个类别编号,供模型拟合,如 0,1和2。


2. Dense Layer Class

密集层级


既然我们不再需要手工输入数据,我们就应该为各种类型的神经网络层创建类似的功能。到目前为止,我们只使用了所谓的密集层或全连接层。这些层在论文、文献和代码中通常被称为 “密集 ”层,但你偶尔也会在代码中看到它们被称为全连接层,简称 “FC”。我们的密集层类将以两个方法开始:

class Layer_Dense:
    # Layer initialization
    def __init__(self, n_inputs, n_neurons):
        # Initialize weights and biases
        pass # using pass statement as a placeholder
        
    # Forward pass
    def forward(self, inputs):
        # Calculate output values from inputs, weights and biases
        pass # using pass statement as a placeholder

如前所述,模型的权重通常是随机初始化的,但不总是这样。如果你希望加载一个预训练的模型,你将把参数初始化为预训练模型完成时的状态。也有可能即使是对于一个新模型,你也有一些除了随机之外的其他初始化规则。现在,我们将坚持使用随机初始化。接下来,我们有前向方法。当我们从头到尾通过模型传递数据时,这被称为前向传递。然而,就像其他一切一样,这并不是唯一的做事方式。你可以让数据回环并做其他有趣的事情。我们将保持通常的做法,执行一个常规的前向传递。

为了继续 Layer_Dense 类的代码,让我们添加权重和偏置的随机初始化:

import numpy as np

class Layer_Dense:
    # Layer initialization
    def __init__(self, n_inputs, n_neurons):
        # Initialize weights and biases
        self.weights = 0.01 * np.random.randn(n_inputs, n_neurons)
        self.biases = np.zeros((1, n_neurons))
        
    # Forward pass
    def forward(self, inputs):
        # Calculate output values from inputs, weights and biases
        pass # using pass statement as a placeholder

在这里,我们将权重设置为随机,偏置设置为0。请注意,我们将权重初始化为(输入,神经元),而不是(神经元,输入)。我们提前这样做,而不是每次执行前向传递时都转置,如上一章所解释的。为什么偏置为零?在特定情况下,例如当许多样本包含0值时,偏置可以确保神经元最初被激活。有时将偏置初始化为某个非零数可能是合适的,但偏置最常见的初始化是0。然而,在这些情况下,你可能会发现以另一种方式做事会成功。这将根据你的用例而有所不同,并且只是你在尝试改进结果时可以调整的许多事情之一。一个你可能想尝试其他方法的情况是所谓的死神经元。我们还没有在实践中讨论激活函数,但想象一下我们之前提到的阶跃函数:

在这里插入图片描述

权重 · 输入 + 偏置没有达到阶跃函数的阈值时,可能会导致神经元输出0。单独来看,这不是一个大问题,但如果每一个输入样本都导致这个神经元发生这种情况,就会成为一个问题(一旦我们讲解反向传播,这将变得清晰)。因此,这个神经元的0输出就成为另一个神经元的输入。任何与零相乘的权重都将是零。随着输出0的神经元数量增加,更多的输入将传递给下一个神经元这些0,使得网络基本上无法训练,或者“死亡”。


接下来,让我们更详细地探讨 np.random.randnnp.zeros 这些方法。这些方法是初始化数组的便捷方式。np.random.randn 产生一个均值为0和方差为1的高斯分布,这意味着它将生成以0为中心的随机数,正负都有,平均值接近0。一般来说,神经网络在 -1 到 +1 之间的值下工作最好,我们将在即将到来的章节中讨论这一点。因此,np.random.randn 生成围绕这些数字的值。我们将乘以 0.01 的高斯分布用于权重,以生成比较小的数值。否则,模型在训练过程中将需要更多时间来适应数据,因为开始的值与训练过程中进行的更新相比过大。这里的想法是用足够小的非零值开始一个模型,这些值不会影响训练。这样,我们就有一堆值可以开始使用,但希望没有太大或为零的值。如果你愿意,可以尝试除0.01之外的其他值。最后,np.random.randn 函数接受维度大小作为参数,并创建具有此形状的输出数组。

这里的权重将是第一维度的输入数量和第二维度的神经元数量。这类似于我们之前虚构的权重数组,只是随机生成的。每当有一个你不确定的函数或代码块时,你总是可以打印它出来。例如:

import numpy as np
import nnfs

nnfs.init()

random_test = np.random.randn(2,5)
zero_array = np.zeros((2,5))

print("random_test:", random_test)
print("zero_array:", zero_array)
>>>
random_test: [[ 1.7640524   0.4001572   0.978738    2.2408931   1.867558  ]
			  [-0.9772779   0.95008844 -0.1513572  -0.10321885  0.41059852]]
zero_array: [[0. 0. 0. 0. 0.]
 			 [0. 0. 0. 0. 0.]]

np.random.randn(2,5)函数调用返回了一个2x5的数组(我们也可以说它的“形状是 ( 2 , 5 ) (2,5) (2,5)”),数据是从均值为0的高斯分布中随机抽样得到的。

在调用 np.random.randn(2, 5) 时:参数 2 和 5 指定了生成数组的形状。 2 表示数组有行。 5 表示数组有列。

接下来,np.zeros 函数接受一个期望的数组形状作为参数,并返回一个填充了零的该形状数组。


我们将以行向量的形式初始化偏置,其形状为 ( 1 , n _ n e u r o n s ) (1, n\_{neurons}) (1,n_neurons),这将使我们能够在以后轻松地将其加到点积的结果上,无需进行转置等额外操作。

看一个我们方法初始化权重和偏置的例子:

import numpy as np
import nnfs

nnfs.init()

n_inputs = 2
n_neurons = 4

weights = 0.01 * np.random.randn(n_inputs, n_neurons)
biases = np.zeros((1, n_neurons))

print("weights:", weights)
print("biases:", biases)
>>>
weights: [[ 0.01764052  0.00400157  0.00978738  0.02240893]
		  [ 0.01867558 -0.00977278  0.00950088 -0.00151357]]
biases: [[0. 0. 0. 0.]]

接下来是我们的正演方法——我们需要用点积+偏差计算来更新它:

import numpy as np

class Layer_Dense:
    # Layer initialization
    def __init__(self, n_inputs, n_neurons):
        # Initialize weights and biases
        self.weights = 0.01 * np.random.randn(n_inputs, n_neurons)
        self.biases = np.zeros((1, n_neurons))
        
    # Forward pass
    def forward(self, inputs):
        # Calculate output values from inputs, weights and biases
        self.output = np.dot(inputs, self.weights) + self.biases

我们已经准备好使用这个新类来代替硬编码计算,因此让我们使用讨论过的数据集创建方法生成一些数据,然后使用我们的新层来执行前向传递:

import numpy as np
import nnfs
from nnfs.datasets import spiral_data

nnfs.init()

class Layer_Dense:
    # Layer initialization
    def __init__(self, n_inputs, n_neurons):
        # Initialize weights and biases
        self.weights = 0.01 * np.random.randn(n_inputs, n_neurons)
        self.biases = np.zeros((1, n_neurons))
        
    # Forward pass
    def forward(self, inputs):
        # Calculate output values from inputs, weights and biases
        self.output = np.dot(inputs, self.weights) + self.biases


# Create dataset
X, y = spiral_data(samples=100, classes=3)

# Create Dense layer with 2 input features and 3 output values
dense1 = Layer_Dense(2, 3)

# Perform a forward pass of our training data through this layer
dense1.forward(X)

# Let's see output of the first few samples:
print(dense1.output[:5])
>>>
[[ 0.0000000e+00  0.0000000e+00  0.0000000e+00]
 [-1.0475188e-04  1.1395361e-04 -4.7983500e-05]
 [-2.7414842e-04  3.1729150e-04 -8.6921798e-05]
 [-4.2188365e-04  5.2666257e-04 -5.5912682e-05]
 [-5.7707680e-04  7.1401405e-04 -8.9430439e-05]]

在输出结果中,你可以看到我们有 5 行数据,每行有 3 个值。这 3 个值中的每一个都是dense1层中 3 个神经元输入每个样本后的值。好极了!我们有了一个神经元网络,所以我们的神经网络模型几乎名副其实了,但我们还缺少激活函数,所以接下来让我们完成激活函数!

代码的可视化:https://nnfs.io/ch3

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推荐一款功能强大的视频修复软件:Apeaksoft Video Fixer

Apeaksoft Video Fixer是一款功能强大的视频修复软件,专门用于修复损坏、不可播放、卡顿、画面失真、黑屏等视频问题。只需提供一个准确且有效的样本视频作为参考,该软件就能将受损视频修复到与样本视频相同的质量。该软件目前支持MP4、MOV、3GP等格式的…

Web前端开发--HTML语言

文章目录 前言1.介绍2.组成3.基本框架4.常见标签4.1双标签4.1.1.标题标签4.2.2段落标签4.1.3文本格式化标签4.1.4超链接标签4.1.5视频标签4.1.6 音频标签 4.2单标签4.2.1换行标签和水平线标签4.2.2 图像标签 5.表单控件结语 前言 生活中处处都有网站,无论你是学习爬…

[ DOS 命令基础 2 ] DOS 命令详解-网络相关命令

🍬 博主介绍 👨‍🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…

gitlab无法创建合并请求是所有分支都不显示

点击Merge Requests ------> New merge request 创建新的合并请求时,在Source branch和Target branch中一个分支都不显示 排查思路: 1.怀疑是权限问题。 发现只有我的一个账号出现,检查了账号的权限,尝试了master、develop角色…

【温度表达转化】

【温度表达转化】 C语言代码C代码Java代码Python代码 💐The Begin💐点点关注,收藏不迷路💐 利用公式 C5∗(F−32)/9 (其中C表示摄氏温度,F表示华氏温度) 进行计算转化。 输出 输出一行&#x…

「QT」几何数据类 之 QPoint 整型点类

✨博客主页何曾参静谧的博客📌文章专栏「QT」QT5程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

[Linux]:高级IO

1. IO 理解 1.1 IO 的基本概念 I/O即输入/输出(input/output),是计算机系统中极为关键的操作环节。 在经典的冯诺依曼体系结构框架下,其核心在于数据的传输流向界定了输入与输出的概念。具体而言,当把数据从诸如键盘…

【GeoJSON在线编辑平台】(2)吸附+删除+挖孔+扩展

前言 在上一篇的基础上继续开发,补充上吸附功能、删除矢量、挖孔功能。 实现 1. 吸附 参考官方案例:Snap Interaction 2. 删除 通过 removeFeature 直接移除选中的要素。 3. 挖孔 首先是引入 Turf.js ,然后通过 mask 方法来实现挖孔的…

【ReactPress】React + antd + NestJS + NextJS + MySQL 的简洁兼时尚的博客网站

ReactPress 是使用React开发的开源发布平台,用户可以在支持React和MySQL数据库的服务器上架设属于自己的博客、网站。也可以把 ReactPress 当作一个内容管理系统(CMS)来使用。 前言 此项目是用于构建博客网站的,包含前台展示、管理…

ZISUOJ 2024算法基础公选课练习一(1)

前言、 又是一年算法公选课&#xff0c;与去年不同的是今年学了一些纯C&#xff08;而不是带类的C&#xff09; 一、我的C模板 1.1 模板1 #include <bits/stdc.h> using i64 long long;int main() {std::cin.tie(nullptr)->sync_with_stdio(false);return 0; } 1…

【1】虚拟机安装

1.安装VMware WorkStation Pro VMware下载地址&#xff1a; 密钥&#xff1a;YF390-0HF8P-M81RQ-2DXQE-M2UT6 2.新建虚拟机 centos7下载地址&#xff1a;centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云

【SpringBoot】SpringBoot自带的Jackson入门使用

导入依赖 springboot自带的&#xff0c;挨个点进去&#xff0c;就能找到 自定义对象转换器 import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModu…

软件工程概论项目(一),git环境的配置和平台代码的拉取

距离软工概论项目答辩还有五个周的时间&#xff0c;需要做一个项目&#xff0c;把心得体会都做一个记录。以便以后进行回顾和反思 这里写目录标题 一、环境的配置gitbash 一、环境的配置 gitbash 安装gitbash&#xff0c;简单说两句&#xff0c;git用于多人协作和代码托管&am…

分布式数据库中间件mycat

MyCat MyCat是一个开源的分布式数据库系统&#xff0c;它实现了MySQL协议&#xff0c;可以作为数据库代理使用。 MyCat(中间件)的核心功能是分库分表&#xff0c;即将一个大表水平分割为多个小表&#xff0c;存储在后端的MySQL服务器或其他数据库中。 它不仅支持MySQL&#xff…

万字长文解读深度学习——循环神经网络RNN、LSTM、GRU、Bi-RNN

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

一文了解什么是腾讯云开发

关于云开发的猜想 说到云开发&#xff0c;作为开发者的大家是否大概就有了想法。比如说过去的开发工作都是在自己本地电脑的开发工具&#xff0c;比如IDEA开发工具进行开发的&#xff0c;开发完成后再部署到服务器测试以及上线。那么腾讯云开发&#xff0c;是不是就是不用本地…

双指针算法的妙用:提高代码效率的秘密(2)

双指针算法的妙用&#xff1a;提高代码效率的秘密&#xff08;2&#xff09; 前言&#xff1a; 小编在前几日讲述了有关双指针算法两道题目的讲解&#xff0c;今天小编继续进行有关双指针算法习题的讲解&#xff0c;老规矩&#xff0c;今天还是两道题目的讲解&#xff0c;希望…

【Python】从入门开始抓取你想要的电影,一周可掌握基础,附完整源码

Python学习很简单&#xff0c;只是你走进了误区。 为什么你一定要先掌握枯燥的基础点后&#xff0c;再去做实际操作呢&#xff1f; 其实&#xff0c;你根本坚持不了那么长时间&#xff0c;但实际上你可以直接去做python项目。 不信&#xff1f;看看我做这个项目的思路&#x…

逐梦代码深林:Linux编译之舞,链接之诗——自举、动静态库的浪漫旅程

文章目录 问题引入&#xff0c;为什么要进行编译->汇编?一、详细解释编译器自举1. 从最初的二进制编程到汇编2. 第一代汇编编译器的诞生3. 编译器自举的出现&#xff1a;从汇编到更高级的编译器4. 自举的延续&#xff1a;从汇编到高级编程语言5. 为什么要进行编译器自举&am…

AI 写作(六):核心技术与多元应用(6/10)

一、AI 写作的核心技术概述 AI 写作在当今数字化时代正发挥着越来越重要的作用。它不仅极大地提高了写作效率&#xff0c;还为不同领域带来了创新的可能性。 AI 写作的核心技术主要包括基于模板的文本生成和基于深度学习的文本生成。基于模板的文本生成通常依赖预先设定的模板…