TensorFlow深度学习实战(8)——卷积神经网络

TensorFlow深度学习实战(8)——卷积神经网络

    • 0. 前言
    • 1. 全连接网络的缺陷
    • 2. 卷积神经网络
      • 2.1 卷积神经网络的基本概念
      • 2.2 TensorFlow 中的卷积层
      • 2.3 TensorFlow 中的池化层
      • 2.4 卷积神经网络总结
    • 3. 构建卷积神经网络
      • 3.1 LeNet
      • 3.2 使用 TensorFlow 实现 LeNet
    • 4. 深度卷积神经网络优势
    • 小结
    • 系列链接

0. 前言

卷积神经网络 (Convolutional Neural Network, CNN) 是一种非常强大的深度学习模型,广泛应用于图像分析、目标检测、图像生成等任务中。CNN 的核心思想是卷积操作和参数共享,卷积操作通过滑动滤波器(也称为卷积核)在输入数据上进行元素级的乘积和求和运算,从而提取局部特征。通过多个滤波器的组合,CNN 可以学习到不同层次的特征表示,从低级到高级的抽象特征。本节从传统全连接神经网络的缺陷为切入点,介绍了卷积神经网络的优势及其基本组件,并使用 TensorFlow 构建卷积神经网络。

1. 全连接网络的缺陷

在全连接网络中每一网络层的神经元都与相邻层的神经元相连接,在使用全连接网络分类 MNIST 手写数字数据集中,输入图像中的每个像素都输入到一个神经元中,共有 784 个( 28 x 28 像素)输入神经元。然而,这种网络未能利用图像之间的空间结构和关系。由于全连接会将每个手写数字图像转换为一个扁平向量,从而移除了局部的空间结构,导致失去了重要的信息:

X_train = X_train.reshape(60000, 784)
X_test = X_test.reshape(10000, 784)

卷积神经网络能够利用空间信息,因此非常适合用于图像分类。这类网络借鉴了人类视觉系统的特性,生物学研究表明,人类的视觉系统基于多个层次,能够识别越来越多的结构化信息。首先观察到单个像素,然后从中识别简单的几何形状,然后是更复杂的元素,如物体、面孔、人体、动物等等。
卷积神经网络已经在多个领域(从文本到视频再到语音)具备了超出人类水平的性能表现。接下来,我们将介绍卷积神经网络的原理,并使用 Tensorflow 构建卷积神经网络。

2. 卷积神经网络

卷积神经网络 (Convolutional Neural Network, CNN) 由多个神经网络层构成,通常交替使用两种不同类型的层:卷积层和池化层,最后通常由一个或多个全连接层组成。

2.1 卷积神经网络的基本概念

2.1.1 卷积

如果我们希望保留图像(或其他形式数据)的空间信息,那么就需要用像素矩阵表示每个图像。这种情况下,编码局部结构的简单方法是将相邻输入神经元的子矩阵连接成下一层中的一个隐藏神经元,单个隐藏神经元代表一个局部感知野,这一操作称为卷积,这也是卷积神经网络名称的由来。
卷积是两个矩阵间的乘法——通常一个矩阵具有较大尺寸,另一个矩阵则较小。要了解卷积,首先讲解以下示例。给定矩阵 A 和矩阵 B 如下:

矩阵

在进行卷积时,我们将较小的矩阵在较大的矩阵上滑动,在上述两个矩阵中,当较小的矩阵 B 需要在较大矩阵 A 的整个区域上滑动时,会得到 9 次乘法运算,过程如下。
在矩阵 A 中从第 1 个元素开始选取与矩阵 B 相同尺寸的子矩阵 [ 1 2 0 1 1 1 3 3 2 ] \left[ \begin{array}{ccc} 1 & 2 & 0\\ 1 & 1 & 1\\ 3 & 3 & 2\\\end{array}\right] 113213012 和矩阵 B 相乘并求和:

卷积-1

