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

PyTorch生成式人工智能实战(1)——神经网络与模型训练过程详解

PyTorch生成式人工智能实战(1)——神经网络与模型训练过程详解

    • 0. 前言
    • 1. 传统机器学习与人工智能
    • 2. 人工神经网络基础
      • 2.1 人工神经网络组成
      • 2.2 神经网络的训练
    • 3. 前向传播
      • 3.1 计算隐藏层值
      • 3.2 执行非线性激活
      • 3.3 计算输出层值
      • 3.4 计算损失值
      • 3.5 实现前向传播
    • 4. 反向传播
      • 4.1 反向传播流程
      • 4.2 梯度下降
      • 4.3 实现梯度下降算法
      • 4.4 使用链式法则实现反向传播
    • 5. 合并前向传播和反向传播
    • 6. 神经网络训练过程总结
    • 小结
    • 系列链接

0. 前言

人工神经网络 (Artificial Neural Network, ANN) 是一种监督学习算法,其灵感来自人类大脑的运作方式。类似于人脑中神经元连接和激活的方式,神经网络接受输入,通过某些函数在网络中进行传递,导致某些后续神经元被激活,从而产生输出。函数越复杂,网络对于输入的数据拟合能力就越大,因此预测的准确性就越高。
有多种不同的 ANN 架构,根据通用逼近定理,我们总能找到一个足够大的包含正确权重集的神经网络架构,可以准确地预测任何给定输入的输出结果。这意味着,对于给定的数据集/任务,我们可以创建一个架构并不断调整其权重,直到 ANN 预测出正确结果,调整网络权重的过程称为训练神经网络。
计算机视觉中的一项重要任务是识别图像中的对象类别,即图像分类,ImageNet 是图像分类领域的一项权威竞赛,历年分类准确率情况如下:

ImageNet历年分类准确率
从上图可以看出,通过利用神经网络,模型错误率显着减少,随着时间的推移,神经网络逐渐变得更深、更复杂,分类错误率不断减少,并表现出超越人类的水平。
在本节中,我们将使用一个简单的数据集创建一个简单的神经网络架构,以了解 ANN 的各个组成部分(前向传播、反向传播、学习率等)对于模型权重调整的作用,以掌握神经网络如何根据给定输入学习预测输出。我们将首先介绍神经网络背后的数学原理,然后从零开始构建一个神经网络,并介绍用于训练神经网络的每个组成部分。

1. 传统机器学习与人工智能

传统应用程序中,系统是通过使用程序员编写的复杂算法来实现智能化的。例如,假设我们希望识别照片中是否包含狗。在传统的机器学习 (Machine Learning, ML) 中,需要机器学习研究人员首先确定需要从图像中提取的特征,然后提取这些特征并将它们作为输入传递给复杂算法,算法解析给定特征以判断图像中是否包含狗:

传统机器学习

然而,如果要为多种类别图像分类手动提取特征,其数量可能是指数级的,因此,传统方法在受限环境中效果很好(例如,识别证件照片),而在不受限制的环境中效果不佳,因为每张图像之间都有较大差异。
我们可以将相同的思想扩展到其他领域,例如文本或结构化数据。过去,如果希望通过编程来解决现实世界的任务,就必须了解有关输入数据的所有内容并编写尽可能多的规则来涵盖所有场景,并且不能保证所有新场景都会遵循已有规则。
而神经网络内含了特征提取的过程,并将这些特征用于分类/回归,几乎不需要手动特征工程,只需要标记数据(例如,哪些图片是狗,哪些图片不是狗)和神经网络架构,不需要手动提出规则来对图像进行分类,这减轻了传统机器学习技术强加给程序员的大部分负担。
训练神经网络需要提供大量样本数据。例如,在前面的例子中,我们需要为模型提供大量的狗和非狗图片,以便它学习特征。神经网络用于分类任务的流程如下,其训练与测试是端到端 (end-to-end) 的:

神经网络训练

2. 人工神经网络基础

2.1 人工神经网络组成

ANN 是张量(权重, weights )和数学运算的集合,其排列方式近似于松散的人脑神经元排列。可以将其视为一种数学函数,它将一个或多个张量作为输入并预测相应输出(一个或多个张量)。将输入连接到输出的操作方式称为神经网络的架构,我们可以根据不同的任务构建不同架构,即基于问题是包含结构化数据还是非结构化(图像,文本,语音)数据,这些数据就是输入和输出张量的列表。ANN 由以下部分组成:

  • 输入层:将自变量作为输入
  • 隐藏(中间)层:连接输入和输出层,在输入数据之上执行转换;此外,隐藏层利用节点单元(下图中的圆圈)将其输入值修改为更高/更低维的值;通过修改中间节点的激活函数可以实现复杂表示函数
  • 输出层:输入变量产生的值

综上,神经网络的典型结构如下:

神经网络架构
输出层中节点的数量(上图中的圆圈)取决于实际任务以及我们是在尝试预测连续变量还是分类变量。如果输出是连续变量,则输出有一个节点。如果输出是具有 m 个可能类别的分类,则输出层中将有 m 个节点。接下来,我们深入介绍节点/神经元的工作原理,神经元按如下方式转换其输入:

神经元

其中, x 1 x_1 x1 x 2 x_2 x2,…, x n x_n xn 是输入变量, w 0 w_0 w0 是偏置项(类似于线性/逻辑回归中的偏差); w 1 w_1 w1 w 2 w_2 w2,…, w n w_n wn 是赋予每个输入变量的权重,输出值 a a a 计算如下:

a = f ( w 0 + ∑ w i N w i x i ) a=f(w_0+\sum _{w_i} ^N w_ix_i) a=f(w0+wiNwixi)

可以看到, a a a 是权重和输入对的乘积之和,之后使用一个附加函数 f ( w 0 + ∑ w i N w i x i ) f(w_0+\sum _{w_i} ^N w_ix_i) f(w0+wiNwixi),函数 f f f 是在乘积之和之上应用的非线性激活函数,用于在输入和它们相应的权重值的总和上引入非线性,可以通过使用多个隐藏层实现更强的非线性能力。
整体而言,神经网络是节点的集合,其中每个节点都有一个可调整的浮点值(权重),并且节点间相互连接,返回由网络架构决定的输出。网络由三个主要部分组成:输入层、隐藏层和输出层。我们可以使用多层 (n) 隐藏层,深度学习通常表示具有多个隐藏层的神经网络。通常,当神经网络需要学习具有复杂上下文或上下文不明显的任务(例如图像识别)时,就必须具有更多隐藏层。

2.2 神经网络的训练

