潮州做网站,如何注册公司邮箱,济宁vi设计公司,网站服务器地址查询昇思25天学习打卡营第17天 文章目录 昇思25天学习打卡营第17天ShuffleNet图像分类ShuffleNet网络介绍模型架构Pointwise Group ConvolutionChannel ShuffleShuffleNet模块构建ShuffleNet网络 模型训练和评估训练集准备与加载模型训练模型评估模型预测 打卡记录 ShuffleNet图像分…昇思25天学习打卡营第17天 文章目录 昇思25天学习打卡营第17天ShuffleNet图像分类ShuffleNet网络介绍模型架构Pointwise Group ConvolutionChannel ShuffleShuffleNet模块构建ShuffleNet网络 模型训练和评估训练集准备与加载模型训练模型评估模型预测 打卡记录 ShuffleNet图像分类 当前案例不支持在GPU设备上静态图模式运行其他模式运行皆支持。 ShuffleNet网络介绍
ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型和MobileNet, SqueezeNet等一样主要应用在移动端所以模型的设计目标就是利用有限的计算资源来达到最好的模型精度。ShuffleNetV1的设计核心是引入了两种操作Pointwise Group Convolution和Channel Shuffle这在保持精度的同时大大降低了模型的计算量。因此ShuffleNetV1和MobileNet类似都是通过设计更高效的网络结构来实现模型的压缩和加速。 了解ShuffleNet更多详细内容详见论文ShuffleNet。 如下图所示ShuffleNet在保持不低的准确率的前提下将参数量几乎降低到了最小因此其运算速度较快单位参数量对模型准确率的贡献非常高。 图片来源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。分组卷积中每个卷积核只处理输入特征图的一部分通道其优点在于参数量会有所降低但输出通道数仍等于卷积核的数量。 图片来源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。
%%capture captured_output
# 实验环境已经预装了mindspore2.2.14如需更换mindspore版本可更改下面mindspore的版本号
!pip uninstall mindspore -y
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore2.2.14# 查看当前 mindspore 版本
!pip show mindsporefrom mindspore import nn
import mindspore.ops as ops
from mindspore import Tensorclass GroupConv(nn.Cell):def __init__(self, in_channels, out_channels, kernel_size,stride, pad_modepad, pad0, groups1, has_biasFalse):super(GroupConv, self).__init__()self.groups groupsself.convs nn.CellList()for _ in range(groups):self.convs.append(nn.Conv2d(in_channels // groups, out_channels // groups,kernel_sizekernel_size, stridestride, has_biashas_bias,paddingpad, pad_modepad_mode, group1, weight_initxavier_uniform))def construct(self, x):features ops.split(x, split_size_or_sectionsint(len(x[0]) // self.groups), axis1)outputs ()for i in range(self.groups):outputs outputs (self.convs[i](features[i].astype(float32)),)out ops.cat(outputs, axis1)return outChannel Shuffle
Group Convolution的弊端在于不同组别的通道无法进行信息交流堆积GConv层后一个问题是不同组之间的特征图是不通信的这就好像分成了g个互不相干的道路每一个人各走各的这可能会降低网络的特征提取能力。这也是XceptionMobileNet等网络采用密集的1x1卷积Dense Pointwise Convolution的原因。
为了解决不同组别通道“近亲繁殖”的问题ShuffleNet优化了大量密集的1x1卷积在使用的情况下计算量占用率达到了惊人的93.4%引入Channel Shuffle机制通道重排。这项操作直观上表现为将不同分组通道均匀分散重组使网络在下一层能处理不同组别通道的信息。 如下图所示对于g组每组有n个通道的特征图首先reshape成g行n列的矩阵再将矩阵转置成n行g列最后进行flatten操作得到新的排列。这些操作都是可微分可导的且计算简单在解决了信息交互的同时符合了ShuffleNet轻量级网络设计的轻量特征。 为了阅读方便将Channel Shuffle的代码实现放在下方ShuffleNet模块的代码中。
ShuffleNet模块
如下图所示ShuffleNet对ResNet中的Bottleneck结构进行由(a)到(b), ©的更改 将开始和最后的 1 × 1 1\times 1 1×1卷积模块降维、升维改成Point Wise Group Convolution 为了进行不同通道的信息交流再降维之后进行Channel Shuffle 降采样模块中 3 × 3 3 \times 3 3×3 Depth Wise Convolution的步长设置为2长宽降为原来的一般因此shortcut中采用步长为2的 3 × 3 3\times 3 3×3平均池化并把相加改成拼接。 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_channelsinp, out_channelsmid_channels,kernel_size1, stride1, pad_modepad, pad0,groups1 if first_group else group),nn.BatchNorm2d(mid_channels),nn.ReLU(),]branch_main_2 [nn.Conv2d(mid_channels, mid_channels, kernel_sizeksize, stridestride,pad_modepad, paddingpad, groupmid_channels,weight_initxavier_uniform, has_biasFalse),nn.BatchNorm2d(mid_channels),GroupConv(in_channelsmid_channels, out_channelsoutputs,kernel_size1, stride1, pad_modepad, pad0,groupsgroup),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_size3, stride2, pad_modesame)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组数3g 3为例首先通过数量24卷积核大小为 3 × 3 3 \times 3 3×3stride为2的卷积层输出特征图大小为 112 × 112 112 \times 112 112×112channel为24然后通过stride为2的最大池化层输出特征图大小为 56 × 56 56 \times 56 56×56channel数不变再堆叠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得到分类概率。 class ShuffleNetV1(nn.Cell):def __init__(self, n_class1000, model_size2.0x, group3):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_initxavier_uniform, has_biasFalse),nn.BatchNorm2d(input_channel),nn.ReLU(),)self.maxpool nn.MaxPool2d(kernel_size3, stride2, pad_modesame)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,groupgroup, first_groupfirst_group,mid_channelsoutput_channel // 4, ksize3, stridestride))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.gzdownload(url, ./dataset, kindtar.gz, replaceTrue)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(prob0.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, usageusage, shuffleTrue)dataset dataset.map(image_trans, image)dataset dataset.map(label_trans, label)dataset dataset.batch(batch_size, drop_remainderTrue)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()对网络进行训练。将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, Top5CategoricalAccuracydef train():mindspore.set_context(modemindspore.PYNATIVE_MODE, device_targetAscend)net ShuffleNetV1(model_size2.0x, n_class10)loss nn.CrossEntropyLoss(weightNone, reductionmean, label_smoothing0.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_epoch250)lr Tensor(lr_scheduler[-1])optimizer nn.Momentum(paramsnet.trainable_params(), learning_ratelr, momentum0.9, weight_decay0.00004, loss_scale1024)loss_scale_manager ms.amp.FixedLossScaleManager(1024, drop_overflow_updateFalse)model Model(net, loss_fnloss, optimizeroptimizer, amp_levelO3, loss_scale_managerloss_scale_manager)callback [TimeMonitor(), LossMonitor()]save_ckpt_path ./config_ckpt CheckpointConfig(save_checkpoint_stepsbatches_per_epoch, keep_checkpoint_max5)ckpt_callback ModelCheckpoint(shufflenetv1, directorysave_ckpt_path, configconfig_ckpt)callback [ckpt_callback]print( Starting Training )start_time time.time()# 由于时间原因epoch 5可根据需求进行调整model.train(5, dataset, callbackscallback)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(modemindspore.GRAPH_MODE, device_targetAscend)dataset get_dataset(./dataset/cifar-10-batches-bin, 128, test)net ShuffleNetV1(model_size2.0x, n_class10)param_dict load_checkpoint(shufflenetv1-5_390.ckpt)load_param_into_net(net, param_dict)net.set_train(False)loss nn.CrossEntropyLoss(weightNone, reductionmean, label_smoothing0.1)eval_metrics {Loss: nn.Loss(), Top_1_Acc: Top1CategoricalAccuracy(),Top_5_Acc: Top5CategoricalAccuracy()}model Model(net, loss_fnloss, metricseval_metrics)start_time time.time()res model.eval(dataset, dataset_sink_modeFalse)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 sprint(log)filename ./eval_log.txtwith open(filename, a) as file_object:file_object.write(log \n)if __name__ __main__:test()结果输出
result:{Loss: 1.567653516928355, Top_1_Acc: 0.5177283653846154, Top_5_Acc: 0.9352964743589743}, ckpt:./shufflenetv1-5_390.ckpt, time: 0h 1m 33s模型预测
在CIFAR-10的测试集上对模型进行预测并将预测结果可视化。
import mindspore
import matplotlib.pyplot as plt
import mindspore.dataset as dsnet ShuffleNetV1(model_size2.0x, n_class10)
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, shuffleFalse, usagetrain)
dataset_show ds.Cifar10Dataset(dataset_dir./dataset/cifar-10-batches-bin, shuffleFalse, usagetrain)
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(prob0.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(), axis1)
index 0
for image in show_images_lst:plt.subplot(2, 8, index1)plt.title({}.format(class_dict[pred[index]]))index 1plt.imshow(image)plt.axis(off)
plt.show()打卡记录