如何从头开始构建神经网络?(附教程)

随着流行的深度学习框架的出现,如 TensorFlow、Keras、PyTorch 以及其他类似库,学习神经网络对于新手来说变得更加便捷。虽然这些框架可以让你在几分钟内解决最复杂的计算任务,但它们并不要求你理解背后所有需求的核心概念和直觉。如果你知道特定函数如何工作,并且能在代码块中准确地使用它,就可以轻松地解决大多数问题。然而,要真正理解神经网络的概念以及完整的工作流程,从零开始学习人工神经网络的工作原理是至关重要的。这些神经网络是如何解决复杂问题的呢?

对于任何对人工智能和深度学习感兴趣的人,理解神经网络的原理以及构建过程都是一项有价值的探索。尽管我们暂时不使用深度学习框架如 TensorFlow、Keras 或 PyTorch,但我们将利用 NumPy 等库来进行数值矩阵计算。通过 NumPy 数组,我们可以进行模拟深度学习效果的复杂计算,并借此理解神经网络的编程流程。借助从头开始构建的这些神经网络,我们将实现一些简单的神经网络解决方案。

准备工作

为了跟进本文,你需要具备一些 Python 编程经验,并对深度学习有初步了解。我们假设所有读者都能访问足够强大的设备以运行提供的代码。

如果你还没有合适的 GPU,建议使用GPU云服务。因为这是最快、相对低成本获得 GPU,且可以简单灵活完成配置的方式。Digital Ocean 的 GPU Droplets 提供 H100 实例,近期限时优惠仅需 2.5刀/小时,点击这里了解 GPU Droplets 更多信息。

关于如何开始使用 Python 代码,我们建议你尝试这个初学者指南,以设置你的系统并准备运行初学者教程。

先了解一些概念

神经网络是深度学习和人工智能未来中最引人入胜的话题之一。虽然“人工神经网络”一词只是受到生物神经元概念的启发,但在构建这些网络时有一些明显的相似之处值得注意。就像人类神经元一样,使用人工神经网络的有趣的地方在于,我们通常可以确定它们在做什么,但很难确切知道它们是如何工作并实现目标的。尽管我们可以回答一些“xx是什么”的问题,但要完全理解模型的行为仍需进一步探索。这就是“黑盒”深度学习的来源,这个称呼适用于许多深度学习系统。不过,有许多神经网络是可解释的,使我们能够轻松地解释其目的和方法,这也取决于具体的用例。

人工智能是一个涉猎广泛的领域,而深度学习和神经网络只是其中的两个子域。在本文中,我们的主要目标是深入理解神经网络的概念,并展示如何在不使用一些知名和流行的深度学习框架的情况下从零开始构建一个架构。在深入学习如何从零实现神经网络之前,让我们直观地了解它们的工作原理。

理解神经元的概念

大多数数学运算可以通过函数连接。函数是神经网络学习几乎任何事物的最基本概念之一。无论函数具体实现什么,神经网络都可以被设计成近似该函数。这便是著名的普遍近似定理,它赋予神经网络处理各种不同挑战的能力,同时也带来了黑盒的特性。

许多现实世界的问题,如计算机视觉任务和自然语言处理任务,也可以表示为相互关联的函数。例如,通过函数,我们可以将几个输入单词映射到特定的输出单词,或将一组图像与各自的输出图像相连。数学和现实世界问题中的大多数概念都可以被重构为函数,从而框定问题并让神经网络找到适当的解决方案。

什么是人工神经网络?它是如何工作的?

人工神经网络通常被称为神经网络、神经网或 NNs。这些网络受到生物神经元的启发。需要再次强调的是,实际上,生物神经元与用于构建神经网络架构的“神经元”之间几乎没有直接关联。尽管两者的基本工作方式截然不同,但它们的共同点在于,结合在一起时,这些“神经元”可以相对容易地解决复杂任务。

为了理解神经网络的基本工作原理,线性方程“y = mx + c”是帮助理解神经网络的关键数学概念之一。方程中的“y = mx”部分帮助操控线条,获得所需的形状和数值。而另一个值,截距“c”,则通过改变在 y 轴上的位置来调整线条的位置。请参见以下两张图,以更清楚地了解此基本概念。

