【昇思25天學習打卡營打卡指南-第十三天】ShuffleNet圖像分類

ShuffleNet圖像分類

ShuffleNet網絡介紹

ShuffleNetV1是曠視科技提出的一種計算高效的CNN模型,和MobileNet, SqueezeNet等一樣主要應用在移動端,所以模型的設計目標就是利用有限的計算資源來達到最好的模型精度。ShuffleNetV1的設計核心是引入了兩種操作:Pointwise Group Convolution和Channel Shuffle,這在保持精度的同時大大降低了模型的計算量。因此,ShuffleNetV1和MobileNet類似,都是通過設計更高效的網絡結構來實現模型的壓縮和加速。

了解ShuffleNet更多詳細內容,詳見論文ShuffleNet。

如下圖所示,ShuffleNet在保持不低的準確率的前提下,將參數量幾乎降低到了最小,因此其運算速度較快,單位參數量對模型準確率的貢獻非常高。

shufflenet1

圖片來源:Bianco S, Cadene R, Celona L, et al. Benchmark analysis of representative deep neural network architectures[J]. IEEE access, 2018, 6: 64270-64277.

模型架構

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。分組卷積中,每個卷積核只處理輸入特征圖的一部分通道,其優點在于參數量會有所降低,但輸出通道數仍等于卷積核的數量

shufflenet2