训练神经网络实际上就是通过重复两个关键步骤来调整神经网络中的权重:前向传播和反向传播。

  1. 在前向传播 (feedforward propagation) 中,我们将一组权重应用于输入数据,将其传递给隐藏层,对隐藏层计算后的输出使用非线性激活,通过若干个隐藏层后,将最后一个隐藏层的输出与另一组权重相乘,就可以得到输出层的结果。对于第一次正向传播,权重的值将随机初始化
  2. 在反向传播 (backpropagation) 中,尝试通过测量输出的误差,然后相应地调整权重以降低误差。神经网络重复正向传播和反向传播以预测输出,直到获得令误差较小的权重为止

3. 前向传播

为了进一步了解前向传播的工作方式,我们将通过一个简单的示例来构建神经网络,其中神经网络的输入为 (1,1),相应(预期)的输出为 0,我们根据这一输入输出对找到神经网络的最佳权重。在实际的神经网络中,会有数以万计的数据样本点用于训练。
我们采用的策略如下:神经网络具有一个隐藏层,一个输入层和一个输出层,其中隐藏层包含三个节点,如下所示:

网络架构

在上图中,每个箭头都包含一个可调整的浮点值(权重)。我们需要找到 9 个浮点数,当输入为 (1,1) 时,令输出尽可能接近 0,这就是我们训练神经网络的目的(令输出尽可能接近目标值)。为简单起见,我们并未在隐藏层单元中添引入偏置项。接下来,我们将针对以上网络介绍以下内容:

  • 计算隐藏层值
  • 执行非线性激活
  • 计算输出层值
  • 计算损失值

3.1 计算隐藏层值

首先,为所有连接分配随机权重;通常,神经网络在训练开始之前使用随机权重进行初始化。为了简单起见,在本节中,前向传播和反向传播时不包括偏执值。
初始权重可以随机初始化至 0-1 之间,但神经网络训练过程后的最终权重不需要在特定的区间内。下图左侧给出了网络中权重和值的可视化表示,右侧给出了网络中随机初始化的权重:

网络中权重和值的可视化表示

接下来,将输入与权重相乘,计算隐藏层中的值。应用激活函数前,隐藏层的单元值如下:
h 11 = x 1 ∗ w 11 + x 2 ∗ w 21 = 1 ∗ 0.8 + 1 ∗ 0.2 = 1 h 12 = x 1 ∗ w 12 + x 2 ∗ w 22 = 1 ∗ 0.4 + 1 ∗ 0.9 = 1.3 h 13 = x 1 ∗ w 13 + x 2 ∗ w 23 = 1 ∗ 0.3 + 1 ∗ 0.5 = 0.8 h_{11}=x_1*w_{11}+x_2*w_{21}=1*0.8+1*0.2=1 \\ h_{12}=x_1*w_{12}+x_2*w_{22}=1*0.4+1*0.9=1.3 \\ h_{13}=x_1*w_{13}+x_2*w_{23}=1*0.3+1*0.5=0.8 h11=x1w11+x2w21=10.8+10.2=1h12=x1w12+x2w22=10.4+10.9=1.3h13=x1w13+x2w23=10.3+10.5=0.8
计算的应用激活前隐藏层的单元值可视化如下图所示:

应用激活前隐藏层的单元值

接下来,我们通过非线性激活传递隐藏层值。需要注意的是,如果我们不在隐藏层中应用非线性激活函数,那么无论存在多少隐藏层,则神经网络本质上都将是从输入到输出线性连接。

3.2 执行非线性激活

