【一起学NLP】Chapter1-基本语法与神经网络的推理

news2024/11/10 16:35:53

备注:本专栏为个人的NLP学习笔记,欢迎大家共同讨论交流学习。代码同步:https://github.com/codesknight/Learning-NLP-Together 参考书籍:《深度学习进阶:自然语言处理》——斋藤康毅

目录

  • 基础知识点复习
      • 测试环境
      • 使用Python的对话模式来生成向量和矩阵
      • 矩阵对应元素的运算
      • 矩阵对应元素相加
      • 广播(对形状不同的矩阵进行扩展运算)
      • 向量内积
      • 矩阵相乘
      • Tip:*与dot的区别
  • 推理一个神经网络
      • 对N笔样本数据进行mini-batch整体处理
      • Tip:广播
      • Tip:矩阵形状
      • 使用Sigmoid激活函数
      • 层的类化及正向传播
      • Tip:正向传播&反向传播
      • 编写网络的代码规范
      • 层视角下的神经网络
      • TwoLayerNet的代码如下所示
      • Tip:params列表可以+=的原因
      • 备注:TwoLayerNet类
      • 备注:predict函数

基础知识点复习

测试环境

# 测试连接
print('hello NLP!')
hello NLP!

使用Python的对话模式来生成向量和矩阵

# 使用Python的对话模式来生成向量和矩阵
import numpy as np
x = np.array([1,2,3])
print(x)
[1 2 3]
print(x.__class__)
<class 'numpy.ndarray'>
x.ndim
1
x.shape
(3,)
w = np.array([[1,2,3],[4,5,6]])
print(w)
[[1 2 3]
 [4 5 6]]
w.ndim
2
w.shape
(2, 3)

矩阵对应元素的运算

# 矩阵对应元素的运算
W = np.array([
    [1,2,3],
    [4,5,6]
])
X = np.array([
    [0,1,2],
    [3,4,5]
])

矩阵对应元素相加

# 矩阵对应元素相加
W+X
array([[ 1,  3,  5],
       [ 7,  9, 11]])

广播(对形状不同的矩阵进行扩展运算)

# 广播(对形状不同的矩阵进行扩展运算)
A = np.array([
    [1,2],
    [3,4]
])

A*10
array([[10, 20],
       [30, 40]])

在这里插入图片描述

A = np.array([
    [1,2],
    [3,4]
])
b = np.array([10,20])

A*b
array([[10, 40],
       [30, 80]])

在这里插入图片描述

向量内积

# 向量内积
a = np.array([1,2,3])
b = np.array([4,5,6])
# 对应元素相乘再求和
np.dot(a,b)
32

矩阵相乘

A = np.array([
    [1,2],
    [3,4]
])
B = np.array([
    [5,6],
    [7,8]
])

np.dot(A,B)
array([[19, 22],
       [43, 50]])

Tip:*与dot的区别

*乘是广播的形式,对应相乘。

dot()函数是乘法函数,是基本的数学定理。

推理一个神经网络

假设一个神经网络如下:

Input Layout Number Of Neurons:2

Hidden Layout Number Of Neurons:4

Output Layout Number Of Neurons:3
在这里插入图片描述

图1-7中的隐藏层的第1个神经元就可以如下进行计算:
在这里插入图片描述

实际上,基于全连接层的变换可以通过矩阵乘积如下进行整理:
在这里插入图片描述

这里,隐藏层的神经元被整理为(h1, h2, h3, h4)​,它可以看作1×4的矩阵(或者行向量)​。另外,输入是(x1, x2)​,这是一个1×2的矩阵。再者,权重是2×4的矩阵,偏置是1×4的矩阵。这样一来,式(1.3)可以如下进行简化:

在这里插入图片描述

这里,输入是x,隐藏层的神经元是h,权重是W,偏置是b,这些都是矩阵。此时,留意式(1.4)的矩阵形状,可知进行了如图1-8所示的变换。
在这里插入图片描述

对N笔样本数据进行mini-batch整体处理

这样一来,我们就可以利用矩阵来整体计算全连接层的变换。不过,这里进行的变换只针对单笔样本数据(输入数据)​。在神经网络领域,我们会同时对多笔样本数据(称为mini-batch,小批量)进行推理和学习。因此,我们将单独的样本数据保存在矩阵x的各行中。假设要将N笔样本数据作为mini-batch整体处理,关注矩阵的形状,其变换如图1-9所示。
在这里插入图片描述

