探索 LeNet-5:卷积神经网络的先驱与手写数字识别传奇

一、引言

在当今深度学习技术蓬勃发展的时代,各种复杂而强大的神经网络架构不断涌现,如 ResNet、VGG、Transformer 等,它们在图像识别、自然语言处理、语音识别等众多领域都取得了令人瞩目的成果。然而,当我们回顾深度学习的发展历程时,不得不提到一个具有开创性意义的神经网络架构 ——LeNet-5。它是由 Yann LeCun 等人在 1998 年提出的,虽然在今天看来它的结构相对简单,但它却为后来深度学习的繁荣奠定了坚实的基础,尤其是在手写数字识别这一经典任务上,LeNet-5 展现出了卓越的性能,成为了计算机视觉领域的一座重要里程碑。

二、

一、引言

在当今深度学习技术蓬勃发展的时代,各种复杂而强大的神经网络架构不断涌现,如 ResNet、VGG、Transformer 等,它们在图像识别、自然语言处理、语音识别等众多领域都取得了令人瞩目的成果。然而,当我们回顾深度学习的发展历程时,不得不提到一个具有开创性意义的神经网络架构 ——LeNet-5。它是由 Yann LeCun 等人在 1998 年提出的,虽然在今天看来它的结构相对简单,但它却为后来深度学习的繁荣奠定了坚实的基础,尤其是在手写数字识别这一经典任务上,LeNet-5 展现出了卓越的性能,成为了计算机视觉领域的一座重要里程碑。

二、LeNet-5 网络架构剖析

(一)输入层

LeNet-5 的输入是手写数字的图像,通常为 32x32 的灰度图像。这一尺寸的选择是经过精心设计的,既能够保留足够的数字特征信息,又在当时的计算资源限制下能够进行有效的处理。

(二)卷积层 C1

这是网络的第一个卷积层,它使用了 6 个大小为 5x5 的卷积核,步长为 1。卷积操作后得到 6 个大小为 28x28 的特征图(因为 (32 - 5 + 1) = 28)。每个卷积核都在学习图像中的不同局部特征,例如边缘、线条等。在这一层,还会进行偏置的添加以及通过激活函数(通常为 Sigmoid 函数)进行非线性变换,以增强网络的表达能力。以下是使用 Python 和 TensorFlow 框架实现 C1 层的示例代码:

收起

python

import tensorflow as tf# 定义输入图像占位符,形状为 [None, 32, 32, 1],None 表示批次大小可以动态变化
input_images = tf.placeholder(tf.float32, [None, 32, 32, 1])# 定义 C1 层的卷积核
weights_c1 = tf.Variable(tf.truncated_normal([5, 5, 1, 6], stddev=0.1))
biases_c1 = tf.Variable(tf.constant(0.1, shape=[6]))# 进行卷积操作
conv1 = tf.nn.conv2d(input_images, weights_c1, strides=[1, 1, 1, 1], padding='VALID')
# 添加偏置
conv1 = tf.nn.bias_add(conv1, biases_c1)
# 使用 Sigmoid 激活函数
c1_output = tf.nn.sigmoid(conv1)

(三)池化层 S2

S2 层是一个下采样层,采用了平均池化操作,池化核大小为 2x2,步长为 2。这一层的作用是对 C1 层输出的特征图进行降维,减少数据量,同时保留主要的特征信息。经过池化后,6 个特征图的大小变为 14x14。以下是 S2 层的代码实现:

收起

python

