深度学习-第T7周——咖啡豆识别

news2024/11/17 8:51:49

深度学习-第T7周——咖啡豆识别

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

深度学习-第T7周——咖啡豆识别

一、前言

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

二、我的环境

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

三、前期工作

1、导入数据集

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

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

data_dir = 'D:/DL_Camp/CNN/T7/49-data'
data_dir = pathlib.Path(data_dir)

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

2、查看图片数目

image_count = len(list(data_dir.glob('*/*.png')))
print("图片总数为:", image_count)

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

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

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

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

四、数据预处理

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.2,
    subset = "training",
    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.2,
    subset = "validation",
    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)

normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)
train_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
val_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))

image_batch, label_batch  = next(iter(val_ds))
first_image = image_batch[0]
print(np.min(first_image), np.max(first_image))

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网络

from tensorflow.keras import layers, models, Input
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten, Dropout

def VGG16(nb_classes, input_shape):
    input_tensor = Input(shape = input_shape)
    
    x = Conv2D(64, (3, 3), activation = 'relu', padding = 'same', name = 'block1_conv1')(input_tensor)
    x = Conv2D(64, (3, 3), activation = 'relu', padding = 'same', name = 'block1_conv2')(x)
    x = MaxPooling2D((2, 2), strides = (2, 2), name = 'block1_pool')(x)
    
    x = Conv2D(128, (3, 3), activation = 'relu', padding = 'same', name = 'block2_conv1')(x)
    x = Conv2D(128, (3, 3), activation = 'relu', padding = 'same', name = 'block2_conv2')(x)
    x = MaxPooling2D((2, 2), strides = (2, 2), name = 'block2_pool')(x)
    
    x = Conv2D(256, (3, 3), activation = 'relu', padding = 'same', name = 'block3_conv1')(x)
    x = Conv2D(256, (3, 3), activation = 'relu', padding = 'same', name = 'block3_conv2')(x)
    x = Conv2D(256, (3, 3), activation = 'relu', padding = 'same', name = 'block3_conv3')(x)
    x = MaxPooling2D((2, 2), strides = (2, 2), name = 'block3_pool')(x)
    
    x = Conv2D(512, (3, 3), activation = 'relu', padding = 'same', name = 'block4_conv1')(x)
    x = Conv2D(512, (3, 3), activation = 'relu', padding = 'same', name = 'block4_conv2')(x)
    x = Conv2D(512, (3, 3), activation = 'relu', padding = 'same', name = 'block4_conv3')(x)
    x = MaxPooling2D((2, 2), strides = (2, 2), name = 'block4_pool')(x)
    
    x = Conv2D(512, (3, 3), activation = 'relu', padding = 'same', name = 'block5_conv1')(x)
    x = Conv2D(512, (3, 3), activation = 'relu', padding = 'same', name = 'block5_conv2')(x)
    x = Conv2D(512, (3, 3), activation = 'relu', padding = 'same', name = 'block5_conv3')(x)
    x = MaxPooling2D((2, 2), strides = (2, 2), name = 'block5_pool')(x)
    
    x = Flatten()(x)
    x = Dense(4096, activation = 'relu', name = 'fc1')(x)
    x = Dense(4096, activation = 'relu', name = 'fc2')(x)
    output_tensor = Dense(nb_classes, activation = 'softmax', name = 'predictions')(x)
    
    model = Model(input_tensor, output_tensor)
    return model

model =  VGG16(len(class_names), (img_width, img_height, 3))
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] 的范围内。
这个操作可以使得神经网络的输入数据归一化,从而更好地适应不同的计算机视觉任务,例如图像分类、目标检测、语义分割等。

在这里插入图片描述

六、编译

initial_learning_rate = 1e-4

lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate,
    decay_steps = 30,
    decay_rate = 0.92,
    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']    )

epochs = 20

history = model.fit(
    train_ds,
    validation_data = val_ds,
    epochs = epochs,
)

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 是自然对数。通过最小化损失函数,模型可以调整参数以提高预测准确率,并不断逼近真实结果

七、训练模型

history = model.fit(
    train_ds,
    validation_data = val_ds,
    epochs = epochs,
 
)

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

其中,epochs = epochs 表示训练的轮数

该方法会返回一个 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()

九、总结

初步了解了VGG16架构。

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

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

相关文章

Vue3+TS知识点补充

一、关于Ref 1.shallowRef() shallowRef 是 Vue 3 中新引入的响应式数据类型之一,它与 ref 类型非常相似,但是有一些不同点。 不同的是,shallowRef 只会对其包装的对象进行浅层次的响应式处理,即如果这个对象的子属性发生改变&…

软件测试——黑盒测试

1.测试概述 1.1综述 本测试报告为计算机程序能力在线测评系统的黑盒测试,黑盒测试可以在不知道程序内部结构和代码的情况下进行,用来测试软件功能是否符合用户需求,是否达到用户预期目标,是否拥有较好的人机交互体验。 图1.1 黑…

media设备节点初始化与Video4Linux初始化

media设备节点初始化与Video4Linux初始化 文章目录 media设备节点初始化与Video4Linux初始化media设备节点初始化Video4Linux初始化 media设备节点初始化 media_devnode_init函数是一个内核初始化函数,用于在Linux内核启动期间进行设备节点初始化。 函数的主要作用…

复习:遥感图像解译复习整理

惭愧,这个课程从始自终就没有认真学过,一部分是因为自己的原因,另一部分也是因为自己的原因。因此,对于整理的资料有不足之处请指正。 另外,资料自word复制,没有时间整理博客的格式。 -- 2023年05月19日记…

深度学习训练营之Densenet网络

深度学习训练营 原文链接环境介绍前言设计理念网络结构实验结果和讨论pytorch实现DenseNet附录 原文链接 🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍦 参考文章:365天深度学习训练营-第J3周:Densenet网络学习&…

第一代AIGC硬件悄然爆发

文 | 智能相对论 作者 | 叶远风 看起来,这可能是一副正常的黑框眼镜,你戴上去彬彬有礼、斯斯文文; 实际上,它里边还装了一个“小伙伴”,你随时可以与它交流,谈天说地或者提出各种问题接受它的帮助&#x…

深度学习之构建MPL神经网络——泰坦尼克号乘客的生存分析

大家好,我是带我去滑雪! 本期使用泰坦尼克号数据集,该数据集的响应变量为乘客是生存还是死亡(survived,其中1表示生存,0表示死亡),特征变量有乘客舱位等级(pclass&#x…

广告投放的关键成功因素:广告归因与广告效果监测

在当今竞争激烈的市场环境中,广告归因和广告效果监测成为了广告投放中至关重要的环节。通过深入了解广告归因和广告效果监测的方法,企业可以更好地评估广告投放的成效,并做出精确的决策,以提高广告效果和最大化投资回报。 本文将带…

昆仑万维“勇闯”百模大战:一个“无懈可击”的商业故事话本?

文丨智能相对论 作者丨沈浪 新能源火了做新能源,元宇宙火了做元宇宙。 如果一个热点领域没有昆仑万维的身影,那一定是这个领域还不够“热”,爆不了。 但凡是热到爆的领域,昆仑万维虽迟但到。 不过,这样说可能有些…

【计算机网络基础】章节测试3 数据链路层

文章目录 判断题选择题辨析题应用题 判断题 相对于广域网而言,局域网的误码率较低。√ 交换机是依据IP地址来转发数据包的。 局域网使用集线器作为网络连接设备时,逻辑上是星型结构。 PPP协议应首先满足的需求是简单,以使得协议在实现的时…

Go语言的学习【2】基础语法

目录 代码组成部分字符串格式化字符数据类型变量遇到的问题及解决办法1 代码组成部分 Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号。 在 Go 程序中,一行代表一个语句结束。 如果你…

【linux】图文并茂,让你轻松掌握Linux基本指令

目录 一,前提 二, 在root身份下,管理用户 1. 判断身份 2. 创建用户 3. 销毁用户 三,文件增,删,移动指令 1. pwd——查看路径 2. ps ——打开文件目录 3. touch——创建文件 4. nano——打开文件 5.…

【大数据】Presto(Trino)REST API 与执行计划介绍

文章目录 一、概述二、环境准备三、常用 REST API1)worker 节点优雅退出2)提交SQL查询请求3)获取查询状态4)获取查询结果5)取消查询请求6)获取Presto 节点信息7)获取Presto服务器使用统计信息8&…

功率放大器电路中的三极管和MOS管,究竟有什么区别?

学习模拟电子技术基础,和电子技术相关领域的朋友,在学习构建功率放大器电路时最常见的电子元器件就是三极管和场效应管(MOS管)了。那么三极管和MOS管有哪些联系和区别呢?在构建功率放大器电路时我们要怎么选择呢&#…

干货 | 利用SPSS进行高级统计分析第一期

Hello,大家好! 这里是壹脑云科研圈,我是喵君姐姐~ 你是否还在为分析实验数据而感到头疼?你是否还在苦于自己不知道如何选择合适的模型来分析数据? 本期我们就来为大家带来了利用SPSS软件进行高级统计分析…

【学习日记】在不可联网电脑上安装Python和深度学习环境

测试环境 Hyer-V上开了个虚拟机,win7-64位企业版,全新未安装任何环境的最基本的操作系统。 因为不联网安装,而且是win7这种古老的操作系统,确实会遇到很多问题。做个记录。 安装Python 打开python-3.7.8.exe 安装程序 此时可能…

离岗识别 yolov5模型

离岗识别通过yolov5网络模型技术,离岗识别可以自动识别现场画面中人员离岗脱岗睡岗等行为,发现违规行为立即抓拍告警。YOLOv5在YOLOv4算法的基础上做了进一步的改进,检测性能得到进一步的提升。虽然YOLOv5算法并没有与YOLOv4算法进行性能比较…

Unity3d 开发Pico4程序闪退弹窗【版权保护】检测的解决方法

前言 最近在进行基于Pico4的应用开发,然后在部分设备上程序是无法正常进入的,而且总是弹出这个版权保护的窗口: 按理说正常的自己开发的测试的程序不应该有这种限制,查询后发现是 PICO 内置了版权保护机制。应用上架后&#xff0…

研发工程师玩转Kubernetes——通过文件创建Service

在《研发工程师玩转Kubernetes——部署应用》一文中,我们使用kubectl expose创建了一个Service,暴露了一个Pod上的nginx服务。这篇文章我们将使用文件的形式创建Service。 为了增加有趣性,我们采用《研发工程师玩转Kubernetes——构建、推送自…

与众不同的夜间开关交互效果

这个夜间模式切换开关效果是不是很炫酷,在短视频曾刷到过是一个国外的设计师看似是为了难为我们前端开发设计了一个元素超多且动画复杂的开关切换效果。 结果在逛 codepen 的时候发现真的被一个大佬给做出来了,效果真的很不错,而且还在原来的…