深度学习-第T6周——好莱坞明星识别

news2024/12/28 3:42:44

深度学习-第T6周——好莱坞明星识别

  • 深度学习-第T6周——好莱坞明星识别
    • 一、前言
    • 二、我的环境
    • 三、前期工作
      • 1、导入数据集
      • 2、查看图片数目
      • 3、查看数据
    • 四、数据预处理
      • 1、 加载数据
        • 1、设置图片格式
        • 2、划分训练集
        • 3、划分验证集
        • 4、查看标签
      • 2、数据可视化
      • 3、检查数据
      • 4、配置数据集
    • 五、搭建CNN网络
    • 六、编译
    • 七、训练模型
    • 八、模型评估
      • 1、Loss和Acc图
      • 2、指定图片进行预测
    • 九、总结

深度学习-第T6周——好莱坞明星识别

一、前言

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

二、我的环境

  • 电脑系统:Windows 10
  • 语言环境:Python 3.8.5
  • 编译器:colab在线编译
  • 深度学习环境:Tensorflow

三、前期工作

1、导入数据集

导入数据集,这里使用k同学的数据集,共17个分类。


import os, PIL, pathlib
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models
import matplotlib.pyplot as plt

data_dir = "/content/drive/MyDrive/Training_Camp_DL/TensorFlow/CNN/48-data"
print(type(data_dir))
data_dir = pathlib.Path(data_dir)
print(type(data_dir))

这段代码将字符串类型的 data_dir 转换为了 pathlib.Path 类型的对象。pathlib 是 Python3.4 中新增的模块,用于处理文件路径。
通过 Path 对象,可以方便地操作文件和目录,如创建、删除、移动、复制等。
在这里,我们使用 pathlib.Path() 函数将 data_dir 转换为路径对象,这样可以更加方便地进行文件路径的操作和读写等操作。

2、查看图片数目

image_count = len(list(data_dir.glob("*/*.jpg")))
print("图片数目:", image_count)

获取指定目录下所有子文件夹中 jpg 格式的文件数量,并将其存储在变量 image_count 中。

data_dir 是一个路径变量,表示需要计算的目标文件夹的路径。
glob() 方法可以返回匹配指定模式(通配符)的文件列表,该方法的参数 “/.jpg” 表示匹配所有子文件夹下以 .jpg 结尾的文件。

list() 方法将 glob() 方法返回的生成器转换为列表,方便进行数量统计。最后,len() 方法计算列表中元素的数量,就得到了指定目录下 jpg 格式文件的总数。

所以,这行代码的作用就是计算指定目录下 jpg 格式文件的数量。
在这里插入图片描述

3、查看数据

roses = list(data_dir.glob("Jennifer Lawrence/*.jpg"))
print(type(roses), roses)
PIL.Image.open(str(roses[0]))

在这里插入图片描述

四、数据预处理

1、 加载数据

1、设置图片格式

batch_size = 32
img_height = 224
img_width = 224

2、划分训练集

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split = 0.1,
    subset = "training",
    label_mode = "categorical",
    seed = 123,
    image_size = (img_height, img_width),
    batch_size = batch_size
)

这行代码使用 TensorFlow 读取指定路径下的图片文件,并生成一个 tf.data.Dataset 对象,用于模型的训练和评估。

具体来说,tf.keras.preprocessing.image_dataset_from_directory() 函数从指定目录中读取图像数据,并自动对其进行标准化和预处理。该函数有以下参数:

directory:指定图像文件所在目录的路径;
seed:用于随机划分数据集的种子;
image_size:指定图像缩放后的尺寸;
batch_size:指定批次中图像的数量。
通过这些参数,函数将指定目录中的图像按照指定大小预处理后,随机划分为训练集和验证集。最终,生成的 tf.data.Dataset 对象包含了划分好的数据集,可以用于后续的模型训练和验证。

需要注意的是,这里的 img_height 和 img_width 变量应该提前定义,并且应该与实际图像的尺寸相对应。同时,batch_size 也应该根据硬件设备的性能合理调整,以充分利用 GPU/CPU 的计算资源。
在这里插入图片描述