# 定义 S2 层的池化操作
pool2 = tf.nn.avg_pool(c1_output, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')

(四)卷积层 C3

C3 层使用了 16 个大小为 5x5 的卷积核,步长为 1。它的输入是 S2 层的输出,通过卷积操作得到 16 个大小为 10x10 的特征图。这一层的卷积核设计与 C1 层有所不同,它与 S2 层的某些特征图进行组合连接,这种连接方式有助于网络学习到更复杂的特征组合。示例代码如下:

收起

python

# 定义 C3 层的卷积核
weights_c3 = tf.Variable(tf.truncated_normal([5, 5, 6, 16], stddev=0.1))
biases_c3 = tf.Variable(tf.constant(0.1, shape=[16]))# 进行卷积操作
conv3 = tf.nn.conv2d(pool2, weights_c3, strides=[1, 1, 1, 1], padding='VALID')
# 添加偏置
conv3 = tf.nn.bias_add(conv3, biases_c3)
# 使用 Sigmoid 激活函数
c3_output = tf.nn.sigmoid(conv3)

(五)池化层 S4

S4 层同样是平均池化层,池化核大小为 2x2,步长为 2,对 C3 层的输出进行下采样,得到 16 个大小为 5x5 的特征图。代码实现如下:

收起

python

# 定义 S4 层的池化操作
pool4 = tf.nn.avg_pool(c3_output, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')

(六)卷积层 C5

C5 层使用了 120 个大小为 5x5 的卷积核,步长为 1,对 S4 层的输出进行卷积操作,得到 120 个大小为 1x1 的特征图,此时数据已经被高度抽象化。代码如下:

收起

python

# 定义 C5 层的卷积核
weights_c5 = tf.Variable(tf.truncated_normal([5, 5, 16, 120], stddev=0.1))
biases_c5 = tf.Variable(tf.constant(0.1, shape=[120]))# 进行卷积操作
conv5 = tf.nn.conv2d(pool4, weights_c5, strides=[1, 1, 1, 1], padding='VALID')
# 添加偏置
conv5 = tf.nn.bias_add(conv5, biases_c5)
# 使用 Sigmoid 激活函数
c5_output = tf.nn.sigmoid(conv5)

(七)全连接层 F6

F6 层是一个全连接层,它将 C5 层的 120 个神经元与 84 个神经元进行全连接,通过权重矩阵和偏置向量进行线性变换,并使用 Sigmoid 激活函数进行非线性变换。这一层进一步对特征进行整合和映射,提取更高级的特征表示。示例代码:

收起

python

# 将 C5 层的输出展平为一维向量
flattened = tf.reshape(c5_output, [-1, 120])# 定义 F6 层的权重和偏置
weights_f6 = tf.Variable(tf.truncated_normal([120, 84], stddev=0.1))
biases_f6 = tf.Variable(tf.constant(0.1, shape=[84]))# 进行全连接操作
f6_output = tf.nn.sigmoid(tf.matmul(flattened, weights_f6) + biases_f6)

(八)输出层

输出层由 10 个神经元组成,对应于 0 - 9 这 10 个数字类别。采用 softmax 激活函数将神经元的输出转换为每个类别的概率分布,从而确定输入图像最可能属于的数字类别。代码如下:

收起

python

# 定义输出层的权重和偏置
weights_out = tf.Variable(tf.truncated_normal([84, 10], stddev=0.1))
biases_out = tf.Variable(tf.constant(0.1, shape=[10]))# 进行全连接操作并使用 softmax 激活函数
logits = tf.matmul(f6_output, weights_out) + biases_out
output = tf.nn.softmax(logits)

三、LeNet-5 在手写数字识别中的训练与应用

(一)数据集准备

常用的手写数字识别数据集是 MNIST 数据集,它包含了大量的手写数字图像及其对应的标签。在使用前,需要对数据集进行加载、预处理,例如将图像数据归一化到 0 - 1 之间,将标签进行 one-hot 编码等操作。以下是使用 TensorFlow 加载和预处理 MNIST 数据集的示例代码:

收起

python

from tensorflow.examples.tutorials.mnist import input_data# 加载 MNIST 数据集
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)# 获取训练集和测试集数据
train_images = mnist.train.images.reshape(-1, 32, 32, 1)
train_labels = mnist.train.labels
test_images = mnist.test.images.reshape(-1, 32, 32, 1)
test_labels = mnist.test.labels

(二)损失函数与优化器选择

在训练 LeNet-5 网络时,通常采用交叉熵损失函数来衡量模型预测结果与真实标签之间的差异。对于优化器,可以选择随机梯度下降(SGD)、Adagrad、Adadelta、Adam 等。这里以 Adam 优化器为例,示例代码如下:

收起

python

# 定义损失函数为交叉熵
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=train_labels))# 选择 Adam 优化器并设置学习率
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)