如图1-9所示,根据形状检查,可知各mini-batch被正确地进行了变换。此时,N笔样本数据整体由全连接层进行变换,隐藏层的N个神经元被整体计算出来。现在,我们用Python写出mini-batch版的全连接层变换。

import numpy as np
W1 = np.random.randn(2,4)#权重
b1 = np.random.randn(4)#偏置
x = np.random.randn(10,2)#输入
# 漂亮的输出
def print_array(name, array):
    print(f"{name}:\n{np.array2string(array, formatter={'float_kind':lambda x: f'{x:.2f}'}).replace('[', ' [ ').replace(']', ' ] ')}\n")

# 漂亮打印
print_array("W1", W1)
print_array("b1", b1)
print_array("x", x)
# print(W1)
# print(b1)
# print(x)
W1:
 [  [ 0.59 -0.03 -0.66 0.34 ] 
  [ 1.26 0.20 0.40 0.39 ]  ] 

b1:
 [ -0.13 0.29 0.71 -0.59 ] 

x:
 [  [ 0.68 -0.30 ] 
  [ 0.61 1.59 ] 
  [ -1.32 -0.22 ] 
  [ -0.28 -1.46 ] 
  [ -0.45 -0.54 ] 
  [ -0.23 0.74 ] 
  [ -0.63 0.06 ] 
  [ -0.69 -0.64 ] 
  [ -1.14 0.08 ] 
  [ -1.91 0.03 ]  ] 
h = np.dot(x,W1)
print(h)
[[ 0.01541824 -0.07780941 -0.56423005  0.11352836]
 [ 2.36181379  0.30508945  0.24420038  0.82618277]
 [-1.05767633 -0.01167805  0.77657853 -0.53929615]
 [-2.00645476 -0.28719947 -0.40608827 -0.66391479]
 [-0.95027583 -0.09784287  0.07836775 -0.36616892]
 [ 0.79998106  0.15462942  0.44639062  0.21033789]
 [-0.29843167  0.02764592  0.43850266 -0.1940934 ]
 [-1.21745191 -0.11217386  0.19384021 -0.48697679]
 [-0.56652608  0.04460651  0.77659209 -0.35778508]
 [-1.08445402  0.05330507  1.25909435 -0.64140617]]
h.shape
(10, 4)
h.ndim
2
b1.shape
(4,)
b1.ndim
1
print(h)
print('------------------------------------------')
print(b1)
[[ 0.01541824 -0.07780941 -0.56423005  0.11352836]
 [ 2.36181379  0.30508945  0.24420038  0.82618277]
 [-1.05767633 -0.01167805  0.77657853 -0.53929615]
 [-2.00645476 -0.28719947 -0.40608827 -0.66391479]
 [-0.95027583 -0.09784287  0.07836775 -0.36616892]
 [ 0.79998106  0.15462942  0.44639062  0.21033789]
 [-0.29843167  0.02764592  0.43850266 -0.1940934 ]
 [-1.21745191 -0.11217386  0.19384021 -0.48697679]
 [-0.56652608  0.04460651  0.77659209 -0.35778508]
 [-1.08445402  0.05330507  1.25909435 -0.64140617]]
------------------------------------------
[-0.13469563  0.28569531  0.70929718 -0.59326618]
h+b1# 广播
array([[-1.19277394e-01,  2.07885894e-01,  1.45067132e-01,
        -4.79737819e-01],
       [ 2.22711816e+00,  5.90784753e-01,  9.53497557e-01,
         2.32916587e-01],
       [-1.19237196e+00,  2.74017260e-01,  1.48587570e+00,
        -1.13256233e+00],
       [-2.14115039e+00, -1.50416032e-03,  3.03208912e-01,
        -1.25718097e+00],
       [-1.08497146e+00,  1.87852434e-01,  7.87664922e-01,
        -9.59435103e-01],
       [ 6.65285424e-01,  4.40324723e-01,  1.15568780e+00,
        -3.82928289e-01],
       [-4.33127306e-01,  3.13341233e-01,  1.14779984e+00,
        -7.87359577e-01],
       [-1.35214754e+00,  1.73521450e-01,  9.03137385e-01,
        -1.08024297e+00],
       [-7.01221716e-01,  3.30301822e-01,  1.48588926e+00,
        -9.51051258e-01],
       [-1.21914965e+00,  3.39000380e-01,  1.96839152e+00,
        -1.23467235e+00]])