1 × 3 + 2 × 1 + 0 × 1 + 1 × 2 + 1 × 3 + 1 × 1 + 3 × 2 + 3 × 2 + 2 × 3 = 29 1\times 3+2\times 1+0\times 1+1\times 2+1\times 3+1\times 1+3\times 2+3\times 2 + 2\times 3=29 1×3+2×1+0×1+1×2+1×3+1×1+3×2+3×2+2×3=29

然后,向右滑动一个窗口,选择第 2 个与矩阵 B 相同尺寸的子矩阵 [ 2 0 2 1 1 2 3 2 1 ] \left[ \begin{array}{ccc} 2 & 0 & 2\\ 1 & 1 & 2\\ 3 & 2 & 1\\\end{array}\right] 213012221 和矩阵 B 相乘并求和:

卷积-2

2 × 3 + 0 × 1 + 2 × 1 + 1 × 2 + 1 × 3 + 2 × 1 + 3 × 2 + 2 × 2 + 1 × 3 = 28 2\times 3+0\times 1+2\times 1+1\times 2+1\times 3+2\times 1+3\times 2+2\times 2 + 1\times 3=28 2×3+0×1+2×1+1×2+1×3+2×1+3×2+2×2+1×3=28

然后,再向右滑动一个窗口,选择第 3 个与矩阵 B 相同尺寸的子矩阵 [ 0 2 3 1 2 0 2 1 2 ] \left[ \begin{array}{ccc} 0 & 2 & 3\\ 1 & 2 & 0\\ 2 & 1 & 2\\\end{array}\right] 012221302 和矩阵 B 相乘并求和:

卷积-3

0 × 3 + 2 × 1 + 3 × 1 + 1 × 2 + 2 × 3 + 0 × 1 + 2 × 2 + 1 × 2 + 2 × 3 = 25 0\times 3+2\times 1+3\times 1+1\times 2+2\times 3+0\times 1+2\times 2+1\times 2 + 2\times 3=25 0×3+2×1+3×1+1×2+2×3+0×1+2×2+1×2+2×3=25

当向右滑到尽头时,向下滑动一个窗口,并从矩阵 A 左边开始,选择第 4 个与矩阵 B 相同尺寸的子矩阵 [ 1 1 1 3 3 2 1 0 2 ] \left[ \begin{array}{ccc} 1 & 1 & 1\\ 3 & 3 & 2\\ 1 & 0 & 2\\\end{array}\right] 131130122 和矩阵 B 相乘并求和:

卷积-4

1 × 3 + 1 × 1 + 1 × 1 + 3 × 2 + 3 × 3 + 2 × 1 + 1 × 2 + 0 × 2 + 2 × 3 = 30 1\times 3+1\times 1+1\times 1+3\times 2+3\times 3+2\times 1+1\times 2+0\times 2 + 2\times 3=30 1×3+1×1+1×1+3×2+3×3+2×1+1×2+0×2+2×3=30

然后,继续向右滑动,并重复以上过程滑动矩阵窗口,直到滑动到最后一个子矩阵为止,得到最终的结果 [ 29 28 25 30 30 27 20 24 34 ] \left[ \begin{array}{ccc} 29 & 28 & 25\\ 30 & 30 & 27\\ 20 & 24 & 34\\\end{array}\right] 293020283024252734

特征图

完整的卷积计算过程如以下动图所示:

卷积

通常,我们把较小的矩阵 B 称为滤波器 (filter) 或卷积核 (kernel),使用 ⊗ \otimes 表示卷积运算,较小矩阵中的值通过梯度下降被优化学习,卷积核中的值则为网络权重。卷积后得到的矩阵,也称为特征图 (feature map)。通过这种方式,每一层将学习一组与位置无关的潜在特征,每一层由一组并行的卷积核组成,每个卷积核只学习一个特征。
卷积核的通道数与其所乘矩阵的通道数相等。例如,当图像输入形状为 5 x 5 x 3 时(其中 3 为图像通道数),形状为 3 x 3 的卷积核也将具有 3 个通道,以便进行矩阵卷积运算:

三通道卷积

可以看到无论卷积核有多少通道,一个卷积核计算后都只能得到一个通道。多为了捕获图像中的更多特征,通常我们会使用多个卷积核,得到多个通道的特征图,当使用多个卷积核时,计算过程如下:

多卷积核

需要注意的是,卷积并不等同于滤波,最直观的区别在于滤波后的图像大小不变,而卷积会改变图像大小。

2.1.2 步幅

在前面的示例中,卷积核每次计算时在水平和垂直方向只移动一个单位,因此可以说卷积核的步幅 (Strides) 为 (1, 1),步幅越大,卷积操作跳过的值越多,例如以下为步幅为 (2, 2) 时的卷积过程:

步幅为2的卷积计算

2.1.3 填充

在前面的示例中,卷积操作对于输入矩阵的不同位置计算的次数并不相同,具体来说对于边缘的数值在卷积时,仅仅使用一次,而位于中心的值则会被多次使用,因此可能导致卷积错过图像边缘的一些重要信息。如果要增加对于图像边缘的考虑,我们将在输入矩阵的边缘周围的填充 (Padding) 零,下图展示了用 0 填充边缘后的矩阵进行的卷积运算,这种填充形式进行的卷积,称为 same 填充,卷积后得到的矩阵大小为 ⌊ d + 2 p − k s ⌋ + 1 \lfloor\frac {d+2p-k} s\rfloor+1 sd+2pk+1,其中 s s s 表示步幅, p p p 表示填充大小, k k k 表示滤波器尺寸。而未进行填充时执行卷积运算,也称为 valid 填充。

填充

2.1.4 激活函数

在传统神经网络中,隐藏层不仅将输入值乘以权重,而且还会对数据应用非线性激活函数,将值通过激活函数传递。CNN 中同样包含激活函数,CNN 支持我们已经学习的所有可用激活函数,包括 SigmoidReLUtanhLeakyReLU 等。

2.1.5 池化

研究了卷积的工作原理之后,我们将了解用于卷积操作之后的另一个常用操作:池化 (Pooling)。假设卷积操作的输出如下,为 2 x 2

[ 29 28 20 24 ] \left[ \begin{array}{cc} 29 & 28\\ 20 & 24\\\end{array}\right] [29202824]

假设使用池化块(或者类比卷积核,我们也可以称之为池化核)为 2 x 2 的最大池化,那么将会输出 29 作为池化结果。假设卷积步骤的输出是一个更大的矩阵,如下所示:
[ 29 28 25 29 20 24 30 26 27 23 26 27 24 25 23 31 ] \left[ \begin{array}{cccc} 29 & 28 & 25 & 29\\ 20 & 24 & 30 & 26\\ 27 & 23 & 26 & 27\\ 24 & 25 & 23 & 31\\\end{array}\right] 29202724282423252530262329262731
当池化核为 2 x 2,且步幅为 2 时,最大池化会将此矩阵划分为 2 x 2 的非重叠块,并且仅保留每个块中最大的元素值,如下所示:

[ 29 28 ∣ 25 29 20 24 ∣ 30 26 — — — — — 27 23 ∣ 26 27 24 25 ∣ 23 31 ] = [ 29 30 27 31 ] \left[ \begin{array}{ccccc} 29 & 28 & | & 25 & 29\\ 20 & 24 & | & 30 & 26\\ —&—&—&—&—\\ 27 & 23 & | & 26 & 27\\ 24 & 25 & | & 23 & 31\\\end{array}\right]=\left[ \begin{array}{cc} 29 & 30\\ 27 & 31\\\end{array}\right] 29202724282423252530262329262731 =[29273031]

从每个池化块中,最大池化仅选择具有最高值的元素。除了最大池化外,也可以使用平均池化,其将输出每个池化块中的平均值作为结果,在实践中,与其他类型的池化相比,最常使用的池化为最大池化。

