T5:运动鞋图片识别

news2024/9/21 4:38:47

T5周:运动鞋品牌识别

      • **一、前期工作**
        • 1.设置GPU(用CPU可忽略该步骤)
        • 2.导入数据
        • 3.查看数据
      • **二、数据预处理**
        • 1.加载数据
        • 2.可视化数据
        • 3.配置数据集
      • **三、构建CNN网络模型**
      • **四、编译模型**
        • **1、设置动态学习率**
      • **五、训练模型**
      • **六、模型评估**
      • **七、预测**
      • **八、总结**

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊

⛽ 我的环境

  • 语言环境:Python3.10.12
  • 编译器:Google Colab
  • 深度学习环境:
    • TensorFlow2.17.0

一、前期工作

1.设置GPU(用CPU可忽略该步骤)
#os提供了一些与操作系统交互的功能,比如文件和目录操作
import os
#提供图像处理的功能,包括打开和显示、保存、裁剪等
import PIL
#pathlib提供了一个面向对象的接口来处理文件系统路径。路径被表示为Path对象,可以调用方法来进行各种文件和目录操作。
import pathlib

#用于绘制图形和可视化数据
import tensorflow as tf
import matplotlib.pyplot as plt
#用于数值计算的库,提供支持多维数组和矩阵运算
import numpy as np
#keras作为高层神经网络API,已被集成进tensorflow,使得训练更方便简单
from tensorflow import keras
#layers提供了神经网络的基本构建块,比如全连接层、卷积层、池化层等
#提供了构建和训练神经网络模型的功能,包括顺序模型(Sequential)和函数式模型(Functional API)
from tensorflow.keras import layers, models
#导入两个重要的回调函数:前者用于训练期间保存模型最佳版本;后者监测到模型性能不再提升时提前停止训练,避免过拟合
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
# 获取所有可用的GPU设备列表,储存在变量gpus中
gpus = tf.config.list_physical_devices("GPU")

# 如果有GPU,即列表不为空
if gpus:
  # 获取第一个 GPU 设备
  gpu0 = gpus[0]
  # 设置 GPU 内存增长策略。开启这个选项可以让tf按需分配gpu内存,而不是一次性分配所有可用内存。
  tf.config.experimental.set_memory_growth(gpu0, True)
  #设置tf只使用指定的gpu(gpu[0])
  tf.config.set_visible_devices([gpu0],"GPU")

gpus
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
2.导入数据
#挂载google drive
from google.colab import drive
drive.mount("/content/drive/")
Mounted at /content/drive/
#更改工作目录
%cd "/content/drive/MyDrive/Colab Notebooks/jupyter notebook/data/"
/content/drive/Othercomputers/My laptop/jupyter notebook/data
#这里使用相对路径
data_dir = './5/'
#将路径转换成pathlib.Path对象
data_dir = pathlib.Path(data_dir)
3.查看数据
# 使用glob方法获取当前目录的子目录里所有以'.jpg'为结尾的文件
# '*/*.jpg' 是一個通配符模式
# 第一个星号表示当前目录
# 第二个星号表示子目录
image_count = len (list(data_dir.glob("*/*/*.jpg")))
#这里相比之前的需要添加一个/*是因为数据集5内有两个子文件夹

print("图片总数:", image_count)
图片总数: 578
ex = list(data_dir.glob("train/adidas/*.jpg"))
PIL.Image.open(str(ex[1]))

在这里插入图片描述

二、数据预处理

1.加载数据

使用image_dataset_from_directory方法将磁盘中的数据加载到tf.data.Dataset

验证集v.s.数据集:

  1. 验证集并没有参与训练过程梯度下降过程的,狭义上来讲是没有参与模型的参数训练更新的。
  2. 但是广义上来讲,验证集存在的意义确实参与了一个“人工调参”的过程,我们根据每一个epoch训练之后模型在valid data上的表现来决定是否需要训练进行early stop,或者根据这个过程模型的性能变化来调整模型的超参数,如学习率,batch_size等等。
  3. 因此,我们也可以认为,验证集也参与了训练,但是并没有使得模型去overfit验证集