圖片來源:Huang G, Liu S, Van der Maaten L, et al. Condensenet: An efficient densenet using learned group convolutions[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2018: 2752-2761.

Depthwise Convolution(深度可分離卷積)將組數g分為和輸入通道相等的in_channels,然后對每一個in_channels做卷積操作,每個卷積核只處理一個通道,記卷積核大小為1*k*k,則卷積核參數量為:in_channels*k*k,得到的feature maps通道數與輸入通道數相等

Pointwise Group Convolution(逐點分組卷積)在分組卷積的基礎上,令每一組的卷積核大小為 1 × 1 1\times 1 1×1,卷積核參數量為(in_channels/g*1*1)*out_channels。

## ShuffleNet網絡介紹ShuffleNetV1是曠視科技提出的一種計算高效的CNN模型,和MobileNet, SqueezeNet等一樣主要應用在移動端,所以模型的設計目標就是利用有限的計算資源來達到最好的模型精度。ShuffleNetV1的設計核心是引入了兩種操作:Pointwise Group Convolution和Channel Shuffle,這在保持精度的同時大大降低了模型的計算量。因此,ShuffleNetV1和MobileNet類似,都是通過設計更高效的網絡結構來實現模型的壓縮和加速。> 了解ShuffleNet更多詳細內容,詳見論文[ShuffleNet](https://arxiv.org/abs/1707.01083)。如下圖所示,ShuffleNet在保持不低的準確率的前提下,將參數量幾乎降低到了最小,因此其運算速度較快,單位參數量對模型準確率的貢獻非常高。![shufflenet1](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.3/tutorials/application/source_zh_cn/cv/images/shufflenet_1.png)> 圖片來源:Bianco S, Cadene R, Celona L, et al. Benchmark analysis of representative deep neural network architectures[J]. IEEE access, 2018, 6: 64270-64277.## 模型架構ShuffleNet最顯著的特點在于對不同通道進行重排來解決Group Convolution帶來的弊端。通過對ResNet的Bottleneck單元進行改進,在較小的計算量的情況下達到了較高的準確率。### Pointwise Group ConvolutionGroup Convolution(分組卷積)原理如下圖所示,相比于普通的卷積操作,分組卷積的情況下,每一組的卷積核大小為in_channels/g\*k\*k,一共有g組,所有組共有(in_channels/g\*k\*k)\*out_channels個參數,是正常卷積參數的1/g。分組卷積中,每個卷積核只處理輸入特征圖的一部分通道,**其優點在于參數量會有所降低,但輸出通道數仍等于卷積核的數量**。![shufflenet2](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.3/tutorials/application/source_zh_cn/cv/images/shufflenet_2.png)> 圖片來源:Huang G, Liu S, Van der Maaten L, et al. Condensenet: An efficient densenet using learned group convolutions[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2018: 2752-2761.Depthwise Convolution(深度可分離卷積)將組數g分為和輸入通道相等的`in_channels`,然后對每一個`in_channels`做卷積操作,每個卷積核只處理一個通道,記卷積核大小為1\*k\*k,則卷積核參數量為:in_channels\*k\*k,**得到的feature maps通道數與輸入通道數相等**;Pointwise Group Convolution(逐點分組卷積)在分組卷積的基礎上,令**每一組的卷積核大小為** $1\times 1$,卷積核參數量為(in_channels/g\*1\*1)\*out_channels。

Channel Shuffle

Group Convolution的弊端在于不同組別的通道無法進行信息交流,堆積GConv層后一個問題是不同組之間的特征圖是不通信的,這就好像分成了g個互不相干的道路,每一個人各走各的,這可能會降低網絡的特征提取能力。這也是Xception,MobileNet等網絡采用密集的1x1卷積(Dense Pointwise Convolution)的原因。

為了解決不同組別通道“近親繁殖”的問題,ShuffleNet優化了大量密集的1x1卷積(在使用的情況下計算量占用率達到了驚人的93.4%),引入Channel Shuffle機制(通道重排)。這項操作直觀上表現為將不同分組通道均勻分散重組,使網絡在下一層能處理不同組別通道的信息。

shufflenet3

如下圖所示,對于g組,每組有n個通道的特征圖,首先reshape成g行n列的矩陣,再將矩陣轉置成n行g列,最后進行flatten操作,得到新的排列。這些操作都是可微分可導的且計算簡單,在解決了信息交互的同時符合了ShuffleNet輕量級網絡設計的輕量特征。

shufflenet4

為了閱讀方便,將Channel Shuffle的代碼實現放在下方ShuffleNet模塊的代碼中。

ShuffleNet模塊

如下圖所示,ShuffleNet對ResNet中的Bottleneck結構進行由(a)到(b), ?的更改:

  1. 將開始和最后的 1 × 1 1\times 1 1×1卷積模塊(降維、升維)改成Point Wise Group Convolution;

  2. 為了進行不同通道的信息交流,再降維之后進行Channel Shuffle;

  3. 降采樣模塊中, 3 × 3 3 \times 3 3×3 Depth Wise Convolution的步長設置為2,長寬降為原來的一般,因此shortcut中采用步長為2的 3 × 3 3\times 3 3×3平均池化,并把相加改成拼接。

shufflenet5

class ShuffleV1Block(nn.Cell):def __init__(self, inp, oup, group, first_group, mid_channels, ksize, stride):super(ShuffleV1Block, self).__init__()self.stride = stridepad = ksize // 2self.group = groupif stride == 2:outputs = oup - inpelse:outputs = oupself.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_xright = old_xout = old_xright = 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 outdef channel_shuffle(self, x):batchsize, num_channels, height, width = ops.shape(x)group_channels = num_channels // self.groupx = 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 224 \times 224 224×224,組數3(g = 3)為例,首先通過數量24,卷積核大小為 3 × 3 3 \times 3 3×3,stride為2的卷積層,輸出特征圖大小為 112 × 112 112 \times 112 112×112,channel為24;然后通過stride為2的最大池化層,輸出特征圖大小為 56 × 56 56 \times 56 56×56,channel數不變;再堆疊3個ShuffleNet模塊(Stage2, Stage3, Stage4),三個模塊分別重復4次、8次、4次,其中每個模塊開始先經過一次下采樣模塊(上圖?),使特征圖長寬減半,channel翻倍(Stage2的下采樣模塊除外,將channel數從24變為240);隨后經過全局平均池化,輸出大小為 1 × 1 × 960 1 \times 1 \times 960 1×1×960,再經過全連接層和softmax,得到分類概率。

shufflenet6

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_sizeif 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 NotImplementedErrorelif 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 NotImplementedErrorinput_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 1first_group = idxstage == 0 and i == 0features.append(ShuffleV1Block(input_channel, output_channel,group=group, first_group=first_group,mid_channels=output_channel // 4, ksize=3, stride=stride))input_channel = output_channelself.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進行預訓練。

訓練集準備與加載

采用CIFAR-10數據集對ShuffleNet進行預訓練。CIFAR-10共有60000張32*32的彩色圖像,均勻地分為10個類別,其中50000張圖片作為訓練集,10000圖片作為測試集。如下示例使用mindspore.dataset.Cifar10Dataset接口下載并加載CIFAR-10的訓練集。目前僅支持二進制版本(CIFAR-10 binary version)。

# 下載數據集
from download import downloadurl = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz"download(url, "./dataset", kind="tar.gz", replace=True)
import mindspore as ms
from mindspore.dataset import Cifar10Dataset
from mindspore.dataset import vision, transformsdef 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 datasetdataset = get_dataset("./dataset/cifar-10-batches-bin", 128, "train")
batches_per_epoch = dataset.get_dataset_size()

模型訓練

本節用隨機初始化的參數做預訓練。首先調用ShuffleNetV1定義網絡,參數量選擇"2.0x",并定義損失函數為交叉熵損失,學習率經過4輪的warmup后采用余弦退火,優化器采用Momentum。最后用train.model中的Model接口將模型、損失函數、優化器封裝在model中,并用model.train()對網絡進行訓練。將ModelCheckpointCheckpointConfigTimeMonitorLossMonitor傳入回調函數中,將會打印訓練的輪數、損失和時間,并將ckpt文件保存在當前目錄下。

import time
import mindspore
import numpy as np
from mindspore import Tensor, nn
from mindspore.train import ModelCheckpoint, CheckpointConfig, TimeMonitor, LossMonitor, Model, Top1CategoricalAccuracy, Top5CategoricalAccuracydef 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.0005base_lr = 0.05lr_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_timehour = 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()

訓練好的模型保存在當前目錄的shufflenetv1-5_390.ckpt中,用作評估。

模型評估

在CIFAR-10的測試集上對模型進行評估。

設置好評估模型的路徑后加載數據集,并設置Top 1, Top 5的評估標準,最后用model.eval()接口對模型進行評估。

from mindspore import load_checkpoint, load_param_into_netdef 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_timehour = 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()

運行結果

result:{'Loss': 1.559962483552786, 'Top_1_Acc': 0.516426282051282, 'Top_5_Acc': 0.9396033653846154}, ckpt:'./shufflenetv1-5_390.ckpt', time: 0h 1m 25s

模型預測

在CIFAR-10的測試集上對模型進行預測,并將預測結果可視化。

import mindspore
import matplotlib.pyplot as plt
import mindspore.dataset as dsnet = 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 += 1plt.imshow(image)plt.axis("off")
plt.show()

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/37537.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37537.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37537.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GPT-5 一年半后發布,打開人工智能新世紀

關于GPT-5一年半后發布的消息,這一預測主要基于OpenAI首席技術官Mira Murati的采訪和聲明。然而,需要明確的是,這個時間點(即2025年底或2026年初)已經與早期傳聞有所不同,顯示了OpenAI對產品質量的重視&…

react18.x+播放文本內容

需要調接口將文字傳遞給后端將文字轉換成音頻文件,然后播放,同時每次播放不同文本時,當前播放的文本需要暫停,切換到播放新點擊的文本 可以設置緩存播放過的音頻,也可以不設置緩存: 設置緩存的代碼如下&am…

驍龍相機拍照流程分析

和你一起終身學習,這里是程序員Android 經典好文推薦,通過閱讀本文,您將收獲以下知識點: 1.deliverInputEvent 拍照點擊事件處理 2.submitRequestList Camera 提交拍照請求 3.createCaptureRequest 拍照請求幀數 驍龍相機通過binder 數據傳輸…

idea 內存參數修改不生效問題解決 VM參數設置不生效解決

很多人配置idea 內存參數,怎么配置都不生效,主要原因是配置文件用的不是你修改的那個。 系統環境變量中的這個才是你真正要修改的配置文件。 找到并修改后保存,重啟idea就可生效

C++ | Leetcode C++題解之第208題實現Trie(前綴樹)

題目&#xff1a; 題解&#xff1a; class Trie { private:vector<Trie*> children;bool isEnd;Trie* searchPrefix(string prefix) {Trie* node this;for (char ch : prefix) {ch - a;if (node->children[ch] nullptr) {return nullptr;}node node->children[…

人工與智能系統之間的交互方式

人工與智能系統之間的交互方式 #mermaid-svg-xSsFZWak2bsyV0un {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xSsFZWak2bsyV0un .error-icon{fill:#552222;}#mermaid-svg-xSsFZWak2bsyV0un .error-text{fill:#5522…

分詞算法在自然語言處理中的基本原理與應用場景

分詞算法在自然語言處理中的基本原理與應用場景 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 分詞是自然語言處理&#xff08;NLP&#xff09;中的重要基礎…

python腳本 限制 外部訪問 linux服務器端口

注意&#xff1a;該腳本會清空linux防火墻的filter表的規則和用戶自定義鏈路 腳本的效果是將端口限制為僅服務器內部訪問&#xff0c;提高服務的安全性&#xff0c;穩定性 可以提供ip地址白名單 具體腳本&#xff1a; #!/usr/bin/python3 import argparse, subprocess, sys,…

13_網絡安全

目錄 網絡安全協議 網絡安全協議 PGP協議 網絡安全技術 防火墻技術 入侵檢測系統 入侵防御系統 殺毒軟件 蜜罐系統 計算機病毒與木馬 網絡安全協議 網絡安全協議 物理層主要使用物理手段隔離、屏蔽物理設備等&#xff0c;其他層都是靠協議來保證傳輸的安全&#xff…

美國服務器租用詳細介紹與租用流程

在數字化時代&#xff0c;服務器租用已成為許多企業和個人拓展業務、存儲數據的重要選擇。美國作為全球科技發展的前沿陣地&#xff0c;其服務器租用服務也備受矚目。下面&#xff0c;我們將詳細介紹美國服務器租用的相關知識及租用流程。 一、美國服務器租用簡介 美國服務器租…

中英雙語介紹美國的州:新澤西州(New Jersey)

中文版 新澤西州&#xff08;New Jersey&#xff09;位于美國東北部&#xff0c;是美國面積較小但人口密度較高的州之一。新澤西州因其便利的地理位置、發達的經濟和豐富的歷史文化而聞名。以下是對新澤西州各方面的詳細介紹&#xff1a; 人口 截至2020年&#xff0c;美國人…

引領汽車軟件開發走向ASPICE認證之路

亞遠景科技與ASPICE認證的關系可以從以下幾個方面來闡述&#xff1a; (要明確的是&#xff1a;在ASPICE行業中專業來說&#xff0c;ASPICE項目是沒有認證&#xff0c;而只有評估。不過&#xff0c;為了方便溝通&#xff0c;人們常將這一評估過程稱為認證。&#xff09; 行業專…

tomcat定時重啟

Tomcat定時重啟&#xff08;linux&#xff09; 1. 編寫腳本 在tomcat的bin目錄下&#xff0c;使用vim restart.sh&#xff0c;編寫restart.sh腳本&#xff0c;插入一下內容&#xff0c;最后并保存&#xff01; #!/bin/bash# 初始化全局環境變量 . /etc/profilecd /usr/loca…

探索數據結構:隊列的的實現與應用

&#x1f511;&#x1f511;博客主頁&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列專欄&#xff1a;漸入佳境之數據結構與算法 歡迎來到泊舟小課堂 &#x1f618;博客制作不易歡迎各位&#x1f44d;點贊?收藏?關注 一、隊列的概念 隊列是一個線性的數據結構&#…

windows環境下創建python虛擬環境

windows環境下創建python虛擬環境 使用virtualenv庫創建虛擬環境&#xff0c;可使不同的項目處于不同的環境中 安裝方法&#xff1a; pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple pip install virtualenvwrapper-win -i https://pypi.tuna.tsinghua…

Spring Cloud Alibaba之負載均衡組件Ribbon

一、什么是負載均衡&#xff1f; &#xff08;1&#xff09;概念&#xff1a; 在基于微服務架構開發的系統里&#xff0c;為了能夠提升系統應對高并發的能力&#xff0c;開發人員通常會把具有相同業務功能的模塊同時部署到多臺的服務器中&#xff0c;并把訪問業務功能的請求均…

談談WebComponents | 前端開發

一、 源起 讓我們以一個例子開始。 假設我們要做一個環形進度條&#xff0c;它可以&#xff1a; 1、根據進度數值的不同&#xff0c;計算出百分比&#xff0c;以渲染對應的角度值。 2、根據設置的進度不同&#xff0c;我們用不同的顏色加以區分。 3、在環的中間我們以動畫遞增的…

小程序、APP對接廣告聯盟進行廣告變現有什么區別?

小程序VS APP對接廣告聯盟有什么區別&#xff1f; 開發完成的小程序對接廣告聯盟廣告變現&#xff0c;開發完成的APP對接廣告聯盟有什么區別&#xff1f; 首先小程序對接廣告聯盟&#xff0c;無論是微信小程序還是抖音小程序都只支持對接單一的廣告聯盟接入。抖音小程序只支持…

【監控】監控平臺部署 Prometheus+Grafana

在 macOS 上部署 Grafana 和 Prometheus 來監控 Java 服務是一個非常實用的操作。以下是詳細的步驟&#xff0c;包括如何安裝和配置 Prometheus、Grafana 以及在 Java 服務中集成 Prometheus 的客戶端庫來收集指標數據。 1. 安裝 Prometheus 1.1 使用 Homebrew 安裝 Promethe…

簡單分享項目內如何快速自動生成自己的庫和更新 requirements.txt

當開發Python項目時&#xff0c;requirements.txt文件被用來清單所有所需的Python包及其版本。這個文件對于在不同環境中安裝和管理項目依賴特別方便&#xff0c;無論是在生產環境、開發環境或者CI/CD流程中。 要自動創建和更新requirements.txt文件&#xff0c;有幾種常見的方…