在神经网络中,Y=WX+B可以用来表示这个方程,Y代表输出值,w代表需要调整的权重,x代表输入值,b代表值,通过使用这个简单的逻辑,神经网络可以使用已知的信息‘b’和‘w’来确定‘x’的值。

为了更好地理解权重和偏差这一特定概念,我们可以通过如下所示的简单代码片段和结果输出来进行探索。通过一些输入值、权重和偏差,我们可以使用输入值与权重转置值的点乘积来计算输出。在得到的结果值上,再添加相应的偏差来得到所需的值。下面的示例相对简单,但足以建立基本理解。不过,在下一节和即将发布的文章中,我们将介绍更复杂的概念。

import numpy as np
inputs = [1, 2, 3, 2.5]
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]
outputs = np.dot(weights, inputs) + biasesOr Use this methodnp.dot(inputs, weights.T) + biasesprint (outputs)

[4.8   1.21  2.385]

当神经网络组合在一起时,它们能够在反向传播的帮助下通过训练过程进行学习。第一步是前向传播,即通过使用随机权重计算每一层直到输出单元所需的信息。然而,这些随机权重通常永远不会接近完美,需要调整权重才能获得更理想的结果。因此,神经网络中的反向传播是其功能中更重要的方面之一。反向传播是操纵和调整权重的地方,通常通过比较手头的输出和预期的输出。我们将在下一节和即将发表的文章中进一步探讨这些概念。

从零开始构建神经网络

在本节中,我们将学习如何从零开始构建神经网络来解决一些任务。在开始构建神经网络之前,先了解我们要解决的问题类型。目标是构建能够理解和解决逻辑门功能的神经网络,例如 AND、OR、NOT、XOR 等逻辑门。对于这个特定示例,我们将研究如何通过从头构建神经网络来解决 XOR 门问题。

逻辑门是电子元件的基本构建块之一。选择这些逻辑门是因为每个门都基于特定的逻辑运行。例如,XOR 门仅在两个输入值不同时输出高电平;如果两个输入值相同,输出为低电平。这些逻辑通常通过真值表表示。上图展示了 XOR 门的符号和真值表表示。我们可以使用数组形式的输入和输出值来训练构建的神经网络,以获得理想结果。

首先,导入构建神经网络所需的库。在本节中,不使用任何深度学习框架,仅使用 NumPy 来简化复杂的张量和数学计算。即使没有 NumPy 库,你也可以选择手动构建神经网络,但这会耗费更多时间。本节唯一的其他库是 matplotlib,用于可视化损失并绘制模型在特定训练时期后的变化。

import numpy as np
import matplotlib.pyplot as plt

让我们描述真值表的输入和 XOR 门的预期输出。读者可以选择使用不同的门并进行相应的实验(请注意,有时你可能无法获得所需的结果)。以下是 XOR 门的输入变量和预期结果的代码片段。

a = np.array([0, 0, 1, 1])
b = np.array([0, 1, 0, 1])# y_and = np.array([[0, 0, 0, 1]])
y_xor = np.array([[0,1,1,0]])

让我们将输入组合成一个数组实体,这样我们就有了一个总输入数组和一个输出数组供神经网络学习。这个组合过程可以通过几种方式完成。在下面的代码块中,我们使用一个列表来组合两个数组,然后将最终列表转换回 numpy 数组格式。在下一节中,我还提到了另一种组合输入数据的方法。

total_input = []total_input = [a, b]total_input = np.array(total_input)

得到的输入数组如下所示:

array([[0, 0, 1, 1],[0, 1, 0, 1]])

对于大多数神经网络问题,数组的形状是最关键的概念。形状不匹配是解决此类任务时最有可能出现的错误。因此,让我们打印并分析输入数组的形状。

(2, 4)

现在让我们定义一些从头开始构建神经网络所需的基本参数。节点的激活函数定义给定一个输入或一组输入时该节点的输出。我们将首先定义 S 型函数,这将是我们执行此任务的主要激活函数。然后,我们将继续定义一些基本参数,例如输入神经元、隐藏神经元、输出神经元的数量、总训练样本以及我们将训练神经网络的学习效率。