(三)模型训练与评估

通过循环迭代训练数据集,不断更新网络的权重和偏置,使损失函数逐渐减小。在训练过程中,可以定期在测试集上评估模型的准确率,以监控模型的训练效果。以下是训练和评估模型的示例代码:

收起

python

# 初始化 TensorFlow 会话
with tf.Session() as sess:sess.run(tf.global_variables_initializer())# 训练循环for epoch in range(10):  # 假设训练 10 个轮次total_loss = 0for i in range(len(train_images) // batch_size):  # 按批次训练batch_images = train_images[i * batch_size:(i + 1) * batch_size]batch_labels = train_labels[i * batch_size:(i + 1) * batch_size]# 运行优化器并计算损失_, batch_loss = sess.run([optimizer, loss], feed_dict={input_images: batch_images, train_labels: batch_labels})total_loss += batch_loss# 计算平均损失average_loss = total_loss / (len(train_images) // batch_size)print(f"Epoch {epoch + 1}, Average Loss: {average_loss}")# 在测试集上评估模型准确率correct_prediction = tf.equal(tf.argmax(output, 1), tf.argmax(test_labels, 1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))test_accuracy = sess.run(accuracy, feed_dict={input_images: test_images, train_labels: test_labels})print(f"Test Accuracy: {test_accuracy}")

四、LeNet-5 的影响与现代拓展

(一)对深度学习发展的深远影响

LeNet-5 的出现为深度学习的发展提供了重要的思路和实践经验。它证明了卷积神经网络在图像识别任务中的有效性,为后续众多神经网络架构的设计提供了参考范例。其引入的卷积层、池化层等基本结构组件成为了现代深度学习架构的标配,推动了深度学习在计算机视觉、语音识别、自然语言处理等多个领域的广泛应用和深入研究。

(二)现代拓展与改进

随着计算能力的大幅提升和数据量的爆炸式增长,现代神经网络在 LeNet-5 的基础上进行了大量的拓展和改进。例如,网络深度不断增加,出现了更深层次的架构如 AlexNet、VGGNet、ResNet 等,这些架构能够学习到更复杂、更抽象的特征表示,从而在各种图像识别任务中取得了更高的准确率。同时,在激活函数方面,也逐渐从 Sigmoid 函数转向了 ReLU 函数及其变种,有效缓解了梯度消失问题,提高了网络的训练效率。此外,在优化算法、正则化技术、数据增强等方面也都有了长足的发展,使得神经网络的性能得到了进一步提升。

五、结论

LeNet-5 作为卷积神经网络的先驱,在手写数字识别领域以及整个深度学习发展历程中都占据着不可替代的重要地位。它的网络架构设计简洁而有效,为我们理解卷积神经网络的工作原理提供了一个清晰的范例。虽然在现代深度学习的浪潮中,LeNet-5 的性能已经无法与更为先进的架构相媲美,但它所蕴含的创新思想和技术贡献却永远铭刻在深度学习的发展史上。通过对 LeNet-5 的深入研究,我们能够更好地把握深度学习的发展脉络,为未来神经网络架构的创新和应用开发提供有益的启示和借鉴。无论是对于深度学习的初学者还是专业研究人员,LeNet-5 都是一个值得深入学习和探究的经典之作。

(一)输入层

LeNet-5 的输入是手写数字的图像,通常为 32x32 的灰度图像。这一尺寸的选择是经过精心设计的,既能够保留足够的数字特征信息,又在当时的计算资源限制下能够进行有效的处理。

(二)卷积层 C1

这是网络的第一个卷积层,它使用了 6 个大小为 5x5 的卷积核,步长为 1。卷积操作后得到 6 个大小为 28x28 的特征图(因为 (32 - 5 + 1) = 28)。每个卷积核都在学习图像中的不同局部特征,例如边缘、线条等。在这一层,还会进行偏置的添加以及通过激活函数(通常为 Sigmoid 函数)进行非线性变换,以增强网络的表达能力。以下是使用 Python 和 TensorFlow 框架实现 C1 层的示例代码:

import tensorflow as tf# 定义输入图像占位符,形状为 [None, 32, 32, 1],None 表示批次大小可以动态变化
input_images = tf.placeholder(tf.float32, [None, 32, 32, 1])# 定义 C1 层的卷积核
weights_c1 = tf.Variable(tf.truncated_normal([5, 5, 1, 6], stddev=0.1))
biases_c1 = tf.Variable(tf.constant(0.1, shape=[6]))# 进行卷积操作
conv1 = tf.nn.conv2d(input_images, weights_c1, strides=[1, 1, 1, 1], padding='VALID')
# 添加偏置
conv1 = tf.nn.bias_add(conv1, biases_c1)
# 使用 Sigmoid 激活函数
c1_output = tf.nn.sigmoid(conv1)

(三)池化层 S2

S2 层是一个下采样层,采用了平均池化操作,池化核大小为 2x2,步长为 2。这一层的作用是对 C1 层输出的特征图进行降维,减少数据量,同时保留主要的特征信息。经过池化后,6 个特征图的大小变为 14x14。以下是 S2 层的代码实现:

# 定义 S2 层的池化操作
pool2 = tf.nn.avg_pool(c1_output, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')

(四)卷积层 C3

C3 层使用了 16 个大小为 5x5 的卷积核,步长为 1。它的输入是 S2 层的输出,通过卷积操作得到 16 个大小为 10x10 的特征图。这一层的卷积核设计与 C1 层有所不同,它与 S2 层的某些特征图进行组合连接,这种连接方式有助于网络学习到更复杂的特征组合。示例代码如下:

# 定义 C3 层的卷积核
weights_c3 = tf.Variable(tf.truncated_normal([5, 5, 6, 16], stddev=0.1))
biases_c3 = tf.Variable(tf.constant(0.1, shape=[16]))# 进行卷积操作
conv3 = tf.nn.conv2d(pool2, weights_c3, strides=[1, 1, 1, 1], padding='VALID')
# 添加偏置
conv3 = tf.nn.bias_add(conv3, biases_c3)
# 使用 Sigmoid 激活函数
c3_output = tf.nn.sigmoid(conv3)

(五)池化层 S4

S4 层同样是平均池化层,池化核大小为 2x2,步长为 2,对 C3 层的输出进行下采样,得到 16 个大小为 5x5 的特征图。代码实现如下:

# 定义 S4 层的池化操作
pool4 = tf.nn.avg_pool(c3_output, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')

(六)卷积层 C5

C5 层使用了 120 个大小为 5x5 的卷积核,步长为 1,对 S4 层的输出进行卷积操作,得到 120 个大小为 1x1 的特征图,此时数据已经被高度抽象化。代码如下:

# 定义 C5 层的卷积核
weights_c5 = tf.Variable(tf.truncated_normal([5, 5, 16, 120], stddev=0.1))
biases_c5 = tf.Variable(tf.constant(0.1, shape=[120]))# 进行卷积操作
conv5 = tf.nn.conv2d(pool4, weights_c5, strides=[1, 1, 1, 1], padding='VALID')
# 添加偏置
conv5 = tf.nn.bias_add(conv5, biases_c5)
# 使用 Sigmoid 激活函数
c5_output = tf.nn.sigmoid(conv5)

(七)全连接层 F6

F6 层是一个全连接层,它将 C5 层的 120 个神经元与 84 个神经元进行全连接,通过权重矩阵和偏置向量进行线性变换,并使用 Sigmoid 激活函数进行非线性变换。这一层进一步对特征进行整合和映射,提取更高级的特征表示。示例代码:

# 将 C5 层的输出展平为一维向量
flattened = tf.reshape(c5_output, [-1, 120])# 定义 F6 层的权重和偏置
weights_f6 = tf.Variable(tf.truncated_normal([120, 84], stddev=0.1))
biases_f6 = tf.Variable(tf.constant(0.1, shape=[84]))# 进行全连接操作
f6_output = tf.nn.sigmoid(tf.matmul(flattened, weights_f6) + biases_f6)

(八)输出层

输出层由 10 个神经元组成,对应于 0 - 9 这 10 个数字类别。采用 softmax 激活函数将神经元的输出转换为每个类别的概率分布,从而确定输入图像最可能属于的数字类别。代码如下:

# 定义输出层的权重和偏置
weights_out = tf.Variable(tf.truncated_normal([84, 10], stddev=0.1))
biases_out = tf.Variable(tf.constant(0.1, shape=[10]))# 进行全连接操作并使用 softmax 激活函数
logits = tf.matmul(f6_output, weights_out) + biases_out
output = tf.nn.softmax(logits)

三、LeNet-5 在手写数字识别中的训练与应用

(一)数据集准备

常用的手写数字识别数据集是 MNIST 数据集,它包含了大量的手写数字图像及其对应的标签。在使用前,需要对数据集进行加载、预处理,例如将图像数据归一化到 0 - 1 之间,将标签进行 one-hot 编码等操作。以下是使用 TensorFlow 加载和预处理 MNIST 数据集的示例代码:

from tensorflow.examples.tutorials.mnist import input_data# 加载 MNIST 数据集
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)# 获取训练集和测试集数据
train_images = mnist.train.images.reshape(-1, 32, 32, 1)
train_labels = mnist.train.labels
test_images = mnist.test.images.reshape(-1, 32, 32, 1)
test_labels = mnist.test.labels

(二)损失函数与优化器选择

在训练 LeNet-5 网络时,通常采用交叉熵损失函数来衡量模型预测结果与真实标签之间的差异。对于优化器,可以选择随机梯度下降(SGD)、Adagrad、Adadelta、Adam 等。这里以 Adam 优化器为例,示例代码如下:

# 定义损失函数为交叉熵
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=train_labels))# 选择 Adam 优化器并设置学习率
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)