Tip:广播

之所以(10, 4)的h=W*x能与(4,)的b相加,是因为广播机制,使得h每一行都能与b1进行加和。
在这里插入图片描述

# 完整代码
import numpy as np
W1 = np.random.randn(2,4)#权重
b1 = np.random.randn(4)#偏置
x = np.random.randn(10,2)#输入
h = np.dot(x,W1)+b1

Tip:矩阵形状

做矩阵乘法时是不存在交换律的,所以 M 1 M_1 M1是AxB形状的矩阵只能与 M 2 M_2 M2是BxC形状的矩阵相乘,np.dot( M 1 M_1 M1, M 2 M_2 M2)中M1和M2位置不可换。

使用Sigmoid激活函数

全连接层的变换是线性变换。激活函数赋予它“非线性”的效果。严格地讲,使用非线性的激活函数,可以增强神经网络的表现力。

σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+ex1

# 绘制Sigmoid图像
import numpy as np
import matplotlib.pyplot as plt

# 定义Sigmoid函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 生成x值
x = np.linspace(-10, 10, 400)
# 计算Sigmoid函数的y值
y = sigmoid(x)

# 绘制图像
plt.figure(figsize=(8, 6))
plt.plot(x, y, label='Sigmoid Function')
plt.title('Sigmoid Function')
plt.xlabel('x')
plt.ylabel('σ(x)')
plt.grid(True)
plt.legend()
plt.show()

在这里插入图片描述

# 使用Python实现Sigmoid函数
def Sigmoid(x):
    return 1/(1+np.exp(-x))
Sigmoid(1)
0.7310585786300049
h
array([[-1.47407497,  0.58802038,  1.70889396,  1.39556953],
       [-2.5615688 ,  0.66517439,  0.6672476 ,  1.00202712],
       [-1.45304224, -0.72274523,  1.06198075,  1.93555729],
       [-3.57669353,  0.40927146, -0.47215332,  0.76801346],
       [-0.73148701,  0.75907423,  2.53416711,  1.57332108],
       [-1.750897  , -0.38816799,  0.93637993,  1.70031646],
       [-1.52285637,  0.88359885,  1.81099956,  1.25913572],
       [-2.44863113,  0.46292231,  0.67646122,  1.12187865],
       [-3.26950728,  0.91233956,  0.08949323,  0.66575883],
       [-0.01011141,  0.18064733,  2.9565039 ,  2.04876192]])
# 现在,我们使用这个sigmoid函数,来变换刚才的隐藏层的神经元。
a = Sigmoid(h)
print(a)
[[0.18632403 0.6429108  0.84669277 0.8014799 ]
 [0.07165312 0.66042178 0.66088658 0.73145695]
 [0.1895338  0.32678875 0.74306889 0.87386325]
 [0.02720709 0.60091318 0.38410671 0.68309101]
 [0.3248685  0.68115271 0.92650262 0.82825654]
 [0.1479341  0.4041584  0.71836784 0.84557606]
 [0.17904129 0.70756744 0.85948264 0.77887729]
 [0.07953871 0.6137072  0.66294842 0.75433702]
 [0.03663221 0.71347867 0.52235839 0.66055284]
 [0.49747217 0.54503942 0.95056998 0.88582246]]
# 完整代码
import numpy as np
# 定义激活函数
def Sigmoid(x):
    return 1/(1+np.exp(-x))
W1 = np.random.randn(2,4) # 权重
b1 = np.random.randn(4) # 偏置
x = np.random.randn(10,2) # 输入
h = np.dot(x,W1)+b1 # 计算隐藏层神经元结果
a = Sigmoid(h) # 使用Sigmoid激活函数对全连接的线性函数进行变换

基于sigmoid函数,可以进行非线性变换。然后,再用另一个全连接层来变换这个激活函数的输出a(也称为activation)​。这里,因为隐藏层有4个神经元,输出层有3个神经元,所以全连接层使用的权重矩阵的形状必须设置为4×3,这样就可以获得输出层的神经元。以上就是神经网络的推理。现在我们用Python将这一段内容总结如下。