# Define the sigmoid activation function:
def sigmoid (x):return 1/(1 + np.exp(-x))# Define the number of neurons
input_neurons, hidden_neurons, output_neurons = 2, 2, 1# Total training examples
samples = total_input.shape[1]# Learning rate
lr = 0.1# Define random seed to replicate the outputs
np.random.seed(42)

下一步,我们将初始化将通过隐藏层和输出层的权重,如下面的代码片段所示。随机化权重而不是为其分配零值通常是一个好主意,因为神经网络有时可能无法学习所需的结果。

# Initializing the weights for hidden and output layersw1 = np.random.rand(hidden_neurons, input_neurons)
w2 = np.random.rand(output_neurons, hidden_neurons)

在下一个代码块中,我们将定义神经网络模型的工作结构。首先,我们将使函数通过神经网络结构执行前向传播。我们将首先计算隐藏层中的权重和输入值,然后将它们传递给我们的 S 型激活函数。然后,我们也将对输出层执行类似的传播,其中我们将利用我们之前定义的第二个权重。随机生成的权重显然无法达到预期的结果,需要进行微调。因此,我们还将实现反向传播机制,以帮助我们的模型更有效地训练。此操作的执行方式与我们在上一节中讨论的方式类似。

# Forward propagation
def forward_prop(w1, w2, x):z1 = np.dot(w1, x)a1 = sigmoid(z1)z2 = np.dot(w2, a1)a2 = sigmoid(z2)return z1, a1, z2, a2# Backward propagation
def back_prop(m, w1, w2, z1, a1, z2, a2, y):dz2 = a2-ydw2 = np.dot(dz2, a1.T)/mdz1 = np.dot(w2.T, dz2) * a1*(1-a1)dw1 = np.dot(dz1, total_input.T)/mdw1 = np.reshape(dw1, w1.shape)dw2 = np.reshape(dw2,w2.shape)return dz2,dw2,dz1,dw1

现在我们已经定义了前向传播和后向传播机制,可以开始训练神经网络了。让我们进行一个训练循环,运行预定义的迭代次数。首先,我们利用前向传播来获取输出值,然后将其与预期输出进行比较,开始计算相应的损失。开始执行神经网络的反向传播后,我们就可以微调权重,以接近预期的最终结果。以下是训练过程的代码块,我们还确保损失不断减少,表明神经网络正在学习如何预测所需结果,并附带相应图表。

losses = []
iterations = 10000for i in range(iterations):z1, a1, z2, a2 = forward_prop(w1, w2, total_input)loss = -(1/samples)*np.sum(y_xor*np.log(a2)+(1-y_xor)*np.log(1-a2))losses.append(loss)da2, dw2, dz1, dw1 = back_prop(samples, w1, w2, z1, a1, z2, a2, y_xor)w2 = w2-lr*dw2w1 = w1-lr*dw1# We plot losses to see how our network is doing
plt.plot(losses)
plt.xlabel("EPOCHS")
plt.ylabel("Loss value")

让我们定义预测函数,通过该函数我们可以利用经过训练的神经网络来计算一些预测。我们将执行前向传播并压缩获得的结果。由于我们在训练过程中对权重进行了微调,因此我们应该能够以 0.5 的阈值实现所需的结果。

# Creating the predict functiondef predict(w1,w2,input):z1, a1, z2, a2 = forward_prop(w1,w2,test)a2 = np.squeeze(a2)if a2>=0.5:print("For input", [i[0] for i in input], "output is 1")else:print("For input", [i[0] for i in input], "output is 0")

现在我们已经完成了预测函数的定义,我们可以测试你构建的神经网络所做的预测,并在对模型进行约 10000 次迭代训练后查看其性能。我们将测试四种可能情况中的每一种预测结果,并将它们与 XOR 门的预期结果进行比较。

test = np.array([[0],[0]])
predict(w1,w2,test)
test = np.array([[0],[1]])
predict(w1,w2,test)
test = np.array([[1],[0]])
predict(w1,w2,test)
test = np.array([[1],[1]])
predict(w1,w2,test)

For input [0, 0] output is 0
For input [0, 1] output is 1
For input [1, 0] output is 1
For input [1, 1] output is 0

