• [算子使用] 使用MindSpore构建LeNet-5模型实现分类任务体验
    # 使用MindSpore构建LeNet-5模型实现分类任务 ## 实验介绍 图像信息中存在中大量的信息,所谓一图盛千言,就是在表达这个意思。 在众多处理图像中,将图像进行分类将是最基本的任务。本实验将利用卷积神经网络进行手写体识别,实验中使用的深度学习框架Mindspore构建是卷积神经网络模型解决图像分类问题。 实验使用的数据集是Cifar-10,CIFAR-10数据集由10个类的60000个32x32彩**像组成,每个类有6000个图像。有50000个训练图像和10000个测试图像,学员们将通过本实验基本理解物理识别的基础理解。 【实验环境要求】: 1. Python 3.7.5 2. Mindspore 0.5 ## 实验总体设计: 1. 环境导入 - 数据集展示 - 数据集载入预处理 - 构建LeNet5模型 - 训练模型 - 设置mindspore环境 - 设计损失函数与优化器 - 设置callback函数 - 模型训练 - 测试网络模型 - 模型优化 - 改善网络 - 重新训练与测试 - 预测效果可视化 ## 实验目的: 1. 加强对基于Mindspore的神经网络模型构建流程的理解 - 掌握如何用Mindspore实现卷积神经网络的构建 - 学会利用checkpoint函数保存模型参数 - 掌握如何利用模型预测单张图像的分类结果 ## 实验详细设计与实现 本节将详细介绍实验的设计与实现。 - 4.1节 导入实验环境; - 4.2节 数据集展示与数据初始化; - 4.3节 构建网络模型; - 4.4节 模型训练与测试; - 4.5节 模型优化与重新训练; - 4.6节 模型测试与可视化。 **说明:如果运行结果中出现WARNING或者UserWarning,无需担心;不会影响实验结果。** ## 导入实验环境 ### 导入相关实验模块 mindspore包主要用于本次实验卷积神经网络的构建,包括很多子模块,在该实验当中,mindspore.dataset主要模块cifar-10数据集的载入与处理,也可以自定义数据集。mindspore.common包中会有诸如type形态转变、权重初始化等的常规工具;mindspore.Tensor提供了mindspore网络可用的张量, context用于设定,mindspore的运行环境与运行设备,Model用来承载网络结构,并能够调用优化器,损失函数,评价指标,mindspord.nn当中主要会包括网络可能涉及到的各类网络层,诸如卷积层,池化层,全连接层;也包括损失函数,激活函数等。mindspore.train.callback下面会涉及到各类回调函数,如checkpoint,lossMonitor等,主要用于在每个epoch训练完的时候自动执行。其他numpy用来处理数组问题,matplotlib用于画图。 ``` import mindspore # 载入mindspore的默认数据集 import mindspore.dataset as ds # 常用转化用算子 import mindspore.dataset.transforms.c_transforms as C # 图像转化用算子 import mindspore.dataset.transforms.vision.c_transforms as CV from mindspore.common import dtype as mstype # mindspore的tensor from mindspore import Tensor # 各类网络层都在nn里面 import mindspore.nn as nn # 参数初始化的方式 from mindspore.common.initializer import TruncatedNormal # 设置mindspore运行的环境 from mindspore import context # 引入训练时候会使用到回调函数,如checkpoint, lossMoniter from mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor, TimeMonitor # 引入模型 from mindspore.train import Model # 引入评估模型的包 from mindspore.nn.metrics import Accuracy # numpy import numpy as np # 画图用 import matplotlib.pyplot as plt ``` ## 数据集展示与数据初始化 CIFAR-10数据集由10个类的60000个32x32彩**像组成,每个类有6000个图像。有50000个训练图像和10000个测试图像。数据集分为五个训练批次和一个测试批次,每个批次有10000个图像。测试批次包含来自每个类别的恰好1000个随机选择的图像。训练批次以随机顺序包含剩余图像,但一些训练批次可能包含来自一个类别的图像比另一个更多。总体来说,五个训练集之和包含来自每个类的正好5000张图像。 10个类完全相互排斥。且类之间没有重叠,汽车和卡车之间没有重叠。“汽车”包括轿车,SUV,这类东西。“卡车”只包括大卡车,都不包括皮卡车。 以下是类的名字:airplane/automobile/bird/cat/deer/dog/frog/horse/ship/truck ### 数据集下载 ``` import os import requests import zipfile current_path = os.getcwd() filename = 'cifar10_mindspore.zip' url = 'https://professional-construction.obs.cn-north-4.myhuaweicloud.com/ComputerVision/cifar10_mindspore.zip' # 使用request下载 print('downloading with requests') r = requests.get(url) with open(filename, 'wb') as code: code.write(r.content) print('download finished') #将打包的文件解压 with zipfile.ZipFile(filename, 'r') as f: for file in f.namelist(): f.extract(file, current_path) # 删除文件 os.remove(os.path.join(current_path,filename)) print('data prepared') ``` ### 查看数据集 注意:这里每次提取出来的数据是随机的。 ``` #创建图像标签列表 category_dict = {0:'airplane',1:'automobile',2:'bird',3:'cat',4:'deer',5:'dog', 6:'frog',7:'horse',8:'ship',9:'truck'} cifar_ds = ds.Cifar10Dataset('./data/10-verify-bin') # 设置图像大小 plt.figure(figsize=(8,8)) i = 1 # 打印9张子图 for dic in cifar_ds.create_dict_iterator(): plt.subplot(3,3,i) plt.imshow(dic['image']) plt.xticks([]) plt.yticks([]) plt.axis('off') plt.title(category_dict[dic['label'].sum()]) i +=1 if i > 9 : break plt.show() ``` ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202011/22/133252fzh6mjcrphtzr9ka.png) ### 定义数据预处理的步骤 定义了两个函数,get_batch用于数据集的读取,使用dataset.Cifar10Dataset()来完成(数据需要预下载);第二个函数process_dataset是对于图像数据特征处理,其中主要包括尺寸大小变更,平移,归一化与标准化,训练时候的随机裁剪,随机翻转。并且内部对于数据集进行了shuffle,变更了一个批量输出的generator. ``` def get_data(datapath): cifar_ds = ds.Cifar10Dataset(datapath) return cifar_ds def process_dataset(cifar_ds,batch_size =32,status="train"): ''' ---- 定义算子 ---- ''' # 归一化 rescale = 1.0 / 255.0 # 平移 shift = 0.0 resize_op = CV.Resize((32, 32)) rescale_op = CV.Rescale(rescale, shift) # 对于RGB三通道分别设定mean和std normalize_op = CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)) if status == "train": # 随机裁剪 random_crop_op = CV.RandomCrop([32, 32], [4, 4, 4, 4]) # 随机翻转 random_horizontal_op = CV.RandomHorizontalFlip() # 通道变化 channel_swap_op = CV.HWC2CHW() # 类型变化 typecast_op = C.TypeCast(mstype.int32) ''' ---- 算子运算 ---- ''' cifar_ds = cifar_ds.map(input_columns="label", operations=typecast_op) if status == "train": cifar_ds = cifar_ds.map(input_columns="image", operations=random_crop_op) cifar_ds = cifar_ds.map(input_columns="image", operations=random_horizontal_op) cifar_ds = cifar_ds.map(input_columns="image", operations=resize_op) cifar_ds = cifar_ds.map(input_columns="image", operations=rescale_op) cifar_ds = cifar_ds.map(input_columns="image", operations=normalize_op) cifar_ds = cifar_ds.map(input_columns="image", operations=channel_swap_op) # shuffle cifar_ds = cifar_ds.shuffle(buffer_size=1000) # 切分数据集到batch_size cifar_ds = cifar_ds.batch(batch_size, drop_remainder=True) return cifar_ds ``` ### 生成训练数据集 引用了上述的函数,训练集的位置在'./data/10-batches-bin'中,我们设置的batch_size=32 ``` data_path='./data/10-batches-bin' batch_size=32 status="train" # 生成训练数据集 cifar_ds = get_data(data_path) ds_train = process_dataset(cifar_ds,batch_size =batch_size, status=status) ``` ## 构建网络模型 ### 定义Lenet网络结构,构建网络 LeNet-5出自论文Gradient-Based Learning Applied to Document Recognition,原本是一种用于手写体字符识别的非常高效的卷积神经网络,包含了深度学习的基本模块:卷积层,池化层,全链接层。 其网络结构包含如下: 1. INPUT(输入层) 32∗32的图片。 2. C1(卷积层)选取6个5∗5卷积核(不包含偏置),得到6个特征图,每个特征图的的一个边为32−5+1=28,也就是神经元的个数由1024减小到了28∗28=784。 3. S2(池化层)池化层是一个下采样层,输出14∗14∗6的特征图。 4. C3(卷积层)选取16个卷积核大小为5∗5,得到特征图大小为10∗10∗16。 5. S4(池化层)窗口大小为2∗2,输出5∗5∗16的特征图。 6. F5(全连接层)120个神经元。 7. F6(全连接层)84个神经元。 8. OUTPUT(全连接层)10个神经元,10分类问题。 ``` """LeNet.""" def conv(in_channels, out_channels, kernel_size, stride=1, padding=0): """weight initial for conv layer""" weight = weight_variable() return nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, weight_init=weight, has_bias=False, pad_mode="valid") def fc_with_initialize(input_channels, out_channels): """weight initial for fc layer""" weight = weight_variable() bias = weight_variable() return nn.Dense(input_channels, out_channels, weight, bias) def weight_variable(): """weight initial""" return TruncatedNormal(0.02) class LeNet5(nn.Cell): """ Lenet network Args: num_class (int): Num classes. Default: 10. Returns: Tensor, output tensor Examples: >>> LeNet(num_class=10) """ def __init__(self, num_class=10, channel=3): super(LeNet5, self).__init__() self.num_class = num_class self.conv1 = conv(channel, 6, 5) self.conv2 = conv(6, 16, 5) self.fc1 = fc_with_initialize(16 * 5 * 5, 120) self.fc2 = fc_with_initialize(120, 84) self.fc3 = fc_with_initialize(84, self.num_class) self.relu = nn.ReLU() self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2) self.flatten = nn.Flatten() def construct(self, x): x = self.conv1(x) x = self.relu(x) x = self.max_pool2d(x) x = self.conv2(x) x = self.relu(x) x = self.max_pool2d(x) x = self.flatten(x) x = self.fc1(x) x = self.relu(x) x = self.fc2(x) x = self.relu(x) x = self.fc3(x) return x # 构建网络 network = LeNet5(10) ``` ## 模型训练与测试 ### 定义损失函数与优化器 这一部分主要给出了用于训练网路的损失函数优化器,本次使用的损失函数为 nn.SoftmaxCrossEntropyWithLogits损失函数,即把网络输出层的值经过softmax函数之后计算真实值与预测值之间的交叉熵损失。优化器使用了Momentum,即动量优化器。 另外我们同时设置了mindspore网路的设备与图的模型,context.GRAPH_MODE指向静态图模型,即在运行之前会把全部图建立编译完毕。设备指定为CPU或Ascend. ``` # 设置模型的设备与图的模式 context.set_context(mode=context.GRAPH_MODE, device_target='Ascend') # 使用交叉熵函数作为损失函数 net_loss = nn.SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=True, reduction="mean") # 优化器为momentum net_opt = nn.Momentum(params=network.trainable_params(), learning_rate=0.01, momentum=0.9) # 监控每个epoch训练的时间 time_cb = TimeMonitor(data_size=ds_train.get_dataset_size()) ``` ### 定义保存路径与训练 这一部分主要函数训练时候的callback函数CheckpointConfig,ModelCheckpoint。Model函数中,确定网路模型,损失函数,优化器,评估指标。 ``` # 设置CheckpointConfig,callback函数。save_checkpoint_steps=训练总数/batch_size config_ck = CheckpointConfig(save_checkpoint_steps=1562, keep_checkpoint_max=10) ckpoint_cb = ModelCheckpoint(prefix="checkpoint_lenet_original", directory='./results',config=config_ck) # 建立可训练模型 model = Model(network = network, loss_fn=net_loss,optimizer=net_opt, metrics={"Accuracy": Accuracy()}) print("============== Starting Training ==============") model.train(10, ds_train,callbacks=[time_cb, ckpoint_cb, LossMonitor(per_print_times=200)],dataset_sink_mode=False) model.eval(ds_train, dataset_sink_mode=False) ``` ### 设置测试集参数并测试 注意:测试集不会进行随机裁剪与翻转 ``` data_path='./data/10-verify-bin' batch_size=32 status="test" # 生成测试数据集 cifar_ds = ds.Cifar10Dataset(data_path) ds_eval = process_dataset(cifar_ds,batch_size=batch_size,status=status) res = model.eval(ds_eval, dataset_sink_mode=False) print(res) ``` ## 模型优化与重新训练 ### 重新定义网络 lenet网络本身并不足以对于cifar-10的图像分类产生出足够的效果,因此需要做进一步改进。总的来说,网络基本维持了lenet的网络结构,增加卷积的个数与卷积核的大小,同时略微增加了网路的深度。 1. 所有的卷积核从5∗5变成3∗3. 2. 增加了一层网路的深度,提升模型的非线性映射能力 3. 提升了卷积核数量,是模型可以提取更多的特征,如64核,128核,512核。 ``` class LeNet5_2(nn.Cell): """ Lenet network Args: num_class (int): Num classes. Default: 10. Returns: Tensor, output tensor Examples: >>> LeNet(num_class=10) """ def __init__(self, num_class=10, channel=3): super(LeNet5_2, self).__init__() self.num_class = num_class self.conv1 = conv(channel, 64, 3) self.conv2 = conv(64, 128, 3) self.conv3 = conv(128, 128, 3) self.fc1 = fc_with_initialize(512, 120) self.fc2 = fc_with_initialize(120, 84) self.fc3 = fc_with_initialize(84, self.num_class) self.relu = nn.ReLU() self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2) self.flatten = nn.Flatten() def construct(self, x): x = self.conv1(x) x = self.relu(x) x = self.max_pool2d(x) x = self.conv2(x) x = self.relu(x) x = self.max_pool2d(x) x = self.conv3(x) x = self.relu(x) x = self.max_pool2d(x) x = self.flatten(x) x = self.fc1(x) x = self.relu(x) x = self.fc2(x) x = self.relu(x) x = self.fc3(x) return x ``` ### 用新网络进行训练 其余损失函数与,优化器等保持不变,以及模型训练的参数保持不变,仅仅将 ModelCheckpoint中保存模型的前缀prefix改为"checkpoint_lenet_verified". ``` network = LeNet5_2(10) # 设置模型的设备 context.set_context(mode=context.GRAPH_MODE, device_target='Ascend') # 使用交叉熵函数作为损失函数 net_loss = nn.SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=True, reduction="mean") # 优化器为momentum net_opt = nn.Momentum(params=network.trainable_params(), learning_rate=0.01, momentum=0.9) # 时间监控,反馈每个epoch的运行时间 time_cb = TimeMonitor(data_size=ds_train.get_dataset_size()) # 设置callback函数。 config_ck = CheckpointConfig(save_checkpoint_steps=1562, keep_checkpoint_max=10) ckpoint_cb = ModelCheckpoint(prefix="checkpoint_lenet_verified",directory='./results', config=config_ck) # 建立可训练模型 model = Model(network = network, loss_fn=net_loss,optimizer=net_opt, metrics={"Accuracy": Accuracy()}) print("============== Starting Training ==============") model.train(10, ds_train,callbacks=[time_cb, ckpoint_cb, LossMonitor(200)],dataset_sink_mode=False) ``` ## 模型测试与可视化 ### 评估模型的有效性 ``` data_path='./data/10-verify-bin' batch_size=32 status="test" ds_eval = get_data(data_path) ds_eval = process_dataset(cifar_ds=ds_eval,batch_size=batch_size,status=status) res_train = model.eval(ds_train, dataset_sink_mode=False) res_test = model.eval(ds_eval, dataset_sink_mode=False) # 评估训练集 print('train results:',res_train) # 评估测试集 print('test results:',res_test) ``` ### 图片类别预测与可视化 ``` #创建图像标签列表 category_dict = {0:'airplane',1:'automobile',2:'bird',3:'cat',4:'deer',5:'dog', 6:'frog',7:'horse',8:'ship',9:'truck'} cifar_ds = get_data('./data/10-verify-bin') df_test = process_dataset(cifar_ds,batch_size=1,status='test') def normalization(data): _range = np.max(data) - np.min(data) return (data - np.min(data)) / _range # 设置图像大小 plt.figure(figsize=(10,10)) i = 1 # 打印9张子图 for dic in df_test: # 预测单张图片 input_img = dic[0] output = model.predict(Tensor(input_img)) output = nn.Softmax()(output) # 反馈可能性最大的类别 predicted = np.argmax(output.asnumpy(),axis=1)[0] # 可视化 plt.subplot(3,3,i) # 删除batch维度 input_image = np.squeeze(input_img,axis=0).transpose(1,2,0) # 重新归一化,方便可视化 input_image = normalization(input_image) plt.imshow(input_image) plt.xticks([]) plt.yticks([]) plt.axis('off') plt.title('True label:%s,\n Predicted:%s'%(category_dict[dic[1].sum()],category_dict[predicted])) i +=1 if i > 9 : break plt.show() ``` ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202011/22/133825tbkhzqqgj1ukiiei.png)
  • [其他问题] 卷积神经网络的一些小疑问
    我们知道卷积神经网络在各种问题中都有广泛应用,如转置卷积、空洞卷积、可变形卷积。我想了解下分组卷积及其应用场景,有没有好心人科普下
  • [其他问题] 卷积神经网络在文本分类任务中如何起作用?
    卷积神经网络在文本分类任务中如何起作用?
  • [交流分享] 【神经网络知识分享】SK-Net学习
    Selective Kernel Networks在标准的卷积网络中,每层网络中神经元的感受野的大小都是相同的。在神经学中,视觉神经元感受野的大小是由刺激机制构建的,但是在卷积网络中却很少考虑这个因素,SK-Net提出可以使神经元对不同尺寸的输入信息进行自适应的调整其感受野的大小。building block为Selective Kernel单元,存在多个分支,每个分支的卷积核的尺寸都不同,不同尺寸的卷积核最后通过softmax进行融合,分支中不同注意力产生不同的有效的感受野,多个SK单元进行堆叠构成SK-Net。SK-Net:提出一种非线性的方法融合不同核的特征进而实现感受野不同尺寸的调整,引入Selective Kernel卷积,包含三个操作:Split,Fuse,Select。 Split:产生多个不同核尺寸的通道与神经元的不同感受野尺寸相关,对于任意输入的FM,使用卷积核为3*3和5*5进行变换,变换由group/depthwise卷积、ReLu、BN等操作组成,为了进一步提高网络性能,5*5卷积核替换为dilation为2的3*3卷积核Fuse:组合融合来自多通道的信息从而获得一个全局及可理解性的表示用于进行权重选择。设计思路:设计一个门机制用于控制流入下一个卷积层中不同分支的信息流,需要融合所有分支的信息。1、通过元素求和从多个分支中融合出结果 2、使用全局平均池化操作来编码全局信息,生成信道统计信息S,s∈,C是模型图中S的特征维数或公式S的特征维数。 3、通过一个全连接层创建一个紧凑的特征Z,用于精确和自适应的选择特征,同时进行降维处理,提高效率z∈Rd*1 其中δ是relu函数,B表示批标准化,W∈Rd*c。为了研究d(全连接后的特征维数,即公式z或模型图中Z的特征维数) 对模型效率的影响,我们使用一个折减比 r 来控制其值。 L表示d的极小值Select:按照信道的方向使用softmax, 然后与Split卷积后的特征进行乘和求和操作 网络结构:每个SK单元由一个1*1的卷积,SK卷积及1*1卷积组成,原网络中所有具有较大尺寸的卷积核都替换为SK卷积使网络选择合适的感受野大小。在SK单元中,参数M决定路径的数量,即选择不同尺寸卷积核进行融合的数量。参数G控制每个路径的基数,R控制fuse操作中的参数数量。通过在自然图像中放大目标对象和缩小背景来模拟刺激,以保持图像大小不变,结果表明:当目标物体越来越大时,大多是神经元会越来越多地从更大的核路径中收集信息,SK-Net中的神经元具有自适应的感受野大小。  
  • [其他问题] 卷积神经网络问题
    在卷积神经网络中,如何计算各层感受野大小
  • [技术干货] CNN(卷积神经网络)、RNN(循环神经网络)、DNN(深度神经网络)的内部网络结构有什么区别?
    看到好多算法介绍里面有讲到所使用的网络结构,盘点了一下,基础的网络结构有CNN、RNN和DNN,那这几个网络结构有什么区别呢?各自擅长用在哪块领域?
  • [其他] 在卷积神经网络中,如何计算各层感受野的大小?
    如题,请专家们回答,谢谢!
  • [其他] 循环神经网络架构 - 扩展算法:与卷积神经网络相结合
    与卷积神经网络相结合 (参见:卷积神经网络) RNN与卷积神经网络相结合的常见例子是循环卷积神经网络(Recurrent CNN, RCNN)。RCNN将卷积神经网络的卷积层替换为内部具有递归结构的循环卷积层(Recurrent Convolutional Layer, RCL),并按前馈连接建立深度结构。 除RCNN外,RNN和卷积神经网络还可以通过其它方式相结合,例如使用卷积神经网络在每个时间步上对序列化的格点输入进行特征学习(time-distributed),并将结果输入RNN。
  • [技术干货] 卷积神经网络
    卷积神经网络是一种特殊的深层的神经网络模型,它的特殊性体现在两个方面,一方面它的神经元间的连接是非全连接的, 另一方面同一层中某些神经元之间的连接的权重是共享的(即相同的)。它的非全连接和权值共享的网络结构使之更类似于生物 神经网络,降低了网络模型的复杂度(对于很难学习的深层结构来说,这是非常重要的),减少了权值的数量。     回想一下BP神经网络。BP网络每一层节点是一个线性的一维排列状态,层与层的网络节点之间是全连接的。这样设想一下,如果BP网络中层与层之间的节点连接不再是全连接,而是局部连接的。这样,就是一种最简单的一维卷积网络。如果我们把上述这个思路扩展到二维,这就是我们在大多数参考资料上看到的卷积神经网络。
  • [热门活动] Tensorflow 2.0实现卷积神经网络CNN对MNIST数字分类
    Tensorflow 2.0实现卷积神经网络CNN对MNIST数字分类本教程演示了如何训练简单的卷积神经网络(CNN)来对MNIST数字进行分类。这个简单的网络将在MNIST测试集上实现99%以上的准确率。因为本教程使用Keras Sequential API,所以创建和训练我们的模型只需几行代码。注意:CNN使用GPU训练更快。1.    导入TensorFlowfrom __future__ import absolute_import, division, print_function, unicode_literals   import tensorflow as tf   try:     import tensorflow.keras as keras   except:     import tensorflow.python.keras as keras2.    下载预处理MNIST数据集#下载预处理MNIST数据集   (train_images, train_labels), (test_images, test_labels) = keras.datasets.mnist.load_data() train_images = train_images.reshape((60000, 28, 28, 1)) test_images = test_images.reshape((10000, 28, 28, 1))   # 特征缩放[0, 1]区间   train_images, test_images = train_images / 255.0, test_images / 255.03.    创建卷积基数下面6行代码使用常见模式定义卷积基数: Conv2D 和MaxPooling2D层的堆栈。作为输入,CNN采用形状的张量(image_height, image_width, color_channels),忽略批量大小。MNIST有一个颜色通道(因为图像是灰度的),而彩**像有三个颜色通道(R,G,B)。在此示例中,我们将配置CNN以处理形状(28,28,1)的输入,这是MNIST图像的格式,我们通过将参数input_shape传递给第一层来完成此操作。#创建卷积基数   model = keras.models.Sequential() model.add(keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1))) model.add(keras.layers.MaxPooling2D((2, 2))) model.add(keras.layers.Conv2D(64, (3, 3), activation='relu')) model.add(keras.layers.MaxPooling2D((2, 2))) model.add(keras.layers.Conv2D(64, (3, 3), activation='relu'))   print(model.summary()) Model: "sequential"_________________________________________________________________Layer (type)                 Output Shape              Param #=================================================================conv2d (Conv2D)              (None, 26, 26, 32)        320_________________________________________________________________max_pooling2d (MaxPooling2D) (None, 13, 13, 32)        0_________________________________________________________________conv2d_1 (Conv2D)            (None, 11, 11, 64)        18496_________________________________________________________________max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64)          0_________________________________________________________________conv2d_2 (Conv2D)            (None, 3, 3, 64)          36928=================================================================...在上面,你可以看到每个Conv2D和MaxPooling2D层的输出都是3D张量的形状(高度,宽度,通道),随着我们在网络中更深入,宽度和高度大小趋于缩小,每个Conv2D层的输出通道的数由第一个参数(例如,32或64)控制。通常,随着宽度和高度的缩小,我们可以(计算地)在每个Conv2D层中添加更多输出通道4.    在顶部添加密集层为了完成我们的模型,我们将最后的输出张量从卷积基(形状(3,3,64))馈送到一个或多个密集层中以执行分类。密集层将矢量作为输入(1D),而当前输出是3D张量。首先,我们将3D输出展平(或展开)为1D,然后在顶部添加一个或多个Dense层。MINST有10个输出类,因此我们使用具有10输出和softmax激活的最终Dense层。model.add(keras.layers.Flatten()) model.add(keras.layers.Dense(64, activation='relu')) model.add(keras.layers.Dense(10, activation='softmax'))   print(model.summary()) # 显示模型的架构 Model: "sequential"_________________________________________________________________Layer (type)                 Output Shape              Param #=================================================================conv2d (Conv2D)              (None, 26, 26, 32)        320_________________________________________________________________max_pooling2d (MaxPooling2D) (None, 13, 13, 32)        0_________________________________________________________________conv2d_1 (Conv2D)            (None, 11, 11, 64)        18496_________________________________________________________________max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64)          0_________________________________________________________________conv2d_2 (Conv2D)            (None, 3, 3, 64)          36928_________________________________________________________________flatten (Flatten)            (None, 576)               0_________________________________________________________________dense (Dense)                (None, 64)                36928_________________________________________________________________dense_1 (Dense)              (None, 10)                650=================================================================...从上面可以看出,在通过两个密集层之前,我们的(3,3,64)输出被展平为矢量(576)。5.    编译和训练模型model.compile(optimizer='adam',               loss='sparse_categorical_crossentropy',               metrics=['accuracy']) model.fit(train_images, train_labels, epochs=5)...Epoch 5/560000/60000 [==============================] - 15s 258us/sample - loss: 0.0190 - accuracy: 0.99416.    评估模型#评估模型   test_loss, test_acc = model.evaluate(test_images, test_labels)   print(test_acc) 10000/10000 [==============================] - 1s 92us/sample - loss: 0.0272 - accuracy: 0.99210.9921 如你所见,我们简单的CNN已经达到了超过99%的测试精度,这几行代码还不错。另一种编写CNN的方式here(使用Keras Subclassing API和GradientTape)。 本实验利用网上已有的北京房价数据集预测了北京的房价,实现了TensorFlow的线性回归应用。更多的技术内容,请访问腾科公司网站 www.togogo.net
  • [教程] 【ModelArts-Lab AI实战营】VGG模型解析(卷积神经网络)
    VGG是牛津大学的Karen Simonyan和Andrew Zisserman在挑战2014年的ILSVRC时提出的系列模型。基于模型研究和比赛结果,两人发表了论文《Very Deep Convolutional Networks For Large-Scale Image Recognition》。VGG的重要意义在于,其研究结果表明增加深度能够提高卷积神经网络的性能。在VGG之后,人们沿着更深层的网络这个方向,取得了一系列新的进展。本文结合原作者的论文,解析VGG模型的结构和基本原理。过程中会简单介绍卷积神经网络的一些基本要点。卷积神经网络卷积和池化是卷及神经网络(以下简称CNN)中的核心。我们使用CNN处理图像时,通过设置卷积核的尺寸和深度,以及池化层的大小,完成图像的特征提取。一般而言,计算机中的图像按照RGB颜色模式存储,本质上是一个(width, height, channels)的三维数组,其中channels为3,代表RGB三个颜色通道,每个通道是一个(width, height)的二维数组,我们通过一个n*n的参数矩阵,对二维数组进行矩阵点乘(每个元素对应相乘),然后将结果矩阵的值相加,计为输出矩阵中的一个单位值。这个过程如下图所示:卷积核还有一个参数深度,表示输出多少个新的矩阵,因此,直观的理解,通过卷积操作之后,图像的尺寸下降而深度增加,我们得到的是更为抽象的信息,例如颜色、轮廓等。卷积之后的矩阵中,相邻元素表示的是相似的信息,我们通过池化将所有信息进行合并。池化也是一个类似卷积的过程,我们通过一个矩阵对二维数组进行扫描,只是该矩阵不带参数,扫描的区域的值简单的进行取最大值或者平均值的操作,将相似信息进行提取。池化的过程如下图所示:VGG模型基本结构通过前面的描述,我们知道卷积核的大小是非常重要的,VGG模型的研究表明,较深的层+较小的卷积核,在特征提取上可以取得更好的效果。VGG是一系列模型,有不同的配置,编号从A到E,深度不断增加,如下表所示: 由于VGG最初用于ImageNet数据集的分类任务,所以输入图片统一尺寸为(224, 224)。整个网络中都用了3x3大小的卷积核,并配合1x1的卷积核进行简单的线型转变(不改变图片大小)。卷积核名字中-之后的数值表示卷积核输出的深度,随着网络深度的增加,卷积核输出深度从64逐步增加到256,而网络深度也从11层增加到19层,这其中包括了最后的3个全连接层。这就是VGG模型的基本结构,非常简单,但取得了非常好的效果,同时也非常易于扩展。VGG模型的研究向我们揭示了什么VGG模型本身非常简单,很容易理解,在VGG模型的实践中,作者通过实验和对比,发现了很多有趣的规律。例如上面提到的"较深的网络+较小的卷积核"可以取得更好的特征提取性能。下面,我们一一介绍作者的发现。"深网络+小卷积核"首先我们了解一下"感受野"的概念。简单的说,感受野就是通过卷积网络之后,输出矩阵的单位对应原矩阵区域的大小。例如,一个5x5的图像,经过3x3的卷积之后,尺寸变为3x3,新的矩阵中一个元素对应原始矩阵中的3x3区域。作者提到,2个3x3的卷基层和1个5x5的卷基层,感受野(receptive field)是一致的,都是4x 4,但是最终实验的结果却表明,前者的效果要优于后者。作者还对比了3x3卷积层和1个7x7卷积层,得到了相同的对比结果。同时,使用深网络+小卷积核还有一个好处,那就是参数较少。假设一个卷积核的深度为C,那么3个3x3卷积核需要的参数为3^2 * C^2 * 3,即27 * C^2(C^2表示C的平方),而1个7x7的卷积核的参数个数为7^2 * C^2,即49 * C^2,后者多出了81%的参数。pretrain与fine tune作者在训练模型时,基本延续了2012年ILSVRC冠军模型AlexNet的训练参数配置,包括对AlexNet的LRN进行了对比(最后发现加入LRN并不会对VGG模型有明显的提升)。最终的训练结果显示,学习率下降了3倍,而且在370K个迭代(74 epochs)就结束了训练。作者认为有2个原因:1,"深度网络+小卷积核"隐含的实现了数据的正态化;2,作者使用了预训练与微调的训练方式。前面我们提到,VGG系列模型从A到E,深度不断增加。作者在训练时,先使用随机初始化对模型A进行训练,然后将训练得到的权重来初始化模型B,模型B只比A多了两层卷积,这两层卷积依然采用随机初始化。这样,有效的降低了模型B的训练时间。不过,作者在提交比赛结果之后发现,使用论文《Understanding the difficulty of training deep feedforward neural networks》的方法,也可以直接使用随机初始化进行训练,不需要预训练参数。图像多尺寸缩放作者在训练模型时,对图像的尺寸进行了调整。ImageNet比赛中的图片尺寸都是224x224,因此,作者将输入图片进行了缩放,设缩放后的图片最小边长为S,然后使用224x224的尺寸对图片进行裁剪,缩放时保证S>=224。当:S=224时,裁剪时可以覆盖全部图片S>>224时,即S远大于224,这时裁剪的结果只能覆盖部分图片,覆盖的范围是图片中的一个物体或物体的一部分。那么,如何缩放图片呢?作者提出了两种方法,一种是S取固定值,先将S固定为256(参考了AlexNet的训练参数)进行训练,然后再基于训练结果将S设置为384,继续训练。第二种方法则是多缩放值训练,在一个范围[S_min, S_max]内随机取值并赋给S(实践中取S_min=256, S_max=512),然后进行训练。因为现实中输入图片的尺寸可能各不相同,这种训练方式可以获得更好的泛化性。同时,作者仍然使用了预训练的思想,以S=384的固定值训练为基础,进行多缩放值的训练。在验证阶段,作者也提出了图片缩放的思想。假设验证时,图片缩放后的最小值为Q,也使用了2种取值方法。第一种为Q取固定值,针对S不同的取值情况:S取固定值时,Q=SS在[S_min, S_max]范围时,Q=0.5(S_min + S_max)第二种为Q取多种值:S取固定值时,Q 从 集合{S-32, S, S+32}中取值S在[S_min, S_max]范围时,Q从集合{ S_min, 0.5(S_min+S_max), S_max }中取值在训练和验证阶段,作者发现对图片进行多值缩放,都可以取得更好的效果。后记以上对VGG模型进行了简单的介绍。人工智能领域的发展是非常迅猛的,作为一个2014年提出的经典模型,VGG虽然被后来的模型超越,但是它给我们带来了很多重要的启示。如卷积网络深度增加可以获得更好的效果,沿着这个方向,人们发现简单的堆叠层并不能获得更好的精度,反而出现了精度的下降,继而诞生了ResNet,将训练深度增加到最多152层;预训练权重对后续模型的初始化,在一定程度上解决了增加深度后,梯度无法收敛的问题;以及图像多值缩放取得更好的泛化效果,指出对数据进行补益可以提高模型效果。在后面的系列文章中,我们还会沿着VGG支出的方向,以及它带给我们的启示,介绍更多的模型和视觉领域的新成果。
  • [教程] 【ModelArts-Lab AI实战营】ResNet模型解析(卷积神经网络)
    从2012年开始,卷积神经网络(Convolutional Neural Networks, CNN)极速发展,不断涌现出诸如AlexNet、VGGNet等优秀的神经网络。到了2015年,一个新型的网络更是颠覆了计算机视觉领域和深度学习领域,这就是ResNet。ResNet(Residual Neural Network)由微软研究院的何凯明等四名华人提出,其论文《Deep Residual Learning for Image Recognition》一举摘得CVPR2016最佳论文,下图就是它在 ILSVRC 和 COCO 2015 上的战绩。残差学习人们在探索深度学习网络的过程中,发现了“网络越深,效果越好”这一规律,从Alexnet的7层发展到了VGG的16乃至19层。然而在继续加深网络的时候遇到了问题:网络越深,模型训练难度越大,收敛速度变得很慢;当网络深度达到一定深度的时候,模型的效果很难再提升;甚至在继续增加深度时出现错误率提高的情况。出现这样类似“退化”的问题,主要是由于网络深度的增加,带来的在网络训练的时候,梯度无法有效的传递到浅层网络,导致出现梯度弥散(vanishing)。何凯明等人提出的残差结构就很好地解决了这个问题。残差的基本结构如下图所示:这有点类似与电路中的“短路”,所以是一种短路连接(shortcut connection),该残差块也被称为shortcut。它的原理是:对于一个堆积层结构(几层堆积而成)当输入为 x 时,其学习到的特征记为 H(x) ,现在我们希望其可以学习到残差 F(x)=H(x)-x ,这样其实原始的学习特征是 F(x)+x 。之所以这样是因为残差学习相比原始特征直接学习更容易。当残差为 0 时,此时堆积层仅仅做了恒等映射,至少网络性能不会下降,实际上残差不会为 0,这也会使得堆积层在输入特征基础上学习到新的特征,从而拥有更好的性能。总的来看,该层的神经网络可以不用学习整个的输出,而是学习上一个网络输出的残差,因此ResNet又叫做残差网络。ResNet网络结构作者为了表明残差网络的有效性,使用如下三种网络进行对比。其一为 VGG-19 网络(这是 VGG paper 中最深的亦是最有效的一种网络结构),另外则是顺着VGG网络思路继续简单地加深层次而形成的一种 VGG 朴素网络,它共有34个含参层。最后则是与上述34层朴素网络相对应的 Resnet 网络,由前面介绍的残差单元来构成。在论文中可以看到详细的实验对比结果,ResNet 的结构可以极快的加速神经网络的训练,收敛性能好;模型的准确率有比较大的提升,分类性能好。在 ResNet 中的网络结构单元被称为模块——block,其中会用到两种残差模块:一种是以两个 3x3 的卷积网络串接在一起作为一个残差模块,用于34-layer;另外一种,考虑到实际计算的时间和效率问题,作者提出了命名为 bottleneck 的结构块来代替常规的 Resedual block,将 1x1 、3x3、1x1 的3个卷积网络串接在一起作为一个残差模块,常用于层数更多的网络中。如下图所示。除上面展示的34-layer的ResNet,还可以构建更深的网络,如下表所示。上面一共提出了5种深度的ResNet,分别是18,34,50,101和152。比较常用的是50-layer,101-layer,152-layer。他们都是由上述的残差模块堆叠在一起实现的。在此以ResNet50为例,拆解其结构,使读者有更直观的了解。在Keras中,ResNet50的网络的整体结构示例为:data  1,3,224,224 conv  filter=64, kernel_size=7, pad=3,stride=2 1,64,112,112 bn activation('relu') maxpool kernel_size=3,stride=2  1,64,56,56 # block 1  (64,64,256) conv_block() in:1,64,56,56 filter=(64,64,256),out=1,256,56,56 identity_block  in=1,256,56,56, filter=(64,64,256),out=1,256,56,56 identity_block  in=1,256,56,56, filter=(64,64,256),out=1,256,56,56 # block 2  (128,128,512) conv_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28 identity_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28 identity_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28 identity_block  in=1,256,56,56 filter=(128,128,512),out=1,512,28,28 # block 3 (256,256,1024) conv_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14 identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14 identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14 identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14 identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14 identity_block  in=1,512,28,28 filter=(256,256,1024),out=1,1024,14,14 # block 4 (512,512,2048) conv_block  in=1,1024,14,14 filter=(512,512,2048),out=1,2048,7,7 identity_block  in=1,1024,14,14 filter=(512,512,2048),out=1,2048,7,7 identity_block  in=1,1024,14,14 filter=(512,512,2048),out=1,2048,7,7 maxpool kernel_size=7, stride=1 out=1,2048,1,1 flatten dence(1,1000) acivation('softmax') probbility(1,1000)在Keras代码中定义该网络模型,如下:def resnet_model(out_class, input_shape):     inputs = Input(shape=input_shape) #1,3,224,224     #     x = Conv2D(64, (7, 7), strides=2, padding='same')(inputs) #conv1  1,64,112,112     x = BatchNormalization(axis=-1)(x) #bn_conv1     x = Activation('relu')(x) #conv1_relu     x = MaxPool2D(pool_size=(3,3),strides=2)(x) # 1,64,56,56     # block1  (64,64,256) 1,2 in:1,64,56,56     x = conv_block(x, [64, 64, 256]) #out=1,256,56,56     x = identity_block(x, [64, 64, 256]) #out=1,256,56,56     x = identity_block(x, [64, 64, 256]) #out=1,256,56,56     # block2  (128,128,512) 1,3 in:1,256,56,56     x = conv_block(x, [128,128,512]) #out=1,512,28,28     x = identity_block(x, [128,128,512]) #out=1,512,28,28     x = identity_block(x, [128,128,512]) #out=1,512,28,28     x = identity_block(x, [128, 128, 512])  # out=1,512,28,28     # block 3 (256,256,1024) 1,5 in:1,512,28,28     x = conv_block(x, [256,256,1024])  # out=1,1024,14,14     x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14     x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14     x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14     x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14     x = identity_block(x, [256, 256, 1024])  # out=1,1024,14,14     # block 4 (512,512,2048) 1,2 in:1,1024,14,14     x = conv_block(x, [512,512,2048])  # out=1,2048,7,7     x = identity_block(x, [512, 512, 2048])  # out=1,2048,7,7     x = identity_block(x, [512, 512, 2048])  # out=1,2048,7,7     # maxpool kernel_size=7, stride=1 out=1,2048,1,1     x = MaxPool2D(pool_size=(7, 7), strides=1)(x)     # flatten     x = Flatten()(x)     # Dense     x = Dense(classes, activation='softmax')(x) # out=1,1000     model = Model(inputs=inputs, outputs=out)     return model下面是一些ResNets的其他特征:网络较深,控制了参数数量。存在明显层级,特征图个数层层递进,保证输出特征的表达能力。使用较少池化层,大量采用下采样,提高传播效率。没有使用 dropout,利用 Batch Normalization 和全局平均池化进行正则化,加快训练速度。层数较高时减少了3x3卷积核的个数,用1x1卷积核控制3x3卷积的输入输出特征 map 的数量。深度残差网络的提出是CNN图像史上的一件里程碑事件,随着对其的不断深入研究,有很多 ResNet 的变体已经出现,如:ResNeXt、DenseNet、WideResNet等,有待读者继续深入关注和了解。
总条数:75 到第
上滑加载中