import numpy as np

# activation function
def sigmoid(x):
    return 1/(1+np.exp(-x))

# Input Layout
x = np.random.randn(10,2)

# Hidden_1 Layout
W1 = np.random.randn(2,4)
b1 = np.random.randn(4)

# Hidden_2 Layout(Output Layout)
W2 = np.random.randn(4,3) # x1(10,4) * W2(4,3) = (10,3)
b2 = np.random.randn(3)

# 神经网络计算过程
h = np.dot(x,W1)+b1
a = sigmoid(h)
s = np.dot(a,W2)+b2

print(s)
[[-0.65295511 -0.21510129  1.4104303 ]
 [-0.69818832 -0.33027493  1.58258664]
 [-1.68172506 -0.70207827  2.7521598 ]
 [-1.54766668 -0.70133203  2.62318762]
 [-1.62995651 -0.68952716  2.67807673]
 [-1.66924263 -0.74728407  2.78568819]
 [-1.22704402 -0.55877071  2.21417014]
 [-1.79847466 -0.69403342  2.85685119]
 [-1.59674403 -0.70376131  2.66984054]
 [-1.77306689 -0.826496    3.10038408]]
s.shape
(10, 3)
s.ndim
2

层的类化及正向传播

现在,我们将神经网络进行的处理实现为层。这里将全连接层的变换实现为Affine层,将sigmoid函数的变换实现为Sigmoid层。因为全连接层的变换相当于几何学领域的仿射变换,所以称为Affine层。另外,将各个层实现为Python的类,将主要的变换实现为类的forward(​)方法。

Tip:正向传播&反向传播

神经网络的推理所进行的处理相当于神经网络的正向传播。顾名思义,正向传播是从输入层到输出层的传播。此时,构成神经网络的各层从输入向输出方向按顺序传播处理结果。之后我们会进行神经网络的学习,那时会按与正向传播相反的顺序传播数据(梯度)​,所以称为反向传播。

编写网络的代码规范

神经网络中有各种各样的层,我们将其实现为Python的类。通过这种模块化,可以像搭建乐高积木一样构建网络。本书在实现这些层时,制定以下“代码规范”​。

  • 所有的层都有forward(​)方法和backward(​)方法
  • 所有的层都有params和grads实例变量简单说明一下这个代码规范。

首先,forward(​)方法和backward(​)方法分别对应正向传播和反向传播。其次,params使用列表保存权重和偏置等参数(参数可能有多个,所以用列表保存)​。grads以与params中的参数对应的形式,使用列表保存各个参数的梯度(后述)​。这就是本书的代码规范。

# 首先实现Sigmoid层
# 因为这里只考虑正向传播,所以我们仅关注代码规范中的以下两点:
# 一是在层中实现forward(​)方法;
# 二是将参数整理到实例变量params中
import numpy as np

#定义激活层
class Sigmoid:
    def __init__(self):
        self.params = []

    def forward(self,x):
        return 1/(1+np.exp(-x))

如上所示,sigmoid函数被实现为一个类,主变换处理被实现为forward(x)方法。这里,因为Sigmoid层没有需要学习的参数,所以使用空列表来初始化实例变量params。下面,我们接着来看一下全连接层Affine层的实现,如下所示

# 定义全连接层
class Affine:
    def __init__(self,W,b):
        self.params = [W,b]

    def forward(self,x):
        W,b = self.params
        out = np.dot(x,W)+b
        return out
    
##流程 x->Affine->Sigmoid

Affine层在初始化时接收权重和偏置。此时,Affine层的参数是权重和偏置(在神经网络的学习时,这两个参数随时被更新)​。因此,我们使用列表将这两个参数保存在实例变量params中。然后,实现基于forward(x)的正向传播的处理。

层视角下的神经网络

现在,我们使用上面实现的层来实现神经网络的推理处理。这里实现如图1-11所示的层结构的神经网络。

神经网络:
在这里插入图片描述

神经网络层结构:
在这里插入图片描述

如图1-11所示,输入X经由Affine层、Sigmoid层和Affine层后输出得分S。我们将这个神经网络实现为名为TwoLayerNet的类,将主推理处理实现为predict(x)方法。

之前,我们在用图表示神经网络时,使用的是像图1-7那样的“神经元视角”的图。与此相对,图1-11是“层视角”的图。