(三)模型训练与评估

通过循环迭代训练数据集,不断更新网络的权重和偏置,使损失函数逐渐减小。在训练过程中,可以定期在测试集上评估模型的准确率,以监控模型的训练效果。以下是训练和评估模型的示例代码:

# 初始化 TensorFlow 会话
with tf.Session() as sess:sess.run(tf.global_variables_initializer())# 训练循环for epoch in range(10):  # 假设训练 10 个轮次total_loss = 0for i in range(len(train_images) // batch_size):  # 按批次训练batch_images = train_images[i * batch_size:(i + 1) * batch_size]batch_labels = train_labels[i * batch_size:(i + 1) * batch_size]# 运行优化器并计算损失_, batch_loss = sess.run([optimizer, loss], feed_dict={input_images: batch_images, train_labels: batch_labels})total_loss += batch_loss# 计算平均损失average_loss = total_loss / (len(train_images) // batch_size)print(f"Epoch {epoch + 1}, Average Loss: {average_loss}")# 在测试集上评估模型准确率correct_prediction = tf.equal(tf.argmax(output, 1), tf.argmax(test_labels, 1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))test_accuracy = sess.run(accuracy, feed_dict={input_images: test_images, train_labels: test_labels})print(f"Test Accuracy: {test_accuracy}")

四、LeNet-5 的影响与现代拓展

(一)对深度学习发展的深远影响

LeNet-5 的出现为深度学习的发展提供了重要的思路和实践经验。它证明了卷积神经网络在图像识别任务中的有效性,为后续众多神经网络架构的设计提供了参考范例。其引入的卷积层、池化层等基本结构组件成为了现代深度学习架构的标配,推动了深度学习在计算机视觉、语音识别、自然语言处理等多个领域的广泛应用和深入研究。

(二)现代拓展与改进

随着计算能力的大幅提升和数据量的爆炸式增长,现代神经网络在 LeNet-5 的基础上进行了大量的拓展和改进。例如,网络深度不断增加,出现了更深层次的架构如 AlexNet、VGGNet、ResNet 等,这些架构能够学习到更复杂、更抽象的特征表示,从而在各种图像识别任务中取得了更高的准确率。同时,在激活函数方面,也逐渐从 Sigmoid 函数转向了 ReLU 函数及其变种,有效缓解了梯度消失问题,提高了网络的训练效率。此外,在优化算法、正则化技术、数据增强等方面也都有了长足的发展,使得神经网络的性能得到了进一步提升。

五、结论