我们可以注意到,神经网络的预测结果与预期结果相似。因此可以得出结论,从零构建的神经网络成功地准确预测了 XOR 门任务。本节中的大部分代码参考了以下 GitHub 资源。如果你想要另一个学习资源,建议查看它。同时,鼓励读者通过从头构建神经网络来尝试解决不同类型的逻辑门,以探索它们的其他变体。

使用深度学习框架的构建进行比较

深度学习和人工神经网络的领域非常广阔。虽然可以从头开始构建神经网络来解决复杂的问题,但由于需要大量的时间以及需要构建的网络的固有复杂性,这通常是不可行的。因此,我们使用深度学习框架(如 TensorFlow、PyTorch、MXNet、Caffe 和其他类似的库(或工具))来设计、训练和验证神经网络模型。

这些深度学习框架允许开发人员和研究人员快速构建他们想要的模型来解决特定任务,而无需在复杂和不必要的细节的底层工作上投入太多。在众多可用的深度学习框架中,目前最流行的两种构建神经网络的工具是 TensorFlow 和 PyTorch。在本节中,我们将借助深度学习框架重建我们在前面几节中构建的项目。

对于这个重建项目,我将使用 TensorFlow 和 Keras 库。以下是我们用于构建神经网络以解决与门和异或门的导入列表。

import tensorflow as tf
from tensorflow import keras
import numpy as np

导入必要的库后,我们可以定义一些必需的参数,我们将利用这些参数构建神经网络来学习与门的输出。与与门类似,我们也将像上一节中那样构建异或门。首先,让我们看看与门的构造。下面是与门的输入和预期结果。与门的逻辑是,只有当两个(或所有)输入都为高时,输出才为高。否则,当任一输入为低时,输出也为低。

a = np.array([0, 0, 1, 1])
b = np.array([0, 1, 0, 1])y_and = np.array([0, 0, 0, 1])

我们声明了输入和预期输出,就该将两个输入数组组合成一个实体了。我们可以通过几种方法来实现这一点,如上一节所述。对于此代码片段,我们将它们附加到一个包含四个单独元素的列表中,每个列表都有两个元素。组合输入元素后获得的最终数组将存储在一个新数组中。

total_input = []for i, j in zip(a, b):input1 = []input1.append(i)input1.append(j)total_input.append(input1)
total_input = np.array(total_input)

两个初始输入列表组合后得到的输入数组如下所示。

array([[0, 0],[0, 1],[1, 0],[1, 1]])

这个最终输入数组的形状如下。

(4, 2)

下一步,我们将创建训练数据及其各自的输出标签。首先,我们将创建列表来存储输入和输出的训练数据。我们完成这些元素的循环后,我们就可以将这些列表保存为数组,并使用它们进行进一步的计算和神经网络训练。

x_train = []
y_train = []for i, j in zip(total_input, y_and):x_train.append(i)y_train.append(j)
x_train = np.array(x_train)
y_train = np.array(y_train)

此类任务的训练过程非常简单。我们可以定义所需的库,即输入层、隐藏层和输出节点的密集层,最后是顺序模型,以便我们可以构建顺序类型模型来解决所需的 AND 门任务。首先,我们将定义模型的类型,然后继续添加输入层,它将按照我们之前的定义接受输入。我们有两个隐藏层,每个隐藏层有十个节点,并带有 ReLU 激活函数。最终的输出层包含一个节点的 Sigmoid 激活函数,为我们提供所需的结果。根据提供的输入,最终输出为零或一。

from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Sequential
model = Sequential()
model.add(Input(shape = x_train[0].shape))
model.add(Dense(10, activation = "relu"))
model.add(Dense(10, activation = "relu"))
model.add(Dense(1, activation = "sigmoid"))
model.summary()

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
dense (Dense)                (None, 10)                30
_________________________________________________________________
dense_1 (Dense)              (None, 10)                110
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 11
=================================================================
Total params: 151
Trainable params: 151
Non-trainable params: 0
_________________________________________________________________