TwoLayerNet的代码如下所示

class TwoLayerNet:
    def __init__(self,input_size,hidden_size,output_size):
        I,H,O = input_size,hidden_size,output_size
        # 初始化权重和偏置
        W1 = np.random.randn(I,H)
        b1 = np.random.randn(H)
        W2 = np.random.randn(H,O)
        b2 = np.random.randn(O)
        # 生成层
        self.layers = [
            Affine(W1,b1),
            Sigmoid(),
            Affine(W2,b2)
        ]

        # 将所有的权重整理到列表中
        self.params= []
        for layer in self.layers:
            self.params += layer.params
    
    def predict(self,x):
        for layer in self.layers:
            x = layer.forward(x)
        return x

在这个类的初始化方法中,首先对权重进行初始化,生成3个层。然后,将要学习的权重参数一起保存在params列表中。这里,因为各个层的实例变量params中都保存了学习参数,所以只需要将它们拼接起来即可。这样一来,TwoLayerNet的params变量中就保存了所有的学习参数。像这样,通过将参数整理到一个列表中,可以很轻松地进行参数的更新和保存。

Tip:params列表可以+=的原因

此外,Python中可以使用+运算符进行列表之间的拼接。下面是一个简单的例子。

    >>> a = ['A' , 'B']
    >>> a += ['C' , 'D']
    >>> a
    ['A', 'B', 'C', 'D']

如上所示,通过列表之间的加法将列表拼接了起来。在上面的TwoLayerNet的实现中,通过将各个层的params列表加起来,从而将全部学习参数整理到了一个列表中。现在,我们使用TwoLayerNet类进行神经网络的推理。

x = np.random.randn(10,2)
model = TwoLayerNet(2,4,3)
s = model.predict(x)
print(s)
[[-1.40815785 -2.75324442 -0.68087566]
 [-0.84448276 -2.14535182 -0.7192525 ]
 [ 0.39915813 -0.89634245 -0.67372793]
 [-0.32721563 -1.59895864 -0.68823956]
 [-0.59388923 -1.83488505 -0.65597035]
 [-0.75710188 -1.79384233 -0.34964915]
 [-0.97025609 -2.00975814 -0.4065426 ]
 [-0.25650267 -1.74562119 -0.96872542]
 [-0.59327156 -1.92385543 -0.7629768 ]
 [-0.77185477 -2.05221365 -0.70222556]]

备注:TwoLayerNet类

你编写的 TwoLayerNet 类表示一个简单的两层神经网络,其中每一层都是通过仿射(Affine)变换和激活函数(Sigmoid)组合而成。这是一个经典的前馈神经网络的设计,常用于处理如分类问题等任务。

我可以进一步解释这个代码的功能和工作原理:

  1. 构造函数 init
  • input_size: 输入层的大小,即输入特征的维度。
  • hidden_size: 隐藏层的大小,即隐藏层神经元的数量。
  • output_size: 输出层的大小,即输出的维度,通常用于多分类或回归任务。

在构造函数中,你进行了以下操作:

初始化权重和偏置:

  • W1: 输入层到隐藏层的权重矩阵,形状为 (I, H),即 input_size x hidden_size。
  • b1: 隐藏层的偏置向量,形状为 (H,)。
  • W2: 隐藏层到输出层的权重矩阵,形状为 (H, O),即 hidden_size x output_size。
  • b2: 输出层的偏置向量,形状为 (O,)。
  • 权重和偏置是通过 np.random.randn 方法随机初始化的。这个方法会生成从标准正态分布(均值为0,方差为1)中抽取的随机数。

生成层:

使用 Affine 层(仿射变换层)和 Sigmoid 激活函数作为隐藏层的激活函数。这里,网络由以下三层构成:

  • 输入经过第一个仿射层 Affine(W1, b1) 计算。
  • 使用 Sigmoid 激活函数。
    = 输出经过第二个仿射层 Affine(W2, b2) 计算。

整理权重到列表中:

将每一层的权重参数 params(假设 Affine 层有 params 属性存储权重和偏置)收集到一个 self.params 列表中,方便之后的更新或管理。

  1. 前向传播函数 predict

predict 函数的功能是计算前向传播。它接收输入 x,然后逐层执行每个层的 forward 方法,将输出作为下一层的输入。