LeNet-5 作为卷积神经网络的先驱,在手写数字识别领域以及整个深度学习发展历程中都占据着不可替代的重要地位。它的网络架构设计简洁而有效,为我们理解卷积神经网络的工作原理提供了一个清晰的范例。虽然在现代深度学习的浪潮中,LeNet-5 的性能已经无法与更为先进的架构相媲美,但它所蕴含的创新思想和技术贡献却永远铭刻在深度学习的发展史上。通过对 LeNet-5 的深入研究,我们能够更好地把握深度学习的发展脉络,为未来神经网络架构的创新和应用开发提供有益的启示和借鉴。无论是对于深度学习的初学者还是专业研究人员,LeNet-5 都是一个值得深入学习和探究的经典之作。

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

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

相关文章

【数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】

目录😋 任务描述 相关知识 测试说明 我的通关代码: 测试结果: 任务描述 本关任务:编写一个程序实现链栈的基本运算。 相关知识 为了完成本关任务,你需要掌握: 初始化栈、销毁栈、判断栈是否为空、进栈、出栈、取栈…

【笔记】架构上篇Day6 法则四:为什么要顺应技术的生命周期?

法则四:为什么要顺应技术的生命周期? 简介:包含模块一 架构师的六大生存法则-法则四:为什么要顺应技术的生命周期?&法则四:架构设计中怎么判断和利用技术趋势? 2024-08-29 17:30:07 你好&am…

Security自定义逻辑认证(极简案例)

项目结构 config SecurityConfig package com.wunaiieq.tmp2024121105.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.password.NoOpPasswordEnco…

docker安装ddns-go(外网连接局域网)

docker先下载镜像,目前最新版是v6.7.6 也可以csdn资源下载 再导入dockers https://download.csdn.net/download/u014756339/90096748 docker load -i ddns-go.tar 启动 docker run -d --name ddns-go --restartalways --nethost -v /opt/ddns-go:/root jeessy/…

技术速递|dotnet scaffold – .NET 的下一代内容创建

作者:Sayed Ibrahim Hashimi - 首席项目经理 排版:Alan Wang Visual Studio 中为 ASP.NET Core 项目搭建脚手架是一项长期特性,是在 ASP.NET Core 发布后不久添加的。多年来,我们一直支持从命令行搭建脚手架。根据从命令行操作中获…

基于ZYNQ 7z010开发板 oled点亮的实现

dc拉高的时候就是发送128字节数据的时候 发送指令dc拉低 模式是00 sck先置低再置高 复位是与开发板上的按键一样都是低有效 25位字节指令 加 3字节的 页地址加起始结束 b0,00,10, timescale 1ns / 1ps module top0(input wire clk ,input wire rst_n,// out…

使用torch模拟 BMM int8量化计算。

使用torch模型BMM int8计算。 模拟:BMM->softmax->BMM 计算流程 import torch import numpy as np torch.manual_seed(777) def int8_quantize_per_token(x: torch.Tensor, axis: int -1, attnsFalse):if x.dtype ! torch.float32:x x.type(torch.float32)…

【CSS in Depth 2 精译_070】11.3 利用 OKLCH 颜色值来处理 CSS 中的颜色问题(下):从页面其他颜色衍生出新颜色

当前内容所在位置(可进入专栏查看其他译好的章节内容) 第四部分 视觉增强技术 ✔️【第 11 章 颜色与对比】 ✔️ 11.1 通过对比进行交流 11.1.1 模式的建立11.1.2 还原设计稿 11.2 颜色的定义 11.2.1 色域与色彩空间11.2.2 CSS 颜色表示法 11.2.2.1 RGB…

HTML:表格重点

用表格就用table caption为该表上部信息,用来说明表的作用 thead为表头主要信息,效果加粗 tbody为表格中的主体内容 tr是 table row 表格的行 td是table data th是table heading表格标题 ,一般表格第一行的数据都是table heading

15.Java 网络编程(网络相关概念、InetAddress、NetworkInterface、TCP 网络通信、UDP 网络通信、超时中断)

一、网络相关概念 1、网络通信 网络通信指两台设备之间通过网络实现数据传输,将数据通过网络从一台设备传输到另一台设备 java.net 包下提供了一系列的类和接口用于完成网络通信 2、网络 两台以上设备通过一定物理设备连接构成网络,根据网络的覆盖范…

项目中使用AntV L7地图(五)添加飞线

项目中使用AntV L7地图,添加 飞线 文档地址:https://l7.antv.antgroup.com/zh/examples/line/animate/#trip_animate 一、初始化地图 使用的地图文件为四川地图JSON,下载地址:https://datav.aliyun.com/portal/school/atlas/area_selector#&…

MySQL-DQL之数据表操作

文章目录 零. 准备工作一. 简单查询1.查询所有的商品.2.查询商品名和商品价格.3.查询结果是表达式(运算查询):将所有商品的价格10元进行显示. 二. 条件查询1. 比较查询2. 范围查询3. 逻辑查询4. 模糊查询5. 非空查询 三. 排序查询四. 聚合查询…

nacos bootstrap.yml 和 spring.config.import 加载配置的流程区别

相关依赖 springboot:2.7.15 nacos:2.2.3 bootstrap.yml加载方式 加载流程如下图所示 从图中可以看出,: 1.bootstrap.yml 的加载是在 BootstrapApplicationListener.onApplicationEvent 接收到 ApplicationEnvironmentPreparedEventEvent 事件后另起一个 Sprin…

Kubernetes Nginx-Ingress | 禁用HSTS/禁止重定向到https

目录 前言禁用HSTS禁止重定向到https关闭 HSTS 和设置 ssl-redirect 为 false 的区别 前言 客户请求经过ingress到服务后,默认加上了strict-transport-security,导致客户服务跨域请求失败,具体Response Headers信息如下; 分析 n…

关于idea-Java-servlet-Tomcat-Web开发中出现404NOT FOUND问题的解决

在做web项目时,第一次使用servlet开发链接前端和后端的操作,果不其然,遇到了诸多问题,而遇到最多的就是运行项目打开页面时出现404NOT FOUND的情况。因为这个问题我也是鼓捣了好久,上网查了许多资料才最终解决&#xf…

开发一套SDK 第一弹

自动安装依赖包 添加条件使能 #ex: filetypesh bash_ls 识别 达到预期,多个硬件环境 等待文件文件系统挂在完成 或者创建 /sys/class/ 属性文件灌入配置操作 AI 提供的 netlink 调试方法,也是目前主流调用方法,socket yyds #include <linux/module.h> #include <linux…

深入理解 Apache Shiro:安全框架全解析

亲爱的小伙伴们&#x1f618;&#xff0c;在求知的漫漫旅途中&#xff0c;若你对深度学习的奥秘、JAVA 、PYTHON与SAP 的奇妙世界&#xff0c;亦或是读研论文的撰写攻略有所探寻&#x1f9d0;&#xff0c;那不妨给我一个小小的关注吧&#x1f970;。我会精心筹备&#xff0c;在…

【PlantUML系列】流程图(四)

目录 目录 一、基础用法 1.1 开始和结束 1.2 操作步骤 1.3 条件判断 1.4 并行处理 1.5 循环 1.6 分区 1.7 泳道 一、基础用法 1.1 开始和结束 开始一般使用start关键字&#xff1b;结束一般使用stop/end关键字。基础用法包括&#xff1a; start ... stopstart ...…

Mac 录制电脑系统内的声音的具体方法?

1.第一步&#xff1a;下载BlackHole 软件 方式1&#xff1a;BlackHole官方下载地址 方式2&#xff1a; 百度云下载 提取码: n5dp 2.第二步&#xff1a;安装BlackHole 双击下载好的BlackHole安装包&#xff0c;安装默认提示安装。 3.第三步&#xff1a;在应用程序中找到音频…

Unity简单操作及使用教程

Unity 是一款强大的跨平台游戏引擎&#xff0c;它不仅支持 2D 和 3D 游戏的开发&#xff0c;还可以用于虚拟现实 (VR)、增强现实 (AR)、动画、建筑可视化等多个领域。Unity 提供了完整的开发环境&#xff0c;具有丰富的功能、工具和资源&#xff0c;可以帮助开发者快速实现创意…