• [其他] 文字识别方法全面整理
    文字识别也是目前CV的主要研究方向之一。本文主要总结目前文字识别方向相关内容,包括单独文字识别以及结合文字检测和文字识别的端到端的文字识别。希望这篇文章能够帮助各位。 图0 文字检测Detection与文字识别Recognition对于文字识别,实际中一般首先需要通过文字检测定位文字在图像中的区域,然后提取区域的序列特征,在此基础上进行专门的字符识别。但是随着CV发展,也出现很多端到端的End2End OCR。文字检测(Text Detection)文字检测定位图片中的文本区域,而Detection定位精度直接影响后续Recognition结果。图1.1如图1.1中,红框代表“LAN”字符ground truth(GT),绿色框代表detection box。在GT与detection box有相同IoU的情况下,识别结果差异巨大。所以Detection对后续Recognition影响非常大! 目前已经有很多文字检测方法,包括:EAST/CTPN/SegLink/PixelLink/TextBoxes/TextBoxes++/TextSnake/MSR/... 其中CTPN方法的介绍如下:场景文字检测—CTPN原理与实现https://zhuanlan.zhihu.com/p/34757009文字识别(Text Recognition)识别水平文本行,一般用CRNN或Seq2Seq两种方法(欢迎移步本专栏相关文章):• CRNN:**CNN+RNN+CTC**一文读懂CRNN+CTC文字识别https://zhuanlan.zhihu.com/p/43534801• CNN+Seq2Seq+AttentionSeq2Seq+Attention原理介绍https://zhuanlan.zhihu.com/p/51383402对应OCR代码如下https://github.com/bai-shang/crnn_seq2seq_ocr_pytorch对于特定的弯曲文本行识别,早在CVPR2016就已经有了相关paper:• Robust Scene Text Recognition with Automatic Rectification. CVPR2016.arxiv.org/abs/1603.03915图2.1对于弯曲不规则文本,如果按照之前的识别方法,直接将整个文本区域图像强行送入CNN+RNN,由于有大量的无效区域会导致识别效果很差。所以这篇文章提出一种通过STN网络学习变换参数,将Rectified Image对应的特征送入后续RNN中识别。图2.2其中Spatial Transformer Network(STN)指:arxiv.org/abs/1506.02025核心就是将传统二维图像变换(如旋转/缩放/仿射等)End2End融入到网络中。具体二维图像变换知识请翻阅:Homograph单应性从传统算法到深度学习:https://zhuanlan.zhihu.com/p/74597564• Scene Text Recognition from Two-Dimensional Perspective. AAAI2018.该篇文章于MEGVII 2019年提出。首先在文字识别网络中加入语义分割分支,获取每个字符的相对位置。图2.4其次,在获取每个字符位置后对字符进行分类,获得文字识别信息。该方法采用分类解决识别问题,并没有像传统方法那样使用RNN。图2.5除此之外,在文章中还是使用了Deformable Convolution可变形卷积。相比传统3x3卷积,可变形卷积可以提取文字区域不同形状的特征。图2.6• SqueezedText: A Real-time Scene Text Recognition by Binary Convolutional Encoderdecoder Network. AAAI2018.https://ren-fengbo.lab.asu.edu/sites/default/files/16354-77074-1-pb.pdf该文章引入二值层(-1 or +1)部分替换CRNN中的float浮点卷积,核心是使用很小的网络进行识别。• Handwriting Recognition in Low-resource Scripts using Adversarial Learning. CVPR2019.arxiv.org/pdf/1811.01396.pdf• ESIR: End-to-end Scene Text Recognition via Iterative Image Rectification. CVPR2019.http:openaccess.thecvf.com/content_CVPR_2019/papers/Zhan_ESIR_End-To-End_Scene_Text_Recognition_via_Iterative_Image_Rectification_CVPR_2019_paper.pdf图2.7ESIR采用cascade R-CNN级联思路,通过3次变换将弯曲字符变换为水平,再经过LSTM识别。具体变换思路请查阅论文。End2End OCR (Detection+ Recognition)由于End2End OCR同时涉及文字检测+文字识别两个方向,对于不熟悉的读者建议首先阅读上述CTPN/CRNN/Seq2Seq三篇文章了解相关内容(当然求点赞喽)。在之前介绍的算法中,文字检测和文字识别是分为两个网络分别完成的,所以一直有研究希望将OCR中的Detection+ Recognition合并成一个End2End网络。目前End2End OCR相关研究如下:• Towards End-to-end Text Spotting with Convolutional Recurrent Neural Networks. ICCV2017.http:openaccess.thecvf.com/content_ICCV_2017/papers/Li_Towards_End-To-End_Text_ICCV_2017_paper.pdf图3.1该篇文章采用Faster R-CNN的Two-stage结构:首先Text Proposal Network(即RPN)生成对应的文本区域Text Proposal,后续通过Bounding Box regression和Box Classification进一步精修文本位置。但是不同的是,在RoI Pooling后接入一个LSTM+Attention的文字识别分支中,如图3.2。由于识别与之前介绍的文字识别方法大同小异,后续不再重复介绍。图3.2但是这样的结构存在问题。举例说明:Faster R-CNN的RPN只是初步产生Proposal,后续还需要再经过一次Bounding Box regression才能获取准确的检测框,该问题在CTPN论文(arxiv.org/abs/1609.03605)中有说明,如图3.3:图3.3 CTPN文章中提及RPN生成Proposal不准的问题所以Text Proposal不一定很准会对后续识别分支产生巨大影响,导致该算法在复杂数据集上其实并不是很work。• Deep TextSpotter: An End-to-End Trainable Scene Text Localization and Recognition Framework. ICCV2017.http:openaccess.thecvf.com/content_ICCV_2017/papers/Busta_Deep_TextSpotter_An_ICCV_2017_paper.pdf图3.4 Deep TextSpotter在与Faster R-CNN不同,Deep TextSpotter生成的Region Proposal包含6个数值: 其中 代表Proposal box在图像中的位置, 代表Proposal box与水平方向的夹角, 代表置信度confidence。 对于Region Proposal所在的特征 ,通过双线性插值可以获得 固定高度的变换后的特征 , 其中 代表双线性采样核,本质就是传统的图像旋转+缩放插值变换。图3.5在获得 后,显然可以后接RNN+CTC进行识别。可以看到Deep TextSpotter通过学习角度 ,将proposal通过双线性插值变换为固定高度的水平特征,然后再进行识别,达到一种End2End的效果。与同时期的上一个方法类似,同样存在RPN生成Proposal不准导致识别率低的问题,所以在复杂数据集实际效果可能并不是太好。图3.6 Deep TextSpotter对应的CTC识别• Attention-based Extraction of Structured Information from Street View Imagery. ICDAR2017.arxiv.org/abs/1704.03549图3.7 spatial attention ocr该文章由Google在2017年提出,主要针对多视角的街景采集数据进行OCR,其关键点为:1. 利用CNN提取不同视角的图片的特征,并将特征concat为一个大的特征矩阵2. 计算图片中文的spatial attention , 越大该区域为文字区域的概率越大3. 通过 抽取 中文字区域特征 ,并送入后续RNN进行识别该方法利用spatial attention(arxiv.org/pdf/1502.03044v3.pdf)进行端到端OCR,相比检测+检测方法更加新颖。• Mask TextSpotter: An End-to-End Trainable Neural Network for Spotting Text with Arbitrary Shapes. ECCV2018.arxiv.org/abs/1807.02242图3.8 Mask TextSpotter该方法由旷视科技 (www.zhihu.com/people/c26b4202ed6af1379f52a967235d94b2) 在2018年提出,主要用于解决不规则弯曲字符End2End的识别问题。相比倾斜字符,处理弯曲不规则字符更难,无法简单通过Proposal角度 对特征进行变换。Mask TextSpotter借鉴了Mask RCNN,首先由RPN网络生成Proposal,再由Faster R-CNN分支对Proposal做进一步分类和位置回归,同时通过Mask分支分割出文本所在区域Global word map和每个字符所在中心Background map。这样不仅可以获得整个文本word区域,还可以获得每个字符character区域。图3.9 Mask TextSpotter进行文字识别在文字识别方面Mask TextSpotter设计0~1和A~Z共计36个“one-hot”形式的Character map进行分类,即没有使用RNN直接强行分类。如果用Mask TextSpotter识别汉字,则需要设计4000+ Character map,这显然是不科学的。另外该方法在识别过程中也没有用到文字的序列信息(总体来说该方法与之前的Scene Text Recognition from Two-Dimensional Perspective思路类似)。• Towards End-to-End License Plate Detection and Recognition: A Large Dataset and Baseline. ECCV2018.http:openaccess.thecvf.com/content_ECCV_2018/papers/Zhenbo_Xu_Towards_End-to-End_License_ECCV_2018_paper.pdf在该文章中提出一个包含250k图的中国车牌数据集CCPD,每个标注包含1个box+4个定位点+识别文字GT:图3.10 车牌数据集CCPD在网络方面该文章提出一种PRNet:1. 利用Box Regression layer层预测车牌位置 ;2. 检测出来 确定位置后,采集对应不同尺度的特征图进行ROI Pooling;3. 把不同尺度特征拼接在一起,进行识别。图3.11 PRNet该文章核心内容就是推出了一个车牌OCR数据集CCPD,并在这个数据集上提出一种BaseLine方法。该方向研究人员可以尝试使用该数据集。在这里特别感谢一下所有开放数据集的研究人员!数据才是cv第一生产力!• An end-to-end TextSpotter with Explicit Alignment and Attention. CVPR2018.http:openaccess.thecvf.com/content_cvpr_2018/papers/He_An_End-to-End_TextSpotter_CVPR_2018_paper.pdf改文章与Deep TextSpotter比较类似,首先生成带有角度 的倾斜Text Proposal,然后通过类似于RoI Pooling的Text-alignment提取固定长度的feature sequence,再送入RNN+Seq2Seq+Attention结构进行识别。图3.13与Deep TextSpotter不同的是,Text-alignment在通过双线性插值提取到整个Proposal特征后,再通过一组Inception卷积获取feature sequence送入RNN,而不是直接把双线性插值结果送入RNN。图3.15• FOTS: Fast Oriented Text Spotting with a Unified Network. CVPR2018.arxiv.org/abs/1801.01671FOTS采用Single-Shot结构结合(arxiv.org/abs/1612.03144)直接检测文字区域,输出带角度 的Bounding Box;之后利用双线性插值RoIRotate获取固定大小的特征,送入双向LSTM进行识别。图3.16 FOTS Architecture图3.17 FPN图3.18 RoIRotate由于使用Single-Shot结构,所以应该是相对“Fast”一点。• SEE: Towards Semi-Supervised End-to-End Scene Text Recognition. AAAI2018.arxiv.org/abs/1712.05404图3.19图3.20另外SEE作者2017年在arXiv上放出STN-OCR的论文,应该是没有中任何会议。考虑到完整性也挂在这里。arxiv.org/abs/1707.08831来自 | 知乎    作者 | 白裳链接 | https://zhuanlan.zhihu.com/p/65707543
  • [其他] Vision Transformer 模型工作机制的最新理论
    在深度神经网络之后,以多头自注意力机制为核心的Vision Transformer因其对输入全局关联的强大建模能力得到了广泛应用和研究。尽管现有研究在模型结构、损失函数、训练机制等方面提出了诸多改进,但少有研究对Vision Transformer的工作机制进行了深入探索。本文为ICLR 2022中的亮点论文之一,提供了不同解释来帮助理解Vision Transformer (ViT)的优良特性:1)多头自注意力机制不仅提高了精度,而且通过使损失的超平面变得平坦,提高了泛化程度;2)多头自注意力机制和卷积模块表现出相反的行为。例如,多头自注意力机制是低通滤波器,而卷积模块是高通滤波器;3)多层的神经网络的行为就像一系列小的个体模型的串联;4)最后阶段的卷积模块在预测中起着关键作用。
  • [技术干货] 【MindSpore】一种参数归一化实现方式
    1. 功能描述:MindSpore实现WeightNorm参数归一化。2. 实现分析:在MindSpore实现高性能方案,建议采用图模式,同时也能保证动静统一。MindSpore图模式需要把归一化操作表达到整图里,可以采用自定义的方式在网络结构中实现。3. 参数归一化功能简介(背景介绍):在深度学习中通常对卷积层的权重进行参数归一化,参数归一化功能根据以下公式对传入的 layer 中的权重参数进行归一化:image.png公式中w是网络权重,g 代表长度变量 ,v代表方向变量。权重归一化可以将神经网络中权重w的向量长度g与其方向v解耦,将w用g和v两个变量表示。 (例如:详细可以参考论文: https://arxiv.org/pdf/1602.07868.pdf。)4. 解决方案:实现MindSpore的WeightNorm需要注意:4.1 MindSpore实现时,需要封装一个Wrapper,将WeightNorm和需要进行参数归一化的网络结构(如卷积)封装为一个整体,这样每次在卷积执行之前,就会先执行WeightNorm。具体伪代码如下:class WeightNorm(nn.Cell):    def __init__(self):        ...        register_w_v_g()        self.layer = layer    def construct(self, inputs):        compute_weight_norm()        result = self.layer(inputs)        return result4.2 使用参数归一化需要能够添加和删除weight norm,但MindSpore静态图编译后无法删除Weight Normremove_weight_norm的场景:4.2.1 inference,即推理阶段需要移除Weight Norm。4.2.2 进行一次Weight Norm计算,然后固定w(WeightNorm.remove()的执行逻辑)remove_weight_norm的使用场景,即模型进行推理时,在加载Checkpoint后进行操作,此时未涉及到静态图的编译阶段,因此可以对实例化的模型进行任意修改。PS: 静态图不支持在训练过程中移除weight norm。MindSpore WeightNorm示例:class WeightNorm (nn.Cell):      def __init__(self, module, dim:int=0):           super().__init__()           if dim is None:               dim = -1          self.dim = dim          self.module = module          self.assign = P.Assign()          # add g and v as new parameters and express w as g/||v|| * v          self.param_g = Parameter(Tensor(norm_except_dim(self.module.weight, 2, dim)))          self.param_v = Parameter(Tensor(self.module.weight.data))          self.module.weight.set_data(_weight_norm(self.param_v, self.param_g, self.dim))          self.use_weight_norm = True     def construct(self, *inputs, **kwargs):           if not self.use_weight_norm:               return self.module(*inputs, **kwargs)          self.assign(self.module.weight, _weight_norm(self.param_v, self.param_g, self.dim))              return self.module(*inputs, **kwargs)     def remove_weight_norm(self):          self.assign(self.module.weight, _weight_norm(self.param_v, self.param_g, self.dim))          self.use_weight_norm = False4.3 use_weight_norm可以达到移除WeightNorm的目的。即调用remove_weight_norm方法后,将self.use_weight_norm设置为False,当再次construct函数时,就会直接调用self.module,忽略Weight Norm计算。4.4 self.param_g = Parameter(Tensor(norm_except_dim(self.module.weight, 2, dim)))实现 w和 ||v|| 的计算,静态图不支持getattr方法,考虑到MindSpore的nn层设计,就固定module的权重为module.weight。def norm_except_dim(v, pow, dim):    if dim == -1:       return mnp.norm(v, pow)    elif dim == 0:       output_size = (v.shape[0],) + (1,) * (v.ndim - 1)       return mnp.norm(v.view((v.shape[0], -1)), pow, 1).view(output_size)    elif dim == (v.ndim - 1):       output_size = (1,) * (v.ndim - 1) + (v.shape[v.ndim - 1])       return mnp.norm(v.view((-1, v.shape[v.ndim - 1])), pow, 0).view(output_size)    else:       return norm_except_dim(v.swapaxes(0, dim), pow, dim).swapaxes(0,dim)def _weight_norm(v, g, dim):    return v * (g / norm_except_dim(v, 2, dim))4.5 上述代码WeightNorm中,self.module.weight是要进行归一化的网络权重,self.param_g是长度变量,self.param_v是方向变量, 其中norm_except_dim函数用于计算指定维度的长度。5. MindSpore的WeightNorm简单使用方式  #assume we need apply weight norm on nn.Dense layer   m = WeightNorm(nn.Dense(20, 40))   #m.param_g.shape is (40, 1)   #m.param_v.shape is (40, 20)   #use m as normal nn.Dense   inputs = Tensor(np.random.randn(10, 20), mstype.float32)   outputs = m(inputs)   #if you want to remove weight norm, just call it   m.remove_weight_norm()   #m.use_weight_norm == False————————————————原文链接:https://blog.csdn.net/qingshuibaifen/article/details/121610743
  • [技术干货] MindSpore优化过程可视化
    概述神经网络训练本质上是高维非凸函数的优化过程,一般可以通过梯度下降方法发现最小值点(如图1所示)。而一般的神经网络参数多达几万甚至几十万,较难直接在三维空间展示其优化地形。用户通过本功能,能够基于方向降维和绘制计算,将神经网络训练路径周围的优化空间展示出来。具体使用步骤共分为两步,以LeNet为例,分类任务,数据集为MNIST,训练数据收集:在训练过程中,利用SummaryCollector的形式收集多个模型前向网络权重,地形图绘制所需参数(如期望绘制区间,地形图分辨率等),代码如下:import mindspore.dataset as dsimport mindspore.dataset.vision.c_transforms as CVimport mindspore.dataset.transforms.c_transforms as Cfrom mindspore.dataset.vision import Interfrom mindspore import dtype as mstypeimport mindspore.nn as nnfrom mindspore.common.initializer import Normalfrom mindspore import contextfrom mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor, TimeMonitor, SummaryCollectorfrom mindspore import Modelfrom mindspore.nn import Accuracyfrom mindspore import set_seedset_seed(1)def create_dataset(data_path, batch_size=32, repeat_size=1,                   num_parallel_workers=1):    """    create dataset for train or test    """    # define dataset    mnist_ds = ds.MnistDataset(data_path, shuffle=False)    resize_height, resize_width = 32, 32    rescale = 1.0 / 255.0    shift = 0.0    rescale_nml = 1 / 0.3081    shift_nml = -1 * 0.1307 / 0.3081    # define map operations    resize_op = CV.Resize((resize_height, resize_width), interpolation=Inter.LINEAR)  # Bilinear mode    rescale_nml_op = CV.Rescale(rescale_nml, shift_nml)    rescale_op = CV.Rescale(rescale, shift)    hwc2chw_op = CV.HWC2CHW()    type_cast_op = C.TypeCast(mstype.int32)    # apply map operations on images    mnist_ds = mnist_ds.map(operations=type_cast_op, input_columns="label", num_parallel_workers=num_parallel_workers)    mnist_ds = mnist_ds.map(operations=resize_op, input_columns="image", num_parallel_workers=num_parallel_workers)    mnist_ds = mnist_ds.map(operations=rescale_op, input_columns="image", num_parallel_workers=num_parallel_workers)    mnist_ds = mnist_ds.map(operations=rescale_nml_op, input_columns="image", num_parallel_workers=num_parallel_workers)    mnist_ds = mnist_ds.map(operations=hwc2chw_op, input_columns="image", num_parallel_workers=num_parallel_workers)    # apply DatasetOps    buffer_size = 10000    mnist_ds = mnist_ds.shuffle(buffer_size=buffer_size)  # 10000 as in LeNet train script    mnist_ds = mnist_ds.batch(batch_size, drop_remainder=True)    mnist_ds = mnist_ds.repeat(repeat_size)    return mnist_dsclass LeNet5(nn.Cell):    """    Lenet network    Args:        num_class (int): Number of classes. Default: 10.        num_channel (int): Number of channels. Default: 1.    Returns:        Tensor, output tensor    Examples:    LeNet(num_class=10)    """    def __init__(self, num_class=10, num_channel=1, include_top=True):        super(LeNet5, self).__init__()        self.conv1 = nn.Conv2d(num_channel, 6, 5, pad_mode='valid', weight_init=Normal(0.02))        self.conv2 = nn.Conv2d(6, 16, 5, pad_mode='valid', weight_init=Normal(0.02))        self.relu = nn.ReLU()        self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2)        self.include_top = include_top        if self.include_top:            self.flatten = nn.Flatten()            self.fc1 = nn.Dense(16 * 5 * 5, 120)            self.fc2 = nn.Dense(120, 84)            self.fc3 = nn.Dense(84, num_class)    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)        if not self.include_top:            return x        x = self.flatten(x)        x = self.relu(self.fc1(x))        x = self.relu(self.fc2(x))        x = self.fc3(x)        return xdef train_lenet():    context.set_context(mode=context.GRAPH_MODE, device_target="GPU")    data_path = YOUR_DATA_PATH    ds_train = create_dataset(data_path)    network = LeNet5(10)    net_loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction="mean")    net_opt = nn.Momentum(network.trainable_params(), 0.01, 0.9)    time_cb = TimeMonitor(data_size=ds_train.get_dataset_size())    config_ck = CheckpointConfig(save_checkpoint_steps=1875, keep_checkpoint_max=10)    ckpoint_cb = ModelCheckpoint(prefix="checkpoint_lenet", config=config_ck)    model = Model(network, net_loss, net_opt, metrics={"Accuracy": Accuracy()})    summary_dir = "./summary/lenet_test2"    interval_1 = [x for x in range(1, 4)]    interval_2 = [x for x in range(7, 11)]    ##Collector landscape information    summary_collector = SummaryCollector(summary_dir, keep_default_action=True,                                         collect_specified_data={'collect_landscape': {'landscape_size': 40,                                                                                       'unit': "epoch",                                                                                       'create_landscape': {'train': True,                                                                                                            'result': True},                                                                                       'num_samples': 512,                                                                                        'intervals': [interval_1,                                                                                                      interval_2                                                                                                      ]                                                                                        }                                                                },                                        collect_freq=1)在这时需要注意的是:1. callback_fn: 用户需要定义函数callback_fn,该函数没有输入,返回model(mindspore.train.Model),network(mindspore.nn.Cell),dataset(mindspore.dataset),metrics(mindspore.nn.Metrics) 。2. collect_landscape: 参数定义与SummaryCollector一致,这里用户可以自由修改绘图参数。3. device_ids: 指定地形图绘制所需要device_ids,支持单机多卡计算。4. device_target: 指定device的类型,如GPU、Ascend或CPU。    print("============== Starting Training ==============")    model.train(10, ds_train, callbacks=[time_cb, ckpoint_cb, LossMonitor(), summary_collector])if __name__ == "__main__":    train_lenet()summary_dir设置了参数的保存路径。summary_collector为初始化的SummaryCollector实例。其中collector_specified_data中的collect_landscape以字典的形式包含了绘制地形图所需要的所有参数设置:landscape_size: 表示地形图的分辨率。40表示地形图的分辨率是40*40。分辨率越大,地形图纹理越细致,同时计算消耗时间也会越久。unit: 表示训练过程中保存参数的间隔单位,分为epoch/step。使用step时,须在model.train中设置dataset_sink_model=False。create_landscape: 表示绘制地形图的方式,目前支持训练过程地形图(带训练轨迹)与训练结果地形图(不带轨迹)。num_samples: 表示绘制地形图数据集的样本数量。512表示地形图所需样本是512。样本数越大,地形图越精确,同时计算消耗时间也会越久。intervals: 表示绘制地形图的区间。如interval_1表示绘制带训练轨迹1-5epoch地形图。地形图绘制:利用训练过程中保存的模型参数,模型与数据集与训练一致,启动新的脚本,正向计算生成地形图信息,不用再次进行训练。(适用于单卡或多卡并行计算绘制地形图)代码如下:from mindspore.nn import Lossfrom mindspore.train.callback import SummaryLandscapedef callback_fn():    network = LeNet5(10)    net_loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction="mean")    metrics = {"Loss": Loss()}    model = Model(network, net_loss, metrics=metrics)    data_path = YOUR_DATA_PATH    ds_eval = create_dataset(data_path)    return model, network, ds_eval, metricsif __name__ == "__main__":    interval_1 = [x for x in range(1, 4)]    interval_2 = [x for x in range(7, 11)]    summary_landscape = SummaryLandscape('./summary/lenet_test2')    # generate loss landscape    summary_landscape.gen_landscapes_with_multi_process(callback_fn,                                                        collect_landscape={"landscape_size": 40,                                                                           "create_landscape": {"train": True,                                                                                                "result": True},                                                                           "num_samples": 512,                                                                           "intervals": [interval_1, interval_2                                                                                        ]},                                                        device_ids=[1, 2],                                                        device_target="GPU")————————————————原文链接:https://blog.csdn.net/JIAJIA14754545/article/details/121856840
  • [技术干货] MindSpore图片分类之LeNet网络卷积原理
    1. 摘要本系列分享我们将一起理解MindSpore官网中展示的MNIST图片数据集分类项目。此项目中使用的是LeNet卷积神经网络,卷积神经网络(convolutional neural network)是含有卷积层(convolutional layer)的神经网络,卷积神经网络均使用最常见的二维卷积层,经常用于处理图像数据的项目中。在LeNet网络中,可分为卷积模块和全连接输出模块。本次我们将介绍卷积计算的工作原理。2. 二维互相关运算首先了解一下卷积核数组在输入数组中的计算方式,虽然卷积层得名于卷积(convolution)运算,但我们通常在卷积层中使用更加直观的互相关(cross-correlation)运算。在二维卷积层中,一个二维输入数组和一个二维核(kernel)数组通过互相关运算输出一个二维数组。这里我们设置一个高和宽均为3的二维输入数组。我们可以将该数组形状记为3×3。核数组的高和宽分别是2。核数组在卷积计算中又称卷积核或过滤器(filter)。卷积核的高和宽决定卷积核窗口的形状,可以记为2×2。在二维互相关运算过程中,卷积窗口将会从输入数组的最左上方开始计算,按照从左到右,从上到下的顺序,依次在输入数组区域内滑动,这里默认情况下卷积核移动的步幅是每次一行或一列。当卷积窗口滑动到输入数组的某一位置时,窗口中的输入子数组与核数组按元素相乘并求和,得到输出数组中相应位置的元素。二维互相关运算得出:0×0+1×1+3×2+4×3=191×0+2×1+4×2+5×3=253×0+4×1+6×2+7×3=374×0+5×1+7×2+8×3=43这就是卷积计算的过程,二维卷积层将输入数组和卷积核做互相关运算,并加上一个标量偏差来得到输出。卷积层的模型参数包括了卷积核和标量偏差。在训练模型的时候,通常我们需要先对卷积核随机初始化,然后再不断迭代卷积核和偏差。实际上,卷积运算与互相关运算是类似的。想要得到卷积运算的输出,我们只需将核数组左右翻转并上下翻转,再与输入数组做互相关运算。所以,卷积运算和互相关运算虽然类似,但如果他们使用相同的核数组和输入数组,输出也并不一定会相同。如果卷积核数组元素在横轴和竖轴上都对称,那么卷积运算和互相关运算结果相同。特征图(feature map)是二维卷积层输出的二维数组可以看作输入空间维度上某一级的表征。影响元素x的前向计算的所有可能输入区域叫做x的感受野(receptive field)。我们可以设置更深的卷积神经网络,那么输入数组通过每一层卷积后,高和宽会渐渐变小,特征图中单个元素的感受野就会变得更加广阔,从而捕捉输入上更大尺寸的特征。3. 填充和步幅3.1 填充填充(padding)是表示在输入高和宽的输入数组两侧填充元素(通常是0元素)。如图2中,我们在输入数组的高和宽的两侧分别添加值为0的元素,每一边新增一层,使得输入高和宽从3变成5,并导致输出高和宽从2变成4。一般卷积情况下,假设输入数组高和宽分别是nh、nw,卷积核数组的高和宽分别是kh、kw,如果在输入数组高的两侧一共填充ph行,在宽的两侧一共填充pw列,那么输出数组形状将会是(nh-kh+ph+1)×(nw-kw+pw+1)这就证明,输出数组的高和宽会分别增加ph和pw。所以,如果想要了解在构造网络时推测每个层的输出形状。我们可以设置ph=kh -1和pw=kw-1使得输入和输出具有相同的高和宽。3.2 步幅步幅是指核数组在输入数组在按照从左到右,从上到下移动过程中,每移动一次核数组跨过的元素行数或列数。目前我们看到的例子里,在高和宽两个方向上步幅均为1。我们也可以使用更大步幅。图3展示了在高上步幅为3、在宽上步幅为2的二维互相关运算。可以看到,输出第一列第二个元素时,卷积窗口向下滑动了3行,而在输出第一行第二个元素时卷积窗口向右滑动了2列。当卷积窗口在输入上再向右滑动2列时,由于输入元素无法填满窗口,无结果输出。图3中的阴影部分为输出元素及其计算所使用的输入和核数组元素。一般来说,当高上步幅为sh,宽上步幅为sw时,输出形状为⌊(nh−kh+ph+sh)/sh⌋×⌊(nw−kw+pw+sw)/sw⌋如果设置ph=kh−1ph=kh−1和pw=kw−1pw=kw−1,那么输出形状可以表示为⌊(nh+sh−1)/sh⌋×⌊(nw+sw−1)/sw⌋更进一步,如果输入的高和宽能分别被高和宽上的步幅整除,那么输出形状将是(nh/sh)×(nw/sw)。填充作用于输出数组的高和宽。这常用来使输出与输入具有相同的高和宽。步幅可以减小输出的高和宽,例如输出的高和宽仅为输入的高和宽的1/n(n为大于1的整数)。4. 多输入通道与多输出通道4.1   多输入通道我们上面用到的输入和输出都是二维数组,但是真实的数据往往维度会更高。例如,彩**片数据集在高和宽的维度外还有RGB(红、绿、蓝)3个颜色通道。假设彩**像的高和宽分别是h和w(像素),那么它可以表示为3×h×w的多维数组。我们将大小为三的这一维称为通道(channel)维。当输入数据含有多个通道时,我们需要构造一个输入通道与输入数据的通道数相同的卷积核,从而能够与含多通道的输入数据做互相关运算。假设输入数据的通道数为ci,那么卷积核的输入通道同样为ci。设卷积核窗口形状为kh×kw。当ci=1时。此时的卷积核是只包含一个形状为kh×kw的二维数组。当ci>1时,每一个输入通道各分配一个形状为kh×kw的核数组。Ci个数组与输入通道维上连结,得到形状为ci×kh×kw的卷积核。此时卷积运算是各个通道上对二维数组和卷积核的二维数组做互相关运算,再将ci个通道的二维输出相加,得到一个二维数组。下面展示的是2个输入通道的二维互相关计算,二维输入数组与二维核数组做互相关运算,再按通道数相加得到输出。(1×1+2×2+4×3+5×4)+(0×0+1×1+3×2+4×3)=564.2 多输出通道通过上面多输入通道的介绍,我们发现对各个通道的结果做累加,无论输入通道数是多少,输出通道总是1。假设输入通道数为ci,想要得到输出通道数为co,我们可以为每个输出通道分别创建形状为ci×kh×kw的核数组。那么此时的卷积核形状为co×ci×kh×kw。在做互相关运算时,每个输出通道上的结果由卷积核在该通道上的核数组与整个输入数组计算得出。1×1卷积层是卷积窗口形状为1×1的多通道卷积层。因为使用了最小窗口,所以1×1卷积是不具有识别高和宽维度上相邻元素构成的模式的功能。1×1卷积主要使用在通道维度上。如图5所示,输入数组形状是3×3×3,卷积核形状为2×3×1×1,我们得到的输出数组形状为2×3×3。输入与输出具有相同的高和宽。输出中的每个元素来自输入中高和宽上相同位置的元素在不同通道之间按权重累加。假设我们将通道维当做特征维,将高和宽维度上的元素当成数据样本,那么1×1卷积层的作用于全连接层等价。使用多通道可以拓展卷积层的模型参数,1×1卷积层通常是用来调整网络层之间的通道数,控制模型的复杂度。5. 总结在卷积计算中,卷积核的使用可以检测图像的边缘,卷积层可以通过重复使用卷积核计算有效地表征局部空间。填充和步幅的主要作用是控住输入数组和输出数组的形状。在多输入通道中,通道数是不可变的,可以使用四维的卷积核数组控制多通道的输出(输出通道数×输入通道数×高×宽),如果输入通道数过多导致模型复杂度很高,可以使用1×1卷积层来调整输出通道,并且不会改变高和宽。————————————————原文链接:https://blog.csdn.net/xi_xiyu/article/details/122681759
  • [技术干货] MindSpore图片分类之LeNet网络池化和全连接
    1. 摘要在上一篇分享中,主要介绍了卷积操作,我们可以通过构造卷积核作用到图像中,对比输入和输出数组就可以精确的找到像素变化的位置。这便是图像物体边缘检测功能。设任意的二维数组X的i行j列的元素为X[i,j]。如果我们构造的卷积核输出Y[i,j]=1,那么说明输入中X[i,j]和X[i,j+1]数值不一样。这可能意味着物体的边缘通过这两个元素之间。在实际图像中,我们要检测的物体不会出现在固定的位置,即使我们连续拍摄同一个物体也会出现偏移。这会导致同一个边缘对应的输出可能出现在卷积输出Y中的不同位置,从而对后面的模式识别造成困难。本片分享我们介绍池化(pooling)层,它的主要作用便是为了缓解卷积层对位置上的过度敏感性。2. 二维最大池化层和平均池化层和卷积计算类似,池化层每一次对输入数组的一个固定形窗口中的元素计算输出。该窗口也称池化窗口。与卷积层的运算法则不同,池化层的法则是直接计算池化窗口元素中的最大值或者平均值。所以也分别叫做最大池化和平均池化。在二维最大池化层中,池化窗口从输入数组的左上角开始,按照从左到右,从上到下的顺序,在输入数组中滑动。当池化窗口滑动到某一个位置时,窗口中的输入子数组的最大值就是输出数组中相应位置的元素。池化的窗口形状是2×2的最大池化,默认步幅都为1。阴影部分为第一个输出元素和计算所使用的输入元素。输出数组的高和宽分别为2,其中的4个元素由取最大值运算max得出:max(0,1,3,4)=4,max(1,2,4,5)=5,max(3,4,6,7)=7,max(4,5,7,8)=8.平均池化层的计算方法与最大池化层类似,只是将每次求池化窗口中的元素最大值改为求平均值。池化窗口形状为p×q的池化层称为p×q池化层,其中的池化运算叫作p×q池化。在最开始我们提到的物体边缘检测的例子。现在我们将卷积层的输出作为2×2最大池化的输入。设该卷积层输入是X、池化层输出为Y。无论是X[i,j]和X[i,j+1]值不同,还是X[i,j+1]和X[i,j+2]不同,池化层输出均有Y[i,j]=1。也就是说,使用2×2最大池化层时,只要卷积层识别的模式在高和宽上移动不超过一个元素,我们依然可以将它检测出来。3. 填充、步幅和多通道和卷积层一样,池化层也可以在输入数组的高和宽两侧填充0元素。并可以设置窗口的移动步幅来改变输出数组形状。池化层填充和步幅与卷积层填充和步幅的工作机制一样。池化层在处理多通道输入数组的时候,与卷积层的工作机制是不同的,卷积层中是将每个通道中的输入数组卷积运算后再相加,会导致输出通道变为1个。而池化层则是在每个出入通道中池化计算,但不将池化结果相加,可以保证输入通道数与输出通道数相同。4. LeNet卷积网络如上图中所示,是LeNet卷积网络的整体流程图,整体包含8个网络层,下面我们将了解每一层的计算。输入层:我们使用的数据集是MNIST数据集,该数据集中的样本数据都是规格为32×32的灰度图,我们以1个样本图片为例。那么我们输入的图片规格就是1×1×32×32,表示一个通道输入1个32×32的数组。C1层:C1层中数组规格为6×1×28×28,从1×1×32×32卷积得到。首先需要6个批次的卷积数组,每一个批次中都有1个规格为5×5的卷积数组,卷积步幅默认为1。即卷积数组规格为6×1×5×5。该卷积层共有6+1×5×5×6=156个参数,其中6个偏置参数。这一层网络**有6×1×28×28=4704个节点,每个节点和当前层5×5=25个节点相连,所以本层卷积层共有6×(1×28×28)×(1×5×5+1)=122304个全连接。S2层:S2层的数组规格为6×1×14×14,从1×1×28×28卷积得到。使用的是2×2,步幅为1的最大池化操作,所以并不改变批次数,只是将每一个输入数组从28×28降到14×14的输出数组。该池化层共有6×2=12个可训练参数,以及6×(1×14×14)×(2×2+1)=5880个全连接。C3层:C3层的数组规格为16×1×10×10,从6×1×14×14卷积得到。输出通道数数改变,所以卷积数组需要16批卷积数组,每一批中有6个卷积核与输入通道对应,每一个卷积数组规格都是5×5,步幅为1。即卷积数组规格为16×6×5×5。该卷积层共有16+1×5×5×16=2416个参数,其中16个偏置参数。这一层网络**有16×1×10×10=1600个节点,每个节点和当前层5×5=25个节点相连,所以本层卷积层共有16×(1×10×10)×(1×5×5+1)=41600个全连接。S4层:S4层的数组规格为16×1×5×5,这一层池化与S2层池化设置相同。所以输出数组只改变每一个数组的规格,不改变数量。该池化层共有16×2=32个可训练参数,以及16×(1×5×5)×(2×2+1)=2000个全连接。C5层:C5层是规格为120×1的一维向量,那么需要将S4层数组转换成一维向量,输入的数组规格是1×(16×1×5×)=1×400。使用全连接层将1×400转为1×120的向量。在全连接层中,每一个节点计算处结果后,都需要再经过激活函数计算,得出的值为输出的值。该连接层共有5×5×16=400个输入节点,参数个数为5×5×16×120+120=48120个,输出节点120个。F6层:F6层是规格为84×1的一维向量,与C5层计算相同,也是通过全连接层计算得到。为什么要转成84个神经元向量呢,如下图中所示,是所有字符标准格式,规格为12×7.所以有84个像素点,然后使用F6层的向量与这些标准图计算相似度。该连接层共有120个输入节点,参数个数为120×84+84=10164个,输出节点84个。输出层:该连接层共有84个输入节点,参数个数为84×10+10=850个,输出节点10个。输出层使用Softmax函数做多分类,在Softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间中,可以看作是每一个类别的概率值,从而实现多分类。Softmax从字面上来看,可以分成Soft和max两部分。Softmax的核心是Soft,对于图片分类来说,一张图片或多或少都会包含其它类别的信息,我们更期待得到图片对于每个类别的概率值,可以简单理解为每一个类别的可信度;max就是最大值的意思,选择概率值最大的当作分类的类别。下面给出Softmax函数的定义其中zi是第i个节点的输出值,C是输出节点的个数,即分类类别的个数。通过Softmax函数可以将多分类的输出值转换为范围在[0,1],并且总和为1的概率分布。当使用Softmax函数作为输出节点的激活函数的时候,一般使用交叉熵作为损失函数。模型有了损失函数后,就可以使用梯度下降的方法求解最优参数值。5. 总结本篇我们主要承接上一次的卷积内容,首先分析了池化操作的运行原理。然后使用LeNet卷积神经网络将一个32×32的灰度图的分类过程,分析了LeNet卷积神经网络网络中每一层之间卷积核信息、池化信息、参数个数、全连接个数,以及最后输出时使用的Softmax函数性质。————————————————原文链接:https://blog.csdn.net/xi_xiyu/article/details/122681854
  • [其他] 再思考图卷积网络的知识图谱补全
    图卷积网络(GCNs)是一种建模图结构的有效方法,它在知识图谱补全(KGC)中越来越受欢迎。基于GCNs的KGC模型首先使用GCNs生成表达实体表示,然后使用知识图嵌入(knowledge graph embedding, KGE)模型捕获实体之间的交互和关系。然而,许多基于GCN的KGC模型未能超过最先进的KGE模型,尽管引入了额外的计算复杂性。这一现象促使我们去探索GCNs在KGC中的真实作用。因此,本文在具有代表性的基于GCNs的KGC模型的基础上,引入变量来找出GCNs在KGC中的关键因子。令人惊讶的是,我们从实验中观察到,GCNs中的图结构建模对KGC模型的性能并没有显著的影响,这与人们普遍认知的相反。相反,实体表示的转换负责性能改进。在此基础上,我们提出了一个简单而有效的框架,名为LTEKGE,该框架将现有的KGE模型与线性变换的实体嵌入相结合。实验表明,LTE-KGE模型与基于gcn的KGC方法具有类似的性能改进,同时具有更高的计算效率。这些结果表明,现有的GCNs在KGC中是不必要的,新的基于GCNs的KGC模型应该依靠更多的消融研究来验证其有效性。所有实验的代码都可以在GitHub的https://github.com/MIRALab-USTC/GCN4KGC上找到。
  • [行业资讯] 原来神经网络处理器,就是包汤圆
    NPU,何许人也? 说起近年来数字电路设计领域的弄潮儿,非“神经网络处理器 NPU”莫属。它更广为人知的花名,就是:AI芯片。 NPU与CPU、GPU等通用处理器之间最大的不同,就在于高度的专用性。作为一种典型的领域专用架构(Domain Specific Architecture, DSA),NPU是专门用于处理神经网络算法的。 神经网络算法良好表现的背后,是密集的运算。如果我们能够为神经网络的处理这一任务定制一款架构,那么我们便能享受到更高的处理性能、更低的功耗。 举个例子,同样是进行一次人脸识别,比起通用处理器,NPU不仅能更快地完成任务,耗电还更少。反映到市场上,这些优势可就是真金白银。 在这样的需求下,大量的人力物力被投入于NPU的设计,使得这一概念早已走出了纸上谈兵的阶段。 而如今,摆在我们眼前的局面似乎是矛盾的。 一方面,在自研芯片的热潮下,不少企业纷纷选择了拿NPU来小试牛刀,让人觉得NPU似乎已经开始走向大规模的市场化。 但另一方面,NPU的研究热仍然持续席卷着各大学术会议,宣告着:“理想的、终极形态的NPU还在路上。” 那么,有关NPU的研究到底进入怎样的技术阶段了呢?亟待解决的问题和有潜力、前景的技术方向又有哪些呢? 处理神经网络模型,跟生产汤圆差不多? 既然是要设计专用的处理器,那么架构自然得跟着目标算法走。一个典型的神经网络模型常常由多个不同类型的层构成。不了解每一层对于整个模型的表现有什么贡献?没关系!我们只需要凭着“不畏浮云遮望眼”的魄力,猛抓主要矛盾——算法中计算量最大的部分。 在典型的神经网络模型中,计算最密集的要属卷积层和全连接层,而两者对应的运算都可以用矩阵乘法的形式来交给硬件处理。打个比方,这是一个小规模的矩阵乘法运算,其中输入矩阵x,权重矩阵w和输出矩阵y的大小均为2×2。今天是元宵节,咱们就用生产汤圆打个比方~ 假设输入矩阵中的四个元素分别代表着四种馅料:芝麻、红豆、花生和草莓,而权重矩阵中的四个元素则对应着原味、紫米、抹茶和芋头这四种外皮,那么输出矩阵的计算便可以看作是生产四袋汤圆,每一袋里有两颗汤圆:比如y0这一袋里的两颗汤圆分别是原味芝麻(x0·w0)和抹茶红豆(x1·w2)口味的。也就是说,每一袋汤圆的生产离不开两种操作:把外皮、内馅揉在一块儿(乘法)和把揉出来的汤圆按计划装袋(加法)。 脉动阵列结构,走向最强汤圆生产商的不二选择? 一说到矩阵乘法,大家是不是突然明白了为什么那些研究深度学习的小伙伴跑实验总是离不开GPU?因为GPU最擅长的,就是靠里面的大量运算单元,处理高并行度的运算任务。 那么在处理神经网络模型中的矩阵乘法运算时,GPU的不足之处在哪? 让我们再次把目光投向汤圆的生产上来。 GPU所对应的生产模式,就像是在工厂里雇佣了大量的师傅,他们各自知道自己当前的任务是什么,但缺少对于整体的生产计划的认知。 于是,在这样一家汤圆生产厂里,我们可以看到这样的现象:师傅张三和李四分别被分配到了“揉一颗原味芝麻汤圆”和“揉一颗抹茶红豆汤圆”的任务,于是他们各自跑到仓库去取原材料、跑回工位上揉汤圆、再把汤圆送回仓库里;之后,师傅王五被分配到了“打包这两颗汤圆”的任务,于是他同样地经历了“跑去仓库取汤圆-跑回工位打包-把包好的汤圆送回仓库”的三段式工作流程。 由于人手多,完成整个生产任务所需要时间仍然能让人满意,但是这样的生产模式意味着极高的人力成本。同时,整体的生产效率更是比理想状态要低得多:由于每位师傅都需要频繁地往来于仓库和工位,因此即使把生产室和仓库间的通道建得再宽敞,他们的大部分工作时间都得花在仓库里和去仓库的路上。这就是“冯·诺依曼瓶颈”——频繁的数据存取拖了处理性能的后腿。 问题就来了,怎样才能建立起一套更合理的生产模式呢? 答案很简单,需要管理者充分地利用自己对于目标生产任务的了解,定制化地指挥各位汤圆师傅们相互配合、而不是各自为战。 对于专用芯片架构设计,这件事带来的启发是,应当把握、利用目标算法的特征,尽可能避免不必要的远距离数据传输——谷歌TPU中采用的脉动阵列(Systolic Array)结构便是一次成功的尝试。在脉动阵列结构中,相邻的处理单元(Processing Element, PE)之间是允许进行数据传递的,且各PE有着自己的存储资源来暂存数据,这就为数据的复用提供了可能性。 整个运算过程是这样的:权重值首先被载入脉动阵列并保持静止;输入值按照特定的排序方式自左向右地“流”过阵列,并在途经的PE中参与运算;输出值,也就是运算结果,将从阵列的底部“流”出。 通过这样的方式完成运算的好处何在?回到老石汤圆厂:在整个生产过程中,每一种馅料和外皮尽管被使用到了两次,但它们从仓库中被取出的次数却被成功地限制在了最低限度一次。 这是因为:每位师傅都被指定负责一种特定外皮的汤圆的制作,比如张三师傅(PE0)负责所有原味外皮(w0)的汤圆的制作任务,李四师傅(PE1)则负责制作紫米外皮(w1)的汤圆,于是,每位师傅便可以反复地使用自己已经取出的外皮。 另一方面,馅料也被允许在相邻的师傅间传递。当李四师傅需要芝麻馅(x0)的时候,他可以从左侧的张三师傅那里得到,而不需要自己再跑一趟仓库。 成也专用性,败也专用性? 但是,这样的脉动阵列结构还称不上是终极的解决方案。 尽管上面给出了一个理想的运算过程,但是需要注意的是,这是建立在目标运算的规模与阵列的大小完美契合的前提条件下的,而这一点在应用场景中其实是难以满足的。 在实际的设计中,出于对峰值算力的追求,脉动阵列的尺寸不宜选择得过小,比如谷歌的Cloud TPU v2配备了两个128×128大小的PE阵列。 而目标运算的规模却是变化的:一方面,同一个神经网络模型中的不同层所对应的运算规模是不同的;另一方面,在很多应用场景下,待处理的神经网络模型也不是单一的。 用固化的硬件去应对变化的运算需求,结果注定是“悲剧”。 这就好比咱们的汤圆厂里雇了大量的汤圆师傅来保证高生产力,而今天接到的生产订单很小,但师傅完成订单的时间并没有变少:因为他们认准了只有位置最靠边的师傅(阵列中最底侧的PE)才能把汤圆送回仓库,于是便执着于无意义的传递行为。 换言之,专用的架构大大简化了对于控制逻辑的需求,但也使得处理器丧失了灵活处理问题的能力。 有人可能会有异议:通过更深入的定制化,可以把同一个算法模型中不同层的运算交给不同大小的脉动阵列,让多个阵列以流水线的方式协同工作,实现运算规模与硬件资源的匹配。这其实是NPU设计中一种常见的理念,但简单地倒向定制化会导致NPU在处理不同神经网络模型时的“彻底躺平”。 为什么完全的专用性并不适用于NPU?这似乎与我们对于“定制化”的一贯理解不太相符。 一切仍然得追溯到需求上。 由于神经网络算法仍在高速发展,关于“最优的神经网络模型”之争还远没有盖棺定论,这就注定了当下的NPU仍然需要具备一定的通用性——假设企业花重金买了NPU,几个月后却发觉它们无法兼容更新、更有效的算法,那么显然没有人愿意为这样的一锤子买卖买单。 这使得NPU始终无法在竞争中甩开GPU,证明自己才是加速神经网络模型处理的最佳选择。 路在何方? 考虑到神经网络算法持续高速发展的大背景,NPU若想与GPU掰手腕、抢占市场份额,哪些技术方向可能成为突破口? 我认为,思路大体上可以分为两种: 1. 适度牺牲专用性,换取通用性;2. 无视通用性,选择彻底的定制化。 前者意味着在架构中额外引入少量的控制逻辑和数据通路,用轻量级的硬件开销去折中专用性与通用性。 对于这一思路,引入多少通用性、如何低成本地引入通用性等等都是需要重点考量的因素,也需要更便捷的生态作为支持。 硬件若是骨架,那么软件便是灵魂。 换句话说,当GPU能够流畅地处理PyTorch、TensorFlow等主流深度学习框架构建的网络模型、而NPU却不能的时候,市场很难更青睐后者。 第二种思路则更接近于设计专用处理器的初心——既然选择了定制化,岂有被通用性局限住的道理? 考虑到通用性来自于“用相同的硬件运行不同的算法”的需求,如果能为每一个神经网络都定制相应的处理器,无视通用性这一想法便站得住脚了。 因此,NPU设计自动化这一方向被寄予了厚望:当用户输入自己搭建的神经网络模型的特征,工具便能自动地生成出对应的、RTL级别的NPU设计。基于FPGA等可编程的器件,该设计能够以较低的成本迅速走向物理实现。由此看来,追求极致的专用性也并不是空中楼阁。 结语 理论上,高度定制化的专用处理器能比通用处理器更高效地完成特定的目标任务。 然而,由于神经网络算法领域自身仍然在高速地发展,NPU的DSA设计并不能完全地摆脱对于通用性的考量,这使得NPU迟迟无法表现出对于GPU的显著优越性。 但这并不意味着NPU这一概念是无意义的,一些技术方向上的潜在突破将成为NPU的取胜之匙。在后续的文章中,我们将结合在近期的顶级学术会议上汇报的相关研究进展,为对这一炙手可热的概念感兴趣的朋友建立一个更加立体的认知。 (注:本文不代表作者任职单位观点。)
  • [其他] GNN-LM基于全局信息的图神经网络语义理解模型
    本文提出了GNN-LM,将图神经网络与语言模型相结合,通过允许在整个训练语料库中引用相似的上下文,扩展了传统的语言模型。使用k近邻检索与输入的表示最相似的邻居,我们为每个输入构建了一个有向异构图,其中节点是来自输入上下文或检索到的邻居上下文的token,边表示token之间的连接。然后利用图神经网络从检索到的上下文中聚合信息,以解码下一个token。实验结果表明,GNN-LM在标准数据集中优于强基线,并且通过与kNN-LM结合,能够在WikiText-103上取得最优效果。论文标题:GNN-LM: Language Modeling based on Global Contexts via GNN作者:Yuxian Meng, Shi Zong, Xiaoya Li, Xiaofei Sun, Tianwei Zhang, Fei Wu, Jiwei Li论文链接:https://www.zhuanzhi.ai/paper/096327d547ab2c5aee0df3e603ac64e6接收会议:ICLR 2022代码链接:https://github.com/ShannonAI/GNN-LM
  • [应用开发] modelzoo上ATC CNN_Transformer(FP16)在Ascend310上推理报错
    【基础环境】CANN 5.0.2版本Ubuntu18.04.1操作系统Atlas800-3000昇腾硬件设备【操作步骤&问题现象】1、modelzoo给出的所用数据集为clean,测试使用validation,使用样例中给出的onnx模型进行模型转换,转换指令如下:atc --framework=5 --model=./wav2vec2-base-960h.onnx --output=./wav2vec2 --input_format=ND --input_shape="input:1,-1" --dynamic_dims="30000;40000;50000;60000;70000;80000;90000;100000;110000;120000;130000;140000;150000;160000;180000;190000;200000;220000;240000;250000;300000;480000" --log=error --soc_version=Ascend3102、模型转换成功后,运行pyacl_infer.py进行推理,在运行到第66个bin文件时报错,报错信息如下:【截图信息】之前在910上进行过测试,能够跑通,没有问题,看报错应该跟某个算子有关,如何解决
  • [其他] 康奈尔Nature论文:一种使用反向传播训练的深度物理神经网络
    深度学习加速器旨在高效地执行深度学习,通常针对推理阶段,并且通常通过利用传统电子设备之外的物理基板。迄今为止的方法一直无法应用反向传播算法来原位训练非常规的新型硬件。反向传播的优势使其成为事实上的大规模神经网络训练方法,因此这一缺陷构成了主要障碍。康奈尔大学的研究人员介绍了一种混合原位-计算机算法,称为物理感知训练,它应用反向传播来训练可控的物理系统。该研究以「Deep physical neural networks trained with backpropagation」为题,于 2022 年 1 月 26 日发布在《Nature》。 深度学习模型已成为科学和工程领域的普遍工具。然而,它们的能源需求现在越来越限制它们的可扩展性。深度学习加速器旨在高效地执行深度学习,通常针对推理阶段,并且通常通过利用传统电子设备之外的物理基板。迄今为止的方法一直无法应用反向传播算法来原位训练非常规的新型硬件。反向传播的优势使其成为事实上的大规模神经网络训练方法,因此这一缺陷构成了主要障碍。 在这里,康奈尔大学的研究人员介绍了一种混合原位-计算机算法,称为物理感知训练,它应用反向传播来训练可控的物理系统。 正如深度学习通过由数学函数层构成的深度神经网络,来实现计算那样,该方法允许研究人员训练由可控物理系统层构成的深度物理神经网络,即使物理层与传统人工神经网络层缺乏任何数学同构。 为了证明该方法的普遍性,研究人员训练了基于光学、力学和电子学的各种物理神经网络,以实验性地执行音频和图像分类任务。物理感知训练将反向传播的可扩展性与原位算法可实现的缺陷和噪声的自动缓解相结合。 物理神经网络具有比传统电子处理器更快、更节能地执行机器学习的潜力,更广泛地说,可以赋予物理系统自动设计的物理功能,例如机器人材料和智能传感器。 该研究以「Deep physical neural networks trained with backpropagation」为题,于 2022 年 1 月 26 日发布在《Nature》。https://www.nature.com/articles/s41586-021-04223-6图示:PNN 简介。(来源:论文)
  • [其他] SegNet:一种用于图像分割的深度卷积编解码体系结构
    作者: Vijay Badrinarayanan,Alex Kendall,Roberto Cipolla发布信息:2015,IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE论文:https://arxiv.org/pdf/1511.00561.pdf代码:https://github.com/aizawan/segnetSegNet是用于进行像素级别图像分割的全卷积网络。SegNet与FCN的思路较为相似,区别则在于Encoder中Pooling和Decoder的Upsampling使用的技术。Decoder进行上采样的方式是Segnet的亮点之一,SegNet主要用于场景理解应用,需要在进行inference时考虑内存的占用及分割的准确率。同时,Segnet的训练参数较少,可以用SGD进行end-to-end训练
  • [推理] 310推理问题
    310推理一致执行到这个位置,建图不成功:能够进行build,构建成功,但是执行../ascend310_infer/out/main 参数.....时候,就报下面错误。尝试过导入别人的mindir文件,能够成功完整执行,但是用我自己export出来的mindir就会报图2问题对比别人的mindir,我的网络用到的思路是卷积和反卷积;所以推理下来,我猜想会有如下问题:第一、export出的mindir问题,但是我的export方式def run_export(args): """ export """ device_id = int(os.getenv('DEVICE_ID', '0')) context.set_context(mode=context.GRAPH_MODE, device_target="Ascend", device_id=device_id) net = get_generator("D-DBPN", args.scale) max_lr_size = int(MAX_HR_SIZE / args.scale) params = load_checkpoint(args.ckpt_path) # net.load_pre_trained_param_dict(param_dict, strict=False) load_param_into_net(net, params) net.set_train(False) print('load mindspore net and checkpoint successfully.') inputs = Tensor(np.ones([args.batch_size, 3, max_lr_size, max_lr_size]), ms.float32) print(inputs.shape) export(net, inputs, file_name=args.file_name, file_format=args.file_format) print('export successfully!') if __name__ == "__main__": run_export(args_1)第二、310推理是否支持反卷积网络操作以上就是我的两个问题。请老师指点。
  • [其他] 使用计算机视觉算法检测钢板中的焊接缺陷
    1. 介绍 焊接缺陷可以定义为焊接零件中出现的焊接表面不规则、不连续、缺陷或不一致。焊接接头的缺陷可能导致零件和组件的报废、昂贵的维修费用、工作条件下的性能显著降低,以及在极端情况下,还会导致财产和生命损失的灾难性故障。此外,由于焊接技术的固有缺陷和金属的特性,在焊接过程中总会存在一定的缺陷。由于固有的冶金几何缺陷、机械性能的不均匀性和残余应力的存在,焊接接头通常是裂纹萌生的位置,因此评估焊接质量非常重要。在实践中,几乎不可能获得完美的焊接,并且在大多数情况下,没有必要提供所需的足够的维修功能。然而,早发现和隔离措施总是比事故更可取的。使用我们的算法,我们可以通过图像轻松检测焊接故障,并精确测量每个故障的严重程度,这将进一步有助于加快图像识别速度并避免出现不利情况。研究发现,使用卷积神经网络算法和 U-Net 架构使该过程更加高效,工作结束时准确率为 98.3%。2. 先决条件 对机器学习的基本理解卷积神经网络的基本思想了解卷积、最大池化和上采样操作U-Net架构思路对残差块中的跳过连接的基本理解(可选)使用 Python、TensorFlow 和 Keras 库的 ConvNets 的工作知识(可选)3. 图像分割 分割将图像划分为包含具有相似属性的像素的不同区域。为了对图像分析和解释有意义且有用,区域应与所描绘的对象或感兴趣的特征密切相关。图像分析的成功取决于分割的可靠性,但图像的准确分割通常是一个非常具有挑战性的问题。心脏(红色)、肺(绿色)和锁骨(蓝色)的胸部 X 光片被分割。4. 图像矩 图像矩是图像像素强度的某个特定加权平均值,图像矩对于描述分割后的对象很有用。通过图像矩发现的图像的简单属性包括:面积(或总强度)质心有关其方向的信息。5. 了解数据 该数据集包含两个目录,原始图像存储在“images”目录中,分割图像存储在“labels”目录中。让我们将数据可视化:来自“images”的原始图像上面的这些原始图像是 RGB 图像,必须用于训练模型和测试模型。这些图片的尺寸各不相同。直观地说,较暗的部分是焊接缺陷,模型需要对这些图像进行图像分割。来自“labels”的二进制图像'labels' 目录中的这些图像是二进制图像或地面真实标签。这是我们的模型必须为给定的原始图像预测的内容。在二值图像中,像素具有“高”值或“低”值,白色区域或“高”值表示缺陷区域,黑色区域或“低”值表示无缺陷。6. 使用的方法和算法 我们将 U-Net 架构解决这个问题。我们将通过三个主要步骤检测故障并测量这些焊接图像的严重程度:图像分割使用颜色表示严重性使用图像矩测量严重性训练模型以下是我们用于模型的 U-Net 架构:使用的 U-Net 架构注意事项:每个蓝色框对应一个多通道特征图通道的数量显示在框的顶部。(x,y) 尺寸位于框的左下边缘。箭头表示不同的操作。图层的名称在图层下方提供。C1、C2、…… C7是卷积运算后的输出层P1、P2、P3是最大池化操作的输出层U1、U2、U3是上采样操作的输出层A1、A2、A3 是跳跃式连接。左侧是收缩路径,其中应用了常规卷积和最大池化操作图像的大小逐渐减小,而深度逐渐增加。右侧是扩展路径,其中应用了 (上采样) 转置卷积和常规卷积操作在扩展路径中,图像尺寸逐渐增大,深度逐渐减小为了获得更精确的位置,在扩展的每个步骤中,我们通过将转置卷积层的输出与来自编码器的特征图在同一级别连接来使用跳过连接:A1 = U1 + C3A2 = U2 + C2A3 = U3 + C1每次连接后,我们再次应用常规卷积,以便模型可以学习组装更精确的输出。import numpy as np import cv2 import os import random import tensorflow as tf h,w = 512,512 def create_model(): inputs = tf.keras.layers.Input(shape=(h,w,3)) conv1 = tf.keras.layers.Conv2D(16,(3,3),activation='relu',padding='same')(inputs) pool1 = tf.keras.layers.MaxPool2D()(conv1) conv2 = tf.keras.layers.Conv2D(32,(3,3),activation='relu',padding='same')(pool1) pool2 = tf.keras.layers.MaxPool2D()(conv2) conv3 = tf.keras.layers.Conv2D(64,(3,3),activation='relu',padding='same')(pool2) pool3 = tf.keras.layers.MaxPool2D()(conv3) conv4 = tf.keras.layers.Conv2D(64,(3,3),activation='relu',padding='same')(pool3) upsm5 = tf.keras.layers.UpSampling2D()(conv4) upad5 = tf.keras.layers.Add()([conv3,upsm5]) conv5 = tf.keras.layers.Conv2D(32,(3,3),activation='relu',padding='same')(upad5) upsm6 = tf.keras.layers.UpSampling2D()(conv5) upad6 = tf.keras.layers.Add()([conv2,upsm6]) conv6 = tf.keras.layers.Conv2D(16,(3,3),activation='relu',padding='same')(upad6) upsm7 = tf.keras.layers.UpSampling2D()(conv6) upad7 = tf.keras.layers.Add()([conv1,upsm7]) conv7 = tf.keras.layers.Conv2D(1,(3,3),activation='relu',padding='same')(upad7) model = tf.keras.models.Model(inputs=inputs, outputs=conv7) return model images = [] labels = [] files = os.listdir('./dataset/images/') random.shuffle(files) for f in files: img = cv2.imread('./dataset/images/' + f) parts = f.split('_') label_name = './dataset/labels/' + 'W0002_' + parts[1] label = cv2.imread(label_name,2) img = cv2.resize(img,(w,h)) label = cv2.resize(label,(w,h)) images.append(img) labels.append(label) images = np.array(images) labels = np.array(labels) labels = np.reshape(labels, (labels.shape[0],labels.shape[1],labels.shape[2],1)) print(images.shape) print(labels.shape) images = images/255 labels = labels/255 model = tf.keras.models.load_model('my_model') #model = create_model() # uncomment this to create a new model print(model.summary()) model.compile(optimizer='adam', loss='binary_crossentropy',metrics=['accuracy']) model.fit(images,labels,epochs=100,batch_size=10) model.evaluate(images,labels) model.save('my_model')模型是用 Adam 优化器编译的,我们使用二进制交叉熵损失函数,因为只有两个类(缺陷和无缺陷)。我们使用批量处理大小为 10 的 100 个 epoch(模型在所有输入上运行的次数)。测试模型由于模型的输入尺寸为 512x512x3 ,因此我们已将输入大小调整为该尺寸。接下来,我们通过将图像除以 255 来规范化图像以加快计算速度。图像已被输入模型,用于预测二进制输出。为了放大像素的强度,二进制输出乘以 1000。然后将图像转换为 16 位整数以便于图像处理。之后,算法会检测缺陷并通过颜色分级以及根据缺陷的严重程度为具有缺陷的像素分配权重,来直观地标记缺陷的严重程度。然后,考虑加权像素在该图像上计算图像矩。图像最终转换回 8 位整数,输出图像显示颜色分级及其严重性值。import numpy as np import cv2 from google.colab.patches import cv2_imshow import os import random import tensorflow as tf h,w = 512,512 num_cases = 10 images = [] labels = [] files = os.listdir('./dataset/images/') random.shuffle(files) model = tf.keras.models.load_model('my_model') lowSevere = 1 midSevere = 2 highSevere = 4 for f in files[0:num_cases]: test_img = cv2.imread('./dataset/images/' + f) resized_img = cv2.resize(test_img,(w,h)) resized_img = resized_img/255 cropped_img = np.reshape(resized_img, (1,resized_img.shape[0],resized_img.shape[1],resized_img.shape[2])) test_out = model.predict(cropped_img) test_out = test_out[0,:,:,0]*1000 test_out = np.clip(test_out,0,255) resized_test_out = cv2.resize(test_out,(test_img.shape[1],test_img.shape[0])) resized_test_out = resized_test_out.astype(np.uint16) test_img = test_img.astype(np.uint16) grey = cv2.cvtColor(test_img, cv2.COLOR_BGR2GRAY) for i in range(test_img.shape[0]): for j in range(test_img.shape[1]): if(grey[i,j]>150 & resized_test_out[i,j]>40): test_img[i,j,1]=test_img[i,j,1] + resized_test_out[i,j] resized_test_out[i,j] = lowSevere elif(grey[i,j]<100 & resized_test_out[i,j]>40): test_img[i,j,2]=test_img[i,j,2] + resized_test_out[i,j] resized_test_out[i,j] = highSevere elif(resized_test_out[i,j]>40): test_img[i,j,0]=test_img[i,j,0] + resized_test_out[i,j] resized_test_out[i,j] = midSevere else: resized_test_out[i,j] = 0 M = cv2.moments(resized_test_out) maxMomentArea = resized_test_out.shape[1]*resized_test_out.shape[0]*highSevere print("0th Moment = " , (M["m00"]*100/maxMomentArea), "%") test_img = np.clip(test_img,0,255) test_img = test_img.astype(np.uint8) cv2_imshow(test_img) cv2.waitKey(0)7. 结果 我们用于严重性检测的视觉指标是颜色,在图像中,颜色为:绿色表示存在严重缺陷的区域。蓝色表示缺陷更严重的区域。红色表示最严重的缺陷区域。第0个时刻以百分比的形式显示在输出图像旁边,作为严重性的经验度量。以下是三个随机样本,显示了原始输入、真实情况和模型生成的输出。文章转载自 小白学视觉 2022-01-27 
  • [行业资讯] 物联网架构的4个必要阶段
    是什么让像动作激活的电灯开关这样的自动化设备与具有相同功能的物联网设备有所不同?一句话:数据。使用连接到物联网的设备,当传感器检测到动作并且执行器打开灯时,这些操作将被捕获为数据,并发送到云或数据中心进行记录和分析。哪里有数据,哪里就需要物联网架构,告诉数据去哪里,使用什么格式,如何到达那里,以及基于这些数据采取什么行动。在本文,我们将快速概述物联网架构,并探讨它如何引导数据往返于设备和数据中心。数据流:从边缘到服务器/云物联网体系架构通常被描述为一个四阶段的过程,在这个过程中,数据从传感器通过网络传输,最终到达企业数据中心或云端进行存储、处理和分析。在物联网中,“物”可以是机器,可以是建筑,甚至可以是人。物联网架构中的进程还以指令或命令的形式向另一个方向发送数据,这些指令或命令告诉执行器或其他物理连接的设备采取某种措施来控制物理进程。执行器可以做一些简单的事情,比如开灯,或者在检测到即将发生故障时关闭装配线。让我们来看看物联网架构的4个阶段。第1阶段:传感器和执行器该过程从传感器和执行器开始,连网设备监测(在传感器的情况下)或控制(在执行器的情况下)某些“东西”或物理进程。传感器捕捉有关流程状态或环境条件的数据,例如温度、湿度、化学成分、储罐中的液位、管道中的流体流量或装配线的速度等等。在某些情况下,传感器可以检测到需要几乎立即响应的状况或事件,以便执行器可以实时执行补救措施,例如,调整流体的流速或工业机器人的运动。在这些情况下,要求传感器与分析/触发致动器之间的延迟非常低。为了避免数据到服务器的往返延迟、数据分析以确定故障以及向“对象”发送控制的延迟,此关键处理进程需要非常靠近要监测或控制的进程。此“边缘”处理可由模块上系统(SOM)设备(例如DigiConnectCore®模块和/或具有Python的Digi Cellular Router)来执行。第2阶段:互联网网关和数据采集系统数据采集系统(DAS)从传感器收集原始数据,并将其从模拟格式转换为数字格式。然后,数据采集系统聚合并格式化数据,再然后利用无线广域网(如Wi-Fi或蜂窝网络)或有线广域网通过互联网网关发送数据,以进行下一阶段的处理。此时,数据量已达到最大值。数量可能非常庞大,尤其是在工厂环境中,数百个传感器可能同时收集数据。因此,数据需要被过滤和压缩到最佳传输大小。第3阶段:预处理——边缘分析一旦物联网数据被数字化和聚合,它将需要处理以进一步减少数据量,然后才能进入数据中心或云。边缘设备可以执行一些分析,以作为预处理的一部分。在此阶段,机器学习对提供系统反馈和持续改进流程非常有帮助,而无需等待从公司数据中心或云返回指令。这种类型的处理通常发生在靠近传感器所在位置的设备上,例如在现场配线柜中。第4阶段:在云或数据中心进行深入分析在该过程的第4阶段,可以使用强大的IT系统来分析、管理和安全地存储数据。这通常发生在企业数据中心或云中,在这里,来自多个现场站点/传感器的数据可以组合在一起,以提供整个物联网系统的更广阔图景,并为IT和业务经理提供可操作的见解。一家公司可能会在不同的地理区域运营,可以分析物联网数据来识别关键趋势和模式,或者发现异常。在此级别上,特定于行业和/或公司的应用程序可用于执行深入分析并应用业务规则,以确定是否需要采取措施。传入的数据可以指示对设备设置的期望更改或优化流程的其他方式,从而形成了有助于不断改进的循环。阶段4还包括将数据存储在数据仓库中,以进行记录保存和进一步分析。流程需要平台除了四阶段物联网架构之外,还必须考虑物联网平台,它提供了阶段之间的连接。平台的架构定义了数据通信的具体细节。它确定哪些数据流向何处,以及在每个阶段执行多少处理。物联网平台可以根据系统的专业化程度进行不同程度的定制。举个例子,世界上任何一个城市的路灯物联网可能都非常相似,而用于制造医疗设备的3D打印机上的传感器和执行器可能是独一无二的。凭借可靠的平台和精心设计的架构,物联网可以提高几乎每个行业的安全性、效率和生产力。合适的物联网平台可以为您提供成功所需的工具。物联网的最佳时刻即将到来虽然物联网已经在许多消费者、商业、工业和基础设施应用中得到广泛使用,但我们可以预计,在不久的将来,物联网系统将以更大的数量和更多的用例出现。(编译iothome)
总条数:936 到第
上滑加载中