这里假设 Affine 和 Sigmoid 类都有 forward 方法,分别执行仿射变换和激活函数。

示例代码的完整性

为了让这个 TwoLayerNet 类完整运作,你需要定义 Affine 和 Sigmoid 类。以下是这两个类的示例实现:

import numpy as np

# 仿射层(线性变换层)
class Affine:
    def __init__(self, W, b):
        self.W = W  # 权重
        self.b = b  # 偏置
        self.params = [W, b]  # 将权重和偏置整理到params中
        
    def forward(self, x):
        # 进行仿射变换,线性运算 xW + b
        return np.dot(x, self.W) + self.b

# Sigmoid激活函数层
class Sigmoid:
    def __init__(self):
        self.params = []  # Sigmoid层没有参数
        
    def forward(self, x):
        # 计算Sigmoid函数
        return 1 / (1 + np.exp(-x))

# 测试
input_size = 4
hidden_size = 5
output_size = 3

# 初始化两层神经网络
net = TwoLayerNet(input_size, hidden_size, output_size)

# 输入一个样本,形状为 (1, input_size)
x = np.random.randn(1, input_size)

# 计算网络的输出
output = net.predict(x)
print(output)

[[-1.20228388 -1.89021118 -1.46129892]]

说明:
Affine 层: 它实现了线性变换 xW + b,其中 x 是输入,W 是权重矩阵,b 是偏置向量。

Sigmoid 层: 它是一个没有参数的激活函数层,执行 Sigmoid 函数的计算。

运行逻辑:

网络从输入层到隐藏层,经过仿射变换和 Sigmoid 激活。

随后,隐藏层到输出层再次经过仿射变换,输出结果。

备注:predict函数

在你的 TwoLayerNet 类中,predict(self, x) 方法用于前向传播,将输入数据通过网络的各个层,逐层计算得到输出。

下面是对该 predict 方法的具体解释:

  1. 方法解析
def predict(self, x):
    for layer in self.layers:
        x = layer.forward(x)
    return x
  • 输入参数

    • x: 输入数据,通常是一个形状为 (batch_size, input_size) 的矩阵(批量输入的样本),其中 batch_size 是样本的数量,input_size 是每个样本的特征维度。
  • 循环执行

    • self.layers 是网络中的各个层(如仿射层 Affine 和激活函数层 Sigmoid),它们已经在 __init__ 中初始化并存储在 self.layers 列表中。
    • layer.forward(x):对每一层执行前向传播操作,其中 forward 是每个层(如 AffineSigmoid)的前向传播函数,计算输入 x 的输出。

    注意:每次 x = layer.forward(x) 都会更新 x,即输入数据逐层传递并被逐步转换。第一次是原始输入数据,之后每次 forward 的输出会成为下一层的输入。

  • 返回值

    • return x: 经过所有层后,最终的输出 x 就是整个神经网络的输出。
  1. 预测的过程

这个 predict 函数通过以下步骤工作:

  1. 初始输入: 输入 x 传递到网络的第一层。

  2. 逐层计算: 输入 x 经过每一层的 forward 方法,逐层传递(从输入层到输出层)。

    • Affine 层:执行仿射变换 xW + b
    • Sigmoid 层:执行非线性激活函数。
  3. 最终输出:网络的最终输出是通过所有层计算的结果,并返回。

  4. 示例流程

假设你已经定义了两层神经网络并使用 AffineSigmoid 层:

input_size = 4   # 输入层大小
hidden_size = 5  # 隐藏层神经元数量
output_size = 3  # 输出层大小

net = TwoLayerNet(input_size, hidden_size, output_size)

# 假设输入一个样本,形状为 (1, 4) 对应 input_size
x = np.random.randn(1, input_size)