上表显示了包含隐藏层和输出节点及其各自参数的顺序类型网络的摘要。现在我们已经构建了模型架构来解决所需的 AND 门任务,我们可以继续编译模型并对其进行相应的训练。我们将利用 Adam 优化器、二元交叉熵损失函数,并计算二元准确度来验证我们的模型有多准确。

model.compile(optimizer = "adam", loss = "binary_crossentropy", metrics = "binary_accuracy")

模型编译完成,让我们开始训练过程,看看模型是否能够达到预期的结果。请注意,从头开始的神经网络的损失函数和优化器等内容尚未涵盖。我们将在未来的文章中介绍这些概念。下面是训练所需模型的代码片段。

model.fit(x_train, y_train, epochs = 500)

我们将对模型进行大约 500 个时期的训练,以确保它能够按预期学习要求。由于这些门控任务的数据较少,因此模型将需要更多的训练来学习并相应地优化结果。训练完成后(大约需要几分钟),我们可以继续使用预测函数来验证获得的结果。让我们对数据集执行预测,如下面的代码片段所示。

model.predict(x_train)

array([[0.00790971],[0.02351646],[0.00969902],[0.93897456]], dtype=float32)

我们可以注意到,AND 门的结果与预期的差不多。对于必须为零的输出值,预测得到的结果能够预测接近零的值,而对于必须为 1 的输出值,我们得到的结果接近 1。我们还可以对这些值进行四舍五入以获得所需的结果。除了我们刚刚完成的 AND 门之外,让我们探索另一个门。

同样,对于 XOR 门,我们也可以继续遵循与 AND 门类似的工作流程。首先,我们将定义 XOR 门所需的输入。它再次是一个 2 通道输入,利用变量 a 和 b 存储输入值。y 变量将把预期的结果值存储在 NumPy 数组中。我们将以类似于本节中使用的方法组合这两个输入数组。输入组合起来,我们得到了所需的组合,我们将数据分为训练输入信息及其结果标签输出。

a = np.array([0, 0, 1, 1])
b = np.array([0, 1, 0, 1])y_xor = np.array([0, 1, 1, 0])total_input = []for i, j in zip(a, b):input1 = []input1.append(i)input1.append(j)total_input.append(input1)total_input = np.array(total_input)x_train = []
y_train = []for i, j in zip(total_input, y_xor):x_train.append(i)y_train.append(j)x_train = np.array(x_train)
y_train = np.array(y_train)

我们将使用与本文本节前面类似的顺序类型架构。代码片段和模型的最终摘要如下所示:

model1 = Sequential()
model1.add(Input(shape = x_train[0].shape))
model1.add(Dense(10, activation = "relu"))
model1.add(Dense(10, activation = "relu"))
model1.add(Dense(1, activation = "sigmoid"))model1.summary()

Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
dense_3 (Dense)              (None, 10)                30
_________________________________________________________________
dense_4 (Dense)              (None, 10)                110
_________________________________________________________________
dense_5 (Dense)              (None, 1)                 11
=================================================================
Total params: 151
Trainable params: 151
Non-trainable params: 0
_________________________________________________________________

我们将定义优化器和损失函数等参数来编译模型,然后拟合模型。对于训练过程,我们将使用第二个模型和新的训练数据输入和输出进行训练。我们将对我们的模型进行一千次训练,然后获得最佳预测。由于要训练的数据样本相对较少,因此训练只需几分钟。

model1.compile(optimizer = "adam", loss = "binary_crossentropy", metrics = "binary_accuracy")model1.fit(x_train, y_train, epochs = 1000)

让我们对训练输入数据进行预测,并查看训练过程完成后模型能够预测的输出。

model1.predict(x_train)

array([[0.01542357],[0.995468  ],[0.99343044],[0.00554709]], dtype=float32)

我们可以注意到,输出值与相应的预期结果非常准确。当预期结果为零时,值更接近零,当预期结果为一时,值更接近一。最后,让我们分别对 AND 门和 XOR 门模型的两个预测值进行四舍五入。执行此步骤将帮助我们获得预期输出所需的单个整数值。

model.predict(x_train).round()
model1.predict(x_train).round()

array([[0.],[0.],[0.],[1.]], dtype=float32)

array([[0.],[1.],[1.],[0.]], dtype=float32)