#设置批量大小,即每次训练模型时输入图像数量
#每次训练迭代时,模型需处理32张图像
batch_size = 32
#图像的高度,加载图像数据时,将所有的图像调整为相同的高度
img_height = 224
#图像的宽度,加载图像数据时,将所有的图像调整为相同的宽度
img_width = 224
"""
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
tr_ds = tf.keras.preprocessing.image_dataset_from_directory(
    "./5/train/",
    #validation_split=0.2,#指定数据集中分割出多少比例数据当作验证集,0.2表示20%数据会被用来当验证集
    #subset="training",#指定是用于训练还是验证的数据子集,这里设定为training
    #用于设置随机数种子,以确保数据集划分的可重复性和一致性。
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)
Found 502 files belonging to 2 classes.
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    "./5/test/",
    #validation_split = 0.2,
    #subset = "validation",
    seed = 123,
    image_size=(img_height,img_width),
    batch_size=batch_size
)
Found 76 files belonging to 2 classes.
class_names = tr_ds.class_names
# 可以通过class_names输出数据集的标签。标签将按字母顺序对应于目录名称
class_names
['adidas', 'nike']

随机数种子相关可参考:https://blog.csdn.net/weixin_51390582/article/details/124246873

2.可视化数据
#创建一个图形对象,设置图形大小宽度20英寸,高度10英寸
plt.figure(figsize=(20, 10))
#tr_ds.take(1)从训练数据集tr_ds中获取一个批次的数据。take(1)返回一个包含一批数据的Dataset对象
#images是这一个批次的图片
#labels是这一个批次的标签

for images, labels in tr_ds.take(1):
  #选择当前批次的前20张图
    for i in range(20):
      #将图形分成5行10列,子图索引为i+1
      ax = plt.subplot(5, 10, i + 1)
      #显示第i张图
      #images[i]是一个张量,使用.numpy()将其转化为Numpy数组,数据类型为float32,(0-255)数据大小,此处直接'/255.0'也可
      #.astype("uint8")将图像数据类型转换为无符号8位整数(uint8),介于0-1之间
      plt.imshow(images[i].numpy().astype("uint8"))
      #设置当前子图标题为当前图片的类别名称
      #labels[i]是当前图片对应的标签,通过该标签检索图片类别
      plt.title(class_names[labels[i]])
      #关闭坐标轴显示
      plt.axis("off")
      #print(images[1].numpy().dtype)--检查图片的数据类型,输出为float32
      #print(f"Min value: {images[1].numpy().min()}, Max value: {images[1].numpy().max()}")--检查像素值范围-(0-255)
#显示图片
plt.show()

在这里插入图片描述

for image_batch, labels_batch in tr_ds:
  print(image_batch.shape)
  print(labels_batch.shape)
  break

#`(32, 224, 224, 3)`--最后一维指的是彩色通道RGB
#`label_batch`是形状(32,)的张量,这些标签对应32张图片
(32, 224, 224, 3)
(32,)
3.配置数据集
#自动调整数据管道性能
AUTOTUNE = tf.data.AUTOTUNE
# 使用 tf.data.AUTOTUNE 具体的好处包括:
#自动调整并行度:自动决定并行处理数据的最佳线程数,以最大化数据吞吐量。
#减少等待时间:通过优化数据加载和预处理,减少模型训练时等待数据的时间。
#提升性能:自动优化数据管道的各个环节,使整个训练过程更高效。
#简化代码:不需要手动调整参数,代码更简洁且易于维护。

#使用cache()方法将训练集缓存到内存中,这样加快数据加载速度
#当多次迭代训练数据时,可以重复使用已经加载到内存的数据而不必重新从磁盘加载
#使用shuffle()对训练数据集进行洗牌操作,打乱数据集中的样本顺序
#参数1000指缓冲区大小,即每次从数据集中随机选择的样本数量
#prefetch()预取数据,节约在训练过程中数据加载时间
tr_ds = tr_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

三、构建CNN网络模型

卷积神经网络(CNN)的输入是张量 (Tensor) 形式的 (image_height, image_width, color_channels),包含了图像高度、宽度及颜色信息。不需要输入batch size。color_channels 为 (R,G,B) 分别对应 RGB 的三个颜色通道(color channel)。在此示例中,我们的 CNN 输入形状是 (224, 224, 3)。我们需要在声明第一层时将形状赋值给参数input_shape。

CNN的输入张量表示图像的结构和颜色信息。每个像素点都被表示为具有color_channels个数值的向量,在训练时,通过一系列卷积层、池化层和全连接层等操作提取和处理图像特征。

num_classes = 2

"""
关于卷积核的计算不懂的可以参考文章:https://blog.csdn.net/qq_38251616/article/details/114278995