# 调用predict函数计算输出
output = net.predict(x)
print(output)
  1. 各个层的作用

  2. 第一层 (Affine 层):

    • 输入经过 W 1 W1 W1 b 1 b1 b1,执行线性变换,输出进入激活函数层。

    z 1 = x ⋅ W 1 + b 1 z_1 = x \cdot W_1 + b_1 z1=xW1+b1

  3. 第二层 (Sigmoid 层):

    • z 1 z_1 z1 应用 Sigmoid 激活函数,产生非线性输出:

    a 1 = σ ( z 1 ) = 1 1 + e − z 1 a_1 = \sigma(z_1) = \frac{1}{1 + e^{-z_1}} a1=σ(z1)=1+ez11

  4. 第三层 (Affine 层):

    • Sigmoid 层的输出作为输入,经过第二个仿射层 W2b2 进行线性变换,最终输出:

    z 2 = a 1 ⋅ W 2 + b 2 z_2 = a_1 \cdot W_2 + b_2 z2=a1W2+b2

  5. 总结

  • predict 方法是前向传播的核心,逐层执行 forward,并将每层的输出作为下一层的输入。
  • 最终返回经过所有层计算后的输出,这就是神经网络的预测结果。

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

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

相关文章

OceanMesh2D | 基于精确距离的沿海海洋/浅水流动模型二维自动网格生成MATLAB工具箱推荐

Precise distance-based two-dimensional automated mesh generation toolbox intended for coastal ocean/shallow water flow models OceanMesh2D | 基于精确距离的沿海海洋/浅水流动模型二维自动网格生成MATLAB工具箱推荐 1. 简介2. 特点3. 代码基本要求:4. 基本流程 1. 简…

一、Numpy使用

1、numpy的简单使用 import numpy as np #利用as给numpy起一个别名np# 使用array来承接这个数组 array np.array([[1,2,3],[2,3,4]])print(array) print("number of dim:", array.ndim) # ndim 数组维度 print("shape:", array.shape) # 数组的形…

c++编程(27)——IO流(1)

欢迎来到博主的专栏&#xff1a;c编程 博主ID&#xff1a;代码小豪 文章目录 标准IO流标准输入输出cincin的四个状态标志 标准IO流 <iostream>库中的IO类在之前已经经常使用了&#xff0c;但是我们还从未仔细的了解过。在c标准库中&#xff0c;IO类分为两种&#xff0c;…

sqli-labs靶场自动化利用工具——第2关

文章目录 概要整体架构流程技术细节执行效果小结 概要 Sqli-Labs靶场对于网安专业的学生或正在学习网安的朋友来说并不陌生&#xff0c;或者说已经很熟悉。那有没有朋友想过自己开发一个测试脚本能实现自动化化测试sqli-labs呢&#xff1f;可能有些人会说不是有sqlmap&#…

摄影社团管理系统

基于springbootvue实现的摄影社团管理系统 &#xff08;源码L文ppt&#xff09;4-075 第四章 系统概要设计 4.1系统设计原理 设计原理是指系统的设计来源&#xff0c;它将需求合理地分解为功能&#xff0c;并抽象地描述系统的模块和其下的功能。在功能模块化后&#xff…

【数据结构】排序算法---桶排序

文章目录 1. 定义2. 算法步骤3. 演示3.1 动态演示13.2 动态演示23.3 图片演示13.4 图片演示2 4. 性质5. 算法分析6. 代码实现C语言PythonJavaCGo 结语 1. 定义 桶排序&#xff08;英文&#xff1a;Bucket sort&#xff09;是计数排序的升级版&#xff0c;适用于待排序数据值域…

【算法】最长公共子序列(C/C++)

最长公共子序列&#xff08;LCS&#xff0c;Longest Common Subsequence&#xff09;问题简称&#xff08;LCS&#xff09;&#xff0c;是动态规划里面里面的基础算法。它的所解决的问题是&#xff0c;在两个序列中找到一个序列&#xff0c;使得它既是第一个序列的子序列&#…

SpringCloud微服务实现服务降级的最佳实践

Spring Cloud是一种用于快速构建分布式系统的框架&#xff0c;它提供了许多有用的功能&#xff0c;其中包括服务降级。 服务降级是一种保护机制&#xff0c;它可以在面临高并发或故障时保持服务的稳定性。当系统资源不足或服务出现故障时&#xff0c;服务降级可以通过关闭一些功…

2.计算机网络基础

2. 计算机网络基础 (1) 计算机网络的定义 计算机网络是指将地理位置不同、具有独立功能的多个计算机系统通过通信线路和设备连接起来,以功能完善的网络软件实现网络中资源共享的系统。最简单的定义是:计算机网络是一些互相连接的、自治的计算机系统的集合。最庞大的计算机网…

MATLAB系列03:分支语句和编程设计