3、划分验证集

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split = 0.1,
    subset = "validation",
    label_mode = "categorical",
    seed = 123,
    image_size = (img_height, img_width),
    batch_size = batch_size
)

这段代码和上一段代码类似,使用 TensorFlow 的 keras.preprocessing.image_dataset_from_directory() 函数从指定的目录中读取图像数据集,并将其划分为训练集和验证集。

其中,data_dir 指定数据集目录的路径,validation_split 表示从数据集中划分出多少比例的数据作为验证集,subset 参数指定为 “validation” 则表示从数据集的 20% 中选择作为验证集,其余 80% 作为训练集。seed 是一个随机种子,用于生成可重复的随机数。image_size 参数指定输出图像的大小,batch_size 表示每批次加载的图像数量。

该函数返回一个 tf.data.Dataset 对象,代表了整个数据集(包含训练集和验证集)。可以使用 train_ds 和 val_ds 两个对象分别表示训练集和验证集。

不过两段代码的 subset 参数值不同,一个是 “training”,一个是 “validation”。

因此,在含有交叉验证或者验证集的深度学习训练过程中,需要定义两个数据集对象 train_ds 和 val_ds。我们已经定义了包含训练集和验证集的数据集对象 train_ds,可以省略这段代码,无需重复定义 val_ds 对象。只要确保最终的训练过程中,两个数据集对象都能够被正确地使用即可。

如果你没有定义 val_ds 对象,可以使用这段代码来创建一个验证数据集对象,用于模型训练和评估,从而提高模型性能。

在这里插入图片描述

4、查看标签

class_names = train_ds.class_names
class_names

train_ds.class_names 是一个属性,它是通过数据集对象 train_ds 中的类别信息自动生成的一个包含类别名称的列表。

在创建数据集对象 train_ds 时,你可以通过 class_names 参数手动指定类别名称,也可以根据图像文件夹的目录结构自动推断出来。
例如,假设你有一个包含猫和狗两种类别的图像数据集,其中猫类别的图像存储在 “cat” 文件夹中,狗类别的图像存储在 “dog” 文件夹中,
那么当你使用 keras.preprocessing.image_dataset_from_directory() 函数加载数据集时,会自动将 “cat” 和 “dog” 文件夹作为两个不同的类别,
并将它们的名称存储在 train_ds.class_names 属性中。

执行该代码后,你就可以在控制台或者输出窗口中看到包含数据集中所有类别名称的列表。这些名称通常是按照字母顺序排列的

因此,train_ds.class_names 属性可以让你方便地查看数据集中所有的类别名称,以便后续的模型训练、预测和评估等任务。
如果你要对数据集进行多类别分类,则需要根据 train_ds.class_names 的元素个数设置输出层的神经元数量,并将每个类别与一个唯一的整数标签相关联。
在这里插入图片描述

2、数据可视化

plt.figure(figsize = (20, 10))

for images, labels in train_ds.take(1):
  for i in range(20):
    ax = plt.subplot(5, 10, i + 1)

    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[np.argmax(labels[i])]) #返回当前处理的图像所代表的类别的索引。

    plt.axis("off")

train_ds.take(1) 是一个方法调用,它返回一个数据集对象 train_ds 中的子集,其中包含了 take() 方法参数指定的数量的样本。
在这个例子中,take(1) 意味着我们从 train_ds 数据集中获取一批包含一个样本的数据块。

因此,for images, labels in train_ds.take(1): 的作用是遍历这个包含一个样本的数据块,并将其中的图像张量和标签张量依次赋值给变量 images 和 labels。具体来说,
它的执行过程如下:

从 train_ds 数据集中获取一批大小为 1 的数据块。
遍历这个数据块,每次获取一个图像张量和一个标签张量。
将当前图像张量赋值给变量 images,将当前标签张量赋值给变量 labels。
执行 for 循环中的代码块,即对当前图像张量和标签张量进行处理。

plt.imshow() 函数是 Matplotlib 库中用于显示图像的函数,它接受一个数组或张量作为输入,并在窗口中显示对应的图像。
在这个代码中,images[i] 表示从训练集中获取的第 i 个图像张量。由于 images 是一个包含多个图像的张量列表,因此使用 images[i] 可以获取其中的一个图像。

由于 imshow() 函数需要输入的数组或张量的类型是整型或浮点型,而从数据集中获取的图像张量通常是浮点型张量,因此需要将其转换为整型张量,以便进行显示。
这里使用了 .numpy().astype(“uint8”) 操作来将图像张量转换为整型张量(uint8 表示无符号8位整数),然后将结果传递给 plt.imshow() 函数进行显示。

因此,plt.imshow(images[i].numpy().astype(“uint8”)) 的作用是在 Matplotlib 窗口中显示训练集中的第 i 个图像。
你可以通过改变 i 的值来显示不同的图像,例如 i = 0 表示显示训练集中的第一张图像。

plt.axis(“off”) 是 Matplotlib 库中的一个函数调用,它用于控制图像显示时的坐标轴是否可见。
具体来说,当参数为 “off” 时,图像的坐标轴会被关闭,不会显示在图像周围。这个函数通常在 plt.imshow() 函数之后调用,以便在显示图像时去掉多余的细节信息,仅仅显示图像本身。

在这里插入图片描述

3、检查数据

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

在这里插入图片描述

4、配置数据集

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size = AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size = AUTOTUNE)

AUTOTUNE 是 TensorFlow 的一个常量,它的值取决于当前硬件配置和运行环境。
它表示 TensorFlow 数据处理流程中可以自动选择最优化参数(例如 GPU 处理数量等)的范围,在不同的硬件配置下可能会有不同的取值。
在这个代码片段中,AUTOTUNE 的作用是为数据集的预处理过程提供了一个启发式的缓冲大小,以便更好地平衡内存使用和计算速度。

train_ds.cache() 和 val_ds.cache() 函数是 Tensorflow 的数据转换函数,它们的作用是将数据集中的元素缓存到内存或者磁盘中,以便后续访问时能够更快地读取数据。
使用缓存可以避免由于磁盘 I/O 等因素导致数据读取速度变慢的问题,从而加速训练或评估过程。

train_ds.shuffle(1000) 函数是 Tensorflow 的数据转换函数,它的作用是将输入数据集中的元素随机打乱顺序。
这样做的目的是防止模型过拟合,并促进模型对不同数据的学习能力。其中,1000 表示用于对数据集进行重排的元素数量,其具体取值可以根据数据集大小进行调整。

train_ds.prefetch(buffer_size = AUTOTUNE) 和 val_ds.prefetch(buffer_size = AUTOTUNE) 函数是 Tensorflow 的数据转换函数,
它们的作用是将输入数据集中的元素通过 AUTOTUNE 参数定义的缓冲大小进行预加载。
具体来说,这个函数可以在当前训练或评估任务执行期间异步读取和处理数据集中的下一批样本,从而减少模型训练或评估过程中的等待时间和延迟。

因此,这段代码的作用是对训练集和验证集进行预处理,并将它们缓存到内存或磁盘中,以便更快地访问数据。
然后,它对训练集进行了一次随机打乱操作,并将缓存结果设为可以提前预加载的形式,以便在训练时能够快速地读取和处理数据。
最后,它将缓存结果也设置为可以提前预加载的形式,以加速评估过程。

五、搭建CNN网络

model = models.Sequential([
    layers.experimental.preprocessing.Rescaling(1./ 255, input_shape = (img_height, img_width, 3)),
    #定义了一个图像预处理层,即 Rescaling 层。该层会将图像的像素值缩放到 [0, 1] 之间,以便模型更好地学习图像特征。
    #其中,1. / 255 是缩放的因子,input_shape 则是可选参数,用于指定输入图像的大小。

    #由于神经网络算法通常对输入数据有一定的要求(如数据必须位于同一尺度或范围内),因此在训练神经网络之前,通常需要对输入数据进行预处理。
    #在这个例子中,将图像的像素值除以 255,可以将像素值缩放到 [0, 1] 范围内。这样做不仅可以提高模型训练的效果,还可以加速模型训练的收敛。

    layers.Conv2D(16, (3, 3), activation = "relu", input_shape = (img_height, img_width)),
    layers.AveragePooling2D((2, 2)),
    layers.Conv2D(32, (3, 3), activation = "relu"),
    layers.AveragePooling2D((2, 2)),
    layers.Dropout(0.5),
    layers.Conv2D(64, (3, 3), activation = "relu"),
    layers.AveragePooling2D((2, 2)),
    layers.Dropout(0.5),
    layers.Conv2D(128, (3, 3), activation = "relu"),
    #layers.AveragePooling2D((2, 2)),
    layers.Dropout(0.5),

    layers.Flatten(),
    layers.Dense(128, activation = "relu"),
    layers.Dense(len(class_names))
])

model.summary()

layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)) 是 TensorFlow 中的一个预处理层,
用于将图像数据缩放至 [0, 1] 范围内,在神经网络的训练过程中稳定模型训练过程。

在这个代码片段中,1./255 表示将输入数据除以 255,这样就把原来范围在 [0, 255] 的像素值缩放到 [0, 1] 的范围内。
这个操作可以使得神经网络的输入数据归一化,从而更好地适应不同的计算机视觉任务,例如图像分类、目标检测、语义分割等。

input_shape=(img_height, img_width, 3) 参数表示输入图像的形状,其中 img_height 和 img_width 分别表示图像的高度和宽度,而 3 表示通道数。
由于这个预处理层是作为神经网络模型的第一层使用的,因此需要指定输入数据的形状。

因此,这行代码的作用是将输入图像的像素值除以 255,从而将像素范围缩放到 [0, 1],并将其作为神经网络模型的第一层,
以便在训练过程中更好地归一化输入数据,并提高模型的鲁棒性和泛化性能。

在这里插入图片描述

六、编译

initial_learning_rate = 1e-4

lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate,
    decay_steps = 60,
    decay_rate = 0.96,
    staircase = True
)

optimizers = tf.keras.optimizers.Adam(learning_rate = lr_schedule)

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

lr_schedule 是一个学习率的调度器,它是基于指数衰减方法来自动调整学习率的。在深度学习中,学习率是一个非常重要的超参数,它会影响模型的性能和训练速度。

这个调度器包含四个参数。initial_learning_rate 为初始学习率,一开始通常需要较大的学习率以便更快地进行收敛,然后逐步减小以提高训练效果。
decay_steps 是衰减步数,指定了多少次更新后进行学习率衰减。 这里设置成30,防止学习率衰减过快。decay_rate 是衰减速率,决定每一次衰减后学习率的大小。
通过以上两个参数,可以控制学习率的下降速度和幅度。staircase 参数则表示是否对步数取整,如果设置为 True,则表示将步数向下取整。

这个调度器的计算公式为:
decayed_learning_rate = initial_learning_rate * decay_rate ^ (step / decay_steps)

其中 step 表示当前训练步数。通过指数函数的方式,学习率会随着训练步数的增加而不断降低。
这种调度器的优点在于,它可以在训练初期使用较大的学习率以便快速接近最优解,而在后期则可以逐渐降低学习率以更精细的调整模型参数。

在上述代码段中,我们使用了初始学习率为 initial_learning_rate,衰减步数为 30,衰减速率为 0.92 的指数衰减策略来更新模型的学习率。
这种学习率调度器是一种常见的方法,在实践中通常可以通过尝试不同的参数设置来确定最佳的学习率调度策略。

SparseCategoricalCrossentropy 是一种常用的损失函数,通常用于多分类问题。
它的输入是模型输出结果经过 softmax 处理后得到的概率分布和真实的分类标签,输出是一个标量值,表示模型在当前数据上的损失值。

其中 from_logits=True 表示输入的模型输出结果是没有进行 softmax 处理的 logits,这种设置可以提高计算效率,并且对于梯度计算也更加稳定。

具体地,SparseCategoricalCrossentropy 的计算公式为:

loss = -Σ[y * log(y_hat)]
其中 y 是真实的分类标签,y_hat 是模型在该分类下的预测概率分布,log 是自然对数。通过最小化损失函数,模型可以调整参数以提高预测准确率,并不断逼近真实结果

七、训练模型

from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping

epochs = 100

checkpoint = ModelCheckpoint("best_model.h5",
                monitor = 'val_accuracy',
                verbose = 1,
                save_best_only = True,
                save_weights_only = True
                )

earlystopper = EarlyStopping(monitor = 'val_accuracy',
                min_delta = 0.001,
                patience = 20,
                verbose = 1
                )

ModelCheckpoint 是 Keras 中的一个回调函数(Callback),用于在训练过程中保存模型的权重。
具体来说,对于每一轮训练后,该回调函数都可以按照一定的条件将这一轮训练得到的最佳模型权重保存下来。

使用 ModelCheckpoint 可以避免在训练过程中出现意外情况导致模型信息的丢失,同时也可以方便地对比不同阶段训练得到的模型效果,进行模型的选择和调整。

具体来说,这段代码中的参数设置如下:

best_model.h5:保存模型权重的文件路径和名称。
monitor=‘val_accuracy’:表示在验证集上监测模型的准确率并作为指标,以便在每个 epoch 结束时评估模型效果。当发现模型在验证集上的准确率有提高时,就会保存当前的模型权重。
verbose=1:表示每个 epoch 结束时,在控制台输出一条信息说明模型权重是否被更新了。
save_best_only=True:表示只有在模型效果提高时才保存模型权重。如果设为 False,则每个 epoch 结束后都会保存模型权重,不管模型效果是否提高。
save_weights_only=True:表示只保存模型的权重,而不保存模型的结构和配置信息。这样可以方便地加载已经训练好的模型权重,并重新构建模型。
综合起来,这段代码的作用是在训练过程中不断保存最佳的模型权重,以便后续的模型加载和使用。

earlystopper 是一个早期停止器,用于在训练过程中监控模型的表现,并在满足终止条件时提前结束训练。它是 tensorflow.keras.callbacks.EarlyStopping 类的一个实例对象。

在深度学习中,由于模型参数非常多,训练时间可能会很长。而对于一些问题,模型可能已经学习到了足够好的特征,此时继续训练只会导致过拟合或者浪费计算资源。
为了避免这种情况的发生,我们可以通过早期停止器来控制模型的训练过程。

通过 EarlyStopping,我们可以设置一些参数来指定如何判断模型是否应该停止训练,并在满足条件时终止训练。其中,monitor = ‘val_accuracy’ 表示监控模型在验证集上的准确率,
min_delta = 0.001 表示设置检测指标的最小变化量,如果变化量小于该值,则认为模型已经不再进步,可以终止训练。patience = 20 表示设置容忍指标在多少个 epoch 中没有进步,
如果超过该次数,则终止训练。verbose = 1 表示在控制台打印提示信息。

当早期停止器被激活时,它会自动停止训练,同时保留模型在最后一个 epoch 的参数。这个参数可以用于进一步的预测和测试任务。在具体实践中,我们可以根据问题和数据集的特点,
合理地设置早期停止器的参数,从而获得更好的训练效果。

history = model.fit(
    train_ds,
    validation_data = val_ds,
    epochs = epochs,
    callbacks = [checkpoint, earlystopper]
)

这段代码是基于给定数据集 train_ds 进行模型训练,并在验证集 val_ds 上评估模型表现。同时,使用了之前定义的 checkpointer 和 earlystopper 两个回调函数来保存模型和控制早期停止。

其中,epochs = epochs 表示训练的轮数,callbacks = [checkpointer, earlystopper] 表示在训练过程中使用了之前定义的回调函数来保存模型和控制早期停止。

该方法会返回一个 history 对象,包含了模型在训练过程中的各种指标,例如训练损失、验证损失、训练准确率、验证准确率等等。
通过对这些指标的分析,我们可以更加深入地了解模型的表现和训练效果,从而进一步调整模型的参数和结构,提高模型的性能并得到更好的预测结果。

在这里插入图片描述

八、模型评估

1、Loss和Acc图

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 Acc")
plt.plot(epochs_range, val_acc, label = "Validation Acc")
plt.legend(loc = 'lower right')
plt.title('Training and Validation Acc')

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()

在这里插入图片描述

把dropout层参数修改为0.2,decay_steps 修改成50后:

在这里插入图片描述
在这里插入图片描述运行了一小时,可以看到,精确度提升了0.03。

2、指定图片进行预测

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

from PIL import Image
import numpy as np

img = Image.open("D:/DL_Camp/CNN/T6/48-data/Hugh Jackman/001_9adc92c2.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。
'''

predictions = model.predict(img_array)
#这个函数用于对输入图像进行分类预测。它使用已经训练好的模型来对输入数据进行推断,并输出每个类别的概率分布。
print("预测结果为:", class_names[np.argmax(predictions)])
'''
将模型输出的概率分布转换为最终预测结果。
具体来说,使用 np.argmax() 函数找到概率最大的类别索引,
然后使用该索引在 class_names 列表中查找相应的类别名称,并输出预测结果。
'''
'''

在这里插入图片描述

九、总结

经过尝试修改模型参数并对比原参数的运行结果,发现调低dropout层的参数和decay_step可以提高模型的精度。不过,在更深入的学习中还需要进一步改进参数设置,引入VGG等相关技术进行优化。后续会按照自己的理解补上。

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

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

相关文章

Flutter学习之旅 - 页面布局Stack层叠组件

文章目录 StackPositioned定位布局浮动导航(StackPositioned)FlutterMediaQuery获取屏幕宽度和高度StackAlign Stack Stack意思是堆的意思,我们可以用Stack结合Align或者Stack结合Positioned来实现页面的定位布局 属性说明alignment配置所有元素显示位置children子组…

23.Lambda表达式

Lambda表达式 一、Lambda表达式背景 Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式…

2023-05-05 背包问题

背包问题 1 01背包和完全背包问题 01背包问题 有N件物品和一个容量为V的背包,第i件物品的体积是v[i]、价值是w[i],每种物品只可以使用一次,求将哪些物品放入背包可以使得价值总和最大。这里的w是weight即权重的意思 这是最基础的背包问题&a…

【飞书ChatGPT机器人】飞书接入ChatGPT,打造智能问答助手

文章目录 前言环境列表视频教程1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 转载自远控源码文章:飞书接入ChatGPT - 将ChatGPT集…

Ubuntu 如何查看 CPU 架构、系统信息、内核版本、版本代号?

Ubuntu 查看 CPU 架构、系统信息、内核版本、版本代号等相关信息有很多方式,本文介绍几种常用的命令。 x86 架构与 ARM 架构的 CPU 架构不同,如果回显为 aarch64 表示为 ARM 架构,如果回显为 x86_64 表示为 x86 架构,参考《CPU 架…

Prometheus快速入门

Prometheus快速入门 环境准备 三台主机,配置好主机名 各自配置好主机名 # hostnamectl set-hostname --static server.cluster.com ... 三台都互相绑定IP与主机名 # vim /etc/hosts 192.168.126.143 server.cluster.com 192.168.126.142 agent.clu…

归并排序(看了就会)

目录 概念1. 基本思想2. 实现逻辑3. 复杂度分析4、代码 概念 归并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。归并排序思路简单&…

智头条|欧盟达成《人工智能法》协议,全球前沿科技齐聚AWE 2023

行业动态 华为云联手多方推进数字化,软通动力深度参与 华为云宣布启动“‘百城万企’应用现代化中国行”,旨在推动应用现代化进程、助力数字中国高质量落地。软通动力是该行动的参与者之一,共同探索符合区域特点、产业趋势、政企现状的数字化…

Python进阶(Linux操作系统)

一,操作系统 1.1,Linux系统基础操作 1.2,linux进程与线程 1.2.1并发,并行 (1)并发:在一段时间内交替的执行多个任务:对于单核CPU处理多任务,操作系统轮流让让各个任务…

BasicVSR++代码解读(总体介绍)

本文代码主要来自于OpenMMLab提供的MMEditing开源工具箱中的BasicVSR代码。第一部分的解读主要是针对每一个部分是在做什么提供一个解释,便于后续细读每一个块的细节代码。 (1)导入库     basicvsr_plusplus_net中主要继承了torch,mmcv,m…

信号的产生——线性调频函数

信号的产生——线性调频函数 产生线性调频扫频信号函数chirp的调用格式如下: (1)y chirp(t,f0, t1,f1) 功能:产生一个线性(频率随时间线性变化)信号,其时间轴设置由数组t定义。时刻0的瞬间频…

SpringBoot的配置文件、日志文件

一、配置文件( .properties、.yml) 1、.properties 配置文件 1.1、格式 1.2、基本语法 1.2.1、如:一般配置(以键值的形式配置的,key 和 value 之间是以“”连接的。) 1.2.2、如:自定义配置&a…

tcc-transaction 源码分析

tcc介绍 tcc介绍查看我之前的文章: https://caicongyang.blog.csdn.net/article/details/119721282?spm1001.2014.3001.5502 tcc-transaction 介绍: http://mengyun.org/zh-cn/index.html 本文基于2.x 最新版本:https://github.com/changmingxie/tcc…

以京东为例,分析优惠价格叠加规则

一、平行优惠计算原则 1、什么是“平行式门槛计算规则”? 平行式门槛计算规则,即每一层级优惠都直接根据商品的单品基准价来计算是否符合门槛,店铺/平台促销、优惠券类优惠之间是并列关系,只要单品基准价或单品基准价总和&#x…

c++(类和对象中)

【本节目标】 1. 类的6个默认成员函数 2. 构造函数 3. 析构函数 4. 拷贝构造函数 5. 赋值运算符重载 6. const成员函数 7. 取地址及const取地址操作符重载 目录 1、类的6个默认成员函数 2、构造函数 2.1概念 2.2特性 3.析构函数 3.1概念 3.2特性 4.拷贝构造函数…

Kafka生产者

一、生产者发送流程 在消息发送的过程中,涉及到了两个线程——main 线程和 Sender 线程。在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator,Sender 线程不断从 RecordAccumulator 中拉取消息发送到 Kafka …

网络应用基础 ——(2023新星计划文章二)

一,TCP/UDP报头 1.1TCP报文头部详解 Source port:源端口号与Destination port目标端口号: 在TCP(传输控制协议)协议中,源端口和目标端口字段用于标识通信会话的端点。 (1)源端口是一个16位字段…

LeetCode 1206. 实现跳表

不使用任何库函数,设计一个跳表。 跳表是在 O(log(n)) 时间内完成增加、删除、搜索操作的数据结构。跳表相比于树堆与红黑树,其功能与性能相当,并且跳表的代码长度相较下更短,其设计思想与链表相似。 例如,一个跳表包…

3.数据查询(实验报告)

目录 一﹑实验目的 二﹑实验平台 三﹑实验内容和步骤 四﹑命令(代码)清单 五﹑调试和测试清单 一﹑实验目的 掌握使用Transact-SQL的SELECT语句进行基本查询的方法;掌握使用SELECT语句进行条件查询的方法;掌握SELECT语句的GROUP BY、ORDER BY以及UN…

MX6U根文件系统配置

编译 BusyBox 构建根文件系统 /home/ /linux/nfs mkdir rootfs tar -vxjf busybox-1.29.0.tar.bz2 依照自己的交叉编译 不然会出错 配置好 busybox 以后就可以编译了,我们可以指定编译结果的存放目录,我们肯定要将编 译结果存放到前面创建的 rootfs 目录…