昇思MindSpore学习笔记6-04计算机视觉--Shufflenet图像分类

摘要:

     记录MindSpore AI框架使用ShuffleNet网络对CIFAR-10数据集进行分类的过程、步骤和方法。包括环境准备、下载数据集、数据集加载和预处理、构建模型、模型训练、模型评估、模型测试等。

一、

1.ShuffleNet网络

旷视科技提出的CNN模型

应用在移动端

通过设计更高效的网络结构来实现模型的压缩和加速。

目标

        利用有限资源达到最好的模型精度。

核心引入了两种操作

        Pointwise Group Convolution

        Channel Shuffle

优点

        保持准确率不低,降低参数量

2.模型架构

ShuffleNet最显著的特点

重排不同通道解决Group Convolution弊端

改进ResNet Bottleneck单元

较小计算量达到较高准确率

Pointwise Group Convolution

Group Convolution(分组卷积)原理图

分组卷积

每组卷积核大小为in_channels/g*k*k

共有g组

所有组共有(in_channels/g*k*k)*out_channels个参数

是正常卷积参数的1/g

每个卷积核只处理输入特征图部分通道

优点

        降低参数量,输出通道数仍等于卷积核的数量

Depthwise Convolution(深度可分离卷积)

将组数g分为和输入通道相等的in_channels

卷积操作每个in_channels

        每个卷积核只处理一个通道

        卷积核大小为1*k*k

        卷积核参数量:in_channels*k*k

        feature maps通道数与输入通道数相等

Pointwise Group Convolution(逐点分组卷积)

分组卷积基础

每组卷积核大小 1×11×1

卷积核参数量为(in_channels/g*1*1)*out_channels

3.Channel Shuffle

通道重排

Group Convolution的弊端

        不同组别的通道无法进行信息交流

        降低网络的特征提取能力

不同分组通道均匀分散重组

下一层网络能处理不同组别通道的信息

对于g组

每组有n个通道的特征图

        reshape成g行n列的矩阵

        矩阵转置成n行g列

        flatten操作得到新排列

        轻操作

二、环境准备

%%capture captured_output
# 实验环境已经预装了mindspore==2.2.14,如需更换mindspore版本,可更改下面mindspore的版本号
!pip uninstall mindspore -y
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.2.14
# 查看当前 mindspore 版本
!pip show mindspore

输出:

Name: mindspore
Version: 2.2.14
Summary: MindSpore is a new open source deep learning training/inference framework that could be used for mobile, edge and cloud scenarios.
Home-page: https://www.mindspore.cn
Author: The MindSpore Authors
Author-email: contact@mindspore.cn
License: Apache 2.0
Location: /home/nginx/miniconda/envs/jupyter/lib/python3.9/site-packages
Requires: asttokens, astunparse, numpy, packaging, pillow, protobuf, psutil, scipy
Required-by: 

分组卷积类

from mindspore import nn
import mindspore.ops as ops
from mindspore import Tensor
​
class GroupConv(nn.Cell):
    def __init__(self, in_channels, out_channels, kernel_size,
                 stride, pad_mode="pad", pad=0, groups=1, has_bias=False):
        super(GroupConv, self).__init__()
        self.groups = groups
        self.convs = nn.CellList()
        for _ in range(groups):
            self.convs.append(nn.Conv2d(in_channels // groups, out_channels // groups,
                                        kernel_size=kernel_size, stride=stride, has_bias=has_bias,
                                        padding=pad, pad_mode=pad_mode, group=1, weight_init='xavier_uniform'))
​
    def construct(self, x):
        features = ops.split(x, split_size_or_sections=int(len(x[0]) // self.groups), axis=1)
        outputs = ()
        for i in range(self.groups):
            outputs = outputs + (self.convs[i](features[i].astype("float32")),)
        out = ops.cat(outputs, axis=1)
        return out

三、ShuffleNet模块

ShuffleNet的改进,从(a)->(b)->(c)

对ResNet中的Bottleneck结构进行由(a)到(b), (c)的更改:

1.(a)中的一、三层1×1Conv卷积模块(降维、升维)改成1×1GConv逐点分组卷积;

2.(a)中一层降维后进行通道重排,让不同通道的信息交流;

3.(a)中的二层3×3 DWConv降采样模块中步长设置为2

        长宽降为原来的一半((c)中三层)

(c)中shortcut中采用步长为2的3×3平均池化

        相加改成拼接

class ShuffleV1Block(nn.Cell):
    def __init__(self, inp, oup, group, first_group, mid_channels, ksize, stride):
        super(ShuffleV1Block, self).__init__()
        self.stride = stride
        pad = ksize // 2
        self.group = group
        if stride == 2:
            outputs = oup - inp
        else:
            outputs = oup
        self.relu = nn.ReLU()
        branch_main_1 = [
            GroupConv(in_channels=inp, out_channels=mid_channels,
                      kernel_size=1, stride=1, pad_mode="pad", pad=0,
                      groups=1 if first_group else group),
            nn.BatchNorm2d(mid_channels),
            nn.ReLU(),
        ]
        branch_main_2 = [
            nn.Conv2d(mid_channels, mid_channels, kernel_size=ksize, stride=stride,
                      pad_mode='pad', padding=pad, group=mid_channels,
                      weight_init='xavier_uniform', has_bias=False),
            nn.BatchNorm2d(mid_channels),
            GroupConv(in_channels=mid_channels, out_channels=outputs,
                      kernel_size=1, stride=1, pad_mode="pad", pad=0,
                      groups=group),
            nn.BatchNorm2d(outputs),
        ]
        self.branch_main_1 = nn.SequentialCell(branch_main_1)
        self.branch_main_2 = nn.SequentialCell(branch_main_2)
        if stride == 2:
            self.branch_proj = nn.AvgPool2d(kernel_size=3, stride=2, pad_mode='same')
​
    def construct(self, old_x):
        left = old_x
        right = old_x
        out = old_x
        right = self.branch_main_1(right)
        if self.group > 1:
            right = self.channel_shuffle(right)
        right = self.branch_main_2(right)
        if self.stride == 1:
            out = self.relu(left + right)
        elif self.stride == 2:
            left = self.branch_proj(left)
            out = ops.cat((left, right), 1)
            out = self.relu(out)
        return out
​
    def channel_shuffle(self, x):
        batchsize, num_channels, height, width = ops.shape(x)
        group_channels = num_channels // self.group
        x = ops.reshape(x, (batchsize, group_channels, self.group, height, width))
        x = ops.transpose(x, (0, 2, 1, 3, 4))
        x = ops.reshape(x, (batchsize, num_channels, height, width))
        return x

四、构建ShuffleNet网络

ShuffleNet网络结构图

输入图像224×224,组数3(g = 3)为例

卷积层

        通过数量24

        卷积核大小为3×3

        stride为2

        输出特征图大小为112×112

        channel为24

最大池化层

        stride为2

        输出特征图大小为56×56

        channel数不变

堆叠3个ShuffleNet模块

        Stage2重复4次

                下采样模块

                        特征图长宽减半

                        Channel 240

        Stage3重复8次

                下采样模块

                        特征图长宽减半

                        Channel 480

        Stage4重复4次

                下采样模块

                        特征图长宽减半

                        Channel 960

全局平均池化

        输出大小为1×1×960

全连接层

Softmax

得到分类概率

class ShuffleNetV1(nn.Cell):
    def __init__(self, n_class=1000, model_size='2.0x', group=3):
        super(ShuffleNetV1, self).__init__()
        print('model size is ', model_size)
        self.stage_repeats = [4, 8, 4]
        self.model_size = model_size
        if group == 3:
            if model_size == '0.5x':
                self.stage_out_channels = [-1, 12, 120, 240, 480]
            elif model_size == '1.0x':
                self.stage_out_channels = [-1, 24, 240, 480, 960]
            elif model_size == '1.5x':
                self.stage_out_channels = [-1, 24, 360, 720, 1440]
            elif model_size == '2.0x':
                self.stage_out_channels = [-1, 48, 480, 960, 1920]
            else:
                raise NotImplementedError
        elif group == 8:
            if model_size == '0.5x':
                self.stage_out_channels = [-1, 16, 192, 384, 768]
            elif model_size == '1.0x':
                self.stage_out_channels = [-1, 24, 384, 768, 1536]
            elif model_size == '1.5x':
                self.stage_out_channels = [-1, 24, 576, 1152, 2304]
            elif model_size == '2.0x':
                self.stage_out_channels = [-1, 48, 768, 1536, 3072]
            else:
                raise NotImplementedError
        input_channel = self.stage_out_channels[1]
        self.first_conv = nn.SequentialCell(
            nn.Conv2d(3, input_channel, 3, 2, 'pad', 1, weight_init='xavier_uniform', has_bias=False),
            nn.BatchNorm2d(input_channel),
            nn.ReLU(),
        )
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='same')
        features = []
        for idxstage in range(len(self.stage_repeats)):
            numrepeat = self.stage_repeats[idxstage]
            output_channel = self.stage_out_channels[idxstage + 2]
            for i in range(numrepeat):
                stride = 2 if i == 0 else 1
                first_group = idxstage == 0 and i == 0
                features.append(ShuffleV1Block(input_channel, output_channel,
                                               group=group, first_group=first_group,
                                               mid_channels=output_channel // 4, ksize=3, stride=stride))
                input_channel = output_channel
        self.features = nn.SequentialCell(features)
        self.globalpool = nn.AvgPool2d(7)
        self.classifier = nn.Dense(self.stage_out_channels[-1], n_class)
​
    def construct(self, x):
        x = self.first_conv(x)
        x = self.maxpool(x)
        x = self.features(x)
        x = self.globalpool(x)
        x = ops.reshape(x, (-1, self.stage_out_channels[-1]))
        x = self.classifier(x)
        return x

五、模型训练和评估

采用CIFAR-10数据集对ShuffleNet进行预训练。

1.训练集准备与加载

CIFAR-10

有60000张32*32的彩色图像

均匀地分为10个类别

50000张图片作为训练集

10000张图片作为测试集

mindspore.dataset.Cifar10Dataset接口

下载CIFAR-10的训练集

加载

from download import download
​
url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz"
​
download(url, "./dataset", kind="tar.gz", replace=True)

输出:

Creating data folder...
Downloading data from https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz (162.2 MB)

file_sizes: 100%|█████████████████████████████| 170M/170M [00:00<00:00, 177MB/s]
Extracting tar.gz file...
Successfully downloaded / unzipped to ./dataset
[6]:
'./dataset'
import mindspore as ms
from mindspore.dataset import Cifar10Dataset
from mindspore.dataset import vision, transforms
​
def get_dataset(train_dataset_path, batch_size, usage):
    image_trans = []
    if usage == "train":
        image_trans = [
            vision.RandomCrop((32, 32), (4, 4, 4, 4)),
            vision.RandomHorizontalFlip(prob=0.5),
            vision.Resize((224, 224)),
            vision.Rescale(1.0 / 255.0, 0.0),
            vision.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]),
            vision.HWC2CHW()
        ]
    elif usage == "test":
        image_trans = [
            vision.Resize((224, 224)),
            vision.Rescale(1.0 / 255.0, 0.0),
            vision.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]),
            vision.HWC2CHW()
        ]
    label_trans = transforms.TypeCast(ms.int32)
    dataset = Cifar10Dataset(train_dataset_path, usage=usage, shuffle=True)
    dataset = dataset.map(image_trans, 'image')
    dataset = dataset.map(label_trans, 'label')
    dataset = dataset.batch(batch_size, drop_remainder=True)
    return dataset
​
dataset = get_dataset("./dataset/cifar-10-batches-bin", 128, "train")
batches_per_epoch = dataset.get_dataset_size()

2.模型训练

随机初始化参数做预训练。

调用ShuffleNetV1定义网络

参数量选择"2.0x"

定义损失函数为交叉熵损失

学习率4轮的warmup后

余弦退火

优化器Momentum

train.model.Model接口封装

model.train()训练

传入回调函数

ModelCheckpoint

CheckpointConfig

TimeMonitor

LossMonitor

打印

训练轮数

损失

时间

保存ckpt文件在当前目录下

import time
import mindspore
import numpy as np
from mindspore import Tensor, nn
from mindspore.train import ModelCheckpoint, CheckpointConfig, TimeMonitor, LossMonitor, Model, Top1CategoricalAccuracy, Top5CategoricalAccuracy
​
def train():
    mindspore.set_context(mode=mindspore.PYNATIVE_MODE, device_target="Ascend")
    net = ShuffleNetV1(model_size="2.0x", n_class=10)
    loss = nn.CrossEntropyLoss(weight=None, reduction='mean', label_smoothing=0.1)
    min_lr = 0.0005
    base_lr = 0.05
    lr_scheduler = mindspore.nn.cosine_decay_lr(min_lr,
                                                base_lr,
                                                batches_per_epoch*250,
                                                batches_per_epoch,
                                                decay_epoch=250)
    lr = Tensor(lr_scheduler[-1])
    optimizer = nn.Momentum(params=net.trainable_params(), learning_rate=lr, momentum=0.9, weight_decay=0.00004, loss_scale=1024)
    loss_scale_manager = ms.amp.FixedLossScaleManager(1024, drop_overflow_update=False)
    model = Model(net, loss_fn=loss, optimizer=optimizer, amp_level="O3", loss_scale_manager=loss_scale_manager)
    callback = [TimeMonitor(), LossMonitor()]
    save_ckpt_path = "./"
    config_ckpt = CheckpointConfig(save_checkpoint_steps=batches_per_epoch, keep_checkpoint_max=5)
    ckpt_callback = ModelCheckpoint("shufflenetv1", directory=save_ckpt_path, config=config_ckpt)
    callback += [ckpt_callback]
​
    print("============== Starting Training ==============")
    start_time = time.time()
    # 由于时间原因,epoch = 5,可根据需求进行调整
    model.train(5, dataset, callbacks=callback)
    use_time = time.time() - start_time
    hour = str(int(use_time // 60 // 60))
    minute = str(int(use_time // 60 % 60))
    second = str(int(use_time % 60))
    print("total time:" + hour + "h " + minute + "m " + second + "s")
    print("============== Train Success ==============")
​
if __name__ == '__main__':
    train()

输出:

model size is  2.0x
============== Starting Training ==============
epoch: 1 step: 1, loss is 2.702430248260498
epoch: 1 step: 2, loss is 2.5544934272766113
epoch: 1 step: 3, loss is 2.3527920246124268
epoch: 1 step: 4, loss is 2.432495355606079
epoch: 1 step: 5, loss is 2.442847490310669
......
epoch: 1 step: 386, loss is 1.8315027952194214
epoch: 1 step: 387, loss is 1.9081732034683228
epoch: 1 step: 388, loss is 1.8965389728546143
epoch: 1 step: 389, loss is 1.8942060470581055
epoch: 1 step: 390, loss is 1.8646998405456543
Train epoch time: 439745.086 ms, per step time: 1127.552 ms
epoch: 2 step: 1, loss is 1.9022231101989746
epoch: 2 step: 2, loss is 1.8828961849212646
epoch: 2 step: 3, loss is 1.8220021724700928
epoch: 2 step: 4, loss is 2.003005027770996
epoch: 2 step: 5, loss is 1.8657888174057007
......
epoch: 2 step: 386, loss is 1.754606008529663
epoch: 2 step: 387, loss is 1.73811674118042
epoch: 2 step: 388, loss is 1.5935282707214355
epoch: 2 step: 389, loss is 1.7022861242294312
epoch: 2 step: 390, loss is 1.7202574014663696
Train epoch time: 121300.859 ms, per step time: 311.028 ms
epoch: 3 step: 1, loss is 1.6813828945159912
epoch: 3 step: 2, loss is 1.7341467142105103
epoch: 3 step: 3, loss is 1.8423044681549072
epoch: 3 step: 4, loss is 1.8151057958602905
epoch: 3 step: 5, loss is 1.727158784866333
......
epoch: 3 step: 386, loss is 1.6009197235107422
epoch: 3 step: 387, loss is 1.7389277219772339
epoch: 3 step: 388, loss is 1.6847612857818604
epoch: 3 step: 389, loss is 1.7618985176086426
epoch: 3 step: 390, loss is 1.719774842262268
Train epoch time: 121936.621 ms, per step time: 312.658 ms
epoch: 4 step: 1, loss is 1.6524462699890137
epoch: 4 step: 2, loss is 1.5743780136108398
epoch: 4 step: 3, loss is 1.7330453395843506
epoch: 4 step: 4, loss is 1.6160061359405518
epoch: 4 step: 5, loss is 1.6632086038589478
......
epoch: 4 step: 386, loss is 1.6585990190505981
epoch: 4 step: 387, loss is 1.6520838737487793
epoch: 4 step: 388, loss is 1.4504361152648926
epoch: 4 step: 389, loss is 1.8115458488464355
epoch: 4 step: 390, loss is 1.6291583776474
Train epoch time: 121944.082 ms, per step time: 312.677 ms
epoch: 5 step: 1, loss is 1.737457275390625
epoch: 5 step: 2, loss is 1.6314475536346436
epoch: 5 step: 3, loss is 1.6039154529571533
epoch: 5 step: 4, loss is 1.59605073928833
epoch: 5 step: 5, loss is 1.6140247583389282
......
epoch: 5 step: 386, loss is 1.599562406539917
epoch: 5 step: 387, loss is 1.486626148223877
epoch: 5 step: 388, loss is 1.6146260499954224
epoch: 5 step: 389, loss is 1.6220197677612305
epoch: 5 step: 390, loss is 1.610574722290039
Train epoch time: 121699.011 ms, per step time: 312.049 ms
total time:0h 15m 26s
============== Train Success ==============

训练好的模型保存在当前目录的shufflenetv1-5_390.ckpt中,用作评估。

3.模型评估

在CIFAR-10的测试集上对模型进行评估。

设置评估模型路径

加载数据集

设置Top 1、Top 5的评估标准

model.eval()接口对模型进行评估

from mindspore import load_checkpoint, load_param_into_net
​
def test():
    mindspore.set_context(mode=mindspore.GRAPH_MODE, device_target="Ascend")
    dataset = get_dataset("./dataset/cifar-10-batches-bin", 128, "test")
    net = ShuffleNetV1(model_size="2.0x", n_class=10)
    param_dict = load_checkpoint("shufflenetv1-5_390.ckpt")
    load_param_into_net(net, param_dict)
    net.set_train(False)
    loss = nn.CrossEntropyLoss(weight=None, reduction='mean', label_smoothing=0.1)
    eval_metrics = {'Loss': nn.Loss(), 'Top_1_Acc': Top1CategoricalAccuracy(),
                    'Top_5_Acc': Top5CategoricalAccuracy()}
    model = Model(net, loss_fn=loss, metrics=eval_metrics)
    start_time = time.time()
    res = model.eval(dataset, dataset_sink_mode=False)
    use_time = time.time() - start_time
    hour = str(int(use_time // 60 // 60))
    minute = str(int(use_time // 60 % 60))
    second = str(int(use_time % 60))
    log = "result:" + str(res) + ", ckpt:'" + "./shufflenetv1-5_390.ckpt" \
        + "', time: " + hour + "h " + minute + "m " + second + "s"
    print(log)
    filename = './eval_log.txt'
    with open(filename, 'a') as file_object:
        file_object.write(log + '\n')
​
if __name__ == '__main__':
    test()

输出:

model size is  2.0x
[ERROR] CORE(263,ffffa833e930,python):2024-07-07-15:29:24.418.000 [mindspore/core/utils/file_utils.cc:253] GetRealPath] Get realpath failed, path[/tmp/ipykernel_263/3162391481.py]
[ERROR] CORE(263,ffffa833e930,python):2024-07-07-15:29:24.418.539 [mindspore/core/utils/file_utils.cc:253] GetRealPath] Get realpath failed, path[/tmp/ipykernel_263/3162391481.py]
......
result:{'Loss': 1.6150915485162, 'Top_1_Acc': 0.4930889423076923, 'Top_5_Acc': 0.9283854166666666}, ckpt:'./shufflenetv1-5_390.ckpt', time: 0h 1m 26s

4.模型预测

在CIFAR-10的测试集上对模型进行预测,并将预测结果可视化。

import mindspore
import matplotlib.pyplot as plt
import mindspore.dataset as ds
​
net = ShuffleNetV1(model_size="2.0x", n_class=10)
show_lst = []
param_dict = load_checkpoint("shufflenetv1-5_390.ckpt")
load_param_into_net(net, param_dict)
model = Model(net)
dataset_predict = ds.Cifar10Dataset(dataset_dir="./dataset/cifar-10-batches-bin", shuffle=False, usage="train")
dataset_show = ds.Cifar10Dataset(dataset_dir="./dataset/cifar-10-batches-bin", shuffle=False, usage="train")
dataset_show = dataset_show.batch(16)
show_images_lst = next(dataset_show.create_dict_iterator())["image"].asnumpy()
image_trans = [
    vision.RandomCrop((32, 32), (4, 4, 4, 4)),
    vision.RandomHorizontalFlip(prob=0.5),
    vision.Resize((224, 224)),
    vision.Rescale(1.0 / 255.0, 0.0),
    vision.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]),
    vision.HWC2CHW()
        ]
dataset_predict = dataset_predict.map(image_trans, 'image')
dataset_predict = dataset_predict.batch(16)
class_dict = {0:"airplane", 1:"automobile", 2:"bird", 3:"cat", 4:"deer", 5:"dog", 6:"frog", 7:"horse", 8:"ship", 9:"truck"}
# 推理效果展示(上方为预测的结果,下方为推理效果图片)
plt.figure(figsize=(16, 5))
predict_data = next(dataset_predict.create_dict_iterator())
output = model.predict(ms.Tensor(predict_data['image']))
pred = np.argmax(output.asnumpy(), axis=1)
index = 0
for image in show_images_lst:
    plt.subplot(2, 8, index+1)
    plt.title('{}'.format(class_dict[pred[index]]))
    index += 1
    plt.imshow(image)
    plt.axis("off")
plt.show()

输出:

model size is  2.0x
[ERROR] CORE(263,ffffa833e930,python):2024-07-07-15:30:55.337.972 [mindspore/core/utils/file_utils.cc:253] GetRealPath] Get realpath failed, path[/tmp/ipykernel_263/1681751341.py]
[ERROR] CORE(263,ffffa833e930,python):2024-07-07-15:30:55.338.097 [mindspore/core/utils/file_utils.cc:253] GetRealPath] Get realpath failed, path[/tmp/ipykernel_263/1681751341.py]
......

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

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

相关文章

【JavaSE】图书管理系统

目录 最终效果book包Book类BookList类 user包User类AdmiUser类&#xff08;管理员类&#xff09;NormalUser类&#xff08;普通用户类&#xff09; opeeration包IOperation接口FindOpertion类&#xff08;查找操作&#xff09;AddOpertion类&#xff08;增加操作&#xff09;De…

关于解决双屏幕鼠标移动方向问题

1.点开设置》系统》屏幕 2.分清屏幕标识&#xff0c;一般笔记本为1 3.点击要移动的屏幕&#xff0c;然后按住鼠标左键不方进行移动 感谢您的浏览&#xff0c;希望可以帮到您&#xff01;

探索多模态预训练:MAnTiS、ActionCLIP、CPT与CoOp的Prompt技巧

上一篇博文整理了 预训练新范式&#xff08;Prompt-tuning&#xff0c;Prefix-tuning&#xff0c;P-tuning&#xff09; &#xff0c;主要是围绕NLP上的成果&#xff0c;具体的概念本文也不做过多赘述。本篇文章将主要整理几篇有代表性的Prompt方法在多模态领域中的应用。 Mult…

unity使用 MQTT复现plant simulate仿真

unity使用 MQTT复现plant simulate仿真 一、plant simulate端配置 1、plant simulate MQTT组件配置,该组件在类库的信息流类目下,端口不变,填写ip即可; 2、设备配置界面,在控件入口和出口处各挂一个脚本,当物料出入该设备时会分别触发执行这两个脚本,粘贴如下代码; E…

视频怎么压缩变小?最佳视频压缩器

即使在云存储和廉价硬盘空间时代&#xff0c;大视频文件使用起来仍然不方便。无论是存储、发送到电子邮件帐户还是刻录到 DVD&#xff0c;拥有最好的免费压缩软件可以确保您快速缩小文件大小&#xff0c;而不必担心视频质量下降。继续阅读以探索一些顶级最佳 免费视频压缩器选项…

小红书矩阵管理系统:多账号运营的智能解决方案

随着社交媒体的多元化发展&#xff0c;内容创作者和品牌商越来越需要一个能够高效管理多个账号的系统。小红书作为国内领先的生活分享平台&#xff0c;其矩阵管理系统应运而生&#xff0c;为用户带来了多账号发布、批量剪辑视频以及一键分发的便捷功能。本文将详细介绍小红书矩…

必看!微信小程序必备证书!

微信小程序必备SSL证书。在日益增长的数字经济中&#xff0c;微信小程序已成为商家与消费者之间重要的交互平台。由于其便捷性和广泛的用户基础&#xff0c;越来越多的企业选择通过小程序来提供服务。然而&#xff0c;在开发和部署微信小程序时&#xff0c;确保数据安全是一个不…

数据结构笔记之树常考性质6

总结&#xff1a; 具有n个结点的m叉树的最小高度可以通过计算并向下取整得到。高度最小时的情况是所有结点都有m个孩子。

计算机前端面试题总结-暑期实习(答案补充2)

目录 技术方面 二、js 1.js数据类型 1&#xff09;值类型(基本类型) 2&#xff09;引用数据类型&#xff08;对象类型&#xff09; ​编辑 2.判断数据类型是否为数组类型 1&#xff09;Array.isArray() 2&#xff09;instanceof操作符 3&#xff09; Object.prototyp…

飞猪惹怒12306,一张火车票让第三方平台耍尽手段……

小柴已经记不清铁路12306是多少次发出提醒&#xff0c;似乎每一次出行高峰&#xff0c;都会提醒一次。 比如一再强调&#xff0c;购买加速包、付费成为会员就能优先出票&#xff0c;找朋友助力砍一刀&#xff0c;就能获得更高的出票概率……都是假的。‍‍ 因为&#xff0c;铁…

PostgreSQL 中如何处理数据的并发更新冲突解决?

文章目录 一、并发更新冲突的场景二、PostgreSQL 中的并发控制机制&#xff08;一&#xff09; 封锁机制&#xff08;二&#xff09; 事务隔离级别 三、并发更新冲突的解决方法&#xff08;一&#xff09; 重试机制&#xff08;二&#xff09; 使用乐观并发控制&#xff08;三&…

使用机器学习 最近邻算法(Nearest Neighbors)进行点云分析

使用 NearestNeighbors 进行点云分析 在数据分析和机器学习领域&#xff0c;最近邻算法&#xff08;Nearest Neighbors&#xff09;是一种常用的非参数方法。它广泛应用于分类、回归和聚类分析等任务。下面将介绍如何使用 scikit-learn 库中的 NearestNeighbors 类来进行点云数…

打开excel时弹出stdole32.tlb

问题描述 打开excel时弹出stdole32.tlb 如下图&#xff1a; 解决方法 打开 Microsoft Excel 并收到关于 stdole32.tlb 的错误提示时&#xff0c;通常意味着与 Excel 相关的某个组件或类型库可能已损坏或不兼容。 stdole32.tlb 是一个用于存储自动化对象定义的类型库&#x…

【解读大模型(LLM)的token】

文末有福利&#xff01; 当人们谈论大型语言模型的大小时&#xff0c;参数会让我们了解神经网络的结构有多复杂&#xff0c;而token的大小会让我们知道有多少数据用于训练参数。 正像陆奇博士所说的那样&#xff0c;大型语言模型为从文本生成到问题回答的各种任务提供了令人印象…

2024年的设计理念革新:快速获取设计趋势的资源集合!

随着2024年第三季度开始&#xff0c;今年的设计趋势也逐渐出现。与2023 年设计相比&#xff0c;趋势变化空间不大&#xff0c;大部分是在 2023 年度设计趋势的延伸和发展。即使趋势不会一直改变&#xff0c;了解趋势对设计师来说仍然非常重要。接下来&#xff0c;本文将与你分享…

拥抱应用创新,拒绝无谓的模型竞争

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

如何查询并下载韩国签证

登录大韩民国签证门户网站&#xff08;https://www.visa.go.kr&#xff09;&#xff0c;点击“查询/签发”- “办理进度查询及打印”。 2) 输入护照号码、英文姓名及出生日期后点击查询。 3) 若签证通过&#xff0c;办理状态信息栏下面会显示签证信息。 4&#xff09;点击“签证…

大数据信用评分太低,是什么原因引起的?

在大数据时代&#xff0c;个人的大数据信用评分变得尤为重要。它不仅影响着我们能否顺利地获得贷款、信用卡等金融服务&#xff0c;还在很多方面影响着我们的日常生活。那么&#xff0c;哪些原因可能会导致我们的大数据信用评分降低呢?本文将对此进行详细的总结&#xff0c;一…

防火墙安全策略用户认证综合实验

实验拓扑&#xff1a; 实验要求&#xff1a; 1&#xff1a;DMz区内的服务器&#xff0c;办公区仅能在办公时间内(9:00-18:00)可以访问&#xff0c;生产区的设备全天可以访问 2&#xff1a;生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网 3&#xff1a;办公…

ARM_Linux驱动开发——字符设备驱动开发(上)

目录 一、Linux驱动开发思维 二、Linux驱动开发分类 三、“ ARM_Linux驱动开发——字符设备驱动开发 ” 字符设备驱动简介 前言 在分享Linux驱动开发之前&#xff0c;我想带大家首先回顾一下裸机驱动开发和Linux驱动开发的区别。 1、运行环境和操作系统&#xff1a; 裸机驱…