我们可以注意到,经过训练的两个模型都能够利用提供的输入生成理想的输出。即使我们的数据量较少,经过长时间的训练,该模型也能够在减少损失的情况下实现预期结果。从头开始学习神经网络所有基本知识的工作原理是相当漫长的。优化器、损失函数、各种损失函数和其他类似主题等复杂概念将在未来的关于从头构建神经网络的文章中介绍。

结论

在本文中,我们展示了从头构建神经网络的大部分基本概念。在简要介绍之后,我们探讨了理解人工神经网络工作原理所需的一些关键要素。掌握了基本概念后,我们开始使用 NumPy 从头构建神经网络,并尝试了一个可以解决 XOR 门问题的 ANN。最后,我们还学习了如何使用深度学习框架(如 TensorFlow 和 Keras)构建 AND 和 XOR 等逻辑门的解决方案。

人工神经网络 (ANN) 和深度学习带来了一场革命,使机器能够完成一些曾经被认为不可能的复杂任务。成功的人工智能和神经网络之旅从简单的感知器模型开始,逐步迈向带有 n 个隐藏层的复杂架构。随着 GPU 的普及和经济实惠的计算资源的普及,任何有兴趣学习如何创建此类模型和框架的人都可以更容易地开始。神经网络的复杂性和概念繁多,尤其是当我们尝试从零开始构建这些网络时,就像我们在本文中所做的那样。在未来的部分中,我们将进一步探索从头构建神经网络的更多基础。

当然如果你还没找到合适的 GPU,但是有希望训练大模型,欢迎尝试 Digitalocean 的

在接下来的文章中,我们将研究更多生成对抗网络的变体,例如 pix-2-pix GAN、BERT Transformer,当然还有从头构建神经网络的第二部分。在此之前,继续探索和学习新知识吧!

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

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

相关文章

Conda安装与使用中的若干问题记录

Conda安装与使用中的若干问题记录 1.Anaconda 安装失败1.1.问题复述1.2.问题解决(安装建议) 2.虚拟环境pip install未安装至本虚拟环境2.1.问题复述2.2.问题解决 3.待补充 最近由于工作上的原因,要使用到Conda进行虚拟环境的管理,…

『OpenCV-Python』视频的读取和保存

点赞 + 关注 + 收藏 = 学会了 推荐关注 《OpenCV-Python专栏》 上一讲介绍了 OpenCV 的读取图片的方法,这一讲简单聊聊 OpenCV 读取和保存视频。 视频的来源主要有2种,一种是本地视频文件,另一种是实时视频流,比如手机和电脑的摄像头。 要读取这两种视频的方法都是一样的…

字节青训-字符串字符类型排序问题、小C点菜问题

目录 一、字符串字符类型排序问题 题目 样例 输入: 输出: 输入: 输出: 输入: 输出: 解题思路: 问题理解 数据结构选择 算法步骤 最终代码: 运行结果: ​…

深入理解接口测试:实用指南与最佳实践5.0(二)

✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…

CSS基础知识05(弹性盒子、布局详解,动画,3D转换,calc)

目录 0、弹性盒子、布局 0.1.弹性盒子的基本概念 0.2.弹性盒子的主轴和交叉轴 0.3.弹性盒子的属性 flex-direction row row-reverse column column-reverse flex-wrap nowrap wrap wrap-reverse flex-dirction和flex-wrap的组合简写模式 justify-content flex-s…

任务调度工具Spring Test

Spring Task 是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。 作用:定时自动执行某段Java代码 应用场景: 信用卡每月还款提醒 银行贷款每月还款提醒 火车票售票系统处理未支付订单 入职纪念日为用户发送通知 一.…

嵌入式硬件杂谈(二)-芯片输入接入0.1uf电容的本质(退耦电容)

引言:对于嵌入式硬件这个庞大的知识体系而言,太多离散的知识点很容易疏漏,因此对于这些容易忘记甚至不明白的知识点做成一个梳理,供大家参考以及学习,本文主要针对芯片输入接入0.1uf电容的本质的知识点的进行学习。 目…

数据结构(单向链表——c语言实现)

