• [活动体验] MindSpore学习笔记10———图像处理(image processing)之对抗示例生成
    近年来随着数据、计算能力、理论的不断发展演进,深度学习在图像、文本、语音、自动驾驶等众多领域都得到了广泛应用。与此同时,人们也越来越关注各类模型在使用过程中的安全问题,因为AI模型很容易受到外界有意无意的攻击而产生错误的结果。在本案例中,我们将以梯度符号攻击FGSM(Fast Gradient Sign Method)为例,演示此类攻击是如何误导模型的。对抗例的出现有助于我们对图片的对比效果拉满,所有这同样是必不可少的。定义Szegedy在2013年最早提出对抗样本的概念:在原始样本处加入人类无法察觉的微小扰动,使得深度模型性能下降,这种样本即对抗样本。如下图所示,本来预测为“panda”的图像在添加噪声之后,模型就将其预测为“gibbon”右边的样本就是一个对抗样本。噪音攻击是种很直白的攻击方式,但却直接有效。同样的,也有很多攻击方式;两种情况攻击者掌握的信息多少:白盒攻击:攻击者具有对模型的全部知识和访问权限,包括模型结构、权重、输入、输出。攻击者在产生对抗性攻击数据的过程中能够与模型系统有所交互。攻击者可以针对被攻击模型的特性设计特定的攻击算法。黑盒攻击:与白盒攻击相反,攻击者仅具有关于模型的有限知识。攻击者对模型的结构权重一无所知,仅了解部分输入输出。    2.攻击者的目的:有目标的攻击:攻击者将模型结果误导为特定分类。无目标的攻击:攻击者只想产生错误结果,而不在乎新结果是什么。Fast Gradient Sign Attack(快速梯度符号攻击)讲述通过对原始数据加入细微的噪声得到一组新数据,在新旧两个数据通过人眼难以辨别的情况下,新数据可以欺骗分类器,从而使分类器做出错误的判断。这种方法可以用来攻击一些分类器,并且是完全可行的。产生的对抗扰动用公式可以表示为:产生的对抗扰动用公式可以表示为:xx:正确分类为“Pandas”的原始输入图像。yy:是xx的输出。θθ:模型参数。εε:攻击系数。J(θ,x,y)J(θ,x,y):训练网络的损失。∇xJ(θ)∇xJ(θ):反向传播梯度θθ:模型参数。εε:攻击系数。J(θ,x,y)J(θ,x,y):训练网络的损失。∇xJ(θ)∇xJ(θ):反向传播梯度。要运行攻击的时候我们要理解由FGSM攻击公式中可以看出,攻击系数εε越大,对梯度的改变就越大。当εε 为零时则攻击效果不体现。代码如下:fgsm = FastGradientSignMethod(net, eps=0.0, loss_fn=net_loss)advs = fgsm.batch_generate(test_images, true_labels, batch_size=32)adv_predicts = model.predict(Tensor(advs)).asnumpy()adv_predicts = np.argmax(adv_predicts, axis=1)accuracy = np.mean(np.equal(adv_predicts, true_labels))print(accuracy)运行结果如下:再将εε设定为0.5,尝试运行攻击:fgsm = FastGradientSignMethod(net, eps=0.5, loss_fn=net_loss)advs = fgsm.batch_generate(test_images, true_labels, batch_size=32)adv_predicts = model.predict(Tensor(advs)).asnumpy()adv_predicts = np.argmax(adv_predicts, axis=1)accuracy = np.mean(np.equal(adv_predicts, true_labels))print(accuracy)结果如下:此时LeNet模型的精度大幅降低。下面演示受攻击照片现在的实际形态,可以看出图片并没有发生明显的改变,然而在精度测试中却有了不一样的结果:import matplotlib.pyplot as pltadv_examples = np.transpose(advs[:10],[0,2,3,1])ori_examples = np.transpose(test_images[:10],[0,2,3,1])plt.figure()for i in range(10):    plt.subplot(2,10,i+1)    plt.imshow(np.squeeze(ori_examples[i]))    plt.subplot(2,10,i+11)    plt.imshow(np.squeeze(adv_examples[i]))plt.show()对比结果:
  • [活动体验] MindSpore学习笔记8———图像处理(image processing)之图像分割模型微调
    图像处理(image processing)用计算机对图像进行分析,以达到所需结果的技术。又称影像处理。图像处理一般指数字图像处理。数字图像是指用工业相机、摄像机、扫描仪等设备经过拍摄得到的一个大的二维数组,该数组的元素称为像素,其值称为灰度值。图像处理技术一般包括图像压缩,增强和复原,匹配、描述和识别3个部分。图像变换:由于图像阵列很大,直接在空间域中进行处理,涉及计算量很大。因此,往往采用各种图像变换的方法,如傅立叶变换、沃尔什变换、离散余弦变换等间接处理技术,将空间域的处理转换为变换域处理,不仅可减少计算量,而且可获得更有效的处理(如傅立叶变换可在频域中进行数字滤波处理)。目前新兴研究的小波变换在时域和频域中都具有良好的局部化特性,它在图像处理中也有着广泛而有效的应用。图像编码压缩:图像编码压缩技术可减少描述图像的数据量(即比特数),以便节省图像传输、处理时间和减少所占用的存储器容量。压缩可以在不失真的前提下获得,也可以在允许的失真条件下进行。编码是压缩技术中最重要的方法,它在图像处理技术中是发展最早且比较成熟的技术。图像增强和复原:图像增强和复原的目的是为了提高图像的质量,如去除噪声,提高图像的清晰度等。图像增强不考虑图像降质的原因,突出图像中所感兴趣的部分。如强化图像高频分量,可使图像中物体轮廓清晰,细节明显;如强化低频分量可减少图像中噪声影响。图像复原要求对图像降质的原因有一定的了解,一般讲应根据降质过程建立“降质模型”,再采用某种滤波方法,恢复或重建原来的图像。图像分割:图像分割是数字图像处理中的关键技术之一。图像分割是将图像中有意义的特征部分提取出来,其有意义的特征有图像中的边缘、区域等,这是进一步进行图像识别、分析和理解的基础。虽然目前已研究出不少边缘提取、区域分割的方法,但还没有一种普遍适用于各种图像的有效方法。因此,对图像分割的研究还在不断深入之中,是目前图像处理中研究的热点之一。图像描述:图像描述是图像识别和理解的必要前提。作为最简单的二值图像可采用其几何特性描述物体的特性,一般图像的描述方法采用二维形状描述,它有边界描述和区域描述两类方法。对于特殊的纹理图像可采用二维纹理特征描述。随着图像处理研究的深入发展,已经开始进行三维物体描述的研究,提出了体积描述、表面描述、广义圆柱体描述等方法。图像分类(识别):图像分类(识别)属于模式识别的范畴,其主要内容是图像经过某些预处理(增强、复原、压缩)后,进行图像分割和特征提取,从而进行判决分类。图像分类常采用经典的模式识别方法,有统计模式分类和句法(结构)模式分类,近年来新发展起来的模糊识别模式和人工神经网络模式分类在图像识别中也越来越受到重视。数据处理COCO数据集说明COCO数据集可以用于图片分类、目标检测、图像分割等场景,是一个评估视觉类模型的业界标准数据集。教程中会使用COCO2017版本对模型进行训练,在正式开始执行代码之前先介绍COCO2017的一些基本信息,以便于用户理解整个数据处理的过程。COCO2017数据集的结构如下,其中annotations文件夹为标注信息json文件,train2017等文件夹存储了大量图片:代码如下:├── annotations # 储存图片标注信息,分为三种类型│   ├── captions_train2017.json             # 看图说话,描述图片的内容│   ├── captions_val2017.json│   ├── instances_train2017.json            # 目标实例,为本例中使用的类型│   ├── instances_val2017.json│   ├── person_keypoints_train2017.json     # 人体关键点检测│   └── person_keypoints_val2017.json├── train2017                               # 用于训练的图片├── test2017                                # 用于测试的图片├── val2017                                 # 用于验证的图片 现在进一步说明实验中用到的instance类型标注。COCO数据集标注信息内容较多,下面一步步从大类拆解到细节。总体上,一张图片的标注结构如下所示:annotation{"id" : int,                         # 序号"image_id" : int,                   # 图片的id,与数据集中的真实图片相对应"category_id" : int,                # 所属的图片类别"segmentation" : RLE or [polygon],  # 使用RLE或polygon格式存储图片"area" : float,                     # 标注区域的面积"bbox" : [x,y,width,height],        # 物体边界框"iscrowd" : 0 or 1,                 # 值为0:采用polygon格式;值为1:采用RLE格式}在数据处理的过程中,会一步步提取出图片、bbox、图片的mask等信息,用于训练Mask R-CNN模型。编写自定义数据集数据集由180张包含书籍的图片组成,图像与标注均来自于COCO。案例中采用自定义数据集的方式加载,完整数据处理代码可参考src/dataset.py。案例中,构造的自定义数据集类为COCOSubDataset,在训练过程中会通过GeneratorDataset接口加载并访问数据集。COCOSubDataset包含三部分。首先,在类函数__init__中完成数据初始化,并且一步步解析出COCO数据集的图像,以及json中储存的bbox、mask、iscrowd等信息。class COCOSubDataset():    def __init__(self, coco_root, is_training=True, config=None):        data_type = config.train_data_type        # 调用COCO数据集的接口读取数据        anno_json = os.path.join(coco_root, config.instance_set.format(data_type))        coco = COCO(anno_json)        self.image_files = []        self.image_anno_dict = {}        self.masks = {}        self.masks_shape = {}        # 读取分类的类别信息        train_cls = config.coco_classes        train_cls_dict = {}        for i, cls in enumerate(train_cls):            train_cls_dict[cls] = i        classs_dict = {}        cat_ids = coco.loadCats(coco.getCatIds())        for cat in cat_ids:            classs_dict[cat["id"]] = cat["name"]        # 读取数据集中的图像、mask、mask_shape        image_ids = coco.getImgIds()        images_num = len(image_ids)        for ind, img_id in enumerate(image_ids):            image_info = coco.loadImgs(img_id)            file_name = image_info[0]["file_name"]            anno_ids = coco.getAnnIds(imgIds=img_id, iscrowd=None)            anno = coco.loadAnns(anno_ids)            image_path = os.path.join(coco_root, data_type, file_name)            annos = []            instance_masks = []            image_height = coco.imgs[img_id]["height"]            image_width = coco.imgs[img_id]["width"]            # 进一步处理,获取图像的mask、box、iscrowd和分类信息            for label in anno:                bbox = label["bbox"]                class_name = classs_dict[label["category_id"]]                if class_name in train_cls:                    # 获取二进制的coco mask                    m = annToMask(label, image_height, image_width)                    if m.max() < 1:                        print("all black mask!!!!")                        continue                    # 根据对象是单个还是一组处理mask数据                    if label['iscrowd'] and (m.shape[0] != image_height or m.shape[1] != image_width):                        m = np.ones([image_height, image_width], dtype=np.bool)                    instance_masks.append(m)                    # 获取coco数据集中的bounding box                    x1, x2 = bbox[0], bbox[0] + bbox[2]                    y1, y2 = bbox[1], bbox[1] + bbox[3]                    annos.append([x1, y1, x2, y2] + [train_cls_dict[class_name]] + [int(label["iscrowd"])])                else:                    print("not in classes: ", class_name)                # 获取图像、标注信息、mask与mask shape                self.image_files.append(image_path)                self.image_anno_dict[image_path] = np.array(annos)                instance_masks = np.stack(instance_masks, axis=0)                self.masks[image_path] = np.array(instance_masks)                self.masks_shape[image_path] = np.array(instance_masks.shape, dtype=np.int32)然后在__getitem__方法中,返回单个图像和与图像关联的分割信息,返回值包括:img:图像annos:图像的bbox、所属分类和iscrowd信息mask:二进制的图像分割蒙版mask_shape:图像分割蒙版shape 代码如下:def __getitem__(self, index):    image_name = self.image_files[index]    img = np.fromfile(image_name, dtype=np.uint8)    annos = np.array(self.image_anno_dict[image_name], dtype=np.int32)    mask = self.masks[image_name]    mask_shape = self.masks_shape[image_name]    return img, annos, mask, mask_shape最后我们要执行:代码如下:执行maskrcnn_fine_tune/train.py文件,利用之前获取的backbone和数据集if __name__ == '__main__':    rank = 0    device_num = 1    # 调用接口进行数据处理    dataset = create_new_dataset(image_dir=config.coco_root, batch_size=config.batch_size, is_training=True, num_parallel_workers=8)    dataset_size = dataset.get_dataset_size()    print("total images num: ", dataset_size)    print("Create dataset done!")    # 实例化网络    net = Mask_Rcnn_Resnet50(config=config)    net = net.set_train()    # 加载预训练模型    load_path = args_opt.pre_trained    if load_path != "":        param_dict = load_checkpoint(load_path)        if config.pretrain_epoch_size == 0:            for item in list(param_dict.keys()):                if not (item.startswith('backbone') or item.startswith('rcnn_mask')):                    param_dict.pop(item)        load_param_into_net(net, param_dict)    # 设定损失函数、学习率、优化器    loss = LossNet()    opt = Momentum(params=net.trainable_params(), learning_rate=0.0001, momentum=config.momentum,                   weight_decay=config.weight_decay, loss_scale=config.loss_scale)    # 包装损失函数    net_with_loss = WithLossCell(net, loss)    # 通过TrainOneStepCell自定义训练过程    net = TrainOneStepCell(net_with_loss, opt, sens=config.loss_scale)    # 监控训练过程    time_cb = TimeMonitor(data_size=dataset_size)    loss_cb = LossCallBack(rank_id=rank)    cb = [time_cb, loss_cb]    # 保存训练后的模型    if config.save_checkpoint:        # 设置模型保存参数        ckptconfig = CheckpointConfig(save_checkpoint_steps=config.save_checkpoint_epochs * dataset_size,                                      keep_checkpoint_max=config.keep_checkpoint_max)        save_checkpoint_path = os.path.join(config.save_checkpoint_path, 'ckpt_' + str(rank) + '/')        # 应用模型保存参数        ckpoint_cb = ModelCheckpoint(prefix='mask_rcnn', directory=save_checkpoint_path, config=ckptconfig)        cb += [ckpoint_cb]    # 进行训练    model = Model(net)    model.train(config.epoch_size, dataset, callbacks=cb, dataset_sink_mode = False)运行结果如下: 原图: 图片中物体分割: 分离物体与背景: