通俗易懂理解MobileNet网络模型

温故而知新,可以为师矣!

一、参考资料

详细且通俗讲解轻量级神经网络——MobileNets【V1、V2、V3】

MobileNet v1 和 MobileNet v2

二、MobileNet v1

原始论文:[1]

MobileNet网络详解

【深度学习】轻量化CNN网络MobileNet系列详解

MobileNet V1 图像分类

1. MobileNet v1创新点

MobileNet v1是专注于移动端或者嵌入式设备这种计算量不是特别大的轻量级CNN网络。如图下图所示,MobileNet v1只是牺牲了一点精度,却大大减少模型的参数量和运算量。
在这里插入图片描述

首先,MobileNet v1最主要的贡献是提出了深度可分离卷积( Depthwise Separable Convolution),它可以大大减少计算量和参数量。如下表格所示,MobileNet v1的计算量和参数量均小于GoogleNet,同时在分类效果上比GoogleNet还要好,这就是深度可分离卷积的功劳了。VGG16的计算量参数量比MobileNet大30倍,但是结果仅仅高了1%不到。

在这里插入图片描述

其次,就是增加超参数α、ρ可以根据需求调节网络的宽度和分辨率。具体来说,超参数α是为了控制卷积核的个数,也就是输出的channel,因此α可以减少模型的参数量;超参数ρ是为了控制图像输入的size,是不会影响模型的参数,但是可以减少计算量。

网络的宽度,代表卷积层的维度,也就是channel,例如512,1024

网络的深度,代表卷积层的层数,也就是网络有多深,例如resnet34、resnet101

2. MobileNet v1网络结构

关于深度可分离卷积的详细介绍,可参考另一篇博客:深入浅出理解深度可分离卷积(Depthwise Separable Convolution)

在这里插入图片描述

3. (PyTorch)代码实现

3.1 搭建MobileNet v1网络模型

import torch.nn as nn# MobileNet v1
class MobileNetV1(nn.Module):def __init__(self,num_classes=1000):super(MobileNetV1, self).__init__()# 第一层的卷积,channel->32,size减半def conv_bn(in_channel, out_channel, stride):return nn.Sequential(nn.Conv2d(in_channel, out_channel, 3, stride, 1, bias=False),nn.BatchNorm2d(out_channel),nn.ReLU(inplace=True))# 深度可分离卷积=depthwise卷积 + pointwise卷积def conv_dw(in_channel, out_channel, stride):return nn.Sequential(# depthwise 卷积,channel不变,stride = 2的时候,size减半nn.Conv2d(in_channel, in_channel, 3, stride, padding=1, groups=in_channel, bias=False),nn.BatchNorm2d(in_channel),nn.ReLU(inplace=True),# pointwise卷积(1*1卷积) same卷积, 只改变channelnn.Conv2d(in_channel, out_channel, 1, 1, padding=0, bias=False),nn.BatchNorm2d(out_channel),nn.ReLU(inplace=True),)self.model = nn.Sequential(conv_bn(3, 32, 2),          # conv/s2           out=224*224*32conv_dw(32, 64, 1),         # conv dw +1*1      out=112*112*64conv_dw(64, 128, 2),        # conv dw +1*1      out=56*56*128conv_dw(128, 128, 1),       # conv dw +1*1      out=56*56*128conv_dw(128, 256, 2),       # conv dw +1*1      out=28*28*256conv_dw(256, 256, 1),       # conv dw +1*1      out=28*28*256conv_dw(256, 512, 2),       # conv dw +1*1      out=14*14*512conv_dw(512, 512, 1),       # 5个 conv dw +1*1 ----> size不变,channel不变,out=14*14*512conv_dw(512, 512, 1),conv_dw(512, 512, 1),conv_dw(512, 512, 1),conv_dw(512, 512, 1),conv_dw(512, 1024, 2),      # conv dw +1*1      out=7*7*1024conv_dw(1024, 1024, 1),     # conv dw +1*1      out=7*7*1024nn.AvgPool2d(7),            # avg pool          out=1*1*1024)self.fc = nn.Linear(1024, num_classes)      # fcdef forward(self, x):x = self.model(x)x = x.view(-1, 1024)x = self.fc(x)return x

3.2 torchsummary查看网络结构

# 安装torchsummary
pip install torchsummary

使用 torchsummary 查看网络结构:

from torchsummary import summary
import torchDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
net = MobileNetV1()
net.to(DEVICE)
print(summary(net, input_size=(3, 224, 224),device=DEVICE))

输出结果

----------------------------------------------------------------Layer (type)               Output Shape         Param #
================================================================Conv2d-1         [-1, 32, 112, 112]             864BatchNorm2d-2         [-1, 32, 112, 112]              64ReLU-3         [-1, 32, 112, 112]               0Conv2d-4         [-1, 32, 112, 112]             288BatchNorm2d-5         [-1, 32, 112, 112]              64ReLU-6         [-1, 32, 112, 112]               0Conv2d-7         [-1, 64, 112, 112]           2,048BatchNorm2d-8         [-1, 64, 112, 112]             128ReLU-9         [-1, 64, 112, 112]               0Conv2d-10           [-1, 64, 56, 56]             576BatchNorm2d-11           [-1, 64, 56, 56]             128ReLU-12           [-1, 64, 56, 56]               0Conv2d-13          [-1, 128, 56, 56]           8,192BatchNorm2d-14          [-1, 128, 56, 56]             256ReLU-15          [-1, 128, 56, 56]               0Conv2d-16          [-1, 128, 56, 56]           1,152BatchNorm2d-17          [-1, 128, 56, 56]             256ReLU-18          [-1, 128, 56, 56]               0Conv2d-19          [-1, 128, 56, 56]          16,384BatchNorm2d-20          [-1, 128, 56, 56]             256ReLU-21          [-1, 128, 56, 56]               0Conv2d-22          [-1, 128, 28, 28]           1,152BatchNorm2d-23          [-1, 128, 28, 28]             256ReLU-24          [-1, 128, 28, 28]               0Conv2d-25          [-1, 256, 28, 28]          32,768BatchNorm2d-26          [-1, 256, 28, 28]             512ReLU-27          [-1, 256, 28, 28]               0Conv2d-28          [-1, 256, 28, 28]           2,304BatchNorm2d-29          [-1, 256, 28, 28]             512ReLU-30          [-1, 256, 28, 28]               0Conv2d-31          [-1, 256, 28, 28]          65,536BatchNorm2d-32          [-1, 256, 28, 28]             512ReLU-33          [-1, 256, 28, 28]               0Conv2d-34          [-1, 256, 14, 14]           2,304BatchNorm2d-35          [-1, 256, 14, 14]             512ReLU-36          [-1, 256, 14, 14]               0Conv2d-37          [-1, 512, 14, 14]         131,072BatchNorm2d-38          [-1, 512, 14, 14]           1,024ReLU-39          [-1, 512, 14, 14]               0Conv2d-40          [-1, 512, 14, 14]           4,608BatchNorm2d-41          [-1, 512, 14, 14]           1,024ReLU-42          [-1, 512, 14, 14]               0Conv2d-43          [-1, 512, 14, 14]         262,144BatchNorm2d-44          [-1, 512, 14, 14]           1,024ReLU-45          [-1, 512, 14, 14]               0Conv2d-46          [-1, 512, 14, 14]           4,608BatchNorm2d-47          [-1, 512, 14, 14]           1,024ReLU-48          [-1, 512, 14, 14]               0Conv2d-49          [-1, 512, 14, 14]         262,144BatchNorm2d-50          [-1, 512, 14, 14]           1,024ReLU-51          [-1, 512, 14, 14]               0Conv2d-52          [-1, 512, 14, 14]           4,608BatchNorm2d-53          [-1, 512, 14, 14]           1,024ReLU-54          [-1, 512, 14, 14]               0Conv2d-55          [-1, 512, 14, 14]         262,144BatchNorm2d-56          [-1, 512, 14, 14]           1,024ReLU-57          [-1, 512, 14, 14]               0Conv2d-58          [-1, 512, 14, 14]           4,608BatchNorm2d-59          [-1, 512, 14, 14]           1,024ReLU-60          [-1, 512, 14, 14]               0Conv2d-61          [-1, 512, 14, 14]         262,144BatchNorm2d-62          [-1, 512, 14, 14]           1,024ReLU-63          [-1, 512, 14, 14]               0Conv2d-64          [-1, 512, 14, 14]           4,608BatchNorm2d-65          [-1, 512, 14, 14]           1,024ReLU-66          [-1, 512, 14, 14]               0Conv2d-67          [-1, 512, 14, 14]         262,144BatchNorm2d-68          [-1, 512, 14, 14]           1,024ReLU-69          [-1, 512, 14, 14]               0Conv2d-70            [-1, 512, 7, 7]           4,608BatchNorm2d-71            [-1, 512, 7, 7]           1,024ReLU-72            [-1, 512, 7, 7]               0Conv2d-73           [-1, 1024, 7, 7]         524,288BatchNorm2d-74           [-1, 1024, 7, 7]           2,048ReLU-75           [-1, 1024, 7, 7]               0Conv2d-76           [-1, 1024, 7, 7]           9,216BatchNorm2d-77           [-1, 1024, 7, 7]           2,048ReLU-78           [-1, 1024, 7, 7]               0Conv2d-79           [-1, 1024, 7, 7]       1,048,576BatchNorm2d-80           [-1, 1024, 7, 7]           2,048ReLU-81           [-1, 1024, 7, 7]               0AvgPool2d-82           [-1, 1024, 1, 1]               0Linear-83                 [-1, 1000]       1,025,000
================================================================
Total params: 4,231,976
Trainable params: 4,231,976
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 115.43
Params size (MB): 16.14
Estimated Total Size (MB): 132.15
----------------------------------------------------------------
None

3.3 train训练模型

import torch
import torch.nn as nn
from torchvision import transforms, datasets
import torch.optim as optim
from model import MobileNetV1
from torch.utils.data import DataLoader
from tqdm import tqdmDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
data_transform = {"train": transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.255])]),"test": transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.255])])}# 训练集
trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=data_transform['train'])
trainloader = DataLoader(trainset, batch_size=16, shuffle=True)# 测试集
testset = datasets.CIFAR10(root='./data', train=False, download=True, transform=data_transform['test'])
testloader = DataLoader(testset, batch_size=16, shuffle=False)# 样本的个数
num_trainset = len(trainset)  # 50000
num_testset = len(testset)  # 10000# 构建网络
net = MobileNetV1(num_classes=10)
net.to(DEVICE)# 加载损失和优化器
loss_function = nn.CrossEntropyLoss()
loss_fun = loss_function.to(DEVICE)learning_rate = 0.0001
optimizer = optim.Adam(net.parameters(), lr=learning_rate)best_acc = 0.0
save_path = './MobileNetV1.pth'for epoch in range(10):net.train()  # 训练模式running_loss = 0.0for data in tqdm(trainloader):images, labels = dataimages, labels = images.to(DEVICE), labels.to(DEVICE)optimizer.zero_grad()out = net(images)  # 总共有三个输出loss = loss_function(out, labels)loss.backward()  # 反向传播optimizer.step()running_loss += loss.item()# test# 测试过程不需要通过反向传播来更新参数。net.eval()  # 测试模式acc = 0.0with torch.no_grad():  # 测试不需要进行反向传播,即不需要梯度变化for test_data in tqdm(testloader):test_images, test_labels = test_datatest_images, test_labels = test_images.to(DEVICE), test_labels.to(DEVICE)outputs = net(test_images)predict_y = torch.max(outputs, dim=1)[1]acc += (predict_y == test_labels).sum().item()accurate = acc / num_testsettrain_loss = running_loss / num_trainsetprint('[epoch %d] train_loss: %.3f  test_accuracy: %.3f' %(epoch + 1, train_loss, accurate))if accurate > best_acc:best_acc = accuratetorch.save(net.state_dict(), save_path)print('Finished Training')

输出结果

Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
170499072it [00:30, 5634555.25it/s]                                
Extracting ./data/cifar-10-python.tar.gz to ./data
Files already downloaded and verified
100%|██████████| 3125/3125 [02:18<00:00, 22.55it/s]
100%|██████████| 625/625 [00:12<00:00, 51.10it/s]
[epoch 1] train_loss: 0.101  test_accuracy: 0.516
100%|██████████| 3125/3125 [02:23<00:00, 21.78it/s]
100%|██████████| 625/625 [00:11<00:00, 54.31it/s]
[epoch 2] train_loss: 0.079  test_accuracy: 0.612
100%|██████████| 3125/3125 [02:20<00:00, 22.17it/s]
100%|██████████| 625/625 [00:11<00:00, 54.28it/s]
[epoch 3] train_loss: 0.066  test_accuracy: 0.672
100%|██████████| 3125/3125 [02:21<00:00, 22.09it/s]
100%|██████████| 625/625 [00:11<00:00, 55.52it/s]
[epoch 4] train_loss: 0.056  test_accuracy: 0.722
100%|██████████| 3125/3125 [02:13<00:00, 23.34it/s]
100%|██████████| 625/625 [00:11<00:00, 55.56it/s]
[epoch 5] train_loss: 0.048  test_accuracy: 0.748
100%|██████████| 3125/3125 [02:14<00:00, 23.31it/s]
100%|██████████| 625/625 [00:11<00:00, 52.19it/s]
[epoch 6] train_loss: 0.042  test_accuracy: 0.763
100%|██████████| 3125/3125 [02:14<00:00, 23.18it/s]
100%|██████████| 625/625 [00:11<00:00, 56.05it/s]
[epoch 7] train_loss: 0.035  test_accuracy: 0.781
100%|██████████| 3125/3125 [02:14<00:00, 23.27it/s]
100%|██████████| 625/625 [00:11<00:00, 55.88it/s]
[epoch 8] train_loss: 0.031  test_accuracy: 0.790
100%|██████████| 3125/3125 [02:13<00:00, 23.32it/s]
100%|██████████| 625/625 [00:11<00:00, 55.89it/s]
[epoch 9] train_loss: 0.026  test_accuracy: 0.801
100%|██████████| 3125/3125 [02:15<00:00, 22.99it/s]
100%|██████████| 625/625 [00:11<00:00, 55.95it/s]
[epoch 10] train_loss: 0.022  test_accuracy: 0.803
Finished TrainingProcess finished with exit code 0

显卡资源占用情况

在这里插入图片描述

3.4 查看模型权重参数

from model import MobileNetV1
import torchDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'net = MobileNetV1(num_classes=10)
net.load_state_dict(torch.load('./MobileNetV1.pth'))
net.to(DEVICE)with torch.no_grad():for i in range(0,14):       # 查看 depthwise 的权值print(net.model[i][0].weight)

3.5 在CIFAR10数据集上测试效果

import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'import torch
import numpy as np
import matplotlib.pyplot as plt
from model import MobileNetV1
from torchvision.transforms import transforms
from torch.utils.data import DataLoader
import torchvisionclasses = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')# 预处理
transformer = transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.255])])# 加载模型
DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
model = MobileNetV1(num_classes=10)
model.load_state_dict(torch.load('./MobileNetV1.pth'))
model.to(DEVICE)# 加载数据
testSet = torchvision.datasets.CIFAR10(root='./data', train=False, download=False, transform=transformer)
testLoader = DataLoader(testSet, batch_size=12, shuffle=True)# 获取一批数据
imgs, labels = next(iter(testLoader))
imgs = imgs.to(DEVICE)# show
with torch.no_grad():model.eval()prediction = model(imgs)  # 预测prediction = torch.max(prediction, dim=1)[1]prediction = prediction.data.cpu().numpy()plt.figure(figsize=(12, 8))for i, (img, label) in enumerate(zip(imgs, labels)):x = np.transpose(img.data.cpu().numpy(), (1, 2, 0))  # 图像x[:, :, 0] = x[:, :, 0] * 0.229 + 0.485  # 去 normalizationx[:, :, 1] = x[:, :, 1] * 0.224 + 0.456  # 去 normalizationx[:, :, 2] = x[:, :, 2] * 0.255 + 0.406  # 去 normalizationy = label.numpy().item()  # labelplt.subplot(3, 4, i + 1)plt.axis(False)plt.imshow(x)plt.title('R:{},P:{}'.format(classes[y], classes[prediction[i]]))plt.show()

结果展示

在这里插入图片描述

三、MobileNet v2

原始论文:[2]

1. 引言

特征图的每个通道的像素值所代表的特征可以映射到一个低维子空间的流形区域上。通常,在进行卷积操作之后往往会接一层激活层,以此增加特征的非线性,一个常见的激活函数就是 ReLU。激活过程会带来信息损耗,而且这种损耗是无法恢复的,当通道数非常少时,ReLU 的信息损耗更为明显。

如下图所示,其输入是一个表示流形数据的矩阵,和卷积操作类似,经过 n 个ReLU的操作得到 n 个通道的Feature Map,然后通过 n 个Feature Map还原输入数据,还原的越像说明信息损耗的越少。
在这里插入图片描述

从上图可以看出,在输入维度是2,3时,输出和输入相比丢失了较多信息;但是在输入维度是15到30时,输出则保留了输入的较多信息。总得来说,当n值较小时,ReLU的信息损耗非常严重,当n值较大时,输入流形能较好还原

根据对上面提到的信息损耗问题分析,我们可以有两种解决方案:

  1. 替换ReLU:既然是 ReLU 导致的信息损耗,那么可以将ReLU替换成线性激活函数
  2. 提高维度:如果比较多的通道数能减少信息损耗,那么可以通过升维将输入的维度变高

MobileNet v2的题目为 MobileNetV2: Inverted Residuals and Linear BottlenecksLinear BottlenecksInverted Residuals 就是MobileNet v2的核心,分别对应上述两种思路。

2. MobileNet v2创新点

MobileNet v2主要是将残差网络和深度可分离卷积(Depthwise Separable Convolution)进行结合,通过分析单通道的流形特征对残差块进行改进,包括对中间层的扩展(d)以及 bottleneck layers 的线性激活©。

在这里插入图片描述

2.1 Linear Bottlenecks

Relu 激活函数替换为线性激活函数,文章中将变换后的块称为 Linear Bottlenecks,结构如下图所示:
在这里插入图片描述

当然不能把 ReLU 全部替换为线性激活函数,不然网络将会退化为单层神经网络,一个折中方案是在输出 feature map 的通道数较少的时候,也就是 bottleneck 部分使用线性激活函数,其它时候使用 ReLULinear Bottlenecks 块的代码实现如下:

def _bottleneck(inputs, nb_filters, t):x = Conv2D(filters=nb_filters * t, kernel_size=(1,1), padding='same')(inputs)x = Activation(relu6)(x)x = DepthwiseConv2D(kernel_size=(3,3), padding='same')(x)x = Activation(relu6)(x)x = Conv2D(filters=nb_filters, kernel_size=(1,1), padding='same')(x)# do not use activation functionif not K.get_variable_shape(inputs)[3] == nb_filters:inputs = Conv2D(filters=nb_filters, kernel_size=(1,1), padding='same')(inputs)outputs = add([x, inputs])return outputs

2. 3Inverted Residual

Inverted Residuals直译为倒残差结构,我们来看看其与正常的残差结构有什么区别和联系:通过下图可以看出,左侧为ResNet中的残差结构,其结构为:1x1卷积降维->3x3卷积->1x1卷积升维;右侧为MobileNet v2中的倒残差结构,其结构为:1x1卷积升维->3x3DW卷积->1x1卷积降维。MobileNet v2先使用 1x1 的卷积进行升维的原因是:高维信息通过ReLU激活函数后丢失的信息更少,因此先进行升维操作
在这里插入图片描述

这部分需要注意的是只有当步长s=1时,才有shortcut连接,步长为2是没有的,如下图所示。

在这里插入图片描述

3. MobileNet v2网络结构

在这里插入图片描述

MobileNet v2所用的参数更少,但mAP值和其它的差不多,甚至超过了Yolov2,其效果如下图所示:
在这里插入图片描述

4. 代码实现

MobileNet v2的实现可以通过堆叠 bottleneck 的形式实现,如下面代码片段:

def MobileNetV2_relu(input_shape, k):inputs = Input(shape = input_shape)x = Conv2D(filters=32, kernel_size=(3,3), padding='same')(inputs)x = _bottleneck_relu(x, 8, 6)x = MaxPooling2D((2,2))(x)x = _bottleneck_relu(x, 16, 6)x = _bottleneck_relu(x, 16, 6)x = MaxPooling2D((2,2))(x)x = _bottleneck_relu(x, 32, 6)x = GlobalAveragePooling2D()(x)x = Dense(128, activation='relu')(x)outputs = Dense(k, activation='softmax')(x)model = Model(inputs, outputs)return model

四、参考文献

[1] Howard A G, Zhu M, Chen B, et al. Mobilenets: Efficient convolutional neural networks for mobile vision applications[J]. arxiv preprint arxiv:1704.04861, 2017.

[2] Sandler M, Howard A, Zhu M, et al. Mobilenetv2: Inverted residuals and linear bottlenecks[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2018: 4510-4520.

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

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

相关文章

RLHF学习

整体流程 三个步骤分解&#xff1a; 预训练一个语言模型 (LM) &#xff1b;聚合问答数据并训练一个奖励模型 (Reward Model&#xff0c;RM) &#xff1b;用强化学习 (RL) 方式微调 LM。 RW RM 的训练是 RLHF 区别于旧范式的开端。这一模型接收一系列文本并返回一个标量奖励&…

力扣hot100 最小栈 变种栈

Problem: 155. 最小栈 文章目录 思路&#x1f496; Stack 自定义 Node&#x1f37b; Code 思路 &#x1f469;‍&#x1f3eb; 甜姨 &#x1f496; Stack 自定义 Node 时间复杂度: O ( 1 ) O(1) O(1) 空间复杂度: O ( n ) O(n) O(n) &#x1f37b; Code class MinS…

轻松打卡:使用Spring Boot和Redis Bitmap构建高效签到系统【redis实战 四】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 轻松打卡&#xff1a;使用Spring Boot和Redis Bitmap构建高效签到系统【redis实战 四】 引言(redis实战)前言回顾bitmap基本概念核心特性使用场景 为什么使用redis中的bitmap实现&#xff1f;1. 存储效…

紫光展锐M6780丨超分辨率技术——画质重构还原经典

上一期&#xff0c;我们揭秘了让画质更加炫彩的AI-PQ技术。面对分辨率较低的老电影&#xff0c;光有高饱和度的色彩是不够的&#xff0c;如何能够提高视频影像的分辨率&#xff0c;使画质更加清晰&#xff0c;实现老片新看&#xff1f; 本期带大家揭晓紫光展锐首颗AI8K超高清智…

【分布式技术专题】「分布式技术架构」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)

探索Tomcat技术架构设计模式的奥秘 Tomcat系统架构分析Tomcat 整体结构Tomcat总体结构图以 Service 作为“婚姻”1) Service 接口方法列表 2) StandardService 的类结构图方法列表 3) StandardService. SetContainer4) StandardService. addConnector 以 Server 为“居”1) Ser…

etcd技术解析:构建高可用分布式系统的利器

1. 引言 随着云原生技术的兴起&#xff0c;分布式系统的构建变得愈发重要。etcd作为一个高可用的分布式键值存储系统&#xff0c;在这个领域发挥着至关重要的作用。本文将深入探讨etcd的技术细节&#xff0c;以及如何利用它构建高可用的分布式系统。 2. etcd简介 etcd是一个开…

JVM系列-9.性能调优

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…

大数据安全 | 期末复习(中)

文章目录 &#x1f4da;感知数据安全⭐️&#x1f407;传感器概述&#x1f407;传感器的静态特性&#x1f407;调制方式&#x1f407;换能攻击&#x1f407;现有防护策略 &#x1f4da;AI安全⭐️&#x1f407;智能语音系统——脆弱性&#x1f407;攻击手段&#x1f407;AI的两…

探索IOC和DI:解密Spring框架中的依赖注入魔法

IOC与DI的详细解析 IOC详解1 bean的声明2 组件扫描 DI详解 IOC详解 1 bean的声明 IOC控制反转&#xff0c;就是将对象的控制权交给Spring的IOC容器&#xff0c;由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。 要把某个对象交给IOC容器管理&#xff0c;需要在类上…

【深度学习】sdxl中的 text_encoder text_encoder_2 区别

镜像问题是&#xff1a;https://editor.csdn.net/md/?articleId135867689 代码仓库&#xff1a; https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/tree/main 截图&#xff1a; 为什么有两个CLIP编码器 text_encoder 和 text_encoder_2 &#xff1f; 在…

那些年与指针的爱恨情仇(一)---- 指针本质及其相关性质用法

关注小庄 顿顿解馋 (≧∇≦) 引言&#xff1a; 小伙伴们在学习c语言过程中是否因为指针而困扰&#xff0c;指针简直就像是小说女主&#xff0c;它逃咱追&#xff0c;我们插翅难飞…本篇文章让博主为你打理打理指针这个傲娇鬼吧~ 本节我们将认识到指针本质&#xff0c;何为指针和…

RHCE项目:使用LNMP搭建私有云存储

目录 一、准备工作 1、关闭防火墙、安全软件 2、搭建LNMP环境 3、上传软件 4、设置nextcloud安装命令权限 二、数据库 1、设置数据库 2、重启数据库 三、配置nginx 四、安装nextcloud 五、内网穿透 1、创建内网映射 2、linux系统安装花生壳客户端 3、重新打开浏览…

林浩然与极限的“无穷”约会

林浩然与极限的“无穷”约会 Lin Haoran’s Encounter with the Mathematical “Infinity” 在数学王国里&#xff0c;有一位名叫林浩然的大侠&#xff0c;他的江湖就是高等数学的殿堂。而他要挑战的终极Boss&#xff0c;便是那个既神秘又顽皮的“极限”。 In the kingdom of …

C# .Net6搭建灵活的RestApi服务器

1、准备 C# .Net6后支持顶级语句&#xff0c;更简单的RestApi服务支持&#xff0c;可以快速搭建一个极为简洁的Web系统。推荐使用Visual Studio 2022&#xff0c;安装"ASP.NET 和Web开发"组件。 2、创建工程 关键步骤如下&#xff1a; 包添加了“Newtonsoft.Json”&…

【Git】项目管理笔记

文章目录 本地电脑初始化docker报错.gitignoregit loggit resetgit statusgit ls-filesgit rm -r -f --cached拉取仓库文件更新本地的项目报错处理! [rejected] master -> master (fetch first)gitgitee.com: Permission denied (publickey).error: remote origin already e…

BACnet转IEC104网关BE104

随着电力系统信息化建设和数字化转型的进程不断加速&#xff0c;对电力能源的智能化需求也日趋增强。健全稳定的智慧电力系统能够为工业生产、基础设施建设以及国防建设提供稳定的能源支持。在此背景下&#xff0c;高性能的工业电力数据传输解决方案——协议转换网关应运而生&a…

研发日记,Matlab/Simulink避坑指南(六)——字节分割Bug

文章目录 前言 背景介绍 问题描述 分析排查 解决方案 总结归纳 前言 见《研发日记&#xff0c;Matlab/Simulink避坑指南&#xff08;一&#xff09;——Data Store Memory模块执行时序Bug》 见《研发日记&#xff0c;Matlab/Simulink避坑指南(二)——非对称数据溢出Bug》…

Arduino开发实例-DRV8833电机驱动器控制直流电机

DRV8833电机驱动器控制直流电机 文章目录 DRV8833电机驱动器控制直流电机1、DRV8833电机驱动器介绍2、硬件接线图3、代码实现DRV8833 使用 MOSFET,而不是 BJT。 MOSFET 的压降几乎可以忽略不计,这意味着几乎所有来自电源的电压都会传递到电机。 这就是为什么 DRV8833 不仅比基…

寒假思维训练day15 牛客练习赛121

牛客练习赛ABCD题解&#xff0c;更新一个题解作为今天的任务收尾。 寒假思维训练day15 摘要&#xff1a; Part1&#xff1a;B题&#xff0c;B-You Brought Me A Gentle Breeze on the Field_牛客练习赛121 (nowcoder.com) Part2: C题&#xff0c;C-氧气少年的水滴 2_牛客练…

职言圈 | 小伙年薪95w,女朋友父母却爱搭不理,如今上岸国家电网,人不到,叔叔阿姨吃饭都不动筷子...

在职场中&#xff0c;每个人都经历着不同的起伏和挑战。有时候&#xff0c;我们会面临着职业生涯上的起伏&#xff0c;但正是这些经历让我们成长&#xff0c;让我们更加坚韧。 就像这位网友一样&#xff0c;他在过去的一年里经历了美团L8的职位和年薪95W&#xff0c;却面临着女…