链式存储的优缺点: 优点: 1、动态分配内存: 链式存储不需要在数据插入之前分配固定大小的数组或内存块,因此它更适合存储动态变化的数据 2、高效的插入和删除操作: 在链表中插入或删除元素只需要调整相邻节点的指…

基于Spring Boot的电子商务平台架构

2 相关技术 2.1 SpringBoot框架介绍 Spring Boot是一种不需要代码生成的一种框架,并且可以不需要配置任何的XML文件就可以,因为Spring Boot里面自带了很多接口,只需要配置不同的接口就会自动的应用并且识别需要的依赖,在配置方面非…

Level DB --- Block

class Block class Block是Level DB里面的重要数据结构,该数据结构用来承载已经存储到文件中的数据。已经被存储的数据当需要再次加载、应用(例如搜索),这时首先要把数据加载、初始化到class Block里面。 数据的组织形式&#x…

记录大学Linux运维上机考试题目和流程

备注:今年的Linux操作系统考试已经全部结束,仅作为一个记录和留念 前提:配置环回网卡和环境和nat网卡 1、搭建dns服务器 2、Apache和http服务 3、搭建postfix邮件服务器实现邮件发送 4、搭建vsftpdFTP服务器实现文件上传 题目如下&…

前端面试笔试(四)

目录 一、数据结构算法等综合篇 1.线性探查法解决哈希冲突 2.请求分页系统中文件区和对换区 3.RADIUS认证协议,运行在哪个网络协议上 二、代码输出篇 1.res[1,2,100].map(parseInt) 如果我们想要输出为[1,2,100],可以: 还可以换map里…

NVR录像机汇聚管理EasyNVR多品牌NVR管理工具视频汇聚技术在智慧安防监控中的应用与优势

随着信息技术的快速发展和数字化时代的到来,安防监控领域也在不断进行技术创新和突破。NVR管理平台EasyNVR作为视频汇聚技术的领先者,凭借其强大的视频处理、汇聚与融合能力,展现出了在安防监控领域巨大的应用潜力和价值。本文将详细介绍Easy…

C/C++运行库

文章目录 入口函数glibc入口函数_start__libc_start_mainMSVC入口函数堆初始化IO初始化 glibc C运行库glibc启动文件gcc补充C全局构造与析构 运行库对于多线程的改进线程局部存储 入口函数 使用C语言编写的一个hello world程序在用户看来的确非常简单,源代码仅需要…

学习使用LVGL,依赖官方网址

LVGL Basics — LVGL documentation LVGL基础知识 LVGL是一个开源的图形库,提供创建嵌入式GUI的一切 LVGL数据流 您为每个物理显示面板 创建一个显示器 (lv_display) ,在其上创建屏幕小部件,将小部件添加到这些屏幕上。要处理触摸、鼠标、…

计算机网络HTTP——针对实习面试

目录 计算机网络HTTP什么是HTTP?HTTP和HTTPS有什么区别?分别说明HTTP/1.0、HTTP/2.0、HTTP/3.0请说明访问网页的全过程请说明HTTP常见的状态码Cookie和Session有什么区别?HTTP请求方式有哪些?请解释GET和POST的区别?HT…

大数据-226 离线数仓 - Flume 优化配置 自定义拦截器 拦截原理 了 拦截器实现 Java

点一下关注吧!!!非常感谢!!持续更新!!! Java篇开始了! 目前开始更新 MyBatis,一起深入浅出! 目前已经更新到了: Hadoop&#xff0…

无人机动力系统测试-实测数据与CFD模拟仿真数据关联对比分析

我们经常被问到这样的问题:“我们计划运行 CFD 仿真,我们还需要对电机和螺旋桨进行实验测试吗?我们可能有偏见,但我们的答案始终是肯定的,而且有充分的理由。我们自己执行了大量的 CFD 仿真,但我们承认&…

验证双随机矩阵(doubly stochastic matrix) 满足C(P)=C(P^T)

验证双随机矩阵(doubly stochastic matrix) 满足C( P P P)C(P T ^T T) 双随机矩阵: 在数学中,一个双随机矩阵(doubly stochastic matrix)是一个满足以下条件的矩阵: 非负矩阵:矩阵中的每个元素都是非负的…