2.2 TensorFlow 中的卷积层

TensorFlow 中,如果要添加一个具有 32 个并行特征(将得到 32 个特征图)和大小为 3 x 3 的卷积核的卷积层,可以写为:

import tensorflow as tf
from tensorflow.keras import datasets, layers, models
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))

这表示在 28 x 28 的图像上应用了 32 个大小为 3 x 3 的卷积,输入通道数为 1,产生 32 个输出通道。

2.3 TensorFlow 中的池化层

TensorFlow 中,如果要定义一个大小为 2 x 2 的最大池化层,可以写为:

model.add(layers.MaxPooling2D((2, 2)))

2.4 卷积神经网络总结

我们已经学习了卷积神经网络 (Convolutional Neural Network, CNN) 的基本概念。CNN 在一维上对音频和文本数据沿时间维度进行卷积和池化操作,在二维上对图像沿(高度 x 宽度)维度进行卷积和池化操作,在三维上对视频沿(高度 x 宽度 x 时间)维度进行卷积和池化操作。
换句话说,一个 CNN 包含多个堆叠在一起的卷积核,这些卷积核学习识别特定的视觉特征,而不受图像中位置的影响。这些视觉特征在网络的初始层中往往较简单,在网络的更深层中变得越来越复杂。训练 CNN 需要确定每个卷积核的权重值,以便当输入通过多个网络层时,激活最后一层的适当神经元,从而预测正确的值。

3. 构建卷积神经网络

3.1 LeNet

Yann LeCun 提出的 LeNet 是用于识别 MNIST 手写数字的卷积神经网络,对简单的几何变换和扭曲具有鲁棒性。LeNet 的核心思想是在较低层交替使用卷积操作和最大池化操作。然后,较高层基于传统的多层感知器,输出层使用 Softmax 激活函数。

LeNet

3.2 使用 TensorFlow 实现 LeNet

使用 Convolution2D 类定义 LeNettf.keras.layers.Conv2Dtf.keras.layers.Convolution2D 的别名,因此可以互换使用:

layers.Convolution2D(20, (5, 5), activation='relu', input_shape=input_shape)

其中第一个参数是卷积中卷积核的数量,下一个元组是每个卷积核的尺寸。padding 是可选参数,包含两个值,padding='valid' 表示卷积仅在输入和卷积核完全重叠的地方计算,因此输出比输入小;而 padding='same' 表示输出与输入的大小相同,输入矩阵周围用零值填充。
此外,需要使用 MaxPooling2D 类:

layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))

其中 pool_size=(2, 2) 是一个包含两个整数的元组,表示图像在垂直和水平方向上缩小的比例。因此,(2, 2) 会在每个维度上将图像缩小一半,strides=(2, 2) 是用于池化的步幅。
接下来,实现 LeNet 模型。

(1) 首先,导入所需库:

import tensorflow as tf
from tensorflow.keras import datasets, layers, models, optimizers

# network and training
EPOCHS = 5
BATCH_SIZE = 128
VERBOSE = 1
OPTIMIZER = tf.keras.optimizers.Adam()
VALIDATION_SPLIT=0.90

IMG_ROWS, IMG_COLS = 28, 28 # input image dimensions
INPUT_SHAPE = (IMG_ROWS, IMG_COLS, 1)
NB_CLASSES = 10  # number of outputs = number of digits

(2) 定义 LeNet 网络:

#define the convnet 
class LeNet:
    @staticmethod
    def build(input_shape, classes):
        model = models.Sequential()

第一个卷积层带有 ReLU 激活函数,接着是最大池化层。第一个卷积层包含 20 个卷积核,每个卷积核大小为 5 x 5。输出形状与输入形状相同,因此为 28 x 28。需要注意的是,模型的第一层还需要定义其输入形状 input_shape

最大池化操作使用滑动窗口在输入上滑动,并在由池化核定义的区域内取最大值:

        # CONV => RELU => POOL
        model.add(layers.Convolution2D(20, (5, 5), activation='relu',
                  input_shape=input_shape))
        model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

