diff --git a/tutorials/source_zh_cn/advanced_use/FasterRcnn_Pytorch2MindSpore b/tutorials/source_zh_cn/advanced_use/FasterRcnn_Pytorch2MindSpore new file mode 100644 index 0000000000000000000000000000000000000000..25d098411e7d3b37797063b1f746e748172af35c --- /dev/null +++ b/tutorials/source_zh_cn/advanced_use/FasterRcnn_Pytorch2MindSpore @@ -0,0 +1,184 @@ +# 迁移Pytorch-FasterRcnn到MindSpore + +## 1. 熟悉你的Pytorch脚本 +Pytorch与MindpSpore在网络结构组织方式上有一定相似性,写法类似,但是由于Mindspore与Pytorch的算子定义存在区别,需要用户能够对网络实现比较了解,以此能够灵活地调用Mindspore的算子来实现网络功能。 + +## 2. 重建网络 +###2.1 基础概念 +在MIndspore中,需要将初始化操作放于`__init__`中,与Pytorch相同,将执行操作放在`construct`中,对应Pytorch中的`forward`函数。 + +### 2.2 单算子网络构造 +[Conv2d](https://www.mindspore.cn/api/zh-CN/master/api/python/mindspore/mindspore.nn.html?highlight=conv#mindspore.nn.Conv2d) 是最常见的算子之一,我们以此为例如何在网络中调用一个算子。 + +在Pytorch中,Conv2d的定义为`torch.nn.Conv2d`,而在Mindspore中,定义为`mindspore.nn.Conv2d`,参考示例如下: + +```python +def _conv7x7(in_channel, out_channel, stride=1): + weight_shape = (out_channel, in_channel, 7, 7) + weight = _weight_variable(weight_shape) + return mindspore.nn.Conv2d(in_channel, out_channel, + kernel_size=7, stride=stride, padding=0, pad_mode='same', weight_init=weight) + +class Net(mindspore.nn.Cell): + def __init__(self): + super(Net, self).__init__() + self.conv = _conv7x7(3, 64) + + def construct(self, inputs): + return self.conv(inputs) +``` +通过上面的例子,我们就实现了一个很简单的单算子网络,调用这个网络,我们就可以获得通过卷积计算得到的输出。 +更多的算子介绍,可以参考https://www.mindspore.cn/api/zh-CN/master/api/python/mindspore/。 + +### 2.2 构造FPN子网络 +在MindSpore中使用`nn.Cell`构造一个子网结构,子网通常包含一个比较完整的功能,在FasterRcnn中,我们以FPN这个模块来举例,如何把Pytorch该模块的网络迁移到Mindspore上。 +FPN意指特征金字塔网络,通常用于生成不同分辨率的特征,其中存在一些重复结构,在MindSpore中,对于内部存在权重参数的子网,定义的Cell是不能重复使用的,如果出现大量重复串联结构,可以使用循环构造多个Cell实例并通过`SequentialCell`来串联,同时,我们可以通过operations来获取一些自定义的算子实现,来满足我们的功能需求。 +FPN子网Mindspore定义可以参考如下: + +```python +import numpy as np +import mindspore.nn as nn +from mindspore import context +from mindspore.ops import operations as P +from mindspore.common.tensor import Tensor +from mindspore.common import dtype as mstype +from mindspore.common.initializer import initializer + +class FeatPyramidNeck(nn.Cell): + """ + Feature pyramid network cell, usually uses as network neck. + + Applies the convolution on multiple, input feature maps + and output feature map with same channel size. if required num of + output larger then num of inputs, add extra maxpooling for further + downsampling; + + Args: + in_channels (tuple) - Channel size of input feature maps. + out_channels (int) - Channel size output. + num_outs (int) - Num of output features. + + Returns: + Tuple, with tensors of same channel size. + + Examples: + neck = FeatPyramidNeck([100,200,300], 50, 4) + input_data = (normal(0,0.1,(1,c,1280//(4*2**i), 768//(4*2**i)), + dtype=np.float32) \ + for i, c in enumerate(config.fpn_in_channels)) + x = neck(input_data) + """ + + def __init__(self, + in_channels, + out_channels, + num_outs): + super(FeatPyramidNeck, self).__init__() + + self.num_outs = num_outs + self.in_channels = in_channels + self.fpn_layer = len(self.in_channels) + + assert not self.num_outs < len(in_channels) + + self.lateral_convs_list_ = [] + self.fpn_convs_ = [] + for i in range(len(in_channels)): + l_conv = _conv(in_channels[i], out_channels, kernel_size=1, stride=1, padding=0, pad_mode='valid') + fpn_conv = _conv(out_channels, out_channels, kernel_size=3, stride=1, padding=0, pad_mode='same') + self.lateral_convs_list_.append(l_conv) + self.fpn_convs_.append(fpn_conv) + self.lateral_convs_list = nn.layer.CellList(self.lateral_convs_list_) + self.fpn_convs_list = nn.layer.CellList(self.fpn_convs_) + self.interpolate1 = P.ResizeNearestNeighbor((48, 80)) + self.interpolate2 = P.ResizeNearestNeighbor((96, 160)) + self.interpolate3 = P.ResizeNearestNeighbor((192, 320)) + self.maxpool = P.MaxPool(ksize=1, strides=2, padding="same") + + def construct(self, inputs): + feat = () + for i in range(self.fpn_layer): + feat += (self.lateral_convs_list[i](inputs[i]),) + + feat_r = (feat[3],) + feat_r = feat_r + (feat[2] + self.interpolate1(feat_r[self.fpn_layer - 4]),) + feat_r = feat_r + (feat[1] + self.interpolate2(feat_r[self.fpn_layer - 3]),) + feat_r = feat_r + (feat[0] + self.interpolate3(feat_r[self.fpn_layer - 2]),) + + feat_add = () + for i in range(self.fpn_layer - 1, -1, -1): + feat_add = feat_add + (feat_r[i],) + + outs = () + for i in range(self.fpn_layer): + outs = outs + (self.fpn_convs_list[i](feat_add[i]),) + + for i in range(self.num_outs - self.fpn_layer): + outs = outs + (self.maxpool(outs[3]),) + return outs + +``` + +### 2.3定义整网结构 +我们能够定义子网结构之后,只需把各子网分别实现后,连接起来,就能够获得整个网络结构,由于FasterRcnn整网代码过多,下面仅示例整网定义: + +```python +class Faster_Rcnn_Resnet50(nn.Cell): + """ + FasterRcnn Network. + + Note: + backbone = resnet50 + + Returns: + Tuple, tuple of output tensor. + rpn_loss: Scalar, Total loss of RPN subnet. + rcnn_loss: Scalar, Total loss of RCNN subnet. + rpn_cls_loss: Scalar, Classification loss of RPN subnet. + rpn_reg_loss: Scalar, Regression loss of RPN subnet. + rcnn_cls_loss: Scalar, Classification loss of RCNN subnet. + rcnn_reg_loss: Scalar, Regression loss of RCNN subnet. + + Examples: + net = Faster_Rcnn_Resnet50() + """ + def __init__(self, batch_size=2, rcnn_num_classes=81): + super(Faster_Rcnn_Resnet50, self).__init__() + + def construct(self, img_data, img_metas, gt_bboxes, gt_labels, gt_valids): + return outpus; +``` + +## 3. 训练 + +### 3.1 准备数据 +首先使用[MindData](https://www.mindspore.cn/tutorial/zh-CN/master/use/data_preparation/data_preparation.html)构造你要使用的数据集,根据数据集格式的不同,`MindData`提供了对接`RawData原始数据`、`TFRecord`, [MindRecord](https://www.mindspore.cn/tutorial/zh-CN/master/use/data_preparation/converting_datasets.html)等多种不同数据格式的数据集接口。 +同时,可以根据自己的需求,实现数据增强。 + +### 3.2 定义loss和优化器 +刚才定义的网络直接输出最后的logits,如果想要进行训练,可参考如下定义loss与优化器: +```python +lr = Tensor(dynamic_lr(config, rank_size = device_num), ms.float32) +opt = SGD(params=net_train.trainable_params(), learning_rate=lr, momentum=0.91, weight_decay=0.0001, loss_scale=1.0) +``` + +### 3.3 构造model +为了方便用户使用,Mindspore提供了Model接口,我们可以将定义的网络原型、loss、优化器传到Model接口内,model内部会自动将其组合为一个可用于训练的网络,直接调用`model.train`即可实现训练,同时,Mindspore提供了metrices,callbacks +等接口,提供了打印精度,loss,保存checkpoint等功能,参考示例如下: + +```python +model = Model(net_train, metrics={'Precision/mAP@.50IOU': coco_metric}) +for i in range(epoch): + model.train(data_size, ds_train, callbacks=[callback, ckpoint_cb]) +``` + +## 4. 验证与推理 +Mindspore提供了`model.eval()`接口来进行模型验证。 +```python +output = model.eval(dataset_eval) +``` + +如果希望运行[端侧推理](https://www.mindspore.cn/tutorial/zh-CN/master/advanced_use/on_device_inference.html?highlight=export),可以调用`export`接口将已训练的模型进行导出。当前提供三种导出模型以供选择: +- GEIR:用于在Ascend310芯片上进行推理 +- ONNX:通用模型格式,用于转换到其他框架和硬件平台上进行推理 +- LITE:移动端模型 \ No newline at end of file