MATLAB系列03&#xff1a;分支语句和编程设计 3. 分支语句和编程设计3.1 自上而下的编程方法简介3.2 伪代码的应用3.3 关系运算符和逻辑运算符3.3.1 关系运算符3.3.2 小心和~运算符3.3.3 逻辑运算符3.3.4 逻辑函数 3.4 选择结构3.4.1 if结构3.4.2 switch结构3.4.3 try/catch结构…

c++的decltype关键字

它可以将变量声明为表达式指定的类型

C语言程序二级 之知识点 程序填空 程序设计 程序修改

一 知识点 宏定义是指用一个宏名(名字)来代表一个字符串。宏定义的功能是在编译预处理时&#xff0c;对程序中所有出现的"宏名"都用宏定义中的字符串去代换&#xff0c;这称为"宏代换"或"宏展开"。无参宏定义的一般格式&#xff1a;#define 标识…

中国光刻机突破28nm?进步巨大但前路漫漫

在近期的报道中&#xff0c;中国国产光刻机进入推广目录的消息引发了广泛关注&#xff0c;其中提到的一款氟化亚光刻机的分辨率达到了65nm&#xff0c;被视作具备28nm制程节点的生产能力。那么&#xff0c;国产光刻机真的已经突破了28nm制程节点了吗&#xff1f;本文将对相关技…

Mysql梳理6——order by排序

目录 6 order by排序 6.1 排序数据 6.2 单列排序 6.3 多行排列 6 order by排序 6.1 排序数据 使用ORDER BY字句排序 ASC&#xff08;ascend&#xff09;:升序DESC(descend):降序 ORDER BY子句在SELECT语句的结尾 6.2 单列排序 如果没有使用排序操作&#xff0c;默认…

第157天: 安全开发-Python 自动化挖掘项目SRC 目标FOFA 资产Web 爬虫解析库

案例一&#xff1a;Python-WEB 爬虫库&数据解析库 这里开发的内容不做过多描述&#xff0c;贴上自己写的代码 爬取数据 要爬取p标签&#xff0c;利用Beautyfulsoup模块 import requests,time from bs4 import BeautifulSoup#url"https://src.sjtu.edu.cn/rank/firm…

教你建设智慧数字乡村如何选供应商,如何落地项目

说到数字乡村建设&#xff0c;大家都有自己的思路和想法&#xff0c;那么如果现在让你来做这个项目你又如何来实施&#xff1f;都需要什么方式&#xff1f;都要具备什么条件&#xff1f; 下面我来说一下我的个人思路&#xff0c;要做数字乡村我觉得前提是必须满足几个条件&…

可视化工具Gephi安装要求和特点

Gephi是进行社会图谱数据可视化分析的工具&#xff0c;不但能处理大规模数据集并且Gephi是一个可视化的网络探索平台&#xff0c;用于构建动态的、分层的数据图表。 Gephi安装要求 ① gephi是一个可多平台使用的绘图软件&#xff0c;能在Windows&#xff0c;OS&#xff0c;Lin…

平价头戴式蓝牙耳机有哪些?四款公认平价性能超强品牌机型推荐

在追求高品质音乐体验的同时&#xff0c;许多消费者希望找到价格亲民的头戴式蓝牙耳机&#xff0c;市场上不乏性能卓越、价格实惠的产品&#xff0c;它们凭借出色的音质、舒适的佩戴体验和可靠的续航能力赢得了用户的青睐&#xff0c;那么在众多的头戴式蓝牙耳机内&#xff0c;…

英伟达:AI时代的领跑者,引领智能计算的未来@附149页PDF文件下载

在人工智能的浪潮中&#xff0c;英伟达&#xff08;NVIDIA&#xff09;以其卓越的GPU技术&#xff0c;成为了这个时代的领跑者。从游戏显卡的霸主到AI计算的领导者&#xff0c;英伟达的转型之路充满了创新与突破。今天&#xff0c;我们将深入探讨2024年英伟达如何通过其战略布局…

Python 中的异步编程:从入门到实践

在现代编程实践中&#xff0c;异步编程已经成为一个不可或缺的技能&#xff0c;尤其是在处理高并发和I/O密集型应用时。Python&#xff0c;作为一种动态、解释型的高级编程语言&#xff0c;提供了强大的异步编程支持&#xff0c;使得开发者能够有效地编写高效、可扩展的应用程序…