layers.Dropout() 作用是防止过拟合,提高模型的泛化能力。

关于Dropout层的更多介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/115826689
"""
#创建序列模型,一种线性堆叠模型,各层按照他们被添加到模型中的顺序来堆叠
model = models.Sequential([
    layers.Input(shape=(img_height,img_width,3)),
    # 数据预处理层:将像素值从 [0, 255] 缩放到 [0, 1]即归一化,输入(224, 224 ,3),
    layers.Rescaling(scale=1./255), #2.17.0的tensorflow已经将experimental.preprocessing移除,改放于layers内(*用Input作为单独输入层)

    #层输入可以手动添加batch size信息,model.summary()中每一层输出shape中None将为指定批次大小:
    #layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3),batch_size = 32),

    # 卷积层1:16 个 3x3 的卷积核,使用 ReLU 激活函数,输出 (222, 222, 16),
    layers.Conv2D(16, (3, 3), activation='relu', input_shape=(img_height, img_width, 3)),

    # 池化层1:2x2 的平均池化,输出(111,111,16)
    layers.AveragePooling2D((2, 2)),  #池化层1,2*2采样

    # 卷积层2:32 个 3x3 的卷积核,使用 ReLU 激活函数,(109,109,32)
    layers.Conv2D(32, (3, 3), activation='relu'), #卷积层2,卷积核3*3

    # 池化层2:2x2 的平均池化,(54,54,32)
    layers.AveragePooling2D((2, 2)),  #池化层2,2*2采样

    # Dropout层:随机停止30%的神经元工作,防止过拟合
    layers.Dropout(0.3),

    # 卷积层3:64 个 3x3 的卷积核,使用 ReLU 激活函数 (52,52,64)
    layers.Conv2D(64, (3, 3), activation='relu'),

    # Dropout层:随机停止30%的神经元工作,防止过拟合
    layers.Dropout(0.3),

    # Flatten层:将多维特征图展平为一维,连接卷积层与全连接层
    layers.Flatten(),

    # 全连接层:128 个神经元,使用 ReLU 激活函数
    layers.Dense(128, activation='relu'),

    # 输出层:输出预期结果,神经元数量为 num_classes
    layers.Dense(num_classes)

    ])
model.summary()  # 打印网络结构

在这里插入图片描述

四、编译模型

在准备对模型进行训练之前,还需要再对其进行一些设置。以下内容是在模型的编译步骤中添加的:

  • 损失函数(loss):用于衡量模型在训练期间的准确率。
  • 优化器(optimizer):决定模型如何根据其看到的数据和自身的损失函数进行更新。
  • 指标(metrics):用于监控训练和测试步骤。以下示例使用了准确率,即被正确分类的图像的比率。
1、设置动态学习率

🍨ExponentialDecay函数(指数衰减方法)

官方文档:Keras 3 API documentation


blog: 神经网络学习率指数衰减ExponentialDecay策略的参数含义与使用方法详解

tf.keras.optimizers.schedules.ExponentialDecay是 TensorFlow 中的一个学习率衰减策略,用于在训练神经网络时动态地降低学习率。学习率衰减是一种常用的技巧,可以帮助优化算法更有效地收敛到全局最小值,从而提高模型的性能。

keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate,
    decay_steps,
    decay_rate,
    staircase=False,
    name="ExponentialDecay",
)

🍨主要参数

  • initial_learning_rate:初始学习率;
  • decay_steps:衰减步数。在经过decay_steps步后,学习率将按照指数函数衰减。例如,如果decay_steps设置为10,则每10步衰减一次;
  • decay_rate:学习率的衰减率。决定了xuexilruhe衰减,通常取值在0到1之间;
  • staircase:阶梯式衰减,默认为False;一个布尔值,控制学习率的衰减方式。若为True,则学习率在每个decay_step之后直接减小,形成阶梯状下降。如果为False,则学习率将持续衰减

“The schedule is a 1-arg callable that produces a decayed learning rate when passed the current optimizer step. This can be useful for changing the learning rate value across different invocations of optimizer functions”

def decayed_learning_rate(step):
  return initial_learning_rate * decay_rate^(step/decay_steps)

如果参数staircaseTrue,那么step / decay_steps是整除(即向下取整),衰减的学习率遵循阶梯函数(即只有step可以整除decay_steps时学习率会变化)。

step的含义和iteration类似。表示在一个epoch中模型进行一次参数更新的操作。通俗地说,在神经网络训练过程中,每次完成对一个batch数据的训练,就是完成了一个step。一个iteration包括了一个step中前向传播、损失计算、反向传播和参数更新的流程。当然,在某些情况下,step和iteration可能会有细微的区别——有时候iteration是指完成一次前向传播和反向传播的过程,而step是指通过优化算法对模型参数进行一次更新的操作。但是绝大多数情况下,我们就认为二者是一样的即可。
参考:https://blog.csdn.net/zhebushibiaoshifu/article/details/131086145

可以将schedule直接传递到keras,optimizers.Optimizer学习率中。

#示例代码:
initial_learning_rate = 0.1
lr_schedule = keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate,
    decay_steps=100000,
    decay_rate=0.96,
    staircase=True)

model.compile(optimizer=keras.optimizers.SGD(learning_rate=lr_schedule),
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(data, labels, epochs=5)
#本次使用代码
# 设置初始学习率
initial_learning_rate = 0.001 #将初始学习率改为0.001

lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
        initial_learning_rate,
        decay_steps=10, # 敲黑板!!!这里是指 steps,不是指epochs
        decay_rate=0.92, # lr经过一次衰减就会变成 decay_rate*lr
        staircase=True)

# 将指数衰减学习率送入优化器
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)

model.compile(optimizer=optimizer,
       loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
       metrics=['accuracy'])

#Adam优化器是一种常用的梯度下降优化算法,用于更新模型的权重以最小化训练过程中的损失函数
#对模型的输出logits进行稀疏分类交叉熵损失计算
#from_logits=True说明模型输出是未经softmax函数转换的原始分数或概率值;
#False则会对经过softmax处理后的输出进行计算

🍨学习率大与学习率小的优缺点分析

参考:https://blog.csdn.net/m0_63880699/article/details/130813151


学习率大

  • 优点:
    • 加快学习速率,较快达到最优解;
    • 有助于跳出局部最优解从而找到全局最优;
  • 缺点:
    • 可能导致参数更新过快,在最优解附近振荡剧烈无法收敛;
    • 容易导致模型不精确:可能导致模型无法充分拟合数据,导致预测结果不精确
  • 改进:使用学习率衰减策略,自适应学习率方法,如AdaGrad、RMSprop或Adam等。

学习率小

  • 优点:

    • 有助于模型收敛细化:每次模型参数的更新调整更加谨慎;
    • 提高模型精读
  • 缺点:

    • 容易陷入局部最优解;
    • 收敛慢:较小的学习率意味着参数更新步长较小,可能需要更多的迭代次数才能达到最优解。
  • 改进:使用动态学习率等同上方法,或使用学习率热启动策略

五、训练模型

🍨EarlyStopping函数:

参考博客:keras中EarlyStopping(早停止)的用法和原理详解

Keras 3 API documentation

EarlyStopping是Callbacks的一种,callbacks用于指定在每个epoch开始和结束的时候进行哪种特定操作。Callbacks中有一些设置好的接口,可以直接使用,如’acc’, 'val_acc’, ’loss’ 和 ’val_loss’等等。

EarlyStopping则是用于提前停止训练的callbacks。具体地,通过监控指定性能标志,当模型在一定数量的训练轮次(epochs)中没有明显改进的时候停止继续训练。

keras.callbacks.EarlyStopping(
    monitor="val_loss",
    min_delta=0,
    patience=0,
    verbose=0,
    mode="auto",
    baseline=None,
    restore_best_weights=False,
    start_from_epoch=0,
)

🍨主要参数:

  • monitor(string):需要监控的性能指标,默认为"val_loss",可选择"acc",“val_acc”,"loss"等;
  • min_delta(float):改进阈值,即被认为是性能提升的最小变化。如果在连续的训练轮次中性能指标未达到此阈值,则会触发提前停止。
  • patience(int):在停止提升之前,允许模型连续训练的轮次数量。当连续patience个训练轮次中性能指标未达到min_delta时,训练将被终止。
  • verbose(int):显示模式,0表示不显示日志信息,1表示显示日志信息;
  • mode(str):{‘auto’, ‘min’, ‘max’}之一。根据monitor指定的性能指标决定提前停止的条件。如果是’min’,则当指标不再减小时停止;如果是’max’,则当指标不再增大时停止;如果是’auto’,将基于指标的名称自动推断停止条件。
  • baseline(float): 监控指标的基线;如果不是None,训练将在指标未显示超过baseline的改进则提前停止。默认为None.
  • restore_best_weights(boolean): 是否从监控指标值最佳的轮次中恢复模型权重。如果False,就使用最近的step更新后的权重。无论相对于baseline的表现如何,都将恢复一个轮次。如果没有一个轮次在基线上有所改善,训练将运行patience轮次并恢复该集合中的最佳轮次的权重。默认为False
  • start_from_epoch(int): 开始监测是否改善之前等待的轮次,这允许有一段热身期,即在这段时间内指标未进步但训练也不会被停止。默认值:0.

    min_delta和patience都和“避免模型停止在抖动过程中”相关。通常情况,若前者降低,那么后者适当减少;前者增加,那么后者需要适当延长。

网络训练轮次太少可能导致欠拟合,太多可能导致过拟合。导致测试准确率下降的原因可能是:1.过拟合;2.学习率过大导致不收敛;3.使用正则项,Loss的减少可能不是因为准确率增加导致的而是权重大小降低。


EarlyStopping主要为了解决轮次数手动设置的问题,也可以视为避免网络发生过拟合的正则化方法。作用是当模型在验证集上的性能不再增加时停止训练,从而达到充分训练的作用,又避免过拟合。因为对模型训练来说,需要在验证集上衡量模型泛化能力,在训练到某一程度时,若在验证集上精度不再提高了则再训练也无益,只会浪费成本。

epochs = 50

# 保存最佳模型参数
checkpointer = ModelCheckpoint(
    '../xunlianying/best5model.weights.h5',
    monitor='val_accuracy',
    verbose=1,
    mode = "max",
    save_best_only=True,
    save_weights_only=True)

# 设置早停
earlystopper = EarlyStopping(monitor='val_accuracy',
    min_delta=0.001,
    patience=20,
    mode = "max",
    verbose=1)
history = model.fit(tr_ds,
      validation_data=val_ds,
      epochs=epochs,
      callbacks=[checkpointer, earlystopper])

在这里插入图片描述
在这里插入图片描述

六、模型评估

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(len(loss))

plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

在这里插入图片描述

七、预测

注释参考:https://blog.csdn.net/qq_45735298/article/details/130056861?spm=1001.2014.3001.5502

model.load_weights('../xunlianying/best5model.weights.h5')
#这段代码用于加载之前训练中保存的最佳模型权重。使用之前保存的模型权重文件路径和名称。
#这样可以避免从头开始训练模型,直接使用已经训练好的最佳模型进行预测的工作。

from PIL import Image
import numpy as np

img = Image.open("./5/test/nike/4.jpg") #使用 PIL 库中的 Image.open() 方法打开一张待预测的图片。
image = tf.image.resize(img, [img_height, img_width])
#这个函数调整输入图像的大小以符合模型的要求。
#在这个例子中,使用 TensorFlow 的 tf.image.resize() 函数将图像缩放为指定大小,其中 img_height 和 img_width 是指定的图像高度和宽度。

img_array = tf.expand_dims(image, 0)
'''
这个函数将输入图像转换为形状为 (1, height, width, channels) 的四维数组,
其中 height 和 width 是图像的高度和宽度,channels 是图像的通道数(例如 RGB 图像有 3 个通道)。
这里使用 TensorFlow 的 tf.expand_dims() 函数来扩展图像数组的维度,以匹配模型的输入格式。

具体来说:
image 是一个二维图片张量,它的形状是 (height, width, channels)。其中 height 和 width 分别为图片的高度和宽度,channels 为图片的颜色通道数。

0 是一个整数值,它指定在哪个维度上扩展此张量,这里表示在最前面(第一个)的维度上扩展。
因此,函数的作用是将输入张量 image 在最前面添加一个额外的维度(batch_size),生成一个四维张量。

tf.expand_dims(input, axis)
其中 input 表示要扩展的输入张量,axis 表示要在哪个维度上进行扩展。在这个例子中,input 是变量 image,axis 是 0。
'''

pre = model.predict(img_array)
#这个函数用于对输入图像进行分类预测。它使用已经训练好的模型来对输入数据进行推断,并输出每个类别的概率分布。
print("预测结果为:", class_names[np.argmax(pre)])


#将模型输出的概率分布转换为最终预测结果。
#具体来说,使用 np.argmax() 函数找到概率最大的类别索引,然后使用该索引在 class_names 列表中查找相应的类别名称,并输出预测结果。

在这里插入图片描述

八、总结

  • 根据tf的版本调整了原先的model中的代码(之前一直偷懒单纯降个版本跑)
  • 学习了keras框架中的动态学习率设置的方法之一(指数衰减方法)并掌握相关函数参数;将初始学习率设置为0.001(原本的0.1跑出来结果在50epoch内完全无法收敛,loss高而acc持续低甚至基本不变。。。)
  • 学习了EarlyStopping函数及参数,包括其设置的意义
  • 最高的val_acc达到84%并在第33轮停止训练。

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

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

相关文章

【iOS】——响应者链和事件传递链

事件传递 事件传递流程 发生触摸事件后,系统会将该事件封装成UIEvent对象加入到一个由UIApplication管理的事件队列 UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口…

什么你还不懂keepalived高可用负载均衡架构?

1、部署keepalived 1.1、keepalived简介 vrrp 协议的软件实现,原生设计目的为了高可用 ipvs 服务 官网: http://keepalived.org/ 功能: 基于 vrrp 协议完成地址流动 为 vip 地址所在的节点生成 ipvs 规则 ( 在配置文件中预先定义 ) 为 ipvs 集群的各 RS 做健康状态检测 基…

Linux 操作系统 --- 信号

序言 在本篇内容中,将为大家介绍在操作系统中的一个重要的机制 — 信号。大家可能感到疑惑,好像我在使用 Linux 的过程中并没有接触过信号,这是啥呀?其实我们经常遇到过,当我们运行的进程当进程尝试访问非法内存地址时…

NC 数组中只出现一次的两个数字

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 一个整型数组…

Apache--简介与基本使用

前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 一、Apache简介 Apache HTTP Server(在Red Hat发行版中俗称Apache或httpd)是由Apache Software Foundation在Apache License…

windows bat脚本基础指令详解

pause暂停批处理的执行并在屏幕上显示"请按任意键继续…"echo显示指令,会把需要显示的内容展示出来。echo off在此语句后所有运行的命令都不显示命令行本身,但是本身的指令是会显示出来的。不显示本行命令行call调用另一个批处理文件&#xff…

Ricardo Milos

目录 一、题目 二、思路 三、payload 四、思考与总结 一、题目 <!-- Challenge --> <form id"ricardo" method"GET"><input name"milos" type"text" class"form-control" placeholder"True" va…

【C++STL详解(十一)】map/set/multimap/multiset的介绍与使用

目录 一、关联式容器 二、键值对 三、set 介绍 简单使用 1.构造 2.相关迭代器 3.容量 4.修改 四、multiset 五、map 介绍 使用 1.定义的方式 2.迭代器相关 3.容量与operator【】(重点) 4.修改 小总结&#xff1a; 六、multimap 一、关联式容器 在CSTL中…

【学习笔记】A2X通信的协议(十三)- 消息功能定义和内容

目录 11 消息功能定义和内容 11.1 概述 11.2 通过PC5信令消息进行的A2X通信 11.2.1 A2X直接链路建立请求 11.2.1.1 消息定义 11.2.1.2 目标用户信息 11.2.1.3 密钥建立信息容器 11.2.1.4 Nonce_1 11.2.1.5 KNRP-sess ID的最高有效位&#xff08;MSB&#xff09; 11.2…

替代 SMR 算法!两步孟德尔随机化方法 TWMR 与 revTWMR 整合xQTL+GWAS数据分析基因表达与疾病的关联

全基因组关联研究&#xff08;GWAS&#xff09;是研究大型队列中基因型与表型关系的重要工具。GWAS的已知局限性主要在于从与致病变异相关的连锁不平衡区域中识别生物学机制&#xff0c;而无法直接获得基因层面的表型关联。为了解决这个问题&#xff0c;基于转录组关联研究&…

C语言——函数专题

1.概念 在C语言中引入函数的概念&#xff0c;有些翻译为子程序。C语言中的函数就是一个完成某项特定任务的一小段代码&#xff0c;这个代码是有特殊的写法和调用方法的。一般我们可以分为两种函数&#xff1a;库函数和自定义函数。 2.库函数 C语言国际标准ANSIC规定了一些常…

Docker 容器运行时如何实现与宿主机的目录挂载

虽然容器启动前挂载目录相对简单,只需要在启动容器的时候通过-v 参数即可轻松实现,但对于已运行的容器进行目录挂载则稍显复杂。本教程将深入讲解如何在不中断容器运行的情况下,为已运行的Docker容器配置目录挂载,实现灵活的数据共享与持久化策略。 一、环境准备 为了本次实…

ffmpeg采用gpu加速增加水印

1.环境需要 系统 windows10 ffmpeg&#xff0c;ffprobe 字体文件 python3以上版本 2.环境配置 从官网上下载ffmpeg版本https://github.com/BtbN/FFmpeg-Builds/releases&#xff0c;这里我用的是这个&#xff0c;解压之后里面包含ffmpeg&#xff0c;ffprobe&#xff0c;f…

使用Kernel Memory进行RAG评估:AI助力企业知识管理新突破

在现代企业知识管理中&#xff0c;随着业务的不断发展和扩展&#xff0c;各种文档和数据呈现爆炸式增长。为了有效且高效地管理这些知识&#xff0c;企业通常会导入大量文档。然而&#xff0c;当涉及到对文档切片质量和回答准确度的判断时&#xff0c;传统的人工方法显得既费时…

复现dom破坏案例和靶场

目录 1.dom型xss平台 第一关 Ma Spaghet !: &#xff08;1&#xff09;&#xff1a;当get参数中存在somebody时&#xff0c;h2回显 &#xff08;2&#xff09;&#xff1a;当get参数中不存在somebody时&#xff0c;h2回显 第二关Jefff&#xff1a; 第三关&#xff1a;Ugan…

【前端面试】挖掘做过的nextJS项目(中)

https://blog.csdn.net/weixin_43342290/article/details/141170360?spm1001.2014.3001.5501文章浏览阅读105次。需求:快速搭建宣传官网1.适应pc、移动端2.基本的路由跳转3.页面渲染优化4.宣传的图片、视频资源的加载优化5.seo优化全栈react web应用、tailwind css原子工具的支…

动态规划篇--代码随想录算法训练营第三十二天|343. 整数拆分,96.不同的二叉搜索树,01背包理论,01背包优化

343. 整数拆分 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 讲解视频&#xff1a; 动态规划&#xff0c;本题关键在于理解递推公式&#xff01;| LeetCode&#xff1a;343. 整数拆分 题目描述&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k …

c++47 二级指针

二级指针的输入和输出模型 指针的输入&#xff1a;主调函数分配内存 指针输出 &#xff1a;被调用函数分配内存 指针做输入第一种模型 #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h>// 二级指针做输…

《计算机组成原理》(第3版)第8章 CPU的结构和功能 复习笔记

第8章 CPU的结构和功能 一、CPU的结构 &#xff08;一&#xff09;CPU的含义 CPU实质包括运算器和控制器两大部分。 对于冯诺依曼结构的计算机而言&#xff0c;一旦程序进入存储器后&#xff0c;就可由计算机自动完成取指令和执行指令的任务&#xff0c;控制器就是专用于完成…

Python爬虫图片:从入门到精通

在数字化时代&#xff0c;图片作为信息传递的重要媒介之一&#xff0c;其获取和处理变得越来越重要。Python作为一种功能强大且易于学习的编程语言&#xff0c;非常适合用来编写爬虫程序&#xff0c;帮助我们自动化地从互联网上获取图片资源。本文将从基础到高级&#xff0c;详…