激活函数有助于对输入和输出之间的复杂关系进行建模,使用它们可以实现高度非线性。一些常用的激活函数如下(其中 x 是输入):
S i g m o i d ( x ) = 1 1 + e − x R e L U ( x ) = { x x > 0 0 x ≤ 0 T a n h ( x ) = e x − e − x e x + e − x L i n e a r ( x ) = x Sigmoid(x)=\frac 1 {1+e^{-x}} \\ ReLU(x)=\left\{ \begin{aligned} x \quad x>0\\ 0 \quad x≤0\\ \end{aligned} \right. \\ Tanh(x)=\frac {e^x-e^{-x}} {e^x+e^{-x}} \\ Linear(x) = x Sigmoid(x)=1+ex1ReLU(x)={xx>00x0Tanh(x)=ex+exexexLinear(x)=x
应用激活函数后,输入值对应的激活可视化如下:

激活函数

使用 Sigmoid 激活函数,通过对隐藏层应用 sigmoid 激活 S ( x ) S(x) S(x),可以得到以下结果:
a 11 = s i g m o i d ( 1.0 ) = 0.73 a 12 = s i g m o i d ( 1.3 ) = 0.78 a 13 = s i g m o i d ( 0.8 ) = 0.69 a_{11} = sigmoid(1.0) = 0.73\\ a_{12} = sigmoid(1.3) = 0.78\\ a_{13} = sigmoid(0.8) = 0.69 a11=sigmoid(1.0)=0.73a12=sigmoid(1.3)=0.78a13=sigmoid(0.8)=0.69

3.3 计算输出层值

接下来,我们将应用激活函数后的隐藏层值通过随机初始化的权重值连接到输出层,使用激活后的隐藏层值和权重值计算网络的输出值:

应用Sigmoid函数

计算隐藏层值和权重值乘积的总和,得到输出值。此外,为了简化对前向传播和反向传播工作细节的理解,我们暂时忽略每个单元(节点)中的偏置项:

o u t p u t = 0.73 × 0.3 + 0.79 × 0.5 + 0.69 × 0.9 = 1.235 output = 0.73\times 0.3+0.79\times 0.5 + 0.69\times 0.9= 1.235 output=0.73×0.3+0.79×0.5+0.69×0.9=1.235

因为我们从一组随机权重开始,所以输出节点的值与目标值有较大差距,根据以上计算可以看到,差值为 1.235 (我们的目标是令目标值与模型输出值之间的差值为 0 )。在下一小节中,我们将学习如何计算当前状态下网络的损失值。

3.4 计算损失值

损失值( Loss values,也称为成本函数 cost functions )是我们需要在神经网络中优化的值。为了了解如何计算损失值,我们分析以下两种情况:

  • 分类(离散)变量预测
  • 连续变量预测
3.4.1 在连续变量预测过程中计算损失

通常,当变量是连续的时,可以计算实际值和预测值之差的平方的平均值作为损失值,也就是说,我们试图通过改变与神经网络相关的权重值来最小化均方误差:

J θ = 1 m ∑ i = 1 m ( y i − y ^ i ) 2 y ^ i = η θ ( x i ) J_{\theta}=\frac 1m\sum_{i=1}^m(y_i-\hat y _i)^2\\ \hat y_i=\eta_{\theta}(x_i) Jθ=m1i=1m(yiy^i)2y^i=ηθ(xi)

其中, y i y_i yi 是实际输出, y ^ i \hat y_i y^i 是由神经网络 η \eta η (权重为 θ \theta θ )计算得到的预测输出,输入为 x i x_i xi m m m 是数据集中训练时使用的样本数。
关键点在于,对于每组不同的权重,神经网络都会得到不同的损失值,理想情况下,我们需要找到令损失为零的最佳权重集,在现实场景中,则需要找到尽可能令损失值接近于零的权重集。
在上一小节的示例中,假设预测结果是连续值,损失函数使用均方误差,计算结果如下:

l o s s ( e r r o r ) = 1.23 5 2 = 1.52 loss(error)=1.235^2=1.52 loss(error)=1.2352=1.52

3.4.2 在分类(离散)变量预测过程中计算损失

当要预测的变量是离散的(即变量只有几个类别)时,我们通常使用分类交叉熵 (categorical cross-entropy) 损失函数。当要预测的变量有两个不同的值时,损失函数为二元交叉熵 (binary cross-entropy),二元交叉熵计算如下:

− 1 m ∑ i = 1 m ( y i ( l o g ( p i ) + ( 1 − y i ) l o g ( 1 − p i ) ) -\frac 1m\sum_{i=1}^m(y_i(log(p_i)+(1-y_i)log(1-p_i)) m1i=1m(yi(log(pi)+(1yi)log(1pi))

分类交叉熵计算如下:

− 1 m ∑ j = 1 C ∑ i = 1 m y i l o g ( p i ) -\frac 1m\sum_{j=1}^C\sum_{i=1}^my_ilog(p_i) m1j=1Ci=1myilog(pi)

其中, y y y 是输出对应的真实值(即数据样本的标签), p p p 是输出的预测值, m m m 是数据样本总数, C C C 是类别总数。

可视化交叉熵损失的一种简单方法是查看预测矩阵。假设我们需要在图像识别问题中预测五个类别——狗、猫、马、羊和牛。神经网络在最后一层必须包含五个神经元,并使用 softmax 激活函数。此时,网络将输出数据样本属于每个类别的概率。假设有五张图像,预测概率如下所示,其中每行中突出显示单元格对应于图像的真实标签(也称目标类别,target class):

类别概率

每一行中的概率总和为 1。在第一行中,当目标是 Dog,预测概率为 0.88 时,对应的损失值为 0.128;类似地,我们也可以计算其他损失值,当正确类别的概率较高时,损失值较小。由于概率介于 01 之间,因此,当概率为 1 时,可能的最小损失为 0,而当概率为 0 时,最大损失可以为无穷大,模型的最终损失是所有行(训练数据样本)的损失平均值。

3.5 实现前向传播

实现前向传播的策略如下:

  1. 通过将输入值乘以权重来神经元输出值
  2. 计算激活值
  3. 在每个神经元上重复前两个步骤,直到输出层
  4. 将预测输出与真实值进行比较计算损失值

我们可以将以上过程封装为一个函数,将输入数据、当前神经网络权重和真实值作为函数输入,并返回网络的当前损失值:

import numpy as np
def feed_forward(inputs, outputs, weights):pre_hidden = np.dot(inputs, weights[0]) + weights[1]hidden = 1/(1+np.exp(-pre_hidden))pred_out = np.dot(hidden, weights[2]) + weights[3]mean_squared_error = np.mean(np.square(pred_out - outputs))return mean_squared_error

(1) 将输入变量值 (inputs)、权重(weights,如果是首次迭代,则随机初始化)和数据的真实输出 (outputs) 作为 feed_forward 函数的参数:

import numpy as np
def feed_forward(inputs, outputs, weights):

由于为每个神经元节点添加偏置项,因此权重数组不仅包含连接不同节点的权重,还包含与隐藏/输出层中的节点相关的偏置项。

(2) 通过执行输入层和权重值 (weights[0]) 的矩阵乘法(np.dot)来计算隐藏层值,并将偏置值 (weights[1]) 添加到隐藏层中,利用权重和偏置值就可以将输入层连接到隐藏层:

    pre_hidden = np.dot(inputs, weights[0]) + weights[1]

(3) 在获得的隐藏层值 (pre_hidden) 之上应用 sigmoid 激活函数:

    hidden = 1/(1+np.exp(-pre_hidden))

(4) 通过对隐藏层激活值 (hidden) 和权重 (weights[2],将隐藏层连接到输出层)执行矩阵乘法 (np.dot) 计算输出层值,然后在输出上添加偏置项 (weights[3]):

    pred_out = np.dot(hidden, weights[2]) + weights[3]

(5) 计算所有数据样本的均方误差值并返回:

    mean_squared_error = np.mean(np.square(pred_out - outputs))return mean_squared_error

其中,pred_out 是预测输出,而 outputs 是输入应对应的实际输出。

4. 反向传播

4.1 反向传播流程

在前向传播中,我们将输入层连接到隐藏层,然后将隐藏层连接到输出层。在第一次迭代时,随机初始化权重,然后计算网络在当前权重值下的损失。在反向传播中,我们采用相反的方法。利用从前向传播中计算的损失值,并以尽可能最小化损失值为目标更新网络权重,网络权重更新步骤如下:

  1. 每次对神经网络中的每个权重进行少量更改
  2. 测量权重变化 ( δ W \delta W δW) 时的损失变化 ( δ L \delta L δL)
  3. 计算 − k δ L δ W -k\frac {\delta L}{\delta W} kδWδL 更新权重(其中 k k k 为学习率,且为正值,是神经网络中重要的超参数)

对特定权重所做的更新与损失值的减少成正比,也就是说,如果改变一个权重可以大幅减少损失,那么权重的更新就会较大,但是,如果改变权重仅能小幅减少损失,那么就只需要小幅度更新权重。
在整个数据集上执行 n 次上述过程(包括前向传播和反向传播),表示模型进行了 nepoch 的训练(执行一次称为一个 epoch)。
由于神经网络通常可能包含数以百万计的权重,因此更改每个权重的值,并检查损失的变化在实践中并不是最佳方法。上述步骤的核心思想是计算权重变化时的“损失变化”,即计算损失值关于权重的梯度。
在本节中,我们将通过一次少量更新一个权重来从零开始实现梯度下降,但在实现反向传播之前,我们首先了解神经网络的另一关键超参数:学习率 (learning rate)。
直观地说,学习率有助于构建更稳定的算法。例如,在确定权重更新的大小时,我们并不会一次性就对其进行大幅度更改,而是采取更谨慎的方法来缓慢地更新权重。这使模型获得更高的稳定性;在之后的学习中,我们还将研究学习率如何帮助提高网络稳定性。

4.2 梯度下降

更新权重以减少误差值的整个过程称为梯度下降 (gradient descent)。随机梯度下降 (stochastic gradient descent, SGD) 是将误差最小化的一种方法,其中随机 (stochastic) 表示随机选择数据集中的训练数据样本,并根据该样本做出决策。除了随机梯度下降外,还有许多其他优化器可以用于减少损失值。之后的学习中,我们还将学习不同的优化器。
接下来,我们将学习如何使用 Python 从零开始实现反向传播,并介绍如何使用链式法则进行反向传播。

4.3 实现梯度下降算法

(1) 定义前馈网络并计算均方误差损失值:

from copy import deepcopy
import numpy as np
def feed_forward(inputs, outputs, weights):pre_hidden = np.dot(inputs, weights[0]) + weights[1]hidden = 1/(1+np.exp(-pre_hidden))pred_out = np.dot(hidden, weights[2]) + weights[3]mean_squared_error = np.mean(np.square(pred_out - outputs))return mean_squared_error

(2) 为每个权重和偏置项增加一个非常小的量 (0.0001),并针对每个权重和偏差的更新计算一个平方误差损失值。

创建 update_weights 函数,通过执行梯度下降来更新权重。函数的输入是网络的输入 inputs、目标输出 outputs、权重 weights 和模型的学习率 lr

def update_weights(inputs, outputs, weights, lr):

由于权重需要在后续步骤中进行操作,因此使用 deepcopy 确保我们可以处理多个权重副本,而不会影响实际权重,创建作为输入传递给函数的原始权重集的三个副本—— original_weightstemp_weightsupdated_weights

    original_weights = deepcopy(weights)temp_weights = deepcopy(weights)updated_weights = deepcopy(weights)

inputsoutputsoriginal_weights 传递给 feed_forward 函数,使用原始权重集计算损失值 (original_loss):

    original_loss = feed_forward(inputs, outputs, original_weights)

遍历网络的所有层:

    for i, layer in enumerate(original_weights):

示例神经网络中包含四个参数列表,前两个列表分别表示将输入连接到隐藏层的权重和偏置项参数,另外两个表示连接隐藏层和输出层的权重和偏置参数。循环遍历所有参数,因为每个参数列表都有不同的形状,因此使用 np.ndenumerate 循环遍历给定列表中的每个参数:

        for index, weight in np.ndenumerate(layer):

将原始权重集存储在 temp_weights 中,循环每一参数并为其增加一个较小值,并使用神经网络的新权重集计算新损失:

            temp_weights = deepcopy(weights)temp_weights[i][index] += 0.0001_loss_plus = feed_forward(inputs, outputs, temp_weights)

在以上代码中,将 temp_weights 重置为原始权重集,因为在每次迭代中,都需要更新一个参数,以计算对参数进行小量更新时的损失。

计算由于权重变化引起的梯度(损失值的变化):

            grad = (_loss_plus - original_loss)/(0.0001)

这种对参数更新一个很小的量,然后计算梯度的过程就相当于微分的过程。

通过损失变化来更新权重,并使用学习率 lr 令权重变化更稳定:

            updated_weights[i][index] -= grad*lr

所有参数值更新后,返回更新后的权重值——updated_weights

    return updated_weights, original_loss

神经网络中的另一个需要考虑的超参数是计算损失值时的批大小 (batch size)。在以上示例中,我们使用了所有数据点来计算损失值。然而,在实践中,数据集中通常包含数数以万甚至百万计的数据点,过多的数据点在计算损失值时的增量贡献遵循收益递减规律,与我们数据样本总数相比,批大小要小得多。训练模型时,一次使用一批数据点应用梯度下降更新网络参数,直到我们在一次训练周期 (epoch) 内遍历所有数据点。构建模型时,批大小通常在 321024 之间。

4.4 使用链式法则实现反向传播

我们已经学习了如何通过对权重进行小量更新,然后计算权重更新前后损失的差异来计算与权重有关的损失梯度。当网络参数较多时,以这种方式更新权重值需要进行大量计算来得到损失值,因此需要较大的资源和时间。在本节中,我们将学习如何利用链式法则来获取与权重值有关的损失梯度。
在上一小节的示例中,第一次迭代输出的预测值为 1.235。将权重和隐藏层值以及隐藏层激活值分别表示为 w w w h h h a a a

网络架构

在本节中,我们将了解如何使用链式法则计算损失值关于 w 11 w_{11} w11 的梯度,可以使用相同的方式计算其他权重和偏置值。此外,为了便于了解链式法则,我们只需要处理一个数据点,其中输入为 {1,1},输出目标值为 {0}
要计算损失值关于 w 11 w_{11} w11 的梯度,可以通过下图了解计算梯度时要包括的所有中间组件(使用黑色标记标示—— h 11 h_{11} h11 a 11 a_{11} a11 y ^ \hat y y^):

链式法则

网络的损失值表示如下:

L o s s M S E ( C ) = ( y − y ^ ) 2 Loss_{MSE}(C)=(y-\hat y)^2 LossMSE(C)=(yy^)2

预测输出值 y ^ \hat y y^ 计算如下:

y ^ = a 11 ∗ w 31 + a 12 ∗ w 32 + a 13 ∗ w 33 \hat y=a_{11}*w_{31}+a_{12}*w_{32}+a_{13}*w_{33} y^=a11w31+a12w32+a13w33

隐藏层激活值( sigmoid 激活)计算如下:

a 11 = 1 1 + e − h 11 a_{11}=\frac 1 {1+e^{-h_{11}}} a11=1+eh111

隐藏层值计算如下:

h 11 = x 1 ∗ w 11 + x 2 ∗ w 21 h_{11}=x_1*w_{11}+x_2*w_{21} h11=x1w11+x2w21

计算损失值 C C C 的变化相对于权重 w 11 w_{11} w11 的变化:

∂ C ∂ w 11 = ∂ C ∂ y ^ ∗ ∂ y ^ ∂ a 11 ∗ ∂ a 11 ∂ h 11 ∗ ∂ h 11 ∂ w 11 \frac {\partial C}{\partial w_{11}}=\frac {\partial C}{\partial \hat y}*\frac {\partial \hat y}{\partial a_{11}}*\frac {\partial a_{11}}{\partial h_{11}}*\frac {\partial h_{11}}{\partial w_{11}} w11C=y^Ca11y^h11a11w11h11

上式称为链式法则 (chain rule),在上式中我们建立了一个偏微分方程链,分别对四个分量执行偏微分,并最终计算损失值相对于权重的导数值 w 11 w_{11} w11。上式中的各个偏导数计算如下。

损失值相对于预测输出值 y ^ \hat y y^ 的偏导数如下:

∂ C ∂ y ^ = ∂ ∂ y ^ ( y − y ^ ) 2 = − 2 ∗ ( y − y ^ ) \frac {\partial C}{\partial \hat y}=\frac {\partial}{\partial \hat y}(y-\hat y)^2=-2*(y-\hat y) y^C=y^(yy^)2=2(yy^)

预测输出值 y ^ \hat y y^ 相对于隐藏层激活值 a 11 a_{11} a11 的偏导数如下:

∂ y ^ ∂ a 11 = ∂ ∂ a 11 ( a 11 ∗ w 31 + a 12 ∗ w 32 + a 13 ∗ w 33 ) = w 31 \frac {\partial \hat y}{\partial a_{11}}=\frac {\partial}{\partial a_{11}}(a_{11}*w_{31}+a_{12}*w_{32}+a_{13}*w_{33})=w_{31} a11y^=a11(a11w31+a12w32+a13w33)=w31

隐藏层激活值 a 11 a_{11} a11 相对于隐藏层值 h 11 h_{11} h11 的偏导如下:

∂ a 11 ∂ h 11 = a 11 ∗ ( 1 − a 11 ) \frac {\partial a_{11}}{\partial h_{11}}=a_{11}*(1-a_{11}) h11a11=a11(1a11)

隐藏层值 h 11 h_{11} h11 相对于权重值 w 11 w_{11} w11 的偏导如下:

∂ h 11 ∂ w 11 = ∂ ∂ w 11 ( x 1 ∗ w 11 + x 2 ∗ w 21 ) = x 1 \frac {\partial h_{11}}{\partial w_{11}}=\frac {\partial}{\partial w_{11}}(x_1*w_{11}+x_2*w_{21})=x_1 w11h11=w11(x1w11+x2w21)=x1

因此,损失值相对于 w 11 w_{11} w11 的梯度可以表示为:

∂ C ∂ w 11 = − 2 ∗ ( y − y ^ ) ∗ w 31 ∗ a 11 ∗ ( 1 − a 11 ) ∗ x 1 \frac {\partial C}{\partial w_{11}}=-2*(y-\hat y)*w_{31}*a_{11}*(1-a_{11})*x_1 w11C=2(yy^)w31a11(1a11)x1

从上式可以看出,我们现在能够直接计算权重值的微小变化对损失值的影响(损失相对于权重的梯度),而无需重新计算前向传播。接下来,更新权重值:

u p d a t e d _ w e i g h t = o r i g i n a l _ w e i g h t − l r ∗ g r a d i e n t _ o f _ l o s s updated\_weight=original\_weight-lr*gradient\_of\_loss updated_weight=original_weightlrgradient_of_loss

5. 合并前向传播和反向传播

在本节中,我们将构建一个带有隐藏层(连接输入与输出)的简单神经网络,使用在上一小节中介绍的简单数据集,并利用 update_weights 函数执行反向传播以获得最佳权重和偏置值。模型定义如下:

  1. 输入连接到具有三个神经元(节点)的隐藏层。
  2. 隐藏层连接到具有一个神经元的输出层

接下来,使用 Python 创建神经网络:

(1) 导入相关库并定义数据集:

import numpy as np 
from copy import deepcopy
import matplotlib.pyplot as plt
x = np.array([[1,1]])
y = np.array([[0]])

(2) 随机初始化权重和偏置值。

隐藏层中有三个神经元,每个输入节点都连接到隐藏层神经元。因此,共有六个权重值和三个偏置值,每个隐藏层神经元包含一个偏置和两个权重(每个输入到隐藏层神经元的连接都对应一个权重);最后一层有一个神经元连接到隐藏层的三个单元,因此包含三个权重和一个偏置值。随机初始化的权重如下:

W = [np.array([[-0.0053, 0.3793],[-0.5820, -0.5204],[-0.2723, 0.1896]], dtype=np.float32).T, np.array([-0.0140, 0.5607, -0.0628], dtype=np.float32), np.array([[ 0.1528, -0.1745, -0.1135]], dtype=np.float32).T, np.array([-0.5516], dtype=np.float32)
]

其中,第一个参数数组对应于将输入层连接到隐藏层的 2 x 3 权重矩阵;第二个参数数组表示与隐藏层的每个神经元相关的偏置值;第三个参数数组对应于将隐藏层连接到输出层的 3 x 1 权重矩阵,最后一个参数数组表示与输出层相关的偏置值。

(3)100epoch 内执行前向传播和反向传播,使用以上部分中定义的 feed_forwardupdate_weights 函数。

在训练期间,更新权重并获取损失值和更新后的权重值:

def feed_forward(inputs, outputs, weights):     pre_hidden = np.dot(inputs,weights[0])+ weights[1]hidden = 1/(1+np.exp(-pre_hidden))out = np.dot(hidden, weights[2]) + weights[3]mean_squared_error = np.mean(np.square(out - outputs))return mean_squared_errordef update_weights(inputs, outputs, weights, lr):original_weights = deepcopy(weights)temp_weights = deepcopy(weights)updated_weights = deepcopy(weights)original_loss = feed_forward(inputs, outputs, original_weights)for i, layer in enumerate(original_weights):for index, weight in np.ndenumerate(layer):temp_weights = deepcopy(weights)temp_weights[i][index] += 0.0001_loss_plus = feed_forward(inputs, outputs, temp_weights)grad = (_loss_plus - original_loss)/(0.0001)updated_weights[i][index] -= grad*lrreturn updated_weights, original_loss

(4) 绘制损失值:

losses = []
for epoch in range(100):W, loss = update_weights(x,y,W,0.01)losses.append(loss)
plt.plot(losses)
plt.title('Loss over increasing number of epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss value')
plt.show()

损失值变化

损失值最初为 0.33 左右,然后逐渐下降到 0.0001 左右,这表明权重是根据输入-输出数据调整的,当给定输入时,我们可以通过调整网络参数得到预期目标值。调整后的权重如下:

print(W)
'''输出结果
[array([[ 0.01424004, -0.5907864 , -0.27549535],[ 0.39883757, -0.52918637,  0.18640439]], dtype=float32), array([ 0.00554004,  0.5519136 , -0.06599568], dtype=float32), array([[ 0.3475135 ],[-0.05529078],[ 0.03760847]], dtype=float32), array([-0.22443289], dtype=float32)]
'''

使用 NumPy 数组从零开始构建网络虽然不是最佳方法,但可以为理解神经网络的工作原理打下坚实的基础。

(5) 获取更新的权重后,通过将输入传递给网络对输入进行预测并计算输出值:

pre_hidden = np.dot(x,W[0]) + W[1]
hidden = 1/(1+np.exp(-pre_hidden))
pred_out = np.dot(hidden, W[2]) + W[3]
print(pred_out)
# [[-0.0174781]]

输出为 -0.017,这个值非常接近预期的输出 0,通过训练更多的 epochpred_out 值会更接近 0

6. 神经网络训练过程总结

训练神经网络主要通过重复两个关键步骤,即以给定的学习率进行前向传播和反向传播,最终神经网络架构得到最佳权重。
在前向传播中,我们对输入数据应用一组权重,将其传递给定义的隐藏层,对隐藏层的输出执行非线性激活,然后通过将隐藏层节点值与另一组权重相乘来将隐藏层连接到输出层,以估计输出值;最终计算出对应于给定权重集的损失。需要注意的是,第一次前向传播时,权重的值是随机初始化的。
在反向传播中,通过在损失减少的方向上调整权重来减少损失值(误差),权重更新的幅度等于梯度乘以学习率。
重复前向传播和反向传播的过程,直到获得尽可能小的损失,在训练结束时,神经网络已经将其权重 θ \theta θ 调整调整到近似最优值,以便获取期望的输出结果。

小结

在本节中,我们了解了传统机器学习与人工神经网络间的差异,并了解了如何在实现前向传播之前连接网络的各个层,以计算与网络当前权重对应的损失值;实现了反向传播以优化权重达到最小化损失值的目标。并实现了网络的所有关键组成——前向传播、激活函数、损失函数、链式法则和梯度下降,从零开始构建并训练了一个简单的神经网络。

系列链接

PyTorch生成式人工智能实战:从零打造创意引擎

相关文章:

PyTorch生成式人工智能实战(1)——神经网络与模型训练过程详解

PyTorch生成式人工智能实战(1)——神经网络与模型训练过程详解 0. 前言1. 传统机器学习与人工智能2. 人工神经网络基础2.1 人工神经网络组成2.2 神经网络的训练 3. 前向传播3.1 计算隐藏层值3.2 执行非线性激活3.3 计算输出层值3.4 计算损失值3.5 实现前…...

【软件系统架构】事件驱动架构

一、引言 在当今的软件开发和系统架构领域,事件驱动架构(Event - Driven Architecture,EDA)正逐渐成为构建复杂、分布式和可扩展系统的热门选择。随着信息技术的不断发展,传统的架构模式在应对高并发、实时性要求高、数…...

Doris FE 常见问题与处理指南

在数据仓库领域,Apache Doris 凭借其卓越性能与便捷性被广泛应用。其中,FE(Frontend)作为核心组件,承担着接收查询请求、管理元数据等关键任务。然而,在实际使用中,FE 难免会遭遇各类问题&#…...

Manus AI “算法-数据-工程“三位一体的创新

Manus AI在多语言手写识别领域的技术突破,通过算法创新、数据工程与场景适配的协同作用,解决了传统手写识别的核心痛点。以下是其关键技术路径与创新点的系统性分析: 一、深度学习模型与算法优化 混合神经网络架构Manus AI采用"CNN与LST…...

Flutter Expanded 与 Flexible 详解

目录 1. 引言 2. Expanded 的基本用法 3. Flexible 的基本用法 4. Expanded vs Flexible 的区别 4.1 基础定义 4.2 关键差异 5. Expanded 深度解析 5.1 按比例分配 5.2 强制填充特性 6. Flexible 深度解析 6.1 基础用法:动态收缩 6.2 结合 fit 参数控制…...

乘用车制动系统设计:保障行车安全的核心技术

摘要 随着汽车工业的快速发展,乘用车制动系统的设计至关重要。本文详细阐述了乘用车制动系统的工作原理、组成部分、常见类型,深入分析了制动系统设计过程中的关键要点,包括制动力分配、制动管路设计、制动助力系统选型等。同时,…...

电力行业在保障用电安全方面正积极采用先进的物联网技术

电力行业在保障用电安全方面正积极采用先进的物联网技术 电力行业的物联网安全用电监管装置正发挥着至关重要的作用。 ASCO 电不着安全用电装置凭借其卓越的性能,成为了解决用电安全问题的得力助手。 当电漏电这种危险情况悄然发生时,物联网 ASCO 电不着…...

TDengine 语言连接器(PHP)

简介 PHP 语言广泛用于 Web 开发的开源脚本语言。它语法简单,容易学习,既支持面向过程,也支持面向对象编程。具有跨平台性,能与多种数据库交互,可与 HTML 等前端技术配合,动态生成网页内容。常用于开发各类…...

使用docker该怎么做:从公有仓库拉取镜像并上传到私有仓库

在容器化部署中,将公有镜像仓库(如Docker Hub)的镜像迁移到私有仓库(如Harbor、Nexus)是常见需求。 一、为什么需要将镜像从公有仓库传到私有仓库? 网络连通性:公有仓库依赖公网访问&#xff…...

list的使用

1:list文档 list文档 在之前我们对于链表有过最初始的模拟实现,现在进入C之后,我们可以在STL库中发现到链表这个容器的使用,list的底层也是我们最初实现的双向链表。 2:list的使用 list的接口有很多,我们…...

Redis遇到Hash冲突怎么办

在 Redis 中,哈希冲突通常是指当多个键的哈希值相同或位于相同的哈希槽中时发生冲突。Redis 通过底层的哈希表和一些冲突解决机制(如开放地址法、链表法等)来处理哈希冲突问题。这些通常是透明的,作为开发者,我们无需直…...

OpenCV 图形API(42)颜色空间转换-----将 BGR图像转换为 I420(YUV 4:2:0)格式函数BGR2I420()

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将图像从BGR色彩空间转换为I420色彩空间。 该函数将输入图像从BGR色彩空间转换为I420。R、G和B通道值的传统范围是0到255。 输出图像必须是8位无…...

简述Apache RocketMQ

整体架构分析 基本流程 模块特性 发送消息流程原理分析 同步发送 sync 异步发送 async 直接发送 one-way 主从同步(HA)机制分析 消息投递 持久化机制 RocketMQ的RPC通信 RocketMQ中Remoting通信模块的具体实现 消息的协议涉及与编码解码 消…...

AI融合SEO关键词实战指南

内容概要 随着人工智能技术的迭代升级,SEO关键词策略正经历从人工经验驱动向数据智能驱动的范式转变。本指南聚焦AI技术在搜索引擎优化中的系统性应用,通过构建多层技术框架实现关键词全生命周期管理。核心方法论涵盖语义分析引擎的构建原理、基于NLP的…...

RK3588 实现音视频对讲

RK3588 实现音视频对讲方案 RK3588是瑞芯微推出的一款高性能处理器,非常适合用于音视频对讲系统的开发。以下是基于RK3588实现音视频对讲的方案概述: 硬件架构 核心处理器:RK3588 (4xCortex-A76 4xCortex-A55)视频处理: 内置8…...

OSPF区域间路由计算

ABR:区域边界路由器,连接两个不同区域的设备就称为ABR(不同厂商不同,定义很模糊) ASBR:自治系统边界路由器,引入了外部路由,将不是自治系统外部的不是OSPF路由的条目变成OSPF路由条目…...

NAT、代理服务、内网穿透

NAT、代理服务、内网穿透 1、NAT1.1、NAT过程1.2、NAPT2、内网穿透3、内网打洞3、代理服务器3.1、正向代理3.2、反向代理1、NAT 1.1、NAT过程 之前我们讨论了IPv4协议中IP地址数量不充足的问题。NAT技术是当前解决IP地址不够用的主要手段,是路由器的一个重要功能。 NAT能够将…...

阿尔特拉 EP1C12F324I7N AlteraFPGA Cyclone

EP1C12F324I7N 属于 Altera Cyclone I 系列 FPGA 中的中低密度型号,面向成本敏感、功耗受限的嵌入式与数据通路应用。该器件采用 0.13 μm 全层铜 SRAM 工艺,集成约 12 060 个逻辑单元(LE)、239 616 位片上 RAM、249 路可编…...

解决“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接“问题

参考链接: https://blog.csdn.net/yyj12138/article/details/123073146...

QtApplets-实现应用程序单例模式,防止重复运行

QtApplets-实现应用程序单例模式,防止重复运行 ​ 文章目录 QtApplets-实现应用程序单例模式,防止重复运行摘要引言实现原理核心代码实现头文件定义实现文件 使用方法技术要点解析1. 文件锁机制2. 进程 ID 管理3. Windows 互斥量4. 跨平台兼容 注意事项…...

nodejs使用pkg打包文件

pkg配置 "pkg": {"assets": ["*.html","*.css","*.js"],"mirror": "https://npmmirror.com/mirrors/node-v8-compile-cache/"},"bin": "server.js",嵌入到exe中的资源使用assets打…...

学习笔记十六——Rust Monad从头学

🧠 零基础也能懂的 Rust Monad:逐步拆解 三大定律通俗讲解 实战技巧 📣 第一部分:Monad 是什么? Monad 是一种“包值 链操作 保持结构”的代码模式,用来处理带上下文的值,并方便连续处理。 …...

Idea连接远程云服务器上的MySQL,开放云服务器端口

1.开放云服务器的3306端口 (1)进入到云服务器的控制台 (2)点击使用的云服务器 (3)点击 配置安全组规则 (4)添加规则 (5)开放端口 2.创建可以远程访问…...

云服务器CVM标准型S5实例性能测评——2025腾讯云

腾讯云服务器CVM标准型S5实例具有稳定的计算性能,CPU采用采用 Intel Xeon Cascade Lake 或者 Intel Xeon Cooper Lake 处理器,主频2.5GHz,睿频3.1GHz,CPU内存配置2核2G、2核4G、4核8G、8核16G等配置,公网带宽可选1M、3…...

【Pytorch之一】--torch.stack()方法详解

torch.stack方法详解 pytorch官网注释 Parameters tensors:张量序列,也就是要进行stack操作的对象们,可以有很多个张量。 dim:按照dim的方式对这些张量进行stack操作,也就是你要按照哪种堆叠方式对张量进行堆叠。dim的…...

监控+日志=DevOps 运维的“千里眼”与“顺风耳”

监控+日志=DevOps 运维的“千里眼”与“顺风耳” 在 DevOps 体系中,监控和日志管理是不可或缺的运维基石。有人说,开发只管把代码写好,运维才是真正的“操盘手”,让系统稳定运行、不宕机、不崩溃。而要做到这一点,精准的监控与日志管理 是关键。 试想一下:如果没有监控…...

实战|使用环信Flutter SDK构建鸿蒙HarmonyOS应用及推送配置

本文为大家介绍如何在 Flutter 环境创建 Harmony 项目并集成环信即时通讯IM以及环信 Flutter Harmony 推送配置。 已经基于环信的 Flutter 项目也可以参考本文适配鸿蒙端。 一、开发环境要求 前置条件 1.安装DevEco-Studio 2.安装模拟器 DevEco-Studio 下载与操作指导&…...

构建知识体系

我认为,仅仅建立知识点之间的连接还不足够,还要建立自己的知识体系。 那么什么是知识体系呢? 知识体系,可以理解为立体的知识系统。 立体的知识系统,代表着跨越了多个领域、行业、学科的知识,是多个层面…...

Android Mainline简介

关键要点 Android Mainline 是通过模块化更新 Android 核心组件的框架,可能提高安全性。允许通过 Google Play 系统更新分发模块,无需完整固件更新。能简化厂商工作并减少碎片化,但覆盖范围有限。 什么是 Android Mainline? And…...

2026《数据结构》考研复习笔记二(C++面向对象)

C面向对象 一、类二、继承三、重载运算符和重载函数四、多态代码示例 一、类 1.1类&对象 class classname//class是关键词,classname是类名 { Access specifiers://访问修饰符:private/public/protected Date members/variables;//变量 Member fun…...

【C++】12.list接口介绍

在C标准库中,std::list 是一个基于双向链表实现的顺序容器,它支持高效的插入和删除操作,但无法直接通过下标进行随机访问。以下是关于 std::list 的简单介绍: 核心特性 底层结构 双向链表实现,每个节点包含数据、前驱指…...

决策卫生问题:考公考编考研能补救高考选取职业的错误吗

对于决策者来说,“认识你自己”是一个永恒的主题;警惕认知中的缺陷,比什么都重要。在判断与决策问题上,管理者和专业人士往往都非常自信。人类远远不如我们想象的那么理性,人类的判断也远远不如我们想象的那么完美。在…...

考研系列-计算机网络-第一章、计算机网络体系结构

一、计算机网络概述 1.知识点总结 性能指标: 注意这个指标: 2.习题总结 (一)选择题 广域网点对点,局域网广播技术 (二)简答题 (1)概念性题目: (2)计算型题目 这个题目主要是注意两种交换方式: 电路交换:…...

状态模式:有限状态机在电商订单系统中的设计与实现

状态模式:有限状态机在电商订单系统中的设计与实现 一、模式核心:用状态切换驱动行为变化 在电商订单系统中,订单状态会随着用户操作动态变化:「已创建」的订单支付后变为「已支付」,发货后变为「已发货」&#xff0…...

nohup命令使用说明

文章目录 如何在后台运行程序呢?如何正常运行代码重定向呢?nohup: ignoring input 如何在后台运行程序呢? 使用nohup命令即可, nohup python dataset/ReferESpatialDataset.py >>dataset_20250417.log 2>&1 &n…...

使用原生button封装一个通用按钮组件

效果图 代码 <script lang"ts" setup> import { computed, ref, watch } from "vue";/*** 按钮属性接口*/ interface ButtonProps {/** 按钮类型&#xff1a;default(默认)/dark/plain/link */type?: "default" | "dark" | &q…...

osu ai 论文笔记 DQN

e https://theses.liacs.nl/pdf/2019-2020-SteeJvander.pdf Creating an AI for the Rhytm Game osu! 20年的论文 用监督学习训练移动模型100首歌能达到95准确率 点击模型用DQN两千首歌65准确率 V抖用的居然不是强化学习&#xff1f; 5,6星打96准确度还是有的东西的 这是5.…...

perf 的使用方法

perf的架构 1.perf event event are pure kernel counters, in this case they are called software events. Examples include: context-switches, minor-faults.events is the processor itself and its Performance Monitoring Unit (PMU). It provides a list of events …...

【MCP教程】Claude Desktop 如何连接部署在远程的remote mcp server服务器(remote host)

前言 最近MCP特别火热&#xff0c;笔者自己也根据官方文档尝试了下。 官方文档给的Demo是在本地部署一个weather.py&#xff0c;然后用本地的Claude Desktop去访问该mcp服务器&#xff0c;从而完成工具的调用&#xff1a; 但是&#xff0c;问题来了&#xff0c;Claude Deskto…...

使用python帮助艺术家完成角色动画和服装模型等任务

使用python帮助艺术家完成角色动画和服装模型等任务 声明&#xff1a;克隆项目第 1 步&#xff1a;准备 Python 环境第 2 步&#xff1a;安装依赖✅ 第 3 步&#xff1a;运行项目主入口报错&#xff1a;报错&#xff1a;**降级 Python 到 3.10 或 3.11**推荐版本&#xff1a; 创…...

Python爬虫实战:基于 Python Scrapy 框架的百度指数数据爬取研究

一、引言 1.1 研究背景 在当今信息时代,市场调研和趋势分析对于企业和研究机构至关重要。百度指数能够精准反映关键词在百度搜索引擎上的热度变化情况,为市场需求洞察、消费者兴趣分析等提供了极具价值的数据支持。通过对百度指数数据的爬取和分析,企业可以及时调整营销策略…...

【Python】python系列之函数闭包概念

目录 一、函数 二、闭包 2.1 概念 2.2闭包的应用场景 2.3代码实例 实例 1&#xff1a;简单计数器闭包 实例 2&#xff1a;带参数的闭包 实例 3&#xff1a;闭包用于数据封装和隐藏 一、函数 函数是实现特定功能的代码段的封装&#xff0c;在需要时可以多次调用函数来实…...

【React】什么是 Hook

useStateuseEffectuseRef 什么是hook&#xff1f;16.8版本出现的新特性。可以在不编写class组件的情况下使用state以及其它的React特性 为什么有hook&#xff1f;class组件很难提取公共的重用的代码&#xff0c;然后反复使用&#xff1b;不编写类组件也可以使用类组件的状态st…...

香港科技大学广州|智能交通学域博士招生宣讲会—北京理工大学专场

香港科技大学广州&#xff5c;智能交通学域博士招生宣讲会—北京理工大学专场 &#x1f559;时间&#xff1a;4月23日&#xff08;星期三&#xff09;16:00 &#x1f3e0;地点&#xff1a;北京理工大学中关村校区唯实报告厅 &#x1f517;报名链接&#xff1a;https://www.wj…...

食品计算—Coarse-to-fine nutrition prediction

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(6):ながら 一边。。一边

日语学习-日语知识点小记-构建基础-JLPT-N4阶段&#xff08;6&#xff09;&#xff1a;ながら 一边。。一边 1、前言&#xff08;1&#xff09;情况说明&#xff08;2&#xff09;工程师的信仰 2、知识点&#xff08;1&#xff09;ながら1&#xff09;一边。。一边2&#xff0…...

Electricity Market Optimization(VI) - 机组组合模型以及 Gurobi 求解

本文参考链接&#xff1a;link \hspace{1.6em} 机组组合问题在电力系统中非常重要&#xff0c;这个问题也是一个优化问题&#xff0c;研究的就是如何调度现有的机组&#xff0c;调度的对象是以煤炭、石油、天然气为燃料的火力发电机以及水力发电机等可预测处理的发电机组&#…...

LoRA个关键超参数:`LoRA_rank`(通常简称为 `rank` 或 `r`)和 `LoRA_alpha`(通常简称为 `alpha`)

LoRA (Low-Rank Adaptation) 中的两个关键超参数&#xff1a;LoRA_rank&#xff08;通常简称为 rank 或 r&#xff09;和 LoRA_alpha&#xff08;通常简称为 alpha&#xff09;。 LoRA 的核心思想是&#xff0c;在对大型预训练模型&#xff08;如 LLM 或 Stable Diffusion&…...

Sql刷题日志(day3)

一、笔试 1、min(date_time)&#xff1a;求最早日期 2、mysql中distinct不能与order by 连用&#xff0c;可以用group by去重 二、面试 1、SQL中如何利用replace函数统计给定重复字段在字符串中的出现次数 (length(all_string)-length(all_string,目标字符串,))/length(ta…...

【AI插件开发】Notepad++ AI插件开发实践:实现对话窗口功能

引言 之前的文章已经介绍实现了AI对话窗口&#xff0c;但只有个空壳&#xff0c;没有实现功能。本次将集中完成对话窗口的功能&#xff0c;主要内容为&#xff1a; 模型动态切换&#xff1a;支持运行时加载配置的AI模型列表交互式输入处理&#xff1a;实现多行文本输入与Ctrl…...