diff --git a/model_zoo/official/cv/fastscnn/README_CN.md b/model_zoo/official/cv/fastscnn/README_CN.md
new file mode 100644
index 00000000000..0d224115557
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/README_CN.md
@@ -0,0 +1,360 @@
+# FastSCNN
+
+
+
+- [FastSCNN](#FastSCNN)
+- [FastSCNN介绍](#FastSCNN介绍)
+- [模型结构](#模型结构)
+- [数据集](#数据集)
+- [环境要求](#环境要求)
+- [快速入门](#快速入门)
+- [脚本说明](#脚本说明)
+ - [脚本及样例代码](#脚本及样例代码)
+ - [脚本参数](#脚本参数)
+ - [训练过程](#训练过程)
+ - [训练](#训练)
+ - [评估过程](#评估过程)
+ - [评估](#评估)
+ - [310推理](#310推理)
+- [模型描述](#模型描述)
+ - [性能](#性能)
+ - [评估性能](#评估性能)
+- [随机情况说明](#随机情况说明)
+- [ModelZoo主页](#modelzoo主页)
+
+
+
+## FastSCNN介绍
+
+FastSCNN 于 2019 年发表在 BMVC ,是英国剑桥大学与东芝欧洲研究院联合研究的快速语义分割算法。它在高分辨率(1024×2048)图像上的 **实时语义分割** 能到达 123.5 FPS 的帧率与 68% 的准确率。作者指出由于 Fast-SCNN 的参数量很小,所以积极的使用数据增强技术不太可能会带来过拟合。作者还通过实验证明,对于 Fast-SCNN 这种小型网络,与大型网络的趋势相反,仅通过预训练或其他带有粗略标记的训练数据,对于最后的分割结果精度上提升效果不明显,而在训练网络时,多训练几个周期就能达到和有预训练辅助一样的分割精度。
+
+[论文](https://arxiv.org/abs/1902.04502):Poudel R , Liwicki S , Cipolla R . Fast-SCNN: Fast Semantic Segmentation Network[J]. 2019.
+
+## 模型结构
+
+Fast-SCNN 包括学习下采样模块、精细化全局特征提取模块、特征融合模块以及标准分类器四个部分。
+
+下采样学习模块:包括三个卷积层,第一层因为输入图片是三通道的原因,采用普通卷积计算,其他两层都是深度可分离卷积;
+
+全局特征提取模块:使用 MobileNetV2 中的高效瓶颈残差块,将其中卷积都换成深度可分离卷积层,最后加入一个金字塔池化模块聚合基于不同区域的上下文信息;
+
+特征融合模块:用于融合 2 个分支的输出特征,与 ICNet 和 ContextNet 相同的是,作者倾向于简单添加功能以确保效率;
+
+分类器:两个深度可分离卷积层加上一个逐点卷积。
+
+## 数据集
+
+数据集:[**Cityscapes**]()
+
+Cityscapes 数据集,即城市景观数据集,包含来自 50 个不同城市的街道场景中记录的多种立体视频序列。
+
+该数据集包含如下:images_base 和 annotations_base 分别对应着文件夹 leftImg8bit(5,030 items, totalling 11.6 GB,factually 5000 items)和 gtFine(30,030 items, totalling 1.1 GB)。里面都包含三个文件夹:train、val、test。总共 5000 张精细标注:2975 张训练图,500 张验证图和 1525 张测试图。
+
+## 环境要求
+
+- 硬件(Ascend/ModelArts)
+ - 准备Ascend或ModelArts处理器搭建硬件环境。
+- 框架
+ - [MindSpore](https://www.mindspore.cn/install)
+- 如需查看详情,请参见如下资源:
+ - [MindSpore教程](https://www.mindspore.cn/tutorials/zh-CN/master/index.html)
+ - [MindSpore Python API](https://www.mindspore.cn/docs/api/zh-CN/master/api_python/mindspore.html)
+
+## 快速入门
+
+通过官方网站安装 MindSpore 后,您可以按照如下步骤进行训练和评估:
+
+```python
+#通过 python 命令行运行单卡训练脚本。
+python train.py \
+--dataset=xxx/dataset/ \
+--base_size=1024 \
+--epochs=1000 \
+--batch_size=2 \
+--lr=0.001 \
+--use_modelarts=0 \
+--output_path=./outputs/ \
+--is_distributed=0 > log.txt 2>&1 &
+
+#通过 bash 命令启动单卡训练。
+bash ./scripts/run_train.sh [train_code_path] [dataset] [epochs] [batch_size] [lr] [output_path]
+
+#Ascend多卡训练。
+bash ./scripts/run_distribute_train.sh [train_code_path] [dataset] [epochs] [batch_size] [lr] [output_path]
+
+# 通过 python 命令行运行推理脚本。
+# resume_path 指 ckpt 所在目录,为了兼容 modelarts,将其拆分为了 “路径” 与 “文件名”
+python eval.py \
+--dataset=xxx/dataset/ \
+--resume_path=xxx/ \
+--resume_name=fastscnn.ckpt \
+--output_path=./outputs/ \
+--is_distributed=0 > log.txt 2>&1 &
+
+#通过 bash 命令启动推理。
+bash ./scripts/run_eval.sh [train_code_path] [dataset] [resume_path] [resume_name] [output_path]
+```
+
+Ascend训练:生成[RANK_TABLE_FILE](https://gitee.com/mindspore/mindspore/tree/master/model_zoo/utils/hccl_tools)
+
+## 脚本说明
+
+### 脚本及样例代码
+
+```bash
+├── model_zoo
+ ├── README.md // 所有模型的说明文件
+ ├── fastscnn
+ ├──ascend310_infer // 310 推理代码目录(C++)
+ │ ├──inc
+ │ │ ├──utils.h // 工具包头文件
+ │ ├──src
+ │ │ ├──main.cc // 310推理代码
+ │ │ ├──utils.cc // 工具包
+ │ ├──build.sh // 代码编译脚本
+ │ ├──CMakeLists.txt // 代码编译设置
+ │ ├──fusion_switch.cfg // 配置文件
+ ├──cal_mIoU.py // 310 推理时计算mIoU的脚本
+ ├──preprocess.py // 310 推理时预处理验证集的脚本
+ ├──score.py // 310 推理时计算mIoU的脚本
+ ├── README_CN.md // fastscnn 的说明文件
+ ├── scripts
+ │ ├──run_distribute_train.sh // Ascend 8卡训练脚本
+ │ ├──run_eval.sh // 推理启动脚本
+ │ ├──run_train.sh // 训练启动脚本
+ │ ├──run_infer_310.sh // 启动310推理的脚本
+ ├── src
+ │ ├──dataloader.py // 数据集处理
+ │ ├──distributed_sampler.py // 8卡并行时的数据集切分操作
+ │ ├──fast_scnn.py // 模型结构
+ │ ├──logger.py // 日志打印文件
+ │ ├──loss.py // 损失函数
+ │ ├──lr_scheduler.py // 学习率衰减策略
+ │ ├──score.py // 推理时的 mIoU 计算脚本
+ │ ├──seg_data_base.py // 语义分割数据集通用处理脚本
+ │ ├──util.py // 边训练边验证时的 mIoU 计算脚本
+ │ ├──visualize.py // 分割结果可视化脚本
+ ├── export.py // 将权重文件导出为 MINDIR 等格式的脚本
+ ├── train.py // 训练脚本
+ ├── eval.py // 推理脚本
+```
+
+### 脚本参数
+
+```bash
+train.py 中的主要参数如下:
+--dataset: 数据集路径
+--base_size: 图片初始大小(图片缩放基准(0.5~2倍缩放))
+--crop_size: 剪切尺寸
+--train_split: 训练类型('test','train','val','testval')
+--aux: 是否使用辅助损失
+--aux_weight: 辅助损失的权重
+--epochs: 训练次数
+--save_every: 保存ckpt的频率
+--resume_path: 预训练文件路径(接着该文件继续训练)
+--resume_name: 预训练文件名
+--batch_size: 批次大小
+--lr: 学习率
+--momentum: SGD的momentum
+--weight_decay: SGD的weight_decay
+--eval_while_train: 是否边训练边验证,(1 for True, 0 for False)
+--eval_steps: 验证频率(边训练边验证)
+--eval_start_epoch: 边训练边验证时的起始 epoch
+--use_modelarts: 是否使用 modelarts(1 for True, 0 for False; 设置为 1 时将使用 moxing 从 obs 拷贝数据)
+--train_url: ( modelsarts 需要的参数,但因该名称存在歧义而在代码中未使用)
+--data_url: ( modelsarts 需要的参数,但因该名称存在歧义而在代码中未使用)
+--output_path: 日志等文件输出目录
+--outer_path: 输出到 obs 外部的目录(仅在 modelarts 上运行时有效)
+--device_target: 运行设备(默认 "Ascend")
+--is_distributed: 是否多卡运行
+--rank: Local rank of distributed. Default: 0
+--group_size: World size of device. Default: 1
+--is_save_on_master: 是否仅保存 0 卡上的运行结果
+--ckpt_save_max: ckpt 保存的最多文件数
+
+eval.py 中的主要参数如下:
+--dataset: 数据集路径
+--base_size: 图片初始大小(图片缩放基准(0.5~2倍缩放))
+--crop_size: 剪切尺寸
+--resume_path: 推理文件路径
+--resume_name: 推理文件名
+--use_modelarts: 是否使用 modelarts(1 for True, 0 for False; 设置为 1 时将使用 moxing 从 obs 拷贝数据)
+--train_url: ( modelsarts 需要的参数,但因该名称存在歧义而在代码中未使用)
+--data_url: ( modelsarts 需要的参数,但因该名称存在歧义而在代码中未使用)
+--output_path: 日志等文件输出目录
+--outer_path: 输出到 obs 外部的目录(仅在 modelarts 上运行时有效)
+--device_target: 运行设备(默认 "Ascend")
+--is_distributed: 是否多卡运行
+--rank: Local rank of distributed. Default: 0
+--group_size: World size of device. Default: 1
+
+export.py 中的主要参数如下:
+--batch_size: 批次大小
+--aux: 是否使用辅助损失
+--image_height: 图片高度
+--image_width: 图片宽度
+--ckpt_file: 权重文件路径
+--file_name: 权重文件名称
+--file_format: 待转文件格式,choices=["AIR", "ONNX", "MINDIR"]
+--device_target: 运行设备(默认 "Ascend")
+--device_id: 运行设备id
+
+preprocess.py 中的主要参数如下:
+--out_dir: 保存处理后的图片及标签的路径
+--image_path: 测试集路径根目录
+--image_height: 切割高度
+--image_width: 切割宽度
+
+cal_mIoU.py 中的主要参数如下:
+--label_path: 标签文件路径
+--output_path: 模型推理完成后的结果保存路径,默认为 xx/scripts/result_Files/
+--image_width: 图片宽度
+--image_height: 图片高度
+--save_mask:是否保存语义分割可视化结果(0:否;1:是)默认保存至--output_path参数指定的路径下
+```
+
+### 训练过程
+
+#### 训练
+
+- Ascend处理器环境运行
+
+ ```python
+ #通过 python 命令行运行单卡训练脚本。
+ python train.py \
+ --dataset=xxx/dataset/ \
+ --base_size=1024 \
+ --epochs=1000 \
+ --batch_size=2 \
+ --lr=0.001 \
+ --use_modelarts=0 \
+ --output_path=./outputs/ \
+ --is_distributed=0 > log.txt 2>&1 &
+
+ #通过 bash 命令启动单卡训练。
+ bash ./scripts/run_train.sh [train_code_path] [dataset] [epochs] [batch_size] [lr] [output_path]
+
+ #上述命令均会使脚本在后台运行,日志将输出到 log.txt,可通过查看该文件了解训练详情
+
+ #Ascend多卡训练(2、4、8卡配置请自行修改run_distribute_train.sh,默认8卡)
+ bash ./scripts/run_distribute_train.sh [train_code_path] [dataset] [epochs] [batch_size] [lr] [output_path]
+ ```
+
+ 训练完成后,您可以在 --output_path 参数指定的目录下找到保存的权重文件,训练过程中的部分 loss 收敛情况如下(4卡并行):
+
+ ```bash
+ # grep "epoch time:" log.txt
+ epoch: 1 step: 372, loss is 1.3456033
+ epoch time: 137732.853 ms, per step time: 370.250 ms
+ epoch: 2 step: 372, loss is 1.0044098
+ epoch time: 58415.648 ms, per step time: 157.031 ms
+ epoch: 3 step: 372, loss is 1.18629
+ epoch time: 58427.821 ms, per step time: 157.064 ms
+ epoch: 4 step: 372, loss is 1.2148521
+ epoch time: 58462.224 ms, per step time: 157.157 ms
+ epoch: 5 step: 372, loss is 1.2190971
+ epoch time: 58443.678 ms, per step time: 157.107 ms
+ epoch: 6 step: 372, loss is 1.3678352
+ epoch time: 58433.127 ms, per step time: 157.078 ms
+ epoch: 7 step: 372, loss is 1.1452634
+ epoch time: 58486.977 ms, per step time: 157.223 ms
+ epoch: 8 step: 372, loss is 0.97296643
+ epoch time: 58435.751 ms, per step time: 157.085 ms
+ epoch: 9 step: 372, loss is 1.3209964
+ epoch time: 58425.310 ms, per step time: 157.057 ms
+ epoch: 10 step: 372, loss is 3.6610103
+ epoch time: 58471.895 ms, per step time: 157.183 ms
+ 2021-06-25 09:59:00,682 :INFO: epoch: 10, pixAcc: 83.403519720267, mIou: 24.45742576986472
+ 2021-06-25 09:59:00,682 :INFO: update best result: 24.45742576986472
+ 2021-06-25 09:59:00,880 :INFO: update best checkpoint at: ./outputs/2021-06-25_time_09_46_46/best_map.ckpt
+ epoch: 11 step: 372, loss is 0.4546556
+ epoch time: 58473.429 ms, per step time: 157.187 ms
+ epoch: 12 step: 372, loss is 0.8289163
+ epoch time: 58415.030 ms, per step time: 157.030 ms
+ epoch: 13 step: 372, loss is 2.704109
+ epoch time: 58482.305 ms, per step time: 157.210 ms
+ epoch: 14 step: 372, loss is 0.6193013
+ epoch time: 58430.010 ms, per step time: 157.070 ms
+ epoch: 15 step: 372, loss is 1.2098892
+ epoch time: 58479.622 ms, per step time: 157.203 ms
+ epoch: 16 step: 372, loss is 1.0399697
+ epoch time: 58434.526 ms, per step time: 157.082 ms
+ epoch: 17 step: 372, loss is 0.70629436
+ epoch time: 58419.096 ms, per step time: 157.041 ms
+ epoch: 18 step: 372, loss is 0.9555901
+ epoch time: 58483.321 ms, per step time: 157.213 ms
+ epoch: 19 step: 372, loss is 0.60520625
+ epoch time: 58427.472 ms, per step time: 157.063 ms
+ epoch: 20 step: 372, loss is 1.1268346
+ epoch time: 58429.871 ms, per step time: 157.070 ms
+ 2021-06-25 10:09:28,363 :INFO: epoch: 20, pixAcc: 89.35572496631883, mIou: 31.57923493725986
+ 2021-06-25 10:09:28,363 :INFO: update best result: 31.57923493725986
+ 2021-06-25 10:09:28,541 :INFO: update best checkpoint at: ./outputs/2021-06-25_time_09_46_46/best_map.ckpt
+ ...
+ ```
+
+### 评估过程
+
+#### 评估
+
+在运行以下命令之前,请检查用于推理评估的权重文件路径是否正确。
+
+- Ascend处理器环境运行
+
+ ```python
+ #通过 python 命令启动评估
+ python eval.py \
+ --dataset=xxx/dataset/ \
+ --resume_path=xxx/ \
+ --resume_name=fastscnn.ckpt \
+ --output_path=./outputs/ \
+ --is_distributed=0 > log.txt 2>&1 &
+
+ #通过 bash 命令启动推理。
+ bash ./scripts/run_eval.sh [train_code_path] [dataset] [resume_path] [resume_name] [output_path]
+ ```
+
+ 运行完成后,您可以在 --output_path 指定的目录下找到最终语义分割结果的效果图;各种类别物体的 iou 值也保存在该文件夹下的 eval_results.txt 文件中。
+
+#### 310 推理
+
+- 在 Ascend 310 处理器环境运行
+
+```python
+#通过 bash 命令启动推理
+bash run_infer_310.sh [model_path] [data_path] [out_image_path] [image_height] [image_width] [device_id]
+#上述命令将完成推理所需的全部工作。执行完成后,将产生 preprocess.log、infer.log、acc.log 三个日志文件。
+#如果您需要单独执行各部分代码,可以参照 run_infer_310.sh 内的流程分别进行编译、图片预处理、推理和 mIoU 计算,请注意核对各部分所需参数!
+```
+
+## 模型描述
+
+### 性能
+
+#### 评估性能
+
+FastSCNN on “Cityscapes ”
+
+| Parameters | FastSCNN |
+| -------------------------- | ------------------------------------------------------------ |
+| Resource | Ascend 910 ;CPU 2.60GHz,192cores; Memory, 755G |
+| uploaded Date | 6/25/2021 (month/day/year) |
+| MindSpore Version | master |
+| Dataset | Cityscapes |
+| Training Parameters | epoch=1000, batch_size=2, lr=0.001 |
+| Optimizer | SGD |
+| Loss Function | MixSoftmaxCrossEntropyLoss |
+| outputs | image with segmentation mask |
+| Loss | 0.4 |
+| Accuracy | 55.48% |
+| Total time | 8p:8h20m |
+| Checkpoint for Fine tuning | 8p: 14.51MB(.ckpt file) |
+| Scripts | https://gitee.com/mindspore/mindspore/tree/master/model_zoo/official/cv/fastscnn |
+
+## 随机情况说明
+
+train.py中设置了随机种子。
+
+## ModelZoo主页
+
+请浏览官网[主页](https://gitee.com/mindspore/mindspore/tree/master/model_zoo)。
diff --git a/model_zoo/official/cv/fastscnn/ascend310_infer/CMakeLists.txt b/model_zoo/official/cv/fastscnn/ascend310_infer/CMakeLists.txt
new file mode 100644
index 00000000000..ee3c8544734
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/ascend310_infer/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.14.1)
+project(Ascend310Infer)
+add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -std=c++17 -Werror -Wall -fPIE -Wl,--allow-shlib-undefined")
+set(PROJECT_SRC_ROOT ${CMAKE_CURRENT_LIST_DIR}/)
+option(MINDSPORE_PATH "mindspore install path" "")
+include_directories(${MINDSPORE_PATH})
+include_directories(${MINDSPORE_PATH}/include)
+include_directories(${PROJECT_SRC_ROOT})
+find_library(MS_LIB libmindspore.so ${MINDSPORE_PATH}/lib)
+file(GLOB_RECURSE MD_LIB ${MINDSPORE_PATH}/_c_dataengine*)
+
+add_executable(main src/main.cc src/utils.cc)
+target_link_libraries(main ${MS_LIB} ${MD_LIB} gflags)
diff --git a/model_zoo/official/cv/fastscnn/ascend310_infer/build.sh b/model_zoo/official/cv/fastscnn/ascend310_infer/build.sh
new file mode 100644
index 00000000000..285514e19f2
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/ascend310_infer/build.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+if [ -d out ]; then
+ rm -rf out
+fi
+
+mkdir out
+cd out || exit
+
+if [ -f "Makefile" ]; then
+ make clean
+fi
+
+cmake .. \
+ -DMINDSPORE_PATH="`pip3.7 show mindspore-ascend | grep Location | awk '{print $2"/mindspore"}' | xargs realpath`"
+make
diff --git a/model_zoo/official/cv/fastscnn/ascend310_infer/fusion_switch.cfg b/model_zoo/official/cv/fastscnn/ascend310_infer/fusion_switch.cfg
new file mode 100644
index 00000000000..22c25638409
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/ascend310_infer/fusion_switch.cfg
@@ -0,0 +1 @@
+ConvBatchnormFusionPass:off
diff --git a/model_zoo/official/cv/fastscnn/ascend310_infer/inc/utils.h b/model_zoo/official/cv/fastscnn/ascend310_infer/inc/utils.h
new file mode 100644
index 00000000000..abeb8fcbf11
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/ascend310_infer/inc/utils.h
@@ -0,0 +1,32 @@
+/**
+ * Copyright 2021 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MINDSPORE_INFERENCE_UTILS_H_
+#define MINDSPORE_INFERENCE_UTILS_H_
+
+#include
+#include
+#include
+#include
+#include
+#include "include/api/types.h"
+
+std::vector GetAllFiles(std::string_view dirName);
+DIR *OpenDir(std::string_view dirName);
+std::string RealPath(std::string_view path);
+mindspore::MSTensor ReadFileToTensor(const std::string &file);
+int WriteResult(const std::string& imageFile, const std::vector &outputs);
+#endif
diff --git a/model_zoo/official/cv/fastscnn/ascend310_infer/src/main.cc b/model_zoo/official/cv/fastscnn/ascend310_infer/src/main.cc
new file mode 100644
index 00000000000..f78f87c4af0
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/ascend310_infer/src/main.cc
@@ -0,0 +1,166 @@
+/**
+ * Copyright 2021 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "include/api/model.h"
+#include "include/api/context.h"
+#include "include/api/types.h"
+#include "include/api/serialization.h"
+#include "include/minddata/dataset/include/vision_ascend.h"
+#include "include/minddata/dataset/include/execute.h"
+#include "include/minddata/dataset/include/transforms.h"
+#include "include/minddata/dataset/include/constants.h"
+#include "include/minddata/dataset/include/vision.h"
+#include "inc/utils.h"
+
+using mindspore::Serialization;
+using mindspore::Model;
+using mindspore::Context;
+using mindspore::Status;
+using mindspore::ModelType;
+using mindspore::Graph;
+using mindspore::GraphCell;
+using mindspore::kSuccess;
+using mindspore::MSTensor;
+using mindspore::DataType;
+
+using mindspore::dataset::Execute;
+using mindspore::dataset::TensorTransform;
+using mindspore::dataset::vision::Decode;
+using mindspore::dataset::vision::Resize;
+using mindspore::dataset::vision::HWC2CHW;
+using mindspore::dataset::vision::Normalize;
+using mindspore::dataset::transforms::TypeCast;
+
+DEFINE_string(model_path, "", "model path");
+DEFINE_string(dataset_path, "", "dataset path");
+DEFINE_int32(device_id, 0, "device id");
+DEFINE_string(fusion_switch_path, ".", "fusion switch path");
+
+int main(int argc, char **argv) {
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
+ if (RealPath(FLAGS_model_path).empty()) {
+ std::cout << "Invalid mindir" << std::endl;
+ return 1;
+ }
+
+ auto context = std::make_shared();
+ auto ascend310_info = std::make_shared();
+ ascend310_info->SetDeviceID(FLAGS_device_id);
+ context->MutableDeviceInfo().push_back(ascend310_info);
+
+ Graph graph;
+ Status ret = Serialization::Load(FLAGS_model_path, ModelType::kMindIR, &graph);
+ if (ret != kSuccess) {
+ std::cout << "Load model failed." << std::endl;
+ return 1;
+ }
+
+ if (RealPath(FLAGS_fusion_switch_path).empty()) {
+ std::cout << "Invalid fusion switch path" << std::endl;
+ return 1;
+ }
+ if (!FLAGS_fusion_switch_path.empty()) {
+ ascend310_info->SetFusionSwitchConfigPath(FLAGS_fusion_switch_path);
+ }
+
+ Model model;
+ ret = model.Build(GraphCell(graph), context);
+ if (ret != kSuccess) {
+ std::cout << "ERROR: Build failed." << std::endl;
+ return 1;
+ }
+
+ std::vector modelInputs = model.GetInputs();
+
+ auto all_files = GetAllFiles(FLAGS_dataset_path);
+ if (all_files.empty()) {
+ std::cout << "ERROR: no input data." << std::endl;
+ return 1;
+ }
+
+ std::map costTime_map;
+ size_t size = all_files.size();
+ // Define transform
+
+ for (size_t i = 0; i < size; ++i) {
+ struct timeval start;
+ struct timeval end;
+ double startTime_ms;
+ double endTime_ms;
+
+ std::vector inputs;
+ std::vector outputs;
+ std::vector outputs0; // when aux==1, there would be 3 outputs, but we only use the first one
+ // when aux==0, there would be 1 output
+
+ std::cout << "Start predict input files:" << all_files[i] << std::endl;
+
+ auto image = ReadFileToTensor(all_files[i]);
+
+ inputs.emplace_back(modelInputs[0].Name(), modelInputs[0].DataType(), modelInputs[0].Shape(),
+ image.Data().get(), image.DataSize());
+
+ gettimeofday(&start, NULL);
+ ret = model.Predict(inputs, &outputs);
+ outputs0.emplace_back(outputs[0]); // when aux==1, outputs0's shape would be (1,19,768,768)
+ // when aux==0, outputs0's shape would be (19,768,768)
+ gettimeofday(&end, NULL);
+ if (ret != kSuccess) {
+ std::cout << "Predict " << all_files[i] << " failed." << std::endl;
+ return 1;
+ }
+ startTime_ms = (1.0 * start.tv_sec * 1000000 + start.tv_usec) / 1000;
+ endTime_ms = (1.0 * end.tv_sec * 1000000 + end.tv_usec) / 1000;
+ costTime_map.insert(std::pair(startTime_ms, endTime_ms));
+
+ WriteResult(all_files[i], outputs0);
+ }
+
+ double average = 0.0;
+ int infer_cnt = 0;
+
+ for (auto iter = costTime_map.begin(); iter != costTime_map.end(); iter++) {
+ double diff = 0.0;
+ diff = iter->second - iter->first;
+ average += diff;
+ infer_cnt++;
+ }
+
+ average = average / infer_cnt;
+ std::stringstream timeCost;
+ timeCost << "NN inference cost average time: "<< average << " ms of infer_count " << infer_cnt << std::endl;
+ std::cout << "NN inference cost average time: "<< average << "ms of infer_count " << infer_cnt << std::endl;
+ std::string file_name = "./time_Result" + std::string("/test_perform_static.txt");
+ std::ofstream file_stream(file_name.c_str(), std::ios::trunc);
+ file_stream << timeCost.str();
+ file_stream.close();
+ costTime_map.clear();
+
+ return 0;
+}
diff --git a/model_zoo/official/cv/fastscnn/ascend310_infer/src/utils.cc b/model_zoo/official/cv/fastscnn/ascend310_infer/src/utils.cc
new file mode 100644
index 00000000000..4557e1c3455
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/ascend310_infer/src/utils.cc
@@ -0,0 +1,127 @@
+/**
+ * Copyright 2021 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "inc/utils.h"
+
+#include
+#include
+#include
+
+using mindspore::MSTensor;
+using mindspore::DataType;
+
+std::vector GetAllFiles(std::string_view dirName) {
+ struct dirent *filename;
+ DIR *dir = OpenDir(dirName);
+ if (dir == nullptr) {
+ return {};
+ }
+ std::vector res;
+ while ((filename = readdir(dir)) != nullptr) {
+ std::string dName = std::string(filename->d_name);
+ if (dName == "." || dName == ".." || filename->d_type != DT_REG) {
+ continue;
+ }
+ res.emplace_back(std::string(dirName) + "/" + filename->d_name);
+ }
+ std::sort(res.begin(), res.end());
+ for (auto &f : res) {
+ std::cout << "image file: " << f << std::endl;
+ }
+ return res;
+}
+
+int WriteResult(const std::string& imageFile, const std::vector &outputs) {
+ std::string homePath = "./result_Files";
+ for (size_t i = 0; i < outputs.size(); ++i) {
+ size_t outputSize;
+ std::shared_ptr netOutput = outputs[i].Data();
+ outputSize = outputs[i].DataSize();
+ int pos = imageFile.rfind('/');
+ std::string fileName(imageFile, pos + 1);
+ fileName.replace(fileName.find('.'), fileName.size() - fileName.find('.'), '_' + std::to_string(i) + ".bin");
+ std::string outFileName = homePath + "/" + fileName;
+ FILE *outputFile = fopen(outFileName.c_str(), "wb");
+ fwrite(netOutput.get(), outputSize, sizeof(char), outputFile);
+ fclose(outputFile);
+ outputFile = nullptr;
+ }
+ return 0;
+}
+
+mindspore::MSTensor ReadFileToTensor(const std::string &file) {
+ if (file.empty()) {
+ std::cout << "Pointer file is nullptr" << std::endl;
+ return mindspore::MSTensor();
+ }
+
+ std::ifstream ifs(file);
+ if (!ifs.good()) {
+ std::cout << "File: " << file << " is not exist" << std::endl;
+ return mindspore::MSTensor();
+ }
+
+ if (!ifs.is_open()) {
+ std::cout << "File: " << file << "open failed" << std::endl;
+ return mindspore::MSTensor();
+ }
+
+ ifs.seekg(0, std::ios::end);
+ size_t size = ifs.tellg();
+ mindspore::MSTensor buffer(file, mindspore::DataType::kNumberTypeUInt8, {static_cast(size)}, nullptr, size);
+
+ ifs.seekg(0, std::ios::beg);
+ ifs.read(reinterpret_cast(buffer.MutableData()), size);
+ ifs.close();
+
+ return buffer;
+}
+
+
+DIR *OpenDir(std::string_view dirName) {
+ if (dirName.empty()) {
+ std::cout << " dirName is null ! " << std::endl;
+ return nullptr;
+ }
+ std::string realPath = RealPath(dirName);
+ struct stat s;
+ lstat(realPath.c_str(), &s);
+ if (!S_ISDIR(s.st_mode)) {
+ std::cout << "dirName is not a valid directory !" << std::endl;
+ return nullptr;
+ }
+ DIR *dir = opendir(realPath.c_str());
+ if (dir == nullptr) {
+ std::cout << "Can not open dir " << dirName << std::endl;
+ return nullptr;
+ }
+ std::cout << "Successfully opened the dir " << dirName << std::endl;
+ return dir;
+}
+
+std::string RealPath(std::string_view path) {
+ char realPathMem[PATH_MAX] = {0};
+ char *realPathRet = nullptr;
+ realPathRet = realpath(path.data(), realPathMem);
+ if (realPathRet == nullptr) {
+ std::cout << "File: " << path << " is not exist.";
+ return "";
+ }
+
+ std::string realPath(realPathMem);
+ std::cout << path << " realpath is: " << realPath << std::endl;
+ return realPath;
+}
diff --git a/model_zoo/official/cv/fastscnn/cal_mIoU.py b/model_zoo/official/cv/fastscnn/cal_mIoU.py
new file mode 100644
index 00000000000..6d300e98ee7
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/cal_mIoU.py
@@ -0,0 +1,106 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+import argparse
+import os
+import time
+import glob
+import numpy as np
+from tabulate import tabulate
+from score import SegmentationMetric
+
+## Params
+parser = argparse.ArgumentParser()
+parser.add_argument('--label_path', type=str
+ , help='directory of dataset label')
+parser.add_argument('--output_path', default='', type=str,
+ help='path of the predict files that generated by the model')
+parser.add_argument('--image_width', default=768, type=int, help='image_width')
+parser.add_argument('--image_height', default=768, type=int, help='image_height')
+parser.add_argument('--save_mask', default=0, type=int, help='0 for False, 1 for True')
+
+args = parser.parse_args()
+
+cityspallete = [
+ 128, 64, 128,
+ 244, 35, 232,
+ 70, 70, 70,
+ 102, 102, 156,
+ 190, 153, 153,
+ 153, 153, 153,
+ 250, 170, 30,
+ 220, 220, 0,
+ 107, 142, 35,
+ 152, 251, 152,
+ 0, 130, 180,
+ 220, 20, 60,
+ 255, 0, 0,
+ 0, 0, 142,
+ 0, 0, 70,
+ 0, 60, 100,
+ 0, 80, 100,
+ 0, 0, 230,
+ 119, 11, 32,
+]
+classes = ('road', 'sidewalk', 'building', 'wall', 'fence', 'pole', 'traffic light',
+ 'traffic sign', 'vegetation', 'terrain', 'sky', 'person', 'rider', 'car',
+ 'truck', 'bus', 'train', 'motorcycle', 'bicycle')
+def cal_mIoU(label_path, output_path, image_width, image_height, save_mask):
+ file_list = glob.glob(label_path+'*') # label_path must end by '/'
+
+ start_time = time.time()
+ metric = SegmentationMetric(19)
+ metric.reset()
+ index = 0
+ for file in file_list:
+ label = np.fromfile(file, dtype=np.int32)
+ label = label.reshape(image_height, image_width)
+
+ filename = file.split(os.sep)[-1][:-10] # get the name of image file
+ predict_path = os.path.join(output_path, filename+"_img_0.bin")
+ predict = np.fromfile(predict_path, dtype=np.float32)
+ predict = predict.reshape(1, 19, image_height, image_width)
+ metric.update(predict, label)
+ pixAcc, mIoU = metric.get()
+ print("[EVAL] Sample: {:d}, pixAcc: {:.3f}, mIoU: {:.3f}".format(index + 1, pixAcc * 100, mIoU * 100))
+ index += 1
+
+ if save_mask == 1:
+ output = np.argmax(predict[0], axis=0)
+ out_img = Image.fromarray(output.astype('uint8'))
+ out_img.putpalette(cityspallete)
+ outname = str(index) + '.png'
+ out_img.save(os.path.join(output_path, outname))
+
+
+ pixAcc, mIoU, category_iou = metric.get(return_category_iou=True)
+ print('End validation pixAcc: {:.3f}, mIoU: {:.3f}'.format(pixAcc * 100, mIoU * 100))
+ txtName = os.path.join(output_path, "eval_results.txt")
+ with open(txtName, "w") as f:
+ string = 'validation pixAcc:' + str(pixAcc * 100) + ', mIoU:' + str(mIoU * 100)
+ f.write(string)
+ f.write('\n')
+ headers = ['class id', 'class name', 'iou']
+ table = []
+ for i, cls_name in enumerate(classes):
+ table.append([cls_name, category_iou[i]])
+ string = 'class name: ' + cls_name + ' iou: ' + str(category_iou[i]) + '\n'
+ f.write(string)
+ print('Category iou: \n {}'.format(tabulate(table, headers, \
+ tablefmt='grid', showindex="always", numalign='center', stralign='center')))
+ time_used = time.time() - start_time
+ print("Time cost:"+str(time_used)+" seconds!")
+
+if __name__ == '__main__':
+ cal_mIoU(args.label_path, args.output_path, args.image_width, args.image_height, args.save_mask)
diff --git a/model_zoo/official/cv/fastscnn/eval.py b/model_zoo/official/cv/fastscnn/eval.py
new file mode 100644
index 00000000000..fd038e53c39
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/eval.py
@@ -0,0 +1,198 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+'''eval.py'''
+import os
+import argparse
+from PIL import Image
+from tabulate import tabulate
+
+from mindspore import context
+import mindspore.ops as ops
+from mindspore.context import ParallelMode
+from mindspore import load_checkpoint, load_param_into_net
+from mindspore.communication.management import init, get_rank, get_group_size
+from mindspore.dataset.transforms.py_transforms import Compose
+from mindspore.dataset.vision.py_transforms import ToTensor, Normalize
+
+from src.dataloader import create_CitySegmentation
+from src.fast_scnn import FastSCNN
+from src.score import SegmentationMetric
+from src.logger import get_logger
+import src.visualize as visualize
+
+def parse_args():
+ """Training Options for Segmentation Experiments"""
+ parser = argparse.ArgumentParser(description='Fast-SCNN on mindspore')
+ parser.add_argument('--dataset', type=str, default='/data/dataset/citys/',
+ help='dataset name (default: /data/dataset/citys/)')
+ parser.add_argument('--base_size', type=int, default=1024, help='base image size')
+ parser.add_argument('--crop_size', type=int, default=(768, 768), help='crop image size')
+ parser.add_argument('--train_split', type=str, default='train',
+ help='dataset train split (default: train)')
+ parser.add_argument('--aux', action='store_true', default=True, help='Auxiliary loss')
+ parser.add_argument('--aux_weight', type=float, default=0.4,
+ help='auxiliary loss weight')
+ parser.add_argument('--epochs', type=int, default=1000, metavar='N',
+ help='number of epochs to train (default: 1000)')
+ parser.add_argument('--save_every', type=int, default=1, metavar='N',
+ help='save ckpt every N epoch')
+ parser.add_argument('--resume_path', type=str, default=None,
+ help='put the path to resuming file if needed')
+ parser.add_argument('--resume_name', type=str, default=None,
+ help='resuming file name')
+ parser.add_argument('--batch_size', type=int, default=2, metavar='N',
+ help='input batch size for training (default: 2)')
+ parser.add_argument('--lr', type=float, default=0.001, metavar='LR',
+ help='base learning rate (default: 0.045)')
+ parser.add_argument('--momentum', type=float, default=0.9, metavar='M',
+ help='momentum (default: 0.9)')
+ parser.add_argument('--weight_decay', type=float, default=4e-5, metavar='M',
+ help='w-decay (default: 4e-5)')
+
+ parser.add_argument('--eval_while_train', type=int, default=1, help='eval while training')
+ parser.add_argument('--eval_steps', type=int, default=10, help='each N epochs we eval')
+ parser.add_argument('--eval_start_epoch', type=int, default=850, help='eval_start_epoch')
+ parser.add_argument('--use_modelarts', type=int, default=0,
+ help='when set True, we should load dataset from obs with moxing')
+ parser.add_argument('--train_url', type=str, default='train_url/',
+ help='needed by modelarts, but we donot use it because the name is ambiguous')
+ parser.add_argument('--data_url', type=str, default='data_url/',
+ help='needed by modelarts, but we donot use it because the name is ambiguous')
+ parser.add_argument('--output_path', type=str, default='./outputs/',
+ help='output_path,when use_modelarts is set True, it will be cache/output/')
+ parser.add_argument('--outer_path', type=str, default='s3://output/',
+ help='obs path,to store e.g ckpt files ')
+
+ parser.add_argument('--device_target', type=str, default='Ascend',
+ help='device where the code will be implemented. (Default: Ascend)')
+ parser.add_argument('--is_distributed', type=int, default=0, help='if multi device')
+ parser.add_argument('--rank', type=int, default=0, help='local rank of distributed')
+ parser.add_argument('--group_size', type=int, default=1, help='world size of distributed')
+ parser.add_argument('--is_save_on_master', type=int, default=1,
+ help='save ckpt on master or all rank')
+ parser.add_argument('--ckpt_save_max', type=int, default=800,
+ help='Maximum number of checkpoint files can be saved. Default: 5.')
+ # the parser
+ args_ = parser.parse_args()
+ return args_
+
+args = parse_args()
+save_dir = args.output_path
+device_id = int(os.getenv('DEVICE_ID', '0'))
+context.set_context(mode=context.GRAPH_MODE,
+ device_target=args.device_target, save_graphs=False)
+
+def validation():
+ '''validation'''
+ if args.is_distributed:
+ assert args.device_target == "Ascend"
+ init()
+ context.set_context(device_id=device_id)
+ args.rank = get_rank()
+ args.group_size = get_group_size()
+ device_num = args.group_size
+ context.reset_auto_parallel_context()
+ context.set_auto_parallel_context(device_num=device_num, parallel_mode=ParallelMode.DATA_PARALLEL,
+ mirror_mean=True)
+ else:
+ if args.device_target in ["Ascend", "GPU"]:
+ context.set_context(device_id=device_id)
+
+ # select for master rank save ckpt or all rank save, compatible for model parallel
+ args.rank_save_ckpt_flag = 0
+ if args.is_save_on_master:
+ if args.rank == 0:
+ args.rank_save_ckpt_flag = 1
+ else:
+ args.rank_save_ckpt_flag = 1
+
+ metric = SegmentationMetric(19)
+ metric.reset()
+
+ # create network
+ model = FastSCNN(num_classes=19, aux=True)
+ if args.resume_path:
+ if args.use_modelarts:
+ import moxing as mox
+ args.logger.info("copying resume checkpoint from obs to cache....")
+ mox.file.copy_parallel(args.resume_path, 'cache/resume_path')
+ args.logger.info("copying resume checkpoint finished....")
+ args.resume_path = 'cache/resume_path/'
+
+ args.resume_path = os.path.join(args.resume_path, args.resume_name)
+ args.logger.info('loading resume checkpoint {} into network'.format(args.resume_path))
+ load_param_into_net(model, load_checkpoint(args.resume_path))
+ args.logger.info('loaded resume checkpoint {} into network'.format(args.resume_path))
+
+ model.set_train(False)
+ # image transform
+ input_transform = Compose([
+ ToTensor(),
+ Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
+ ])
+ if args.use_modelarts:
+ import moxing as mox
+ args.logger.info("copying dataset from obs to cache....")
+ mox.file.copy_parallel(args.dataset, 'cache/dataset')
+ args.logger.info("copying dataset finished....")
+ args.dataset = 'cache/dataset/'
+
+ val_dataset, _ = create_CitySegmentation(args, data_path=args.dataset, \
+ split='val', mode='val', transform=input_transform, \
+ base_size=args.base_size, crop_size=args.crop_size, \
+ batch_size=1, device_num=args.group_size, \
+ rank=args.rank, shuffle=False)
+ classes = ('road', 'sidewalk', 'building', 'wall', 'fence', 'pole', 'traffic light',
+ 'traffic sign', 'vegetation', 'terrain', 'sky', 'person', 'rider', 'car',
+ 'truck', 'bus', 'train', 'motorcycle', 'bicycle')
+
+ data_loader = val_dataset.create_dict_iterator()
+ for i, data in enumerate(data_loader):
+ images = data["image"]
+ targets = data["label"]
+ output = model(images)[0]
+ metric.update(output, targets)
+ pixAcc, mIoU = metric.get()
+ args.logger.info("[EVAL] Sample: {:d}, pixAcc: {:.3f}, mIoU: {:.3f}".format(i + 1, pixAcc * 100, mIoU * 100))
+
+ output = ops.Argmax(axis=0)(output[0]).asnumpy()
+ out_img = Image.fromarray(output.astype('uint8'))
+ out_img.putpalette(visualize.cityspallete)
+ outname = str(i) + '.png'
+ out_img.save(os.path.join(save_dir, outname))
+
+ pixAcc, mIoU = metric.get()
+ args.logger.info("[EVAL END] pixAcc: {:.3f}, mIoU: {:.3f}".format(pixAcc * 100, mIoU * 100))
+
+ pixAcc, mIoU, category_iou = metric.get(return_category_iou=True)
+ args.logger.info('End validation pixAcc: {:.3f}, mIoU: {:.3f}'.format(pixAcc * 100, mIoU * 100))
+ txtName = os.path.join(save_dir, "eval_results.txt")
+ with open(txtName, "w") as f:
+ string = 'validation pixAcc:' + str(pixAcc * 100) + ', mIoU:' + str(mIoU * 100)
+ f.write(string)
+ f.write('\n')
+ headers = ['class id', 'class name', 'iou']
+ table = []
+ for i, cls_name in enumerate(classes):
+ table.append([cls_name, category_iou[i]])
+ string = 'class name: ' + cls_name + ' iou: ' + str(category_iou[i]) + '\n'
+ f.write(string)
+ args.logger.info('Category iou: \n {}'.format(tabulate(table, headers, \
+ tablefmt='grid', showindex="always", numalign='center', stralign='center')))
+
+if __name__ == '__main__':
+ args.logger = get_logger(save_dir, "Fast_SCNN", args.rank)
+ args.logger.save_args(args)
+ validation()
diff --git a/model_zoo/official/cv/fastscnn/export.py b/model_zoo/official/cv/fastscnn/export.py
new file mode 100644
index 00000000000..719430f7f85
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/export.py
@@ -0,0 +1,54 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""
+##############export checkpoint file into air, onnx, mindir models#################
+python export.py
+"""
+import argparse
+import numpy as np
+
+import mindspore as ms
+from mindspore import context, Tensor, load_checkpoint, load_param_into_net, export
+from src.fast_scnn import FastSCNN
+
+
+## Params
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--batch_size', default=1, type=int, help='batch size')
+parser.add_argument('--aux', action='store_true', default=True, help='Auxiliary loss')
+parser.add_argument("--image_height", type=int, default=768, help="Image height.")
+parser.add_argument("--image_width", type=int, default=768, help="Image width.")
+parser.add_argument("--ckpt_file", type=str, required=True, help="Checkpoint file path.")
+parser.add_argument("--file_name", type=str, default="fastscnn", help="output file name.")
+parser.add_argument("--file_format", type=str, choices=["AIR", "ONNX", "MINDIR"], default="AIR", help="file format")
+parser.add_argument('--device_target', type=str, default='Ascend'
+ , help='device where the code will be implemented. (Default: Ascend)')
+parser.add_argument("--device_id", type=int, default=0, help="Device id")
+
+args_opt = parser.parse_args()
+
+context.set_context(mode=context.GRAPH_MODE, device_target=args_opt.device_target, device_id=args_opt.device_id)
+
+if __name__ == '__main__':
+
+ net = FastSCNN(num_classes=19, aux=args_opt.aux)
+
+ param_dict = load_checkpoint(args_opt.ckpt_file)
+ load_param_into_net(net, param_dict)
+
+ input_arr = Tensor(np.zeros([args_opt.batch_size, 3, \
+ args_opt.image_height, args_opt.image_width]), ms.float32)
+ export(net, input_arr, file_name=args_opt.file_name, file_format=args_opt.file_format)
diff --git a/model_zoo/official/cv/fastscnn/preprocess.py b/model_zoo/official/cv/fastscnn/preprocess.py
new file mode 100644
index 00000000000..5a5ff78f042
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/preprocess.py
@@ -0,0 +1,152 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+import argparse
+import os
+import numpy as np
+import PIL.Image as Image
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--out_dir', type=str, required=True
+ , help='directory to store the image after being cropped')
+parser.add_argument('--image_path', type=str, required=True,
+ help='directory of image to crop')
+parser.add_argument('--image_height', type=int, default=768
+ , help='image height after being cropped')
+parser.add_argument('--image_width', type=int, default=768
+ , help='image width after being cropped')
+args = parser.parse_args()
+
+valid_classes = [7, 8, 11, 12, 13, 17, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 31, 32, 33]
+
+_key = np.array([-1, -1, -1, -1, -1, -1,
+ -1, -1, 0, 1, -1, -1,
+ 2, 3, 4, -1, -1, -1,
+ 5, -1, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15,
+ -1, -1, 16, 17, 18])
+_mapping = np.array(range(-1, len(_key) - 1)).astype('int32')
+
+def _get_city_pairs(folder, split='train'):
+ '''_get_city_pairs'''
+ def get_path_pairs(img_folder, mask_folder):
+ img_paths = []
+ mask_paths = []
+ for root, _, files in os.walk(img_folder):
+ for filename in files:
+ if filename.startswith('._'):
+ continue
+ if filename.endswith('.png'):
+ imgpath = os.path.join(root, filename)
+ foldername = os.path.basename(os.path.dirname(imgpath))
+ maskname = filename.replace('leftImg8bit', 'gtFine_labelIds')
+ maskpath = os.path.join(mask_folder, foldername, maskname)
+ if os.path.isfile(imgpath) and os.path.isfile(maskpath):
+ img_paths.append(imgpath)
+ mask_paths.append(maskpath)
+ else:
+ print('cannot find the mask or image:', imgpath, maskpath)
+ print('Found {} images in the folder {}'.format(len(img_paths), img_folder))
+ return img_paths, mask_paths
+
+ if split in ('train', 'val'):
+ img_folder = os.path.join(folder, 'leftImg8bit' + os.sep + split)
+ mask_folder = os.path.join(folder, 'gtFine' + os.sep + split)
+ img_paths, mask_paths = get_path_pairs(img_folder, mask_folder)
+ return img_paths, mask_paths
+ assert split == 'trainval'
+ print('trainval set')
+ train_img_folder = os.path.join(folder, 'leftImg8bit' + os.sep + 'train')
+ train_mask_folder = os.path.join(folder, 'gtFine' + os.sep + 'train')
+ val_img_folder = os.path.join(folder, 'leftImg8bit' + os.sep + 'val')
+ val_mask_folder = os.path.join(folder, 'gtFine' + os.sep + 'val')
+ train_img_paths, train_mask_paths = get_path_pairs(train_img_folder, train_mask_folder)
+ val_img_paths, val_mask_paths = get_path_pairs(val_img_folder, val_mask_folder)
+ img_paths = train_img_paths + val_img_paths
+ mask_paths = train_mask_paths + val_mask_paths
+ return img_paths, mask_paths
+
+def _val_sync_transform(outsize, img, mask):
+ '''_val_sync_transform'''
+ short_size = min(outsize)
+ w, h = img.size
+ if w > h:
+ oh = short_size
+ ow = int(1.0 * w * oh / h)
+ else:
+ ow = short_size
+ oh = int(1.0 * h * ow / w)
+ img = img.resize((ow, oh), Image.BILINEAR)
+ mask = mask.resize((ow, oh), Image.NEAREST)
+ # center crop
+ w, h = img.size
+ x1 = int(round((w - outsize[1]) / 2.))
+ y1 = int(round((h - outsize[0]) / 2.))
+ img = img.crop((x1, y1, x1 + outsize[1], y1 + outsize[0]))
+ mask = mask.crop((x1, y1, x1 + outsize[1], y1 + outsize[0]))
+
+ # final transform
+ img, mask = np.array(img), _mask_transform(mask)
+ return img, mask
+
+def _class_to_index(mask):
+ # assert the value
+ values = np.unique(mask)
+ for value in values:
+ assert value in _mapping
+ index = np.digitize(mask.ravel(), _mapping, right=True)
+ return _key[index].reshape(mask.shape)
+
+def _mask_transform(mask):
+ target = _class_to_index(np.array(mask).astype('int32'))
+ return np.array(target).astype('int32')
+
+def crop_imageAndLabel(out_dir, image_path, image_height, image_width):
+ if not os.path.exists(os.path.join(out_dir, "images")):
+ os.makedirs(os.path.join(out_dir, "images"))
+ if not os.path.exists(os.path.join(out_dir, "labels")):
+ os.makedirs(os.path.join(out_dir, "labels"))
+
+ assert os.path.exists(image_path), "Please put dataset in {SEG_ROOT}/datasets/cityscapes"
+ images, mask_paths = _get_city_pairs(image_path, 'val')
+ assert len(images) == len(mask_paths)
+ if not images:
+ raise RuntimeError("Found 0 images in subfolders of:" + image_path + "\n")
+
+ for index in range(len(images)):
+ print("Processing ", images[index])
+ img = Image.open(images[index]).convert('RGB')
+ mask = Image.open(mask_paths[index])
+ img, mask = _val_sync_transform((image_height, image_width), img, mask)
+
+ img = img.astype(np.float32)
+ mask = mask.astype(np.int32)
+ mean = [0.485, 0.456, 0.406]
+ std = [0.229, 0.224, 0.225]
+ img = img.transpose((2, 0, 1))#HWC->CHW
+ for channel, _ in enumerate(img):
+ # Normalization
+ img[channel] /= 255
+ img[channel] -= mean[channel]
+ img[channel] /= std[channel]
+
+ img = np.expand_dims(img, 0)#NCHW
+ mask = np.expand_dims(mask, 0)#NHW
+ filename = images[index].split(os.sep)[-1].split('.')[0] # get the name of image file
+ img.tofile(os.path.join(os.path.join(out_dir, "images"), filename+'_img.bin'))
+ mask.tofile(os.path.join(os.path.join(out_dir, "labels"), filename+'_label.bin'))
+
+if __name__ == "__main__":
+ crop_imageAndLabel(args.out_dir, args.image_path, args.image_height, args.image_width)
diff --git a/model_zoo/official/cv/fastscnn/score.py b/model_zoo/official/cv/fastscnn/score.py
new file mode 100644
index 00000000000..ff820b377f2
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/score.py
@@ -0,0 +1,160 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Evaluation Metrics for Semantic Segmentation"""
+import numpy as np
+
+__all__ = ['SegmentationMetric', 'batch_pix_accuracy', 'batch_intersection_union',
+ 'pixelAccuracy', 'intersectionAndUnion', 'hist_info', 'compute_score']
+
+class SegmentationMetric():
+ """Computes pixAcc and mIoU metric scores
+ """
+
+ def __init__(self, nclass):
+ super(SegmentationMetric, self).__init__()
+ self.nclass = nclass
+ self.reset()
+
+ def update(self, preds, labels):
+ """Updates the internal evaluation result.
+
+ Parameters
+ ----------
+ labels : 'NumpyArray' or list of `NumpyArray`
+ The labels of the data.
+ preds : 'NumpyArray' or list of `NumpyArray`
+ Predicted values.
+ """
+ def evaluate_worker(self, pred, label):
+ correct, labeled = batch_pix_accuracy(pred, label)
+ inter, union = batch_intersection_union(pred, label, self.nclass)
+ self.total_correct += correct
+ self.total_label += labeled
+ self.total_inter += inter
+ self.total_union += union
+ evaluate_worker(self, preds, labels)
+
+ def get(self, return_category_iou=False):
+ """Gets the current evaluation result.
+
+ Returns
+ -------
+ metrics : tuple of float
+ pixAcc and mIoU
+ """
+ # remove np.spacing(1)
+ pixAcc = 1.0 * self.total_correct / (2.220446049250313e-16 + self.total_label)
+ IoU = 1.0 * self.total_inter / (2.220446049250313e-16 + self.total_union)
+ mIoU = IoU.mean().item()
+ if return_category_iou:
+ return pixAcc, mIoU, IoU
+ return pixAcc, mIoU
+
+ def reset(self):
+ """Resets the internal evaluation result to initial state."""
+ self.total_inter = np.zeros(self.nclass)
+ self.total_union = np.zeros(self.nclass)
+ self.total_correct = 0
+ self.total_label = 0
+
+def batch_pix_accuracy(output, target):
+ """PixAcc"""
+ # inputs are numpy array, output 4D NCHW where 'C' means label classes, target 3D NHW
+
+ predict = np.argmax(output.astype(np.int64), 1) + 1
+ target = target.astype(np.int64) + 1
+ pixel_labeled = (target > 0).sum()
+ pixel_correct = ((predict == target) * (target > 0)).sum()
+ assert pixel_correct <= pixel_labeled, "Correct area should be smaller than Labeled"
+ return pixel_correct, pixel_labeled
+
+def batch_intersection_union(output, target, nclass):
+ """mIoU"""
+ # inputs are numpy array, output 4D, target 3D
+ mini = 1
+ maxi = nclass
+ nbins = nclass
+ predict = np.argmax(output.astype(np.float32), 1) + 1
+ target = target.astype(np.float32) + 1
+
+ predict = predict.astype(np.float32) * (target > 0).astype(np.float32)
+ intersection = predict * (predict == target).astype(np.float32)
+ # areas of intersection and union
+ # element 0 in intersection occur the main difference from np.bincount. set boundary to -1 is necessary.
+ area_inter, _ = np.histogram(intersection, bins=nbins, range=(mini, maxi))
+ area_pred, _ = np.histogram(predict, bins=nbins, range=(mini, maxi))
+ area_lab, _ = np.histogram(target, bins=nbins, range=(mini, maxi))
+ area_union = area_pred + area_lab - area_inter
+ assert (area_inter > area_union).sum() == 0, "Intersection area should be smaller than Union area"
+ return area_inter.astype(np.float32), area_union.astype(np.float32)
+
+
+def pixelAccuracy(imPred, imLab):
+ """
+ This function takes the prediction and label of a single image, returns pixel-wise accuracy
+ To compute over many images do:
+ for i = range(Nimages):
+ (pixel_accuracy[i], pixel_correct[i], pixel_labeled[i]) = \
+ pixelAccuracy(imPred[i], imLab[i])
+ mean_pixel_accuracy = 1.0 * np.sum(pixel_correct) / (np.spacing(1) + np.sum(pixel_labeled))
+ """
+ # Remove classes from unlabeled pixels in gt image.
+ # We should not penalize detections in unlabeled portions of the image.
+ pixel_labeled = np.sum(imLab >= 0)
+ pixel_correct = np.sum((imPred == imLab) * (imLab >= 0))
+ pixel_accuracy = 1.0 * pixel_correct / pixel_labeled
+ return (pixel_accuracy, pixel_correct, pixel_labeled)
+
+
+def intersectionAndUnion(imPred, imLab, numClass):
+ """
+ This function takes the prediction and label of a single image,
+ returns intersection and union areas for each class
+ To compute over many images do:
+ for i in range(Nimages):
+ (area_intersection[:,i], area_union[:,i]) = intersectionAndUnion(imPred[i], imLab[i])
+ IoU = 1.0 * np.sum(area_intersection, axis=1) / np.sum(np.spacing(1)+area_union, axis=1)
+ """
+ # Remove classes from unlabeled pixels in gt image.
+ # We should not penalize detections in unlabeled portions of the image.
+ imPred = imPred * (imLab >= 0)
+
+ # Compute area intersection:
+ intersection = imPred * (imPred == imLab)
+ (area_intersection, _) = np.histogram(intersection, bins=numClass, range=(1, numClass))
+
+ # Compute area union:
+ (area_pred, _) = np.histogram(imPred, bins=numClass, range=(1, numClass))
+ (area_lab, _) = np.histogram(imLab, bins=numClass, range=(1, numClass))
+ area_union = area_pred + area_lab - area_intersection
+ return (area_intersection, area_union)
+
+
+def hist_info(pred, label, num_cls):
+ assert pred.shape == label.shape
+ k = (label >= 0) & (label < num_cls)
+ labeled = np.sum(k)
+ correct = np.sum((pred[k] == label[k]))
+
+ return np.bincount(num_cls * label[k].astype(int) + pred[k], \
+ minlength=num_cls ** 2).reshape(num_cls, num_cls), labeled, correct
+
+def compute_score(hist, correct, labeled):
+ iu = np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))
+ mean_IU = np.nanmean(iu)
+ mean_IU_no_back = np.nanmean(iu[1:])
+ mean_pixel_acc = correct / labeled
+
+ return iu, mean_IU, mean_IU_no_back, mean_pixel_acc
diff --git a/model_zoo/official/cv/fastscnn/scripts/run_distribute_train.sh b/model_zoo/official/cv/fastscnn/scripts/run_distribute_train.sh
new file mode 100644
index 00000000000..499b4a621df
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/scripts/run_distribute_train.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+
+if [ $# != 6 ]; then
+ echo "Usage: sh run_distribute_train.sh [train_code_path] [dataset]" \
+ "[epochs] [batch_size] [lr] [output_path]"
+ exit 1
+fi
+
+get_real_path() {
+ if [ "${1:0:1}" == "/" ]; then
+ echo "$1"
+ else
+ echo "$(realpath -m $PWD/$1)/"
+ fi
+}
+
+train_code_path=$(get_real_path $1)
+echo "train_code_path: "$train_code_path
+
+dataset=$(get_real_path $2)
+echo "dataset: "$dataset
+
+if [ ! -d $train_code_path ]
+then
+ echo "error: train_code_path=$train_code_path is not a dictionary."
+exit 1
+fi
+
+if [ ! -d $dataset ]
+then
+ echo "error: dataset=$dataset is not a dictionary."
+exit 1
+fi
+
+
+
+ulimit -c unlimited
+export SLOG_PRINT_TO_STDOUT=0
+export RANK_TABLE_FILE=${train_code_path}scripts/hccl_8p_01234567_10.155.170.118.json
+export RANK_SIZE=8
+export RANK_START_ID=0
+
+
+for((i=0;i<=$RANK_SIZE-1;i++));
+do
+ export RANK_ID=${i}
+ export DEVICE_ID=$((i + RANK_START_ID))
+ echo 'start rank='${i}', device id='${DEVICE_ID}'...'
+ if [ -d ${train_code_path}/device${DEVICE_ID} ]; then
+ rm -rf ${train_code_path}/device${DEVICE_ID}
+ fi
+ mkdir ${train_code_path}/device${DEVICE_ID}
+ cd ${train_code_path}/device${DEVICE_ID} || exit
+ nohup python ${train_code_path}train.py --is_distributed=1 \
+ --dataset=${dataset} \
+ --epochs=$3 \
+ --batch_size=$4 \
+ --lr=$5 \
+ --output_path=$6 > log.txt 2>&1 &
+done
diff --git a/model_zoo/official/cv/fastscnn/scripts/run_eval.sh b/model_zoo/official/cv/fastscnn/scripts/run_eval.sh
new file mode 100644
index 00000000000..47d224dcf05
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/scripts/run_eval.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+
+if [ $# != 5 ]; then
+ echo "Usage: sh run_eval.sh [train_code_path] [dataset] [resume_path]" \
+ "[resume_name] [output_path]"
+ exit 1
+fi
+
+get_real_path() {
+ if [ "${1:0:1}" == "/" ]; then
+ echo "$1"
+ else
+ echo "$(realpath -m $PWD/$1)/"
+ fi
+}
+
+train_code_path=$(get_real_path $1)
+echo "train_code_path: "$train_code_path
+
+dataset=$(get_real_path $2)
+echo "dataset: "$dataset
+
+resume_path=$(get_real_path $3)
+echo "resume_path: "$resume_path
+
+if [ ! -d $train_code_path ]
+then
+ echo "error: train_code_path=$train_code_path is not a dictionary."
+exit 1
+fi
+
+if [ ! -d $dataset ]
+then
+ echo "error: dataset=$dataset is not a dictionary."
+exit 1
+fi
+
+if [ ! -d $resume_path ]
+then
+ echo "error: resume_path=$resume_path is not a dictionary."
+exit 1
+fi
+
+python ${train_code_path}eval.py --is_distributed=0 \
+--dataset=$dataset \
+--resume_path=$resume_path \
+--resume_name=$4 \
+--output_path=$5 > log.txt 2>&1 &
diff --git a/model_zoo/official/cv/fastscnn/scripts/run_infer_310.sh b/model_zoo/official/cv/fastscnn/scripts/run_infer_310.sh
new file mode 100644
index 00000000000..94957b71289
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/scripts/run_infer_310.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+
+if [ $# != 6 ]; then
+ echo "Usage: sh run_infer_310.sh [model_path] [data_path]" \
+ "[out_image_path] [image_height] [image_width] [device_id]"
+exit 1
+fi
+
+get_real_path_name() {
+ if [ "${1:0:1}" == "/" ]; then
+ echo "$1"
+ else
+ echo "$(realpath -m $PWD/$1)"
+ fi
+}
+
+get_real_path() {
+ if [ "${1:0:1}" == "/" ]; then
+ echo "$1"
+ else
+ echo "$(realpath -m $PWD/$1)/"
+ fi
+}
+
+model=$(get_real_path_name $1)
+data_path=$(get_real_path $2)
+out_image_path=$(get_real_path $3)
+image_height=$4
+image_width=$5
+device_id=$6
+
+echo "model path: "$model
+echo "dataset path: "$data_path
+echo "out image path: "$out_image_path
+echo "image_height: "$image_height
+echo "image_width: "$image_width
+echo "device id: "$device_id
+
+export ASCEND_HOME=/usr/local/Ascend/
+if [ -d ${ASCEND_HOME}/ascend-toolkit ]; then
+ export PATH=$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/ascend-toolkit/latest/atc/bin:$PATH
+ export LD_LIBRARY_PATH=/usr/local/lib:$ASCEND_HOME/ascend-toolkit/latest/atc/lib64:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/lib64:$ASCEND_HOME/driver/lib64:$ASCEND_HOME/add-ons:$LD_LIBRARY_PATH
+ export TBE_IMPL_PATH=$ASCEND_HOME/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe
+ export PYTHONPATH=${TBE_IMPL_PATH}:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/python/site-packages:$PYTHONPATH
+ export ASCEND_OPP_PATH=$ASCEND_HOME/ascend-toolkit/latest/opp
+else
+ export PATH=$ASCEND_HOME/atc/ccec_compiler/bin:$ASCEND_HOME/atc/bin:$PATH
+ export LD_LIBRARY_PATH=/usr/local/lib:$ASCEND_HOME/atc/lib64:$ASCEND_HOME/acllib/lib64:$ASCEND_HOME/driver/lib64:$ASCEND_HOME/add-ons:$LD_LIBRARY_PATH
+ export PYTHONPATH=$ASCEND_HOME/atc/python/site-packages:$PYTHONPATH
+ export ASCEND_OPP_PATH=$ASCEND_HOME/opp
+fi
+
+function compile_app()
+{
+ cd ../ascend310_infer/ || exit
+ if [ -f "Makefile" ]; then
+ make clean
+ fi
+ sh build.sh &> build.log
+}
+
+function preprocess()
+{
+ cd ../ || exit
+ echo "\nstart preprocess"
+ echo "waitting for preprocess finish..."
+ python3.7 preprocess.py --out_dir=$out_image_path --image_path=$data_path --image_height=$image_height --image_width=$image_width > preprocess.log 2>&1
+ echo "preprocess finished! you can see the log in preprocess.log!"
+}
+
+function infer()
+{
+ cd ./scripts || exit
+ if [ -d result_Files ]; then
+ rm -rf ./result_Files
+ fi
+ if [ -d time_Result ]; then
+ rm -rf ./time_Result
+ fi
+ mkdir result_Files
+ mkdir time_Result
+ echo "\nstart infer..."
+ echo "waitting for infer finish..."
+ ../ascend310_infer/out/main --model_path=$model --dataset_path=$out_image_path/images/ --device_id=$device_id > infer.log 2>&1
+ echo "infer finished! you can see the log in infer.log!"
+}
+
+function cal_mIoU()
+{
+ echo "\nstart calculate mIoU..."
+ echo "waitting for calculate finish..."
+ python3.7 ../cal_mIoU.py --label_path=$out_image_path/labels/ --output_path=./result_Files --image_height=$image_height --image_width=$image_width --save_mask=0 >acc.log 2>&1
+ echo "infer finished! you can see the log in acc.log\n"
+}
+
+compile_app
+if [ $? -ne 0 ]; then
+ echo "compile app code failed"
+ exit 1
+fi
+
+preprocess
+if [ $? -ne 0 ]; then
+ echo "execute preprocess failed"
+ exit 1
+fi
+
+infer
+if [ $? -ne 0 ]; then
+ echo " execute inference failed"
+ exit 1
+fi
+
+cal_mIoU
+if [ $? -ne 0 ]; then
+ echo "calculate mIoU failed"
+ exit 1
+fi
diff --git a/model_zoo/official/cv/fastscnn/scripts/run_train.sh b/model_zoo/official/cv/fastscnn/scripts/run_train.sh
new file mode 100644
index 00000000000..2cdb0a03e64
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/scripts/run_train.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+
+if [ $# != 6 ]; then
+ echo "Usage: sh run_train.sh [train_code_path] [dataset]" \
+ "[epochs] [batch_size] [lr] [output_path]"
+ exit 1
+fi
+
+get_real_path() {
+ if [ "${1:0:1}" == "/" ]; then
+ echo "$1"
+ else
+ echo "$(realpath -m $PWD/$1)/"
+ fi
+}
+
+train_code_path=$(get_real_path $1)
+echo "train_code_path: "$train_code_path
+
+dataset=$(get_real_path $2)
+echo "dataset: "$dataset
+
+if [ ! -d $train_code_path ]
+then
+ echo "error: train_code_path=$train_code_path is not a dictionary."
+exit 1
+fi
+
+if [ ! -d $dataset ]
+then
+ echo "error: dataset=$dataset is not a dictionary."
+exit 1
+fi
+
+nohup python ${train_code_path}train.py --is_distributed=0 \
+--dataset=${dataset} \
+--epochs=$3 \
+--batch_size=$4 \
+--lr=$5 \
+--output_path=$6 > log.txt 2>&1 &
+
+echo 'Train task has been started successfully!'
+echo 'Please check the log at log.txt'
diff --git a/model_zoo/official/cv/fastscnn/src/dataloader.py b/model_zoo/official/cv/fastscnn/src/dataloader.py
new file mode 100644
index 00000000000..88d941af369
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/dataloader.py
@@ -0,0 +1,196 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Prepare Cityscapes dataset"""
+import os
+import numpy as np
+from PIL import Image
+
+import mindspore.dataset as ds
+import mindspore.dataset.vision.c_transforms as CV
+
+from src.seg_data_base import SegmentationDataset
+from src.distributed_sampler import DistributedSampler
+
+
+__all__ = ['CitySegmentation']
+
+
+class CitySegmentation(SegmentationDataset):
+ """Cityscapes Semantic Segmentation Dataset.
+
+ Parameters
+ ----------
+ root : string
+ Path to Cityscapes folder. Default is './datasets/cityscapes'
+ split: string
+ 'train', 'val' or 'test'
+ transform : callable, optional
+ A function that transforms the image
+ Examples
+ --------
+ >>> # Transforms for Normalization
+ >>> input_transform = transforms.Compose([
+ >>> transforms.ToTensor(),
+ >>> transforms.Normalize((.485, .456, .406), (.229, .224, .225)),
+ >>> ])
+ >>> # Create Dataset
+ >>> trainset = CitySegmentation(split='train', transform=input_transform)
+ >>> # Create Training Loader
+ >>> train_data = data.DataLoader(
+ >>> trainset, 4, shuffle=True,
+ >>> num_workers=4)
+ """
+ BASE_DIR = 'cityscapes'
+ NUM_CLASS = 19
+
+ def __init__(self, args, root='/data/Fast_SCNN/dataset/', split='train', mode=None, **kwargs):
+ super(CitySegmentation, self).__init__(root, split, mode, **kwargs)
+
+ self.args = args
+ assert os.path.exists(self.root), "Please put dataset in {SEG_ROOT}/datasets/cityscapes"
+ self.images, self.mask_paths = _get_city_pairs(args, self.root, self.split)
+ assert len(self.images) == len(self.mask_paths)
+ if not self.images:
+ raise RuntimeError("Found 0 images in subfolders of:" + root + "\n")
+ self.valid_classes = [7, 8, 11, 12, 13, 17, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 31, 32, 33]
+ self._key = np.array([-1, -1, -1, -1, -1, -1,
+ -1, -1, 0, 1, -1, -1,
+ 2, 3, 4, -1, -1, -1,
+ 5, -1, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15,
+ -1, -1, 16, 17, 18])
+ self._mapping = np.array(range(-1, len(self._key) - 1)).astype('int32')
+
+ def _class_to_index(self, mask):
+ # assert the value
+ values = np.unique(mask)
+ for value in values:
+ assert value in self._mapping
+ index = np.digitize(mask.ravel(), self._mapping, right=True)
+ return self._key[index].reshape(mask.shape)
+
+ def __getitem__(self, index):
+ img = Image.open(self.images[index]).convert('RGB')
+ if self.mode == 'test':
+ return img, os.path.basename(self.images[index])
+
+ mask = Image.open(self.mask_paths[index])
+ # synchrosized transform
+ if self.mode == 'train':
+ img, mask = self._sync_transform(img, mask)
+ elif self.mode == 'val':
+ img, mask = self._val_sync_transform(img, mask)
+ else:
+ assert self.mode == 'testval'
+ img, mask = self._img_transform(img), self._mask_transform(mask)
+
+ return img, mask
+
+ def _mask_transform(self, mask):
+ target = self._class_to_index(np.array(mask).astype('int32'))
+ return np.array(target).astype('int32')
+
+ def __len__(self):
+ return len(self.images)
+
+ @property
+ def pred_offset(self):
+ return 0
+
+ @property
+ def classes(self):
+ """Category names."""
+ return ('road', 'sidewalk', 'building', 'wall', 'fence', 'pole', 'traffic light',
+ 'traffic sign', 'vegetation', 'terrain', 'sky', 'person', 'rider', 'car',
+ 'truck', 'bus', 'train', 'motorcycle', 'bicycle')
+
+def _get_city_pairs(args, folder, split='train'):
+ '''_get_city_pairs'''
+ def get_path_pairs(img_folder, mask_folder):
+ img_paths = []
+ mask_paths = []
+ for root, _, files in os.walk(img_folder):
+ for filename in files:
+ if filename.startswith('._'):
+ continue
+ if filename.endswith('.png'):
+ imgpath = os.path.join(root, filename)
+ foldername = os.path.basename(os.path.dirname(imgpath))
+ maskname = filename.replace('leftImg8bit', 'gtFine_labelIds')
+ maskpath = os.path.join(mask_folder, foldername, maskname)
+ if os.path.isfile(imgpath) and os.path.isfile(maskpath):
+ img_paths.append(imgpath)
+ mask_paths.append(maskpath)
+ else:
+ args.logger.info('cannot find the mask or image:', imgpath, maskpath)
+ args.logger.info('Found {} images in the folder {}'.format(len(img_paths), img_folder))
+ return img_paths, mask_paths
+
+ if split in ('train', 'val'):
+ img_folder = os.path.join(folder, 'leftImg8bit/' + split)
+ mask_folder = os.path.join(folder, 'gtFine/' + split)
+ img_paths, mask_paths = get_path_pairs(img_folder, mask_folder)
+ return img_paths, mask_paths
+ assert split == 'trainval'
+ args.logger.info('trainval set')
+ train_img_folder = os.path.join(folder, 'leftImg8bit/train')
+ train_mask_folder = os.path.join(folder, 'gtFine/train')
+ val_img_folder = os.path.join(folder, 'leftImg8bit/val')
+ val_mask_folder = os.path.join(folder, 'gtFine/val')
+ train_img_paths, train_mask_paths = get_path_pairs(train_img_folder, train_mask_folder)
+ val_img_paths, val_mask_paths = get_path_pairs(val_img_folder, val_mask_folder)
+ img_paths = train_img_paths + val_img_paths
+ mask_paths = train_mask_paths + val_mask_paths
+ return img_paths, mask_paths
+
+def create_CitySegmentation(args, data_path='../dataset/', split='train', mode=None, \
+ transform=None, base_size=1024, crop_size=(512, 1024), \
+ batch_size=2, device_num=1, rank=0, shuffle=True):
+ '''create_CitySegmentation'''
+ dataset = CitySegmentation(args, root=data_path, split=split, mode=mode, \
+ base_size=base_size, crop_size=crop_size)
+ dataset_len = len(dataset)
+ distributed_sampler = DistributedSampler(dataset_len, device_num, rank, shuffle=shuffle)
+
+ data_set = ds.GeneratorDataset(dataset, column_names=["image", "label"], num_parallel_workers=8, \
+ shuffle=shuffle, sampler=distributed_sampler)
+ # general resize, normalize and toTensor
+ if transform is not None:
+ data_set = data_set.map(input_columns=["image"], operations=transform, num_parallel_workers=8)
+ else:
+ hwc_to_chw = CV.HWC2CHW()
+ data_set = data_set.map(input_columns=["image"], operations=hwc_to_chw, num_parallel_workers=8)
+
+ data_set = data_set.batch(batch_size, drop_remainder=True)
+ return data_set, dataset_len
+
+if __name__ == '__main__':
+
+ ds = create_CitySegmentation(
+ data_path=r"./dataset/leftImg8bit_trainvaltest",
+ split='train',
+ mode='train',
+ base_size=1024,
+ crop_size=(512, 1024),
+ batch_size=1,
+ device_num=1,
+ rank=0,
+ shuffle=True)
+ data_loader = ds.create_dict_iterator()
+ for i, data in enumerate(data_loader):
+ print(data['image'])
+ print(data['label'])
+ print(i)
diff --git a/model_zoo/official/cv/fastscnn/src/distributed_sampler.py b/model_zoo/official/cv/fastscnn/src/distributed_sampler.py
new file mode 100644
index 00000000000..11c4eff96fb
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/distributed_sampler.py
@@ -0,0 +1,60 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""distributed sampler."""
+from __future__ import division
+import math
+import numpy as np
+
+
+class DistributedSampler:
+ """Distributed sampler."""
+ def __init__(self, dataset_size, num_replicas=None, rank=None, shuffle=True):
+ if num_replicas is None:
+ print("***********Setting world_size to 1 since it is not passed in ******************")
+ num_replicas = 1
+ if rank is None:
+ print("***********Setting rank to 0 since it is not passed in ******************")
+ rank = 0
+ self.dataset_size = dataset_size
+ self.num_replicas = num_replicas
+ self.rank = rank
+ self.epoch = 0
+ self.num_samples = int(math.ceil(dataset_size * 1.0 / self.num_replicas))
+ self.total_size = self.num_samples * self.num_replicas
+ self.shuffle = shuffle
+
+ def __iter__(self):
+ # deterministically shuffle based on epoch
+ if self.shuffle:
+ indices = np.random.RandomState(seed=self.epoch).permutation(self.dataset_size)
+ # np.array type. number from 0 to len(dataset_size)-1, used as index of dataset
+ indices = indices.tolist()
+ self.epoch += 1
+ # change to list type
+ else:
+ indices = list(range(self.dataset_size))
+
+ # add extra samples to make it evenly divisible
+ indices += indices[:(self.total_size - len(indices))]
+ assert len(indices) == self.total_size
+
+ # subsample
+ indices = indices[self.rank:self.total_size:self.num_replicas]
+ assert len(indices) == self.num_samples
+
+ return iter(indices)
+
+ def __len__(self):
+ return self.num_samples
diff --git a/model_zoo/official/cv/fastscnn/src/fast_scnn.py b/model_zoo/official/cv/fastscnn/src/fast_scnn.py
new file mode 100644
index 00000000000..3f7accabd33
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/fast_scnn.py
@@ -0,0 +1,264 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Fast Segmentation Convolutional Neural Network"""
+import mindspore.nn as nn
+from mindspore.ops import operations as P
+from src.loss import MixSoftmaxCrossEntropyLoss
+
+__all__ = ['FastSCNN', 'FastSCNNWithLossCell']
+
+class FastSCNN(nn.Cell):
+ '''FastSCNN'''
+ def __init__(self, num_classes, aux=False):
+ super(FastSCNN, self).__init__()
+ self.aux = aux
+ self.learning_to_downsample = LearningToDownsample(32, 48, 64)
+ self.global_feature_extractor = GlobalFeatureExtractor(64, \
+ [64, 96, 128], 128, 6, [3, 3, 3])
+ self.feature_fusion = FeatureFusionModule(64, 128, 128)
+ self.classifier = Classifier(128, num_classes)
+ if self.aux:
+ self.auxlayer1 = nn.SequentialCell(
+ [nn.Conv2d(64, 32, 3, pad_mode='pad', padding=1, has_bias=False),
+ nn.BatchNorm2d(32),
+ nn.ReLU(),
+ nn.Dropout(0.9),#1-0.9=0.1
+ nn.Conv2d(32, num_classes, 1, has_bias=True)]
+ )
+ self.auxlayer2 = nn.SequentialCell(
+ [nn.Conv2d(128, 32, 3, pad_mode='pad', padding=1, has_bias=False),
+ nn.BatchNorm2d(32),
+ nn.ReLU(),
+ nn.Dropout(0.9),#1-0.9=0.1
+ nn.Conv2d(32, num_classes, 1, has_bias=True)]
+ )
+ self.ResizeBilinear = nn.ResizeBilinear()
+ def construct(self, x):
+ '''construct'''
+ size = x.shape[2:]
+ higher_res_features = self.learning_to_downsample(x)
+ lower_res_features = self.global_feature_extractor(higher_res_features)
+ x = self.feature_fusion(higher_res_features, lower_res_features)
+ x = self.classifier(x)
+
+ x = self.ResizeBilinear(x, size, align_corners=True)
+ if self.aux:
+ auxout = self.auxlayer1(higher_res_features)
+ auxout = self.ResizeBilinear(auxout, size, align_corners=True)
+ auxout2 = self.auxlayer2(lower_res_features)
+ auxout2 = self.ResizeBilinear(auxout2, size, align_corners=True)
+ return x, auxout, auxout2
+ return x
+
+class _ConvBNReLU(nn.Cell):
+ """Conv-BN-ReLU"""
+ def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=0):
+ super(_ConvBNReLU, self).__init__()
+ self.conv = nn.SequentialCell(
+ [nn.Conv2d(in_channels=in_channels, out_channels=out_channels, \
+ kernel_size=kernel_size, stride=stride, padding=padding, has_bias=False),
+ nn.BatchNorm2d(out_channels),
+ nn.ReLU()]
+ )
+ def construct(self, x):
+ return self.conv(x)
+
+class _DSConv(nn.Cell):
+ """Depthwise Separable Convolutions"""
+ def __init__(self, dw_channels, out_channels, stride=1):
+ super(_DSConv, self).__init__()
+ self.conv = nn.SequentialCell(
+ [nn.Conv2d(in_channels=dw_channels, out_channels=dw_channels, \
+ kernel_size=3, stride=stride, pad_mode="pad", \
+ padding=1, group=dw_channels, has_bias=False),
+ nn.BatchNorm2d(dw_channels),
+ nn.ReLU(),
+ nn.Conv2d(in_channels=dw_channels, out_channels=out_channels, \
+ kernel_size=1, has_bias=False),
+ nn.BatchNorm2d(out_channels),
+ nn.ReLU()]
+ )
+ def construct(self, x):
+ return self.conv(x)
+
+class _DWConv(nn.Cell):
+ '''_DWConv'''
+ def __init__(self, dw_channels, out_channels, stride=1):
+ super(_DWConv, self).__init__()
+ self.conv = nn.SequentialCell(
+ [nn.Conv2d(in_channels=dw_channels, out_channels=out_channels, \
+ kernel_size=3, stride=stride, pad_mode="pad", padding=1, \
+ group=dw_channels, has_bias=False),
+ nn.BatchNorm2d(out_channels),
+ nn.ReLU()]
+ )
+ def construct(self, x):
+ return self.conv(x)
+
+class LinearBottleneck(nn.Cell):
+ """LinearBottleneck used in MobileNetV2"""
+ def __init__(self, in_channels, out_channels, t=6, stride=2):
+ super(LinearBottleneck, self).__init__()
+ self.use_shortcut = (stride == 1) and (in_channels == out_channels)
+ self.block = nn.SequentialCell([
+ # pw
+ _ConvBNReLU(in_channels, in_channels * t, 1),
+ # dw
+ _DWConv(in_channels * t, in_channels * t, stride),
+ # pw-linear
+ nn.Conv2d(in_channels * t, out_channels, 1, has_bias=False),
+ nn.BatchNorm2d(out_channels)])
+
+ def construct(self, x):
+ out = self.block(x)
+ if self.use_shortcut:
+ out = x + out
+ return out
+
+class PyramidPooling(nn.Cell):
+ """Pyramid pooling module"""
+
+ def __init__(self, in_channels, out_channels):
+ super(PyramidPooling, self).__init__()
+ inter_channels = int(in_channels / 4)
+ self.conv1 = _ConvBNReLU(in_channels, inter_channels, 1)
+ self.conv2 = _ConvBNReLU(in_channels, inter_channels, 1)
+ self.conv3 = _ConvBNReLU(in_channels, inter_channels, 1)
+ self.conv4 = _ConvBNReLU(in_channels, inter_channels, 1)
+ self.out = _ConvBNReLU(in_channels * 2, out_channels, 1)
+ self.concat = P.Concat(axis=1)
+ self.pool24 = nn.AvgPool2d(kernel_size=24, stride=24)
+ self.pool12 = nn.AvgPool2d(kernel_size=12, stride=12)
+ self.pool8 = nn.AvgPool2d(kernel_size=8, stride=8)
+ self.pool6 = nn.AvgPool2d(kernel_size=4, stride=4)
+ self.resizeBilinear = nn.ResizeBilinear()
+
+ def _AdaptiveAvgPool2d(self, x, output_size):
+ #NCHW, for NCx24x24 and size in (1,2,3,6) only
+ if output_size == 1:
+ return self.pool24(x)
+ if output_size == 2:
+ return self.pool12(x)
+ if output_size == 3:
+ return self.pool8(x)
+ return self.pool6(x)
+
+ def upsample(self, x, size):
+ return self.resizeBilinear(x, size, align_corners=True)
+
+ def construct(self, x):
+ size = x.shape[2:]
+ feat1 = self.upsample(self.conv1(self._AdaptiveAvgPool2d(x, 1)), size)
+ feat2 = self.upsample(self.conv2(self._AdaptiveAvgPool2d(x, 2)), size)
+ feat3 = self.upsample(self.conv3(self._AdaptiveAvgPool2d(x, 3)), size)
+ feat4 = self.upsample(self.conv4(self._AdaptiveAvgPool2d(x, 6)), size)
+ x = self.concat((x, feat1, feat2, feat3, feat4))
+ x = self.out(x)
+ return x
+
+class LearningToDownsample(nn.Cell):
+ """Learning to downsample module"""
+
+ def __init__(self, dw_channels1=32, dw_channels2=48, out_channels=64):
+ super(LearningToDownsample, self).__init__()
+ self.conv = _ConvBNReLU(3, dw_channels1, 3, 2)
+ self.dsconv1 = _DSConv(dw_channels1, dw_channels2, 2)
+ self.dsconv2 = _DSConv(dw_channels2, out_channels, 2)
+ def construct(self, x):
+ x = self.conv(x)
+ x = self.dsconv1(x)
+ x = self.dsconv2(x)
+ return x
+
+class GlobalFeatureExtractor(nn.Cell):
+ """Global feature extractor module"""
+
+ def __init__(self, in_channels=64, block_channels=(64, 96, 128),
+ out_channels=128, t=6, num_blocks=(3, 3, 3)):
+ super(GlobalFeatureExtractor, self).__init__()
+ self.bottleneck1 = self._make_layer(LinearBottleneck, in_channels, \
+ block_channels[0], num_blocks[0], t, 2)
+ self.bottleneck2 = self._make_layer(LinearBottleneck, block_channels[0], \
+ block_channels[1], num_blocks[1], t, 2)
+ self.bottleneck3 = self._make_layer(LinearBottleneck, block_channels[1], \
+ block_channels[2], num_blocks[2], t, 1)
+ self.ppm = PyramidPooling(block_channels[2], out_channels)
+
+ def _make_layer(self, block, inplanes, planes, blocks, t=6, stride=1):
+ layers = []
+ layers.append(block(inplanes, planes, t, stride))
+ for _ in range(1, blocks):
+ layers.append(block(planes, planes, t, 1))
+ return nn.SequentialCell(layers)
+
+ def construct(self, x):
+ x = self.bottleneck1(x)
+ x = self.bottleneck2(x)
+ x = self.bottleneck3(x)
+ x = self.ppm(x)
+ return x
+
+class FeatureFusionModule(nn.Cell):
+ """Feature fusion module"""
+
+ def __init__(self, highter_in_channels, lower_in_channels, out_channels, scale_factor=4):
+ super(FeatureFusionModule, self).__init__()
+ self.scale_factor = scale_factor
+ self.dwconv = _DWConv(lower_in_channels, out_channels, 1)
+ self.conv_lower_res = nn.SequentialCell([
+ nn.Conv2d(out_channels, out_channels, 1),
+ nn.BatchNorm2d(out_channels)])
+ self.conv_higher_res = nn.SequentialCell([
+ nn.Conv2d(highter_in_channels, out_channels, 1),
+ nn.BatchNorm2d(out_channels)])
+ self.relu = nn.ReLU()
+ self.ResizeBilinear = nn.ResizeBilinear()
+ def construct(self, higher_res_feature, lower_res_feature):
+ lower_res_feature = self.ResizeBilinear(lower_res_feature, \
+ scale_factor=4, align_corners=True)
+ lower_res_feature = self.dwconv(lower_res_feature)
+ lower_res_feature = self.conv_lower_res(lower_res_feature)
+ higher_res_feature = self.conv_higher_res(higher_res_feature)
+ out = higher_res_feature + lower_res_feature
+ return self.relu(out)
+
+class Classifier(nn.Cell):
+ """Classifier"""
+ def __init__(self, dw_channels, num_classes, stride=1, **kwargs):
+ super(Classifier, self).__init__()
+ self.dsconv1 = _DSConv(dw_channels, dw_channels, stride)
+ self.dsconv2 = _DSConv(dw_channels, dw_channels, stride)
+ self.conv = nn.SequentialCell([
+ nn.Dropout(0.9), # 1-0.9=0.1
+ nn.Conv2d(dw_channels, num_classes, 1)])
+
+ def construct(self, x):
+ x = self.dsconv1(x)
+ x = self.dsconv2(x)
+ x = self.conv(x)
+ return x
+
+class FastSCNNWithLossCell(nn.Cell):
+ """FastSCNN loss, MixSoftmaxCrossEntropyLoss."""
+ def __init__(self, network, args):
+ super(FastSCNNWithLossCell, self).__init__()
+ self.network = network
+ self.aux = args.aux
+ self.loss = MixSoftmaxCrossEntropyLoss(args, aux=args.aux, aux_weight=args.aux_weight)
+ def construct(self, images, targets):
+ outputs = self.network(images)
+ if self.aux:
+ return self.loss(outputs[0], outputs[1], outputs[2], targets)
+ return self.loss(outputs, targets)
diff --git a/model_zoo/official/cv/fastscnn/src/logger.py b/model_zoo/official/cv/fastscnn/src/logger.py
new file mode 100644
index 00000000000..d4edb379618
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/logger.py
@@ -0,0 +1,80 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Custom Logger."""
+import os
+import sys
+import logging
+from datetime import datetime
+
+
+class LOGGER(logging.Logger):
+ """
+ Logger.
+
+ Args:
+ logger_name: String. Logger name.
+ rank: Integer. Rank id.
+ """
+ def __init__(self, logger_name, rank=0):
+ super(LOGGER, self).__init__(logger_name)
+ self.rank = rank
+ if rank % 8 == 0:
+ console = logging.StreamHandler(sys.stdout)
+ console.setLevel(logging.INFO)
+ formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s')
+ console.setFormatter(formatter)
+ self.addHandler(console)
+
+ def setup_logging_file(self, log_dir, rank=0):
+ """Setup logging file."""
+ self.rank = rank
+ if not os.path.exists(log_dir):
+ os.makedirs(log_dir, exist_ok=True)
+ log_name = datetime.now().strftime('%Y-%m-%d_time_%H_%M_%S') + '_rank_{}.log'.format(rank)
+ self.log_fn = os.path.join(log_dir, log_name)
+ fh = logging.FileHandler(self.log_fn)
+ fh.setLevel(logging.INFO)
+ formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s')
+ fh.setFormatter(formatter)
+ self.addHandler(fh)
+
+ def info(self, msg, *args, **kwargs):
+ if self.isEnabledFor(logging.INFO):
+ self._log(logging.INFO, msg, args, **kwargs)
+
+ def save_args(self, args):
+ self.info('Args:')
+ args_dict = vars(args)
+ for key in args_dict.keys():
+ self.info('--> %s: %s', key, args_dict[key])
+ self.info('')
+
+ def important_info(self, msg, *args, **kwargs):
+ if self.isEnabledFor(logging.INFO) and self.rank == 0:
+ line_width = 2
+ important_msg = '\n'
+ important_msg += ('*'*70 + '\n')*line_width
+ important_msg += ('*'*line_width + '\n')*2
+ important_msg += '*'*line_width + ' '*8 + msg + '\n'
+ important_msg += ('*'*line_width + '\n')*2
+ important_msg += ('*'*70 + '\n')*line_width
+ self.info(important_msg, *args, **kwargs)
+
+
+def get_logger(path, logger_name, rank):
+ """Get Logger."""
+ logger = LOGGER(logger_name, rank)
+ logger.setup_logging_file(path, rank)
+ return logger
diff --git a/model_zoo/official/cv/fastscnn/src/loss.py b/model_zoo/official/cv/fastscnn/src/loss.py
new file mode 100644
index 00000000000..eab5276bb4f
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/loss.py
@@ -0,0 +1,66 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Custom losses."""
+
+import mindspore
+import mindspore.nn as nn
+import mindspore.ops as ops
+from mindspore.common.tensor import Tensor
+from mindspore.nn import SoftmaxCrossEntropyWithLogits
+
+__all__ = ['MixSoftmaxCrossEntropyLoss']
+class MixSoftmaxCrossEntropyLoss(nn.Cell):
+ '''MixSoftmaxCrossEntropyLoss'''
+ def __init__(self, args, ignore_label=-1, aux=True, aux_weight=0.4, \
+ sparse=True, reduction='none', one_d_length=2*768*768, **kwargs):
+ super(MixSoftmaxCrossEntropyLoss, self).__init__()
+ self.ignore_label = ignore_label
+ self.weight = aux_weight if aux else 1.0
+ self.select = ops.Select()
+ self.reduceSum = ops.ReduceSum(keep_dims=False)
+ self.div_no_nan = ops.DivNoNan()
+ self.mul = ops.Mul()
+ self.reshape = ops.Reshape()
+ self.cast = ops.Cast()
+ self.transpose = ops.Transpose()
+ self.zero_tensor = Tensor([0]*one_d_length, mindspore.float32)
+ self.SoftmaxCrossEntropyWithLogits = \
+ SoftmaxCrossEntropyWithLogits(sparse=sparse, reduction="none")
+ args.logger.info('using MixSoftmaxCrossEntropyLoss....')
+ args.logger.info('self.ignore_label:' + str(self.ignore_label))
+ args.logger.info('self.aux:' + str(aux))
+ args.logger.info('self.weight:' + str(self.weight))
+ args.logger.info('one_d_length:' + str(one_d_length))
+ def construct(self, *inputs, **kwargs):
+ '''construct'''
+ preds, target = inputs[:-1], inputs[-1]
+ target = self.reshape(target, (-1,))
+ valid_flag = target != self.ignore_label
+ num_valid = self.reduceSum(self.cast(valid_flag, mindspore.float32))
+
+ z = self.transpose(preds[0], (0, 2, 3, 1))#move the C-dim to the last, then reshape it.
+ #This operation is vital, or the data would be soiled.
+ loss = self.SoftmaxCrossEntropyWithLogits(self.reshape(z, (-1, 19)), target)
+ loss = self.select(valid_flag, loss, self.zero_tensor)
+ loss = self.reduceSum(loss)
+ loss = self.div_no_nan(loss, num_valid)
+ for i in range(1, len(preds)):
+ z = self.transpose(preds[i], (0, 2, 3, 1))
+ aux_loss = self.SoftmaxCrossEntropyWithLogits(self.reshape(z, (-1, 19)), target)
+ aux_loss = self.select(valid_flag, aux_loss, self.zero_tensor)
+ aux_loss = self.reduceSum(aux_loss)
+ aux_loss = self.div_no_nan(aux_loss, num_valid)
+ loss += self.mul(self.weight, aux_loss)
+ return loss
diff --git a/model_zoo/official/cv/fastscnn/src/lr_scheduler.py b/model_zoo/official/cv/fastscnn/src/lr_scheduler.py
new file mode 100644
index 00000000000..885fad30858
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/lr_scheduler.py
@@ -0,0 +1,113 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Popular Learning Rate Schedulers"""
+import math
+
+class LRScheduler():
+ r"""Learning Rate Scheduler
+
+ Parameters
+ ----------
+ mode : str
+ Modes for learning rate scheduler.
+ Currently it supports 'constant', 'step', 'linear', 'poly' and 'cosine'.
+ base_lr : float
+ Base learning rate, i.e. the starting learning rate.
+ target_lr : float
+ Target learning rate, i.e. the ending learning rate.
+ With constant mode target_lr is ignored.
+ niters : int
+ Number of iterations to be scheduled.
+ nepochs : int
+ Number of epochs to be scheduled.
+ iters_per_epoch : int
+ Number of iterations in each epoch.
+ offset : int
+ Number of iterations before this scheduler.
+ power : float
+ Power parameter of poly scheduler.
+ step_iter : list
+ A list of iterations to decay the learning rate.
+ step_epoch : list
+ A list of epochs to decay the learning rate.
+ step_factor : float
+ Learning rate decay factor.
+ """
+
+ def __init__(self, mode, base_lr=0.01, target_lr=0, niters=0, nepochs=0, iters_per_epoch=0,
+ offset=0, power=2, step_iter=None, step_epoch=None, step_factor=0.1):
+ super(LRScheduler, self).__init__()
+ assert (mode in ['constant', 'step', 'linear', 'poly', 'cosine'])
+
+ self.mode = mode
+ if mode == 'step':
+ assert (step_iter is not None or step_epoch is not None)
+ self.base_lr = base_lr
+ self.target_lr = target_lr
+ if self.mode == 'constant':
+ self.target_lr = self.base_lr
+
+ self.niters = niters
+ self.step = step_iter
+ epoch_iters = nepochs * iters_per_epoch
+ if epoch_iters > 0:
+ self.niters = epoch_iters
+ if step_epoch is not None:
+ self.step = [s * iters_per_epoch for s in step_epoch]
+
+ self.offset = offset
+ self.power = power
+ self.step_factor = step_factor
+
+ def __call__(self, total_steps):
+ lr_each_step = []
+ for i in range(total_steps):
+ self.update(i)
+ lr_each_step.append(self.learning_rate)
+ return lr_each_step
+
+ def update(self, num_update):
+ '''update'''
+ N = self.niters - 1
+ T = num_update - self.offset
+ T = min(max(0, T), N)
+
+ if self.mode == 'constant':
+ factor = 0
+ elif self.mode == 'linear':
+ factor = 1 - T / N
+ elif self.mode == 'poly':
+ factor = pow(1 - T / N, self.power)
+ elif self.mode == 'cosine':
+ factor = (1 + math.cos(math.pi * T / N)) / 2
+ elif self.mode == 'step':
+ if self.step is not None:
+ count = sum([1 for s in self.step if s <= T])
+ factor = pow(self.step_factor, count)
+ else:
+ factor = 1
+ else:
+ raise NotImplementedError
+
+ if self.mode == 'step':
+ self.learning_rate = self.base_lr * factor
+ else:
+ self.learning_rate = self.target_lr + (self.base_lr - self.target_lr) * factor
+
+if __name__ == '__main__':
+ lr_scheduler = LRScheduler(mode='poly', base_lr=0.01, nepochs=60,
+ iters_per_epoch=176, power=0.9)
+ lr = lr_scheduler(200)
+ print(lr)
diff --git a/model_zoo/official/cv/fastscnn/src/score.py b/model_zoo/official/cv/fastscnn/src/score.py
new file mode 100644
index 00000000000..275fcccff89
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/score.py
@@ -0,0 +1,167 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Evaluation Metrics for Semantic Segmentation"""
+import numpy as np
+from mindspore.common.tensor import Tensor
+
+__all__ = ['SegmentationMetric', 'batch_pix_accuracy', 'batch_intersection_union',
+ 'pixelAccuracy', 'intersectionAndUnion', 'hist_info', 'compute_score']
+
+class SegmentationMetric():
+ """Computes pixAcc and mIoU metric scores
+ """
+
+ def __init__(self, nclass):
+ super(SegmentationMetric, self).__init__()
+ self.nclass = nclass
+ self.reset()
+
+ def update(self, preds, labels):
+ """Updates the internal evaluation result.
+
+ Parameters
+ ----------
+ labels : 'NumpyArray' or list of `NumpyArray`
+ The labels of the data.
+ preds : 'NumpyArray' or list of `NumpyArray`
+ Predicted values.
+ """
+ def evaluate_worker(self, pred, label):
+ correct, labeled = batch_pix_accuracy(pred.asnumpy(), label.asnumpy())
+ inter, union = batch_intersection_union(pred.asnumpy(), label.asnumpy(), self.nclass)
+
+ self.total_correct += correct
+ self.total_label += labeled
+ self.total_inter += inter
+ self.total_union += union
+
+ if isinstance(preds, Tensor):
+ evaluate_worker(self, preds, labels)
+ elif isinstance(preds, (list, tuple)):
+ for (pred, label) in zip(preds, labels):
+ evaluate_worker(self, pred, label)
+
+ def get(self, return_category_iou=False):
+ """Gets the current evaluation result.
+
+ Returns
+ -------
+ metrics : tuple of float
+ pixAcc and mIoU
+ """
+ # remove np.spacing(1)
+ pixAcc = 1.0 * self.total_correct / (2.220446049250313e-16 + self.total_label)
+ IoU = 1.0 * self.total_inter / (2.220446049250313e-16 + self.total_union)
+ mIoU = IoU.mean().item()
+ if return_category_iou:
+ return pixAcc, mIoU, IoU
+ return pixAcc, mIoU
+
+ def reset(self):
+ """Resets the internal evaluation result to initial state."""
+ self.total_inter = np.zeros(self.nclass)
+ self.total_union = np.zeros(self.nclass)
+ self.total_correct = 0
+ self.total_label = 0
+
+def batch_pix_accuracy(output, target):
+ """PixAcc"""
+ # inputs are numpy array, output 4D NCHW where 'C' means label classes, target 3D NHW
+
+ predict = np.argmax(output.astype(np.int64), 1) + 1
+ target = target.astype(np.int64) + 1
+ pixel_labeled = (target > 0).sum()
+ pixel_correct = ((predict == target) * (target > 0)).sum()
+ assert pixel_correct <= pixel_labeled, "Correct area should be smaller than Labeled"
+ return pixel_correct, pixel_labeled
+
+def batch_intersection_union(output, target, nclass):
+ """mIoU"""
+ # inputs are numpy array, output 4D, target 3D
+ mini = 1
+ maxi = nclass
+ nbins = nclass
+ predict = np.argmax(output.astype(np.float32), 1) + 1
+ target = target.astype(np.float32) + 1
+
+ predict = predict.astype(np.float32) * (target > 0).astype(np.float32)
+ intersection = predict * (predict == target).astype(np.float32)
+ # areas of intersection and union
+ # element 0 in intersection occur the main difference from np.bincount. set boundary to -1 is necessary.
+ area_inter, _ = np.histogram(intersection, bins=nbins, range=(mini, maxi))
+ area_pred, _ = np.histogram(predict, bins=nbins, range=(mini, maxi))
+ area_lab, _ = np.histogram(target, bins=nbins, range=(mini, maxi))
+ area_union = area_pred + area_lab - area_inter
+ assert (area_inter > area_union).sum() == 0, "Intersection area should be smaller than Union area"
+ return area_inter.astype(np.float32), area_union.astype(np.float32)
+
+
+def pixelAccuracy(imPred, imLab):
+ """
+ This function takes the prediction and label of a single image, returns pixel-wise accuracy
+ To compute over many images do:
+ for i = range(Nimages):
+ (pixel_accuracy[i], pixel_correct[i], pixel_labeled[i]) = \
+ pixelAccuracy(imPred[i], imLab[i])
+ mean_pixel_accuracy = 1.0 * np.sum(pixel_correct) / (np.spacing(1) + np.sum(pixel_labeled))
+ """
+ # Remove classes from unlabeled pixels in gt image.
+ # We should not penalize detections in unlabeled portions of the image.
+ pixel_labeled = np.sum(imLab >= 0)
+ pixel_correct = np.sum((imPred == imLab) * (imLab >= 0))
+ pixel_accuracy = 1.0 * pixel_correct / pixel_labeled
+ return (pixel_accuracy, pixel_correct, pixel_labeled)
+
+
+def intersectionAndUnion(imPred, imLab, numClass):
+ """
+ This function takes the prediction and label of a single image,
+ returns intersection and union areas for each class
+ To compute over many images do:
+ for i in range(Nimages):
+ (area_intersection[:,i], area_union[:,i]) = intersectionAndUnion(imPred[i], imLab[i])
+ IoU = 1.0 * np.sum(area_intersection, axis=1) / np.sum(np.spacing(1)+area_union, axis=1)
+ """
+ # Remove classes from unlabeled pixels in gt image.
+ # We should not penalize detections in unlabeled portions of the image.
+ imPred = imPred * (imLab >= 0)
+
+ # Compute area intersection:
+ intersection = imPred * (imPred == imLab)
+ (area_intersection, _) = np.histogram(intersection, bins=numClass, range=(1, numClass))
+
+ # Compute area union:
+ (area_pred, _) = np.histogram(imPred, bins=numClass, range=(1, numClass))
+ (area_lab, _) = np.histogram(imLab, bins=numClass, range=(1, numClass))
+ area_union = area_pred + area_lab - area_intersection
+ return (area_intersection, area_union)
+
+
+def hist_info(pred, label, num_cls):
+ assert pred.shape == label.shape
+ k = (label >= 0) & (label < num_cls)
+ labeled = np.sum(k)
+ correct = np.sum((pred[k] == label[k]))
+
+ return np.bincount(num_cls * label[k].astype(int) + pred[k], \
+ minlength=num_cls ** 2).reshape(num_cls, num_cls), labeled, correct
+
+def compute_score(hist, correct, labeled):
+ iu = np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))
+ mean_IU = np.nanmean(iu)
+ mean_IU_no_back = np.nanmean(iu[1:])
+ mean_pixel_acc = correct / labeled
+
+ return iu, mean_IU, mean_IU_no_back, mean_pixel_acc
diff --git a/model_zoo/official/cv/fastscnn/src/seg_data_base.py b/model_zoo/official/cv/fastscnn/src/seg_data_base.py
new file mode 100644
index 00000000000..c392ea3226c
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/seg_data_base.py
@@ -0,0 +1,118 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Base segmentation dataset"""
+import random
+import numpy as np
+
+from PIL import Image, ImageOps, ImageFilter
+
+__all__ = ['SegmentationDataset']
+
+
+class SegmentationDataset():
+ """Segmentation Base Dataset"""
+
+ def __init__(self, root, split, mode, base_size=520, crop_size=480):
+ super(SegmentationDataset, self).__init__()
+ self.root = root
+ self.split = split
+ self.mode = mode if mode is not None else split
+ self.base_size = base_size
+ self.crop_size = self.to_tuple(crop_size)
+
+ def to_tuple(self, size):
+ if isinstance(size, (list, tuple)):
+ return tuple(size)
+ if isinstance(size, (int, float)):
+ return tuple((size, size))
+ raise ValueError('Unsupport datatype: {}'.format(type(size)))
+
+ def _val_sync_transform(self, img, mask):
+ '''_val_sync_transform'''
+ outsize = self.crop_size
+ short_size = min(outsize)
+ w, h = img.size
+ if w > h:
+ oh = short_size
+ ow = int(1.0 * w * oh / h)
+ else:
+ ow = short_size
+ oh = int(1.0 * h * ow / w)
+ img = img.resize((ow, oh), Image.BILINEAR)
+ mask = mask.resize((ow, oh), Image.NEAREST)
+ # center crop
+ w, h = img.size
+ x1 = int(round((w - outsize[1]) / 2.))
+ y1 = int(round((h - outsize[0]) / 2.))
+ img = img.crop((x1, y1, x1 + outsize[1], y1 + outsize[0]))
+ mask = mask.crop((x1, y1, x1 + outsize[1], y1 + outsize[0]))
+
+ # final transform
+ img, mask = self._img_transform(img), self._mask_transform(mask)
+ return img, mask
+
+ def _sync_transform(self, img, mask):
+ '''_sync_transform'''
+ # random mirror
+ if random.random() < 0.5:
+ img = img.transpose(Image.FLIP_LEFT_RIGHT)
+ mask = mask.transpose(Image.FLIP_LEFT_RIGHT)
+ crop_size = self.crop_size
+ # random scale (short edge)
+ short_size = random.randint(int(self.base_size * 0.5), int(self.base_size * 2.0))
+ w, h = img.size
+ if h > w:
+ ow = short_size
+ oh = int(1.0 * h * ow / w)
+ else:
+ oh = short_size
+ ow = int(1.0 * w * oh / h)
+ img = img.resize((ow, oh), Image.BILINEAR)
+ mask = mask.resize((ow, oh), Image.NEAREST)
+ # pad crop
+ if short_size < min(crop_size):
+ padh = crop_size[0] - oh if oh < crop_size[0] else 0
+ padw = crop_size[1] - ow if ow < crop_size[1] else 0
+ img = ImageOps.expand(img, border=(0, 0, padw, padh), fill=0)
+ mask = ImageOps.expand(mask, border=(0, 0, padw, padh), fill=-1)
+ # random crop crop_size
+ w, h = img.size
+ x1 = random.randint(0, w - crop_size[1])
+ y1 = random.randint(0, h - crop_size[0])
+ img = img.crop((x1, y1, x1 + crop_size[1], y1 + crop_size[0]))
+ mask = mask.crop((x1, y1, x1 + crop_size[1], y1 + crop_size[0]))
+ # gaussian blur as in PSP
+ if random.random() < 0.5:
+ img = img.filter(ImageFilter.GaussianBlur(
+ radius=random.random()))
+
+ # final transform
+ img, mask = self._img_transform(img), self._mask_transform(mask)
+ return img, mask
+
+ def _img_transform(self, img):
+ return np.array(img)
+
+ def _mask_transform(self, mask):
+ return np.array(mask).astype('int32')
+
+ @property
+ def num_class(self):
+ """Number of categories."""
+ return self.NUM_CLASS
+
+ @property
+ def pred_offset(self):
+ return 0
diff --git a/model_zoo/official/cv/fastscnn/src/util.py b/model_zoo/official/cv/fastscnn/src/util.py
new file mode 100644
index 00000000000..36162888d58
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/util.py
@@ -0,0 +1,260 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Util class or function."""
+
+import os
+import stat
+from datetime import datetime
+import numpy as np
+
+from mindspore import nn
+from mindspore import save_checkpoint
+from mindspore import log as logger
+from mindspore.train.callback import Callback
+from mindspore.common.tensor import Tensor
+
+def apply_eval(eval_param_dict):
+ """run Evaluation"""
+ model = eval_param_dict["model"]
+ dataset = eval_param_dict["dataset"]
+ eval_score = model.eval(dataset, dataset_sink_mode=False)["SegmentationMetric"]
+ return eval_score
+
+class TempLoss(nn.Cell):
+ """A temp loss cell."""
+ def construct(self, *inputs, **kwargs):
+ return 0.1
+
+class SegmentationMetric(nn.Metric):
+ """FastSCNN Metric, computes pixAcc and mIoU metric scores."""
+ def __init__(self, nclass):
+ super(SegmentationMetric, self).__init__()
+ self.nclass = nclass
+ self.clear()
+
+ def clear(self):
+ """Resets the internal evaluation result to initial state."""
+ self.total_inter = np.zeros(self.nclass)
+ self.total_union = np.zeros(self.nclass)
+ self.total_correct = 0
+ self.total_label = 0
+
+ def update(self, *inputs):
+ """Updates the internal evaluation result.
+
+ Parameters
+ ----------
+ labels : 'NumpyArray' or list of `NumpyArray`
+ The labels of the data.
+ preds : 'NumpyArray' or list of `NumpyArray`
+ Predicted values.
+ """
+ preds, labels = inputs[0], inputs[-1]
+ preds = preds[0]
+ #print("preds:",preds)
+ #print("labels:",labels)
+ def evaluate_worker(self, pred, label):
+ correct, labeled = batch_pix_accuracy(pred.asnumpy(), label.asnumpy())
+ inter, union = batch_intersection_union(pred.asnumpy(), label.asnumpy(), self.nclass)
+
+ self.total_correct += correct
+ self.total_label += labeled
+ self.total_inter += inter
+ self.total_union += union
+
+ if isinstance(preds, Tensor):
+ evaluate_worker(self, preds, labels)
+ elif isinstance(preds, (list, tuple)):
+ for (pred, label) in zip(preds, labels):
+ evaluate_worker(self, pred, label)
+
+ def eval(self):
+ """Gets the current evaluation result.
+
+ Returns
+ -------
+ metrics : tuple of float
+ pixAcc and mIoU
+ """
+ # remove np.spacing(1)
+ pixAcc = 1.0 * self.total_correct / (2.220446049250313e-16 + self.total_label)
+ IoU = 1.0 * self.total_inter / (2.220446049250313e-16 + self.total_union)
+ mIoU = IoU.mean().item()
+ return pixAcc, mIoU
+
+
+class EvalCallBack(Callback):
+ """
+ Evaluation callback when training.
+
+ Args:
+ eval_function (function): evaluation function.
+ eval_param_dict (dict): evaluation parameters' configure dict.
+ interval (int): run evaluation interval, default is 1.
+ eval_start_epoch (int): evaluation start epoch, default is 1.
+ save_best_ckpt (bool): Whether to save best checkpoint, default is True.
+ besk_ckpt_name (str): bast checkpoint name, default is `best.ckpt`.
+ metrics_name (str): evaluation metrics name, default is `acc`.
+
+ Returns:
+ None
+
+ Examples:
+ >>> EvalCallBack(eval_function, eval_param_dict)
+ """
+
+ def __init__(self, eval_function, eval_param_dict, interval=1, eval_start_epoch=1, \
+ save_best_ckpt=True, ckpt_directory="./", besk_ckpt_name="best.ckpt", metrics_name="acc"):
+ super(EvalCallBack, self).__init__()
+ self.eval_param_dict = eval_param_dict
+ self.eval_function = eval_function
+ self.eval_start_epoch = eval_start_epoch
+ if interval < 1:
+ raise ValueError("interval should >= 1.")
+ self.interval = interval
+ self.save_best_ckpt = save_best_ckpt
+ self.best_res = 0
+ self.best_epoch = 0
+ if not os.path.isdir(ckpt_directory):
+ os.makedirs(ckpt_directory)
+ self.bast_ckpt_path = os.path.join(ckpt_directory, besk_ckpt_name)
+ self.metrics_name = metrics_name
+
+ def remove_ckpoint_file(self, file_name):
+ """Remove the specified checkpoint file from this checkpoint manager and also from the directory."""
+ try:
+ os.chmod(file_name, stat.S_IWRITE)
+ os.remove(file_name)
+ except OSError:
+ logger.warning("OSError, failed to remove the older ckpt file %s.", file_name)
+ except ValueError:
+ logger.warning("ValueError, failed to remove the older ckpt file %s.", file_name)
+
+ def epoch_end(self, run_context):
+ """Callback when epoch end."""
+ cb_params = run_context.original_args()
+ cur_epoch = cb_params.cur_epoch_num
+ if cur_epoch >= self.eval_start_epoch and (cur_epoch - self.eval_start_epoch) % self.interval == 0:
+ res = self.eval_function(self.eval_param_dict)
+ print(datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')[:-3],\
+ ":INFO: epoch: {}, {}: {}, {}: {}".format(cur_epoch, self.metrics_name[0], \
+ res[0]*100, self.metrics_name[1], res[1]*100), flush=True)
+ if res[1] >= self.best_res:
+ self.best_res = res[1]
+ self.best_epoch = cur_epoch
+ print(datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')[:-3],\
+ ":INFO: update best result: {}".format(res[1]*100), flush=True)
+ if self.save_best_ckpt:
+ if os.path.exists(self.bast_ckpt_path):
+ self.remove_ckpoint_file(self.bast_ckpt_path)
+ save_checkpoint(cb_params.train_network, self.bast_ckpt_path)
+ print(datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')[:-3],\
+ ":INFO: update best checkpoint at: {}".format(self.bast_ckpt_path), flush=True)
+
+ def end(self, run_context):
+ print(datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')[:-3],\
+ ":INFO: End training, the best {0} is: {1}, it's epoch is {2}".format(self.metrics_name[1],\
+ self.best_res*100, self.best_epoch), flush=True)
+
+def batch_pix_accuracy(output, target):
+ """PixAcc"""
+ # inputs are numpy array, output 4D NCHW where 'C' means label classes, target 3D NHW
+
+ predict = np.argmax(output.astype(np.int64), 1) + 1
+ target = target.astype(np.int64) + 1
+ pixel_labeled = (target > 0).sum()
+ pixel_correct = ((predict == target) * (target > 0)).sum()
+ assert pixel_correct <= pixel_labeled, "Correct area should be smaller than Labeled"
+ return pixel_correct, pixel_labeled
+
+def batch_intersection_union(output, target, nclass):
+ """mIoU"""
+ # inputs are numpy array, output 4D, target 3D
+ mini = 1
+ maxi = nclass
+ nbins = nclass
+ predict = np.argmax(output.astype(np.float32), 1) + 1
+ target = target.astype(np.float32) + 1
+
+ predict = predict.astype(np.float32) * (target > 0).astype(np.float32)
+ intersection = predict * (predict == target).astype(np.float32)
+ # areas of intersection and union
+ # element 0 in intersection occur the main difference from np.bincount. set boundary to -1 is necessary.
+ area_inter, _ = np.histogram(intersection, bins=nbins, range=(mini, maxi))
+ area_pred, _ = np.histogram(predict, bins=nbins, range=(mini, maxi))
+ area_lab, _ = np.histogram(target, bins=nbins, range=(mini, maxi))
+ area_union = area_pred + area_lab - area_inter
+ assert (area_inter > area_union).sum() == 0, "Intersection area should be smaller than Union area"
+ return area_inter.astype(np.float32), area_union.astype(np.float32)
+
+
+def pixelAccuracy(imPred, imLab):
+ """
+ This function takes the prediction and label of a single image, returns pixel-wise accuracy
+ To compute over many images do:
+ for i = range(Nimages):
+ (pixel_accuracy[i], pixel_correct[i], pixel_labeled[i]) = \
+ pixelAccuracy(imPred[i], imLab[i])
+ mean_pixel_accuracy = 1.0 * np.sum(pixel_correct) / (np.spacing(1) + np.sum(pixel_labeled))
+ """
+ # Remove classes from unlabeled pixels in gt image.
+ # We should not penalize detections in unlabeled portions of the image.
+ pixel_labeled = np.sum(imLab >= 0)
+ pixel_correct = np.sum((imPred == imLab) * (imLab >= 0))
+ pixel_accuracy = 1.0 * pixel_correct / pixel_labeled
+ return (pixel_accuracy, pixel_correct, pixel_labeled)
+
+def intersectionAndUnion(imPred, imLab, numClass):
+ """
+ This function takes the prediction and label of a single image,
+ returns intersection and union areas for each class
+ To compute over many images do:
+ for i in range(Nimages):
+ (area_intersection[:,i], area_union[:,i]) = intersectionAndUnion(imPred[i], imLab[i])
+ IoU = 1.0 * np.sum(area_intersection, axis=1) / np.sum(np.spacing(1)+area_union, axis=1)
+ """
+ # Remove classes from unlabeled pixels in gt image.
+ # We should not penalize detections in unlabeled portions of the image.
+ imPred = imPred * (imLab >= 0)
+
+ # Compute area intersection:
+ intersection = imPred * (imPred == imLab)
+ (area_intersection, _) = np.histogram(intersection, bins=numClass, range=(1, numClass))
+
+ # Compute area union:
+ (area_pred, _) = np.histogram(imPred, bins=numClass, range=(1, numClass))
+ (area_lab, _) = np.histogram(imLab, bins=numClass, range=(1, numClass))
+ area_union = area_pred + area_lab - area_intersection
+ return (area_intersection, area_union)
+
+
+def hist_info(pred, label, num_cls):
+ assert pred.shape == label.shape
+ k = (label >= 0) & (label < num_cls)
+ labeled = np.sum(k)
+ correct = np.sum((pred[k] == label[k]))
+
+ return np.bincount(num_cls * label[k].astype(int) + pred[k], minlength=num_cls ** 2).\
+ reshape(num_cls, num_cls), labeled, correct
+
+def compute_score(hist, correct, labeled):
+ iu = np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))
+ mean_IU = np.nanmean(iu)
+ mean_IU_no_back = np.nanmean(iu[1:])
+ #freq = hist.sum(1) / hist.sum()
+ # freq_IU = (iu[freq > 0] * freq[freq > 0]).sum()
+ mean_pixel_acc = correct / labeled
+
+ return iu, mean_IU, mean_IU_no_back, mean_pixel_acc
diff --git a/model_zoo/official/cv/fastscnn/src/visualize.py b/model_zoo/official/cv/fastscnn/src/visualize.py
new file mode 100644
index 00000000000..180c9bf4eda
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/src/visualize.py
@@ -0,0 +1,114 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+"""Visualization Utils"""
+from PIL import Image
+
+__all__ = ['get_color_pallete']
+
+
+def get_color_pallete(npimg, dataset='citys'):
+ """Visualize image.
+
+ Parameters
+ ----------
+ npimg : numpy.ndarray
+ Single channel image with shape `H, W, 1`.
+ dataset : str, default: 'pascal_voc'
+ The dataset that model pretrained on. ('pascal_voc', 'ade20k')
+ Returns
+ -------
+ out_img : PIL.Image
+ Image with color palette
+ """
+ # recovery boundary
+ if dataset in ('pascal_voc', 'pascal_aug'):
+ npimg[npimg == -1] = 255
+ # put colormap
+ if dataset == 'ade20k':
+ npimg = npimg + 1
+ out_img = Image.fromarray(npimg.astype('uint8'))
+ out_img.putpalette(adepallete)
+ return out_img
+ if dataset == 'citys':
+ out_img = Image.fromarray(npimg.astype('uint8'))
+ out_img.putpalette(cityspallete)
+ return out_img
+ out_img = Image.fromarray(npimg.astype('uint8'))
+ out_img.putpalette(vocpallete)
+ return out_img
+
+
+def _getvocpallete(num_cls):
+ '''_getvocpallete'''
+ n = num_cls
+ palette = [0] * (n * 3)
+ for j in range(0, n):
+ lab = j
+ palette[j * 3 + 0] = 0
+ palette[j * 3 + 1] = 0
+ palette[j * 3 + 2] = 0
+ i = 0
+ while lab > 0:
+ palette[j * 3 + 0] |= (((lab >> 0) & 1) << (7 - i))
+ palette[j * 3 + 1] |= (((lab >> 1) & 1) << (7 - i))
+ palette[j * 3 + 2] |= (((lab >> 2) & 1) << (7 - i))
+ i = i + 1
+ lab >>= 3
+ return palette
+
+
+vocpallete = _getvocpallete(256)
+
+adepallete = [
+ 0, 0, 0, 120, 120, 120, 180, 120, 120, 6, 230, 230, 80, 50, 50, 4, 200, 3, 120, 120, 80, 140, 140, 140, 204,
+ 5, 255, 230, 230, 230, 4, 250, 7, 224, 5, 255, 235, 255, 7, 150, 5, 61, 120, 120, 70, 8, 255, 51, 255, 6, 82,
+ 143, 255, 140, 204, 255, 4, 255, 51, 7, 204, 70, 3, 0, 102, 200, 61, 230, 250, 255, 6, 51, 11, 102, 255, 255,
+ 7, 71, 255, 9, 224, 9, 7, 230, 220, 220, 220, 255, 9, 92, 112, 9, 255, 8, 255, 214, 7, 255, 224, 255, 184, 6,
+ 10, 255, 71, 255, 41, 10, 7, 255, 255, 224, 255, 8, 102, 8, 255, 255, 61, 6, 255, 194, 7, 255, 122, 8, 0, 255,
+ 20, 255, 8, 41, 255, 5, 153, 6, 51, 255, 235, 12, 255, 160, 150, 20, 0, 163, 255, 140, 140, 140, 250, 10, 15,
+ 20, 255, 0, 31, 255, 0, 255, 31, 0, 255, 224, 0, 153, 255, 0, 0, 0, 255, 255, 71, 0, 0, 235, 255, 0, 173, 255,
+ 31, 0, 255, 11, 200, 200, 255, 82, 0, 0, 255, 245, 0, 61, 255, 0, 255, 112, 0, 255, 133, 255, 0, 0, 255, 163,
+ 0, 255, 102, 0, 194, 255, 0, 0, 143, 255, 51, 255, 0, 0, 82, 255, 0, 255, 41, 0, 255, 173, 10, 0, 255, 173, 255,
+ 0, 0, 255, 153, 255, 92, 0, 255, 0, 255, 255, 0, 245, 255, 0, 102, 255, 173, 0, 255, 0, 20, 255, 184, 184, 0,
+ 31, 255, 0, 255, 61, 0, 71, 255, 255, 0, 204, 0, 255, 194, 0, 255, 82, 0, 10, 255, 0, 112, 255, 51, 0, 255, 0,
+ 194, 255, 0, 122, 255, 0, 255, 163, 255, 153, 0, 0, 255, 10, 255, 112, 0, 143, 255, 0, 82, 0, 255, 163, 255,
+ 0, 255, 235, 0, 8, 184, 170, 133, 0, 255, 0, 255, 92, 184, 0, 255, 255, 0, 31, 0, 184, 255, 0, 214, 255, 255,
+ 0, 112, 92, 255, 0, 0, 224, 255, 112, 224, 255, 70, 184, 160, 163, 0, 255, 153, 0, 255, 71, 255, 0, 255, 0,
+ 163, 255, 204, 0, 255, 0, 143, 0, 255, 235, 133, 255, 0, 255, 0, 235, 245, 0, 255, 255, 0, 122, 255, 245, 0,
+ 10, 190, 212, 214, 255, 0, 0, 204, 255, 20, 0, 255, 255, 255, 0, 0, 153, 255, 0, 41, 255, 0, 255, 204, 41, 0,
+ 255, 41, 255, 0, 173, 0, 255, 0, 245, 255, 71, 0, 255, 122, 0, 255, 0, 255, 184, 0, 92, 255, 184, 255, 0, 0,
+ 133, 255, 255, 214, 0, 25, 194, 194, 102, 255, 0, 92, 0, 255]
+
+cityspallete = [
+ 128, 64, 128,
+ 244, 35, 232,
+ 70, 70, 70,
+ 102, 102, 156,
+ 190, 153, 153,
+ 153, 153, 153,
+ 250, 170, 30,
+ 220, 220, 0,
+ 107, 142, 35,
+ 152, 251, 152,
+ 0, 130, 180,
+ 220, 20, 60,
+ 255, 0, 0,
+ 0, 0, 142,
+ 0, 0, 70,
+ 0, 60, 100,
+ 0, 80, 100,
+ 0, 0, 230,
+ 119, 11, 32,
+]
diff --git a/model_zoo/official/cv/fastscnn/train.py b/model_zoo/official/cv/fastscnn/train.py
new file mode 100644
index 00000000000..a2bca200744
--- /dev/null
+++ b/model_zoo/official/cv/fastscnn/train.py
@@ -0,0 +1,227 @@
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
+'''train.py'''
+import os
+import math
+import argparse
+import datetime
+
+import mindspore
+import mindspore.nn as nn
+from mindspore import context
+from mindspore.train import Model
+from mindspore.common import set_seed
+from mindspore.common.tensor import Tensor
+from mindspore.context import ParallelMode
+from mindspore import FixedLossScaleManager
+from mindspore import load_checkpoint, load_param_into_net
+from mindspore.dataset.transforms.py_transforms import Compose
+from mindspore.dataset.vision.py_transforms import ToTensor, Normalize
+from mindspore.communication.management import init, get_rank, get_group_size
+from mindspore.train.callback import TimeMonitor, LossMonitor, CheckpointConfig, ModelCheckpoint
+
+from src.logger import get_logger
+from src.lr_scheduler import LRScheduler
+from src.dataloader import create_CitySegmentation
+from src.fast_scnn import FastSCNN, FastSCNNWithLossCell
+from src.util import SegmentationMetric, EvalCallBack, apply_eval, TempLoss
+
+
+def parse_args():
+ """Training Options for Segmentation Experiments"""
+ parser = argparse.ArgumentParser(description='Fast-SCNN on mindspore')
+ parser.add_argument('--dataset', type=str, default='/data/dataset/citys/',
+ help='dataset name (default: /data/dataset/citys/)')
+ parser.add_argument('--base_size', type=int, default=1024, help='base image size')
+ parser.add_argument('--crop_size', type=int, default=(768, 768), help='crop image size')
+ parser.add_argument('--train_split', type=str, default='train',
+ help='dataset train split (default: train)')
+ parser.add_argument('--aux', action='store_true', default=True, help='Auxiliary loss')
+ parser.add_argument('--aux_weight', type=float, default=0.4,
+ help='auxiliary loss weight')
+ parser.add_argument('--epochs', type=int, default=1000, metavar='N',
+ help='number of epochs to train (default: 1000)')
+ parser.add_argument('--save_every', type=int, default=1, metavar='N',
+ help='save ckpt every N epoch')
+ parser.add_argument('--resume_path', type=str, default=None,
+ help='put the path to resuming file if needed')
+ parser.add_argument('--resume_name', type=str, default=None,
+ help='resuming file name')
+ parser.add_argument('--batch_size', type=int, default=2, metavar='N',
+ help='input batch size for training (default: 2)')
+ parser.add_argument('--lr', type=float, default=0.001, metavar='LR',
+ help='base learning rate (default: 0.045)')
+ parser.add_argument('--momentum', type=float, default=0.9, metavar='M',
+ help='momentum (default: 0.9)')
+ parser.add_argument('--weight_decay', type=float, default=4e-5, metavar='M',
+ help='w-decay (default: 4e-5)')
+
+ parser.add_argument('--eval_while_train', type=int, default=1, help='eval while training')
+ parser.add_argument('--eval_steps', type=int, default=10, help='each N epochs we eval')
+ parser.add_argument('--eval_start_epoch', type=int, default=850, help='eval_start_epoch')
+ parser.add_argument('--use_modelarts', type=int, default=0,
+ help='when set True, we should load dataset from obs with moxing')
+ parser.add_argument('--train_url', type=str, default='train_url/',
+ help='needed by modelarts, but we donot use it because the name is ambiguous')
+ parser.add_argument('--data_url', type=str, default='data_url/',
+ help='needed by modelarts, but we donot use it because the name is ambiguous')
+ parser.add_argument('--output_path', type=str, default='./outputs/',
+ help='output_path,when use_modelarts is set True, it will be cache/output/')
+ parser.add_argument('--outer_path', type=str, default='s3://output/',
+ help='obs path,to store e.g ckpt files ')
+
+ parser.add_argument('--device_target', type=str, default='Ascend',
+ help='device where the code will be implemented. (Default: Ascend)')
+ parser.add_argument('--is_distributed', type=int, default=0, help='if multi device')
+ parser.add_argument('--rank', type=int, default=0, help='local rank of distributed')
+ parser.add_argument('--group_size', type=int, default=1, help='world size of distributed')
+ parser.add_argument('--is_save_on_master', type=int, default=1,
+ help='save ckpt on master or all rank')
+ parser.add_argument('--ckpt_save_max', type=int, default=800,
+ help='Maximum number of checkpoint files can be saved. Default: 800')
+ # the parser
+ args_ = parser.parse_args()
+ return args_
+
+args = parse_args()
+set_seed(1)
+device_id = int(os.getenv('DEVICE_ID', '0'))
+context.set_context(mode=context.GRAPH_MODE, device_target=args.device_target, save_graphs=False)
+save_dir = os.path.join(args.output_path, datetime.datetime.now().strftime('%Y-%m-%d_time_%H_%M_%S'))
+
+def train():
+ '''train'''
+ if args.is_distributed:
+ assert args.device_target == "Ascend"
+ context.set_context(device_id=device_id)
+ init()
+ args.rank = get_rank()
+ args.group_size = get_group_size()
+ device_num = args.group_size
+ context.reset_auto_parallel_context()
+ context.set_auto_parallel_context(device_num=device_num, parallel_mode=ParallelMode.DATA_PARALLEL)
+ else:
+ if args.device_target in ["Ascend", "GPU"]:
+ context.set_context(device_id=device_id)
+
+ # select for master rank save ckpt or all rank save, compatible for model parallel
+ args.rank_save_ckpt_flag = 0
+ if args.is_save_on_master:
+ if args.rank == 0:
+ args.rank_save_ckpt_flag = 1
+ else:
+ args.rank_save_ckpt_flag = 1
+
+ args.logger = get_logger(save_dir, "Fast_SCNN", args.rank)
+ args.logger.save_args(args)
+
+ # image transform
+ input_transform = Compose([
+ ToTensor(),
+ Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
+ ])
+
+ if args.use_modelarts:
+ import moxing as mox
+ args.logger.info("copying dataset from obs to cache....")
+ mox.file.copy_parallel(args.dataset, 'cache/dataset')
+ args.logger.info("copying dataset finished....")
+ args.dataset = 'cache/dataset/'
+
+ train_dataset, train_dataset_len = create_CitySegmentation(args, data_path=args.dataset, \
+ split=args.train_split, mode='train', transform=input_transform, \
+ base_size=args.base_size, crop_size=args.crop_size, batch_size=args.batch_size, \
+ device_num=args.group_size, rank=args.rank, shuffle=True)
+
+ args.steps_per_epoch = math.ceil(train_dataset_len / args.batch_size / args.group_size)
+
+ # create network
+ f_model = FastSCNN(num_classes=19, aux=args.aux)
+
+ # resume checkpoint if needed
+ # resume checkpoint if needed
+ if args.resume_path:
+ if args.use_modelarts:
+ import moxing as mox
+ args.logger.info("copying resume checkpoint from obs to cache....")
+ mox.file.copy_parallel(args.resume_path, 'cache/resume_path')
+ args.logger.info("copying resume checkpoint finished....")
+ args.resume_path = 'cache/resume_path/'
+
+ args.resume_path = os.path.join(args.resume_path, args.resume_name)
+ args.logger.info('loading resume checkpoint {} into network'.format(args.resume_path))
+ load_param_into_net(f_model, load_checkpoint(args.resume_path))
+ args.logger.info('loaded resume checkpoint {} into network'.format(args.resume_path))
+
+ model = FastSCNNWithLossCell(f_model, args)
+ model.set_train()
+
+ # lr scheduling
+ lr_list = LRScheduler(mode='cosine', base_lr=args.lr, nepochs=args.epochs, \
+ iters_per_epoch=args.steps_per_epoch, power=0.9)(args.epochs*args.steps_per_epoch)
+
+ # optimizer
+ optimizer = nn.SGD(params=model.trainable_params(), momentum=args.momentum, \
+ learning_rate=Tensor(lr_list, mindspore.float32), \
+ weight_decay=args.weight_decay, loss_scale=1024)
+ loss_scale = FixedLossScaleManager(1024, drop_overflow_update=False)
+ model = Model(model, optimizer=optimizer, loss_scale_manager=loss_scale, amp_level="O0")
+
+ # define callbacks
+ if args.rank == 0:
+ time_cb = TimeMonitor(data_size=train_dataset_len)
+ loss_cb = LossMonitor()
+ callbacks = [time_cb, loss_cb]
+ else:
+ callbacks = None
+
+ if args.rank_save_ckpt_flag:
+ ckpt_config = CheckpointConfig(save_checkpoint_steps=args.steps_per_epoch*args.save_every,
+ keep_checkpoint_max=args.ckpt_save_max)
+ save_ckpt_path = os.path.join(save_dir, 'ckpt_' + str(args.rank) + '/')
+ ckpt_cb = ModelCheckpoint(config=ckpt_config,
+ directory=save_ckpt_path,
+ prefix='rank_'+str(args.rank))
+ callbacks.append(ckpt_cb)
+
+ if args.eval_while_train == 1 and args.rank == 0:
+
+ val_dataset, _ = create_CitySegmentation(args, data_path=args.dataset, \
+ split='val', mode='val', transform=input_transform, \
+ base_size=args.base_size, crop_size=args.crop_size, \
+ batch_size=1, device_num=1, \
+ rank=args.rank, shuffle=False)
+ loss_f = TempLoss()
+ network_eval = Model(f_model, loss_fn=loss_f, metrics={"SegmentationMetric": SegmentationMetric(19)})
+
+ eval_param_dict = {"model": network_eval, "dataset": val_dataset}
+ eval_cb = EvalCallBack(apply_eval, eval_param_dict, interval=args.eval_steps,
+ eval_start_epoch=args.eval_start_epoch, save_best_ckpt=True,
+ ckpt_directory=save_dir, besk_ckpt_name="best_map.ckpt",
+ metrics_name=("pixAcc", "mIou"))
+ callbacks.append(eval_cb)
+
+ model.train(args.epochs, train_dataset, callbacks=callbacks, dataset_sink_mode=True)
+
+ args.logger.info("training finished....")
+ if args.use_modelarts:
+ import moxing as mox
+ args.logger.info("copying files from cache to obs....")
+ mox.file.copy_parallel(save_dir, args.outer_path)
+ args.logger.info("copying finished....")
+
+if __name__ == '__main__':
+ print('Starting training, Total Epochs: %d' % (args.epochs))
+ train()