定义第二个带 ReLU 激活的卷积层,以及第二个最大池化层。第二个卷积层的卷积核数量增加为 50,逐渐增加卷积核的数量是卷积神经网络中常见的技巧之一:

        # CONV => RELU => POOL
        model.add(layers.Convolution2D(50, (5, 5), activation='relu'))
        model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

在展平层后添加一个包含 500 个神经元的全连接层,最后是一个使用 softmax 激活函数且包含 10 个神经元的全连接层(分类器):

        # Flatten => RELU layers
        model.add(layers.Flatten())
        model.add(layers.Dense(500, activation='relu'))
        # a softmax classifier
        model.add(layers.Dense(classes, activation="softmax"))
        return model

(3) 训练网络,并打印损失:

# data: shuffled and split between train and test sets
(X_train, y_train), (X_test, y_test) = datasets.mnist.load_data()

# reshape
X_train = X_train.reshape((60000, 28, 28, 1))
X_test = X_test.reshape((10000, 28, 28, 1))

# normalize
X_train, X_test = X_train / 255.0, X_test / 255.0

# cast
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')

print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')

# convert class vectors to binary class matrices
y_train = tf.keras.utils.to_categorical(y_train, NB_CLASSES)
y_test = tf.keras.utils.to_categorical(y_test, NB_CLASSES)

# initialize the optimizer and model
model = LeNet.build(input_shape=INPUT_SHAPE, classes=NB_CLASSES)
model.compile(loss="categorical_crossentropy", optimizer=OPTIMIZER,
	metrics=["accuracy"])
model.summary()

# use TensorBoard, princess Aurora!
callbacks = [
            # Write TensorBoard logs to `./logs` directory
            tf.keras.callbacks.TensorBoard(log_dir='./logs')
]

# fit 
history = model.fit(X_train, y_train, 
                    batch_size=BATCH_SIZE, epochs=EPOCHS, 
                    verbose=VERBOSE, validation_split=VALIDATION_SPLIT,
                    callbacks=callbacks)

score = model.evaluate(X_test, y_test, verbose=VERBOSE)
print("\nTest score:", score[0])
print('Test accuracy:', score[1])

运行代码。可以看到,模型在训练集上的准确率为 100%,在验证集上的准确率为 97.83%

模型训练过程

绘制模型训练过程中的准确率和损失变化情况,可以看到,只需 20epoch 模型即可达到大约 98.25% 的准确率:

模型训练过程

查看 MNIST 图像样本,以便了解 98.25% 准确率究竟如何。例如,人们书写数字 9 有许多种方式,如下所示。数字 3745 也是如此,而下图中第 2 列第 3 行的数字 5 非常难以识别,即使是人类也可能会有困扰:

样本示例

可以采用多种神经网络优化技术改进该简单 CNN,例如使用不同优化器、添加 Dropout 层、使用批归一化等,在不同模型上手写数字识别情况如下所示。简单的全连接网络只有 90.71% 的准确率,这意味着大约每 100 个手写字符中就有 9 个被错误识别。然后,通过使用深度学习架构,模型获得了 8% 的提升,达到了 98.25% 的准确率,这意味着每 100 个手写字符中大约只有 1 个被错误识别。

不同模型性能对比

4. 深度卷积神经网络优势

为了更好地理解深度学习和卷积神经网络的性能,我们进行另一项测试,通过减少训练集的大小观察性能的衰减情况。将包含 50,000 个样本的训练集分割为两个不同的集合:

  • 用于训练模型的训练集逐渐减小,分别包含 5,9003,0001,800600300 个样本
  • 使用数据集中的剩余样本作为验证集测试模型训练效果
  • 测试集始终包含 10000 个样本不变

将上一小节定义的深度神经网络与简单神经网络进行比较,可以看到,当训练的可用数据增加时,深度神经网络优于简单网络。当训练样本为 5,900 个时,深度神经网络的准确率为 97.23%,而简单网络的准确率为 94%
简单而言,深度神经网络需要更多的训练数据才能充分展现其潜力:

性能对比

MNIST 数据集上训练的一系列深度学习模型性能能够在线查看。截至目前,最佳模型的错误率为 0.21%

深度学习模型

小结

卷积神经网络 (Convolutional Neural Network, CNN) 是一种广泛应用的深度学习模型。通过参数共享、局部感知和空间结构等优势,能够更好地处理图像数据,并在图像识别、目标检测和图像生成等任务中展现出强大的能力。在本节中,介绍了卷积的计算方法以及卷积神经网络的基本组件,并使用 TensorFlow 构建卷积神经网络 LeNet 以深入了解其工作原理。

系列链接

TensorFlow深度学习实战(1)——神经网络与模型训练过程详解
TensorFlow深度学习实战(2)——使用TensorFlow构建神经网络
TensorFlow深度学习实战(3)——深度学习中常用激活函数详解
TensorFlow深度学习实战(4)——正则化技术详解
TensorFlow深度学习实战(5)——神经网络性能优化技术详解
TensorFlow深度学习实战(6)——回归分析详解
TensorFlow深度学习实战(7)——分类任务详解

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.NET + Vue3 的前后端项目在IIS的发布

目录 一、发布准备 1、安装 IIS 2、安装 Windows Hosting Bundle(.NET Core 托管捆绑包) 3、安装 IIS URL Rewrite 二、项目发布 1、后端项目发布 2、前端项目发布 3、将项目部署到 IIS中 三、网站配置 1、IP配置 2、防火墙配置 3、跨域配置…

电脑想安装 Windows 11 需要开启 TPM 2.0 怎么办?

尽管 TPM 2.0 已经内置在许多新电脑中,但很多人并不知道如何激活这一功能,甚至完全忽略了它的存在。其实,只需简单的几步操作,你就能开启这项强大的安全特性,为你的数字生活增添一层坚固的防护屏障。无论你是普通用户还…

嵌入式开发岗位认识

目录 1.核心定义2.岗位方向3.行业方向4.技术方向5.工作职责6.核心技能7.等级标准8.优势与劣势9.市场薪资10. 发展路径11. 市场趋势12. 技术趋势 1.核心定义 嵌入式系统: 以应用为中心,以计算机技术为基础,软硬件可裁剪的专用计算机系统 特点…

爱普生 SG-8101CE 可编程晶振在笔记本电脑的应用

在笔记本电脑的精密架构中,每一个微小的元件都如同精密仪器中的齿轮,虽小却对整体性能起着关键作用。如今的笔记本电脑早已不再局限于简单的办公用途,其功能愈发丰富多样。从日常轻松的文字处理、网页浏览,到专业领域中对图形处理…

Python VsCode DeepSeek接入

Python VsCode DeepSeek接入 创建API key 首先进入DeepSeek官网,https://www.deepseek.com/ 点击左侧“API Keys”,创建API key,输出名称为“AI” 点击“创建",将API key保存,复制在其它地方。 在VsCode中下载…

基于eBPF的全栈可观测性系统:重新定义云原生环境诊断范式

引言:突破传统APM的性能桎梏 某头部电商平台采用eBPF重构可观测体系后,生产环境指标采集性能提升327倍:百万QPS场景下传统代理模式CPU占用达63%,而eBPF直采方案仅消耗0.9%内核资源。核心业务的全链路追踪时延从900μs降至18μs&a…

java项目之风顺农场供销一体系统的设计与实现(源码+文档)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的风顺农场供销一体系统的设计与实现。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 风顺农场供销…

Spring MVC 的核心以及执行流程

Spring MVC的核心 Spring MVC是Spring框架中的一个重要模块,它采用了经典的MVC(Model-View-Controller)设计模式。 MVC是一种软件架构的思想,它将软件按照模型(Model)、视图(View)…

SQLMesh 系列教程6- 详解 Python 模型

本文将介绍 SQLMesh 的 Python 模型,探讨其定义、优势及在企业业务场景中的应用。SQLMesh 不仅支持 SQL 模型,还允许通过 Python 编写数据模型,提供更高的灵活性和可编程性。我们将通过一个电商平台的实例,展示如何使用 Python 模…

苍穹外卖知识点

导入依赖 Component Aspect public class MyselfAspect{Before("excution(* com.services.*.(..))")public myBefore(JointPoint jointPoint){System.out.println("在前面执行");} }只要注意如何使用Before注解就行了,里面存放的是*&#xff…

MySQL系列之身份鉴别(安全)

导览 前言Q:如何保障MySQL数据库身份鉴别的有效性一、有效性检查 1. 用户唯一2. 启用密码验证3. 是否存在空口令用户4. 是否启用口令复杂度校验5. 是否设置口令的有效期6. 是否限制登录失败尝试次数7. 是否设置(超过尝试次数)锁定的最小时长…

OneNote手机/平板“更多笔记本”中有许多已经删掉或改名的,如何删除

问题描述: OneNote 在手机或平板上添加“更多笔记本”中,有许多已经删掉或改名的笔记本!如何删除? OR:如何彻底删除OneNote中的笔记本? 处理做法: 这个列表对应365里面的【最近打开】&#…

区块链共识机制深度揭秘:从PoW到PoS,谁能主宰未来?

区块链的技术背后,最大的挑战之一就是如何让多个分布在全球各地的节点在没有中心化管理者的情况下达成一致,确保数据的一致性和安全性。这一切都依赖于区块链的核心——共识机制。共识机制不仅决定了区块链的安全性、效率和去中心化程度,还对…

观察者模式说明(C语言版本)

观察者模式主要是为了实现一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。下面使用C语言实现了一个具体的应用示例,有需要的可以参考…

Linux System V - 消息队列与责任链模式

概念 消息队列是一种以消息为单位的进程间通信机制,允许一个或多个进程向队列中发送消息,同时允许一个或多个进程从队列中接收消息。消息队列由内核维护,具有以下特点: 异步通信:发送方和接收方不需要同时运行&#x…

微信小程序客服消息接收不到微信的回调

微信小程序客服消息,可以接收到用户进入会话事件的回调,但是接收不到用户发送消息的回调接口。需要在微信公众平台,把转发消息给客服的开关关闭。需要把这个开关关闭,否则消息会直接发送给设置的客服,并不会走设置的回…

pycharm社区版有个window和arm64版本,到底下载哪一个?还有pycharm官网

首先pycharm官网是这一个。我是在2025年2月16日9:57进入的网站。如果网站还没有更新的话,那么就往下滑一下找到 community Edition,这个就是社区版了免费的。PyCharm:适用于数据科学和 Web 开发的 Python IDE 适用于数据科学和 Web 开发的 Python IDE&am…

风险价值VaR、CVaR与ES

风险价值VaR、CVaR与ES 一、VaR风险价值1. VaR的定义及基本概念2.VaR的主要性质3.风险价值的优缺点 二、CVaR条件风险价值与ES预期损失1.CVaR的基本概念2.性质3.ES预期损失 一、VaR风险价值 1. VaR的定义及基本概念 20年前,JP的大佬要每天下午收盘后的4:15在桌上看…

老游戏回顾:d2

游戏中玩家创建属于自己的角色,在一片片暗黑大地上奔跑、杀敌、寻宝、成长,最终打败统治各个大陆的黑暗势力,拯救游戏中的各个种族。 《暗黑破坏神II》的制作团队包括编程小组、运动物体制作小组和背景制作小组。游戏设计很大程度上是开放的&…

The Heliosphere 日球层

转自 The Heliosphere - NASA This is an artists concept of our Heliosphere as it travels through our galaxy with the major features labeled. Termination Shock: Blowing outward billions of kilometers from the Sun is the solar wind, a thin stream of electrica…