精华内容
下载资源
问答
  • 神经网络直观解释

    2017-10-24 16:03:15
    神经网络直观解释 标签: 神经网络 2017-05-12 21:00 460人阅读 评论(0) 收藏 举报 分类: 图像处理(3) 作者同类文章X 目录(?)[+] 什么是卷积神经网络为...

    神经网络的直观解释

    标签: 神经网络
    460人阅读 评论(0) 收藏 举报
    category_icon.jpg分类:

    什么是卷积神经网络?为什么它们很重要?

    卷积神经网络(ConvNets 或者 CNNs)属于神经网络的范畴,已经在诸如图像识别和分类的领域证明了其高效的能力。卷积神经网络可以成功识别人脸、物体和交通信号,从而为机器人和自动驾驶汽车提供视力。

    图 1

    在上图中,卷积神经网络可以识别场景,也可以提供相关的标签,比如“桥梁”、“火车”和“网球”;而下图展示了卷积神经网络可以用来识别日常物体、人和动物。最近,卷积神经网络也在一些自然语言处理任务(比如语句分类)上面展示了良好的效果。

    图 2

    因此,卷积神经网络对于今天大多数的机器学习用户来说都是一个重要的工具。然而,理解卷积神经网络以及首次学习使用它们有时会很痛苦。那本篇博客的主要目的就是让我们对卷积神经网络如何处理图像有一个基本的了解。

    如果你是神经网络的新手,我建议你阅读下这篇短小的多层感知器的教程,在进一步阅读前对神经网络有一定的理解。在本篇博客中,多层感知器叫做“全连接层”。

    LeNet 架构 (1990s)

    LeNet 是推进深度学习领域发展的最早的卷积神经网络之一。经过多次成功迭代,到 1988 年,Yann LeCun 把这一先驱工作命名为LeNet5。当时,LeNet 架构主要用于字符识别任务,比如读取邮政编码、数字等等。

    接下来,我们将会了解 LeNet 架构是如何学会识别图像的。近年来有许多在 LeNet 上面改进的新架构被提出来,但它们都使用了 LeNet 中的主要概念,如果你对 LeNet 有一个清晰的认识,就相对比较容易理解。

    图 3

    上图中的卷积神经网络和原始的 LeNet 的结构比较相似,可以把输入的图像分为四类:狗、猫、船或者鸟(原始的 LeNet 主要用于字符识别任务)。正如上图说示,当输入为一张船的图片时,网络可以正确的从四个类别中把最高的概率分配给船(0.94)。在输出层所有概率的和应该为一(本文稍后会解释)。

    There are four main operations in the ConvNet shown in Figure 3 above:
    在上图中的 ConvNet 有四个主要操作:

    1. 卷积
    2. 非线性处理(ReLU)
    3. 池化或者亚采样
    4. 分类(全连接层)

    这些操作对于各个卷积神经网络来说都是基本组件,因此理解它们的工作原理有助于充分了解卷积神经网络。下面我们将会尝试理解各步操作背后的原理。

    图像是像素值的矩阵

    本质上来说,每张图像都可以表示为像素值的矩阵:

    图4

    通道 常用于表示图像的某种组成。一个标准数字相机拍摄的图像会有三通道 - 红、绿和蓝;你可以把它们看作是互相堆叠在一起的二维矩阵(每一个通道代表一个颜色),每个通道的像素值在 0 到 255 的范围内。

    灰度图像,仅仅只有一个通道。在本篇文章中,我们仅考虑灰度图像,这样我们就只有一个二维的矩阵来表示图像。矩阵中各个像素的值在 0 到 255 的范围内——零表示黑色,255 表示白色。

    卷积

    卷积神经网络的名字就来自于其中的卷积操作。卷积的主要目的是为了从输入图像中提取特征。卷积可以通过从输入的一小块数据中学到图像的特征,并可以保留像素间的空间关系。我们在这里并不会详细讲解卷积的数学细节,但我们会试着理解卷积是如何处理图像的。

    As we discussed above, every image can be considered as a matrix of pixel values. Consider a 5 x 5 image whose pixel values are only 0 and 1 (note that for a grayscale image, pixel values range from 0 to 255, the green matrix below is a special case where pixel values are only 0 and 1):
    正如我们上面所说,每张图像都可以看作是像素值的矩阵。考虑一下一个 5 x 5 的图像,它的像素值仅为 0 或者 1(注意对于灰度图像而言,像素值的范围是 0 到 255,下面像素值为 0 和 1 的绿色矩阵仅为特例):

    图 5

    同时,考虑下另一个 3 x 3 的矩阵,如下所示:

    图 6

    接下来,5 x 5 的图像和 3 x 3 的矩阵的卷积可以按下图所示的动画一样计算:

    图 7

    现在停下来好好理解下上面的计算是怎么完成的。我们用橙色的矩阵在原始图像(绿色)上滑动,每次滑动一个像素(也叫做“步长”),在每个位置上,我们计算对应元素的乘积(两个矩阵间),并把乘积的和作为最后的结果,得到输出矩阵(粉色)中的每一个元素的值。注意,3 x 3 的矩阵每次步长中仅可以“看到”输入图像的一部分。

    在 CNN 的术语中,3x3 的矩阵叫做“滤波器(filter)”或者“核(kernel)”或者“特征检测器(feature detector)”,通过在图像上滑动滤波器并计算点乘得到矩阵叫做“卷积特征(Convolved Feature)”或者“激活图(Activation Map)”或者“特征图(Feature Map)”。记住滤波器在原始输入图像上的作用是特征检测器。

    从上面图中的动画可以看出,对于同样的输入图像,不同值的滤波器将会生成不同的特征图。比如,对于下面这张输入图像:

    xiaolu

    In the table below, we can see the effects of convolution of the above image with different filters. As shown, we can perform operations such as Edge Detection, Sharpen and Blur just by changing the numeric values of our filter matrix before the convolution operation 8 – this means that different filters can detect different features from an image, for example edges, curves etc. More such examples are available in Section 8.2.4 here.

    在下表中,我们可以看到不同滤波器对上图卷积的效果。正如表中所示,通过在卷积操作前修改滤波矩阵的数值,我们可以进行诸如边缘检测、锐化和模糊等操作 —— 这表明不同的滤波器可以从图中检测到不同的特征,比如边缘、曲线等。在这里的 8.2.4 部分中可以看到更多的例子。

    卷积

    另一个理解卷积操作的好方法是看下面这张图的动画:

    卷积

    滤波器(红色框)在输入图像滑过(卷积操作),生成一个特征图。另一个滤波器(绿色框)在同一张图像上卷积可以得到一个不同的特征图。注意卷积操作可以从原图上获取局部依赖信息。同时注意这两个不同的滤波器是如何从同一张图像上生成不同的特征图。记住上面的图像和两个滤波器仅仅是我们上面讨论的数值矩阵。

    在实践中,CNN 会在训练过程中学习到这些滤波器的值(尽管我们依然需要在训练前指定诸如滤波器的个数、滤波器的大小、网络架构等参数)。我们使用的滤波器越多,提取到的图像特征就越多,网络所能在未知图像上识别的模式也就越好。

    特征图的大小(卷积特征)由下面三个参数控制,我们需要在卷积前确定它们:

    • 深度(Depth):深度对应的是卷积操作所需的滤波器个数。在下图的网络中,我们使用三个不同的滤波器对原始图像进行卷积操作,这样就可以生成三个不同的特征图。你可以把这三个特征图看作是堆叠的 2d 矩阵,那么,特征图的“深度”就是三。

    深度

    • 步长(Stride):步长是我们在输入矩阵上滑动滤波矩阵的像素数。当步长为 1 时,我们每次移动滤波器一个像素的位置。当步长为 2 时,我们每次移动滤波器会跳过 2 个像素。步长越大,将会得到更小的特征图。

    • 零填充(Zero-padding):有时,在输入矩阵的边缘使用零值进行填充,这样我们就可以对输入图像矩阵的边缘进行滤波。零填充的一大好处是可以让我们控制特征图的大小。使用零填充的也叫做泛卷积,不适用零填充的叫做严格卷积。这个概念在下面的参考文献 14 中介绍的非常详细。

    非线性简介(ReLU)

    An additional operation called ReLU has been used after every Convolution operation in Figure 3 above. ReLU stands for Rectified Linear Unit and is a non-linear operation. Its output is given by:

    在上面图中,在每次的卷积操作后都使用了一个叫做 ReLU 的操作。ReLU 表示修正线性单元(Rectified Linear Unit),是一个非线性操作。它的输入如下所示:

    ReLU

    ReLU 是一个元素级别的操作(应用到各个像素),并将特征图中的所有小于 0 的像素值设置为零。ReLU 的目的是在 ConvNet 中引入非线性,因为在大部分的我们希望 ConvNet 学习的实际数据是非线性的(卷积是一个线性操作——元素级别的矩阵相乘和相加,所以我们需要通过使用非线性函数 ReLU 来引入非线性。

    ReLU 操作可以从下面的图中理解。它展示的 ReLU 操作是应用到上面图 6 得到的特征图之一。这里的输出特征图也可以看作是“修正”过的特征图。

    ReLU

    其他非线性函数,比如 tanh 或者 sigmoid 也可以用来替代 ReLU,但 ReLU 在大部分情况下表现是更好的。

    池化操作

    空间池化(Spatial Pooling)(也叫做亚采用或者下采样)降低了各个特征图的维度,但可以保持大部分重要的信息。空间池化有下面几种方式:最大化、平均化、加和等等。

    对于最大池化(Max Pooling),我们定义一个空间邻域(比如,2x2 的窗口),并从窗口内的修正特征图中取出最大的元素。除了取最大元素,我们也可以取平均(Average Pooling)或者对窗口内的元素求和。在实际中,最大池化被证明效果更好一些。

    下面的图展示了使用 2x2 窗口在修正特征图(在卷积 + ReLU 操作后得到)使用最大池化的例子。

    ReLU

    我们以 2 个元素(也叫做“步长”)滑动我们 2x2 的窗口,并在每个区域内取最大值。如上图所示,这样操作可以降低我们特征图的维度。

    在下图展示的网络中,池化操作是分开应用到各个特征图的(注意,因为这样的操作,我们可以从三个输入图中得到三个输出图)。

    网络

    下图展示了在图 9 中我们在 ReLU 操作后得到的修正特征图的池化操作的效果。

    池化

    池化函数可以逐渐降低输入表示的空间尺度。特别地,池化:

    • 使输入表示(特征维度)变得更小,并且网络中的参数和计算的数量更加可控的减小,因此,可以控制过拟合
    • 使网络对于输入图像中更小的变化、冗余和变换变得不变性(输入的微小冗余将不会改变池化的输出——因为我们在局部邻域中使用了最大化/平均值的操作。
    • 帮助我们获取图像最大程度上的尺度不变性(准确的词是“不变性”)。它非常的强大,因为我们可以检测图像中的物体,无论它们位置在哪里(参考 18 和 19 获取详细信息)。

    目前为止的故事

    网络

    到目前为止我们了解了卷积、ReLU 和池化是如何操作的。理解这些层是构建任意 CNN 的基础是很重要的。正如上图所示,我们有两组卷积、ReLU & 池化层 —— 第二组卷积层使用六个滤波器对第一组的池化层的输出继续卷积,得到一共六个特征图。接下来对所有六个特征图应用 ReLU。接着我们对六个修正特征图分别进行最大池化操作。

    这些层一起就可以从图像中提取有用的特征,并在网络中引入非线性,减少特征维度,同时保持这些特征具有某种程度上的尺度变化不变性。

    第二组池化层的输出作为全连接层的输入,我们会在下一部分介绍全连接层。

    全连接层

    全连接层是传统的多层感知器,在输出层使用的是 softmax 激活函数(也可以使用其他像 SVM 的分类器,但在本文中只使用 softmax)。“全连接(Fully Connected)”这个词表明前面层的所有神经元都与下一层的所有神经元连接。如果你对多层感知器不熟悉的话,我推荐你阅读这篇文章

    卷积和池化层的输出表示了输入图像的高级特征。全连接层的目的是为了使用这些特征把输入图像基于训练数据集进行分类。比如,在下面图中我们进行的图像分类有四个可能的输出结果(注意下图并没有显示全连接层的节点连接)。

    全连接

    除了分类,添加一个全连接层也(一般)是学习这些特征的非线性组合的简单方法。从卷积和池化层得到的大多数特征可能对分类任务有效,但这些特征的组合可能会更好。

    从全连接层得到的输出概率和为 1。这个可以在输出层使用 softmax 作为激活函数进行保证。softmax 函数输入一个任意大于 0 值的矢量,并把它们转换为零一之间的数值矢量,其和为一。

    把它们组合起来——使用反向传播进行训练

    正如上面讨论的,卷积 + 池化层的作用是从输入图像中提取特征,而全连接层的作用是分类器。

    注意在下面的图中,因为输入的图像是船,对于船这一类的目标概率是 1,而其他三类的目标概率是 0,即

    • 输入图像 = 船
    • 目标矢量 = [0, 0, 1, 0]

    网络

    完整的卷积网络的训练过程可以总结如下:

    • 第一步:我们初始化所有的滤波器,使用随机值设置参数/权重

    • 第二步:网络接收一张训练图像作为输入,通过前向传播过程(卷积、ReLU 和池化操作,以及全连接层的前向传播),找到各个类的输出概率

      • 我们假设船这张图像的输出概率是 [0.2, 0.4, 0.1, 0.3]
      • 因为对于第一张训练样本的权重是随机分配的,输出的概率也是随机的
    • 第三步:在输出层计算总误差(计算 4 类的和)

      • Total Error = ∑  ½ (target probability – output probability) ²
    • 第四步:使用反向传播算法,根据网络的权重计算误差的梯度,并使用梯度下降算法更新所有滤波器的值/权重以及参数的值,使输出误差最小化

      • 权重的更新与它们对总误差的占比有关
      • 当同样的图像再次作为输入,这时的输出概率可能会是 [0.1, 0.1, 0.7, 0.1],这就与目标矢量 [0, 0, 1, 0] 更接近了
      • 这表明网络已经通过调节权重/滤波器,可以正确对这张特定图像的分类,这样输出的误差就减小了
      • 像滤波器数量、滤波器大小、网络结构等这样的参数,在第一步前都是固定的,在训练过程中保持不变——仅仅是滤波器矩阵的值和连接权重在更新
    • 第五步:对训练数据中所有的图像重复步骤 1 ~ 4

    上面的这些步骤可以训练 ConvNet —— 这本质上意味着对于训练数据集中的图像,ConvNet 在更新了所有权重和参数后,已经优化为可以对这些图像进行正确分类。

    当一张新的(未见过的)图像作为 ConvNet 的输入,网络将会再次进行前向传播过程,并输出各个类别的概率(对于新的图像,输出概率是使用已经在前面训练样本上优化分类的参数进行计算的)。如果我们的训练数据集非常的大,网络将会(有希望)对新的图像有很好的泛化,并把它们分到正确的类别中去。

    注 1: 上面的步骤已经简化,也避免了数学详情,只为提供训练过程的直观内容。可以参考文献 4 和 12 了解数学公式和完整过程。

    注 2:在上面的例子中我们使用了两组卷积和池化层。然而请记住,这些操作可以在一个 ConvNet 中重复多次。实际上,现在有些表现最好的 ConvNet 拥有多达十几层的卷积和池化层!同时,每次卷积层后面不一定要有池化层。如下图所示,我们可以在池化操作前连续使用多个卷积 + ReLU 操作。还有,请注意 ConvNet 的各层在下图中是如何可视化的。

    car

    卷积神经网络的可视化

    一般而言,越多的卷积步骤,网络可以学到的识别特征就越复杂。比如,ConvNet 的图像分类可能在第一层从原始像素中检测出边缘,然后在第二层使用边缘检测简单的形状,接着使用这些形状检测更高级的特征,比如更高层的人脸。下面的图中展示了这些内容——我们使用卷积深度置信网络学习到的特征,这张图仅仅是用来证明上面的内容(这仅仅是一个例子:真正的卷积滤波器可能会检测到对我们毫无意义的物体)。

    demo

    Adam Harley 创建了一个卷积神经网络的可视化结果,使用的是 MNIST 手写数字的训练集13。我强烈建议使用它来理解 CNN 的工作原理。

    我们可以在下图中看到网络是如何识别输入 “8” 的。注意下图中的可视化并没有单独展示 ReLU 操作。

    Conv_all

    输入图像包含 1024 个像素(32 x 32 大小),第一个卷积层(卷积层 1)由六个独特的 5x5 (步长为 1)的滤波器组成。如图可见,使用六个不同的滤波器得到一个深度为六的特征图。

    卷积层 1 后面是池化层 1,在卷积层 1 得到的六个特征图上分别进行 2x2 的最大池化(步长为 2)的操作。你可以在池化层上把鼠标移动到任意的像素上,观察在前面卷积层(如上图所示)得到的 4x4 的小格。你会发现 4x4 小格中的最大值(最亮)的像素将会进入到池化层。

    pooling

    池化层 1 后面的是六个 5x5 (步长为 1)的卷积滤波器,进行卷积操作。后面就是池化层 2,进行 2x2 的最大池化(步长为 2)的操作。这两层的概念和前面描述的一样。

    接下来我们就到了三个全连接层。它们是:

    • 第一个全连接层有 120 个神经元
    • 第二层全连接层有 100 个神经元
    • 第三个全连接层有 10 个神经元,对应 10 个数字——也就做输出层

    注意在下图中,输出层中的 10 个节点的各个都与第二个全连接层的所有 100 个节点相连(因此叫做全连接)。

    同时,注意在输出层那个唯一的亮的节点是如何对应于数字 “8” 的——这表明网络把我们的手写数字正确分类(越亮的节点表明从它得到的输出值越高,即,8 是所有数字中概率最高的)。

    final

    同样的 3D 可视化可以在这里看到。

    其他的 ConvNet 架构

    卷积神经网络从上世纪 90 年代初期开始出现。我们上面提到的 LeNet 是早期卷积神经网络之一。其他有一定影响力的架构如下所示3

    • LeNet (1990s): 本文已介绍。
    • 1990s to 2012:在上世纪 90 年代后期至 2010 年初期,卷积神经网络进入孵化期。随着数据量和计算能力的逐渐发展,卷积神经网络可以处理的问题变得越来越有趣。
    • AlexNet (2012) – 在 2012,Alex Krizhevsky (与其他人)发布了 AlexNet,它是比 LeNet 更深更宽的版本,并在 2012 年的 ImageNet 大规模视觉识别大赛(ImageNet Large Scale Visual Recognition Challenge,ILSVRC)中以巨大优势获胜。这对于以前的方法具有巨大的突破,当前 CNN 大范围的应用也是基于这个工作。
    • ZF Net (2013) – ILSVRC 2013 的获胜者是来自 Matthew Zeiler 和 Rob Fergus 的卷积神经网络。它以 ZFNet (Zeiler & Fergus Net 的缩写)出名。它是在 AlexNet 架构超参数上进行调整得到的效果提升。
    • GoogLeNet (2014) – ILSVRC 2014 的获胜者是来自于 Google 的 Szegedy等人的卷积神经网络。它的主要贡献在于使用了一个 Inception 模块,可以大量减少网络的参数个数(4M,AlexNet 有 60M 的参数)。
    • VGGNet (2014) – 在 ILSVRC 2014 的领先者中有一个 VGGNet 的网络。它的主要贡献是展示了网络的深度(层数)对于性能具有很大的影响。
    • ResNets (2015) – 残差网络是何凯明(和其他人)开发的,并赢得 ILSVRC 2015 的冠军。ResNets 是当前卷积神经网络中最好的模型,也是实践中使用 ConvNet 的默认选择(截至到 2016 年五月)。
    • DenseNet (2016 八月) – 近来由 Gao Huang (和其他人)发表的,the Densely Connected Convolutional Network 的各层都直接于其他层以前向的方式连接。DenseNet 在五种竞争积累的目标识别基准任务中,比以前最好的架构有显著的提升。可以在这里看 Torch 实现。

    总结

    在本篇文章中,我尝试使用简单的方式来解释卷积神经网络背后的主要概念。我简化/跳过了一些细节,但希望本篇文章可以让你对它们有一定的了解。

    本文最开始是受 Denny Britz 的理解用于自然语言处理的卷积神经网络(我强烈建议阅读)启发,大量的解释也是基于那篇文章。如果你想要对这些概念有更深的理解,我建议你浏览一下 Stanford 的 ConvNet 课程中的笔记,以及下面所列的参考文献。如果你对上面的概念有什么疑问,或者有问题和建议,欢迎在下面留言。

    本文中使用的所有图像和动画的版权都归下面参考文献中对应作者所有。

    参考文献

    1. Clarifai Home Page
    2. Shaoqing Ren, et al, “Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”, 2015,arXiv:1506.01497
    3. Neural Network Architectures, Eugenio Culurciello’s blog
    4. CS231n Convolutional Neural Networks for Visual Recognition, Stanford
    5. Clarifai / Technology
    6. Machine Learning is Fun! Part 3: Deep Learning and Convolutional Neural Networks
    7. Feature extraction using convolution, Stanford
    8. Wikipedia article on Kernel (image processing)
    9. Deep Learning Methods for Vision, CVPR 2012 Tutorial
    10. Neural Networks by Rob Fergus, Machine Learning Summer School 2015
    11. What do the fully connected layers do in CNNs?
    12. Convolutional Neural Networks, Andrew Gibiansky
    13. A. W. Harley, “An Interactive Node-Link Visualization of Convolutional Neural Networks,” in ISVC, pages 867-877, 2015 (link)
    14. Understanding Convolutional Neural Networks for NLP
    15. Backpropagation in Convolutional Neural Networks
    16. A Beginner’s Guide To Understanding Convolutional Neural Networks
      Vincent Dumoulin, et al, “A guide to convolution arithmetic for deep learning”, 2015, arXiv:1603.07285
    17. What is the difference between deep learning and usual machine learning?
    18. [How is a convolutional neural network able to learn invariant features?63
    19. A Taxonomy of Deep Convolutional Neural Nets for Computer Vision


    原文链接:http://www.hackcv.com/index.PHP/archives/104/

    英文原文:https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/

    1
    0

    展开全文
  • 面向对象编程的解释

    2015-06-22 06:56:00
    同类对象抽象出其共性,形成类。类中大多数数据,只能用本类方法进行处理。类通过一个简单外部接口与外界发生关系,对象与对象之间通过消息进行通信。程序流程由用户在使用中决定。 一、封装:  封装是...

    面对对象就是:
    把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。程序流程由用户在使用中决定。

    一、封装:

      封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。被封装的对象通常被称为抽象数据类型。 

     封装的意义:
      封装的意义在于保护或者防止代码(数据)被我们无意中破坏。在面向对象程序设计中数据被看作是一个中心的元素并且和使用它的函数结合的很密切,从而保护它不被其它的函数意外的修改。

      封装提供了一个有效的途径来保护数据不被意外的破坏。相比我们将数据(用域来实现)在程序中定义为公用的(public)我们将它们 (fields)定义为私有的(privat)在很多方面会更好。私有的数据可以用两种方式来间接的控制。第一种方法,我们使用传统的存、取方法。第二种 方法我们用属性(property)。

      使用属性不仅可以控制存取数据的合法性,同时也提供了“读写”、“只读”、“只写”灵活的操作方法。

    访问修饰符:

    Private:只有类本身能存取.
    Protected:类和派生类可以存取.
    Internal:只有同一个项目中的类可以存取.
    Protected Internal:是Protected和Internal的结合.
    Public:完全存取.

     二、继承:

      继承主要实现重用代码,节省开发时间。

    1、C#中的继承符合下列规则:

      1. 继承是可传递的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。Object类作为所有类的基类。
      2. 派生类应当是对基类的扩展。派生类可以添加新的成员,但不能除去已经继承的成员的定义。
      3. 构造函数和析构函数不能被继承。除此之外的其它成员,不论对它们定义了怎样的访问方式,都能被继承。基类中成员的访问方式只能决定派生类能否访问它们。
      4. 派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不因为这派生类删除了这些成员,只是不能再访问这些成员。
      5. 类可以定义虚文法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态性。

      2、new关键字

       如果父类中声明了一个没有friend修饰的protected或public方法,子类中也声明了同名的方法。则用new可以隐藏父类中的方法。(不建议使用)

      3、base关键字

       base 关键字用于从派生类中访问基类的成员:

      1. 调用基类上已被其他方法重写的方法。
      2. 指定创建派生类实例时应调用的基类构造函数。

    三、多态

      1、多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

      编译时的多态性:

      编译时的多态性是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。

      运行时的多态性:

      运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中,运行时的多态性通过虚成员实现。

      编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。

       2、实现多态:

      1. 接口多态性。
      2. 继承多态性。
      3. 通过抽象类实现的多态性。

      3、override关键字:

       重写父类中的virtual修饰的方法,实现多态。

    转载于:https://www.cnblogs.com/zhao123/p/4592848.html

    展开全文
  • static修饰成员变量:如果有数据需要被共享给所有对象使用时,那么就可以使用static修饰。 总结: 1、在普通方法中,可以直接直接访问非静态变量和静态...2、静态方法中可以直接调用同类静态成员,但不能直...

    static修饰成员变量 :如果有数据需要被共享给所有对象使用时,那么就可以使用static修饰。 

    总结:

    1、在普通方法中,可以直接直接访问非静态变量和静态变量。

    2、在被static修饰的静态方法,如main方法,要访问非静态,必须通过创建对象去访问。

     

    1、被static静态修饰的方法可以直接使用类名或者对象调用方法

     

    2、静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员

     

    如果希望在静态方法中调用非静态变量,可以通过创建类的对象,然后通过对象来访问非静态变量。如:

    静态方法中不能直接调用非静态方法,需要通过对象问非静态方法。如:

     

     void:如果方法不需要返回值,就用void。

    如果不加入void,那么需要返回值也就是return  语句

    转载于:https://www.cnblogs.com/zengjiao/p/6641553.html

    展开全文
  • 递归(英语:recursion)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。1 递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。2 绝大多数编程...

    递归和尾递归的运行流程解释

    ###递归定义

    递归(英语:recursion)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法1 递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。2 绝大多数编程语言支持函数的自调用,在这些语言中函数可以通过调用自身来进行递归。计算理论可以证明递归的作用可以完全取代循环,因此有很多在函数编程语言(如Scheme)中用递归来取代循环的例子。(摘自维基百科)

    ###尾递归定义

    在计算机学里,尾调用是指一个函数里的最后一个动作是返回一个函数的调用结果的情形,即最后一步新调用的返回值直接被当前函数的返回结果。1此时,该尾部调用位置被称为尾位置。尾调用中有一种重要而特殊的情形叫做尾递归。经过适当处理,尾递归形式的函数的运行效率可以被极大地优化。1尾调用原则上都可以通过简化函数调用栈的结构而获得性能优化(称为“尾调用消除”),但是优化尾调用是否方便可行取决于运行环境对此类优化的支持程度如何。(摘自维基百科)

    ###前提知识

    • 递归我将它分为两个过程,一个我将它称为递归,另一个我将它称为回溯. 递归的函数的运行主要有这两个流程,递归的进入,回溯的退出,这两个过程的分界是以递归出口为分界的.
    • 递归的实现形式是使用,递归函数的进入(递归)类似与压栈,递归函数的退出(回溯)类似于出栈.

    递归样例和解释

    【编程题】幂运算三(递归函数
    题目ID:1137
    【问题描述】 求x^n。
    【输入形式】一行2个数,第一个整数表示x,第二个大于等于零的整数表示n,二数之间用空格分隔。
    【输出形式】一行一个整数,表示x的n次方
    【样例输入】2 3
    【样例输出】8

    【样例说明】2的3次方结果为8
    【评分标准】5组测试用例,每组2分,共计10分

    【测试用例】
    1)
    输入:
    2 3
    输出:
    8
    2)
    输入:
    3 5
    输出:
    243

    3)
    输入:
    -17 4
    输出:
    83521

    4)
    输入:
    22 0
    输出:
    1

    5)
    输入:
    -1287 0
    输出:
    1

    //普通递归
    #include<stdio.h>
    long my_pow1(long x,int n){
        if(n==0) return 1;      //递归出口
        return x*(my_pow1(x,--n));  //除了调用自身外还乘多了个x,即一般的递归
    }
    int main(){
        long  x;
        int  n;
        scanf("%ld%d",&x,&n);
        printf("%ld\n",my_pow1(x,n));
        return 0;
    }  
    • 运行图解
      图片描述
      解释:
      普通的递归过程是在一个函数中,结果依靠自身的调用来得出,例如求幂运算,pow(2,3)代表求2的3次方,由于pow(2,3)未知,我们可以把它分解成2*pow(2,2),pow(2,2)也未知,又可分解成2*pow(2,1),以此类推,直到pow(2,0)可知(if中定义0时返回1),即pow(2,0)返回值是1.
      在这个递归过程中,pow函数的建立就是一个个压栈的过程
      我把它称为函数栈

    clipboard.png
    压栈压入所以函数后,直到最后一个,可以获得最后一个函数的返回值,由这个返回值可以依次推出栈内所有函数的返回值(回溯),即退栈,pow(2,0)返回1,推的pow(2,1)返回2*pow(2,0),即2*1=2,pow(2,2)返回2*pow(2,1),即2*2=4,直到退到栈内最后一个函数pow(2,3),可获得pow(2,3)的返回值为2*pow(2,2)即8;

    ###尾递归样例和解释

    【编程题】吃糖(尾递归函数
    题目ID:1135
    【问题描述】小樱是个爱吃糖的女孩, 哥哥送了她n(1<=n<=30)颗糖,怎么吃?一天吃1颗;一天吃2颗。嗯,那就每天吃一颗或两颗吧。
    1颗糖,肯定只有(1)一种吃法;2颗糖,有(1,1)和(2)两种吃法;3颗糖,有(1,1,1)、(1,2)和(2,1)三种吃法。注 (2,1)表示第一天吃2颗,第二天吃1颗。*
    你能帮小樱算出,吃完这n颗糖,有多少种吃法吗?请编写一个尾递归函数来解决此问题

    【测试用例】
    1)
    输入:
    1
    输出:
    result=1

    2)
    输入:
    4
    输出:
    result=5

    3)
    输入:
    15
    输出:
    result=987

    4)
    输入:
    20
    输出:
    result=10946

    5)
    输入:
    30
    输出:
    result=1346269

    实际上这道题是一个斐波那契数列的变体,可用尾递归函数解决

    //尾递归
    #include <stdio.h>
    int ci(int n,int pre,int next)
    {
        int sum;
        if (n==1){              //递归出口(递归和回溯的分界点)
            return pre;
        }
        return ci(n-1,next,pre+next);  //除了调用自身外没有其他操作即为尾递归
    }
    int main()
    {
        int n;
        int sum;
        scanf ("%d",&n);
        printf ("result=%d",ci(n,1,2));
        return 0;
    }

    运行图解
    图片描述

    解释:

    • 尾递归是属于递归的,它也有递归压栈两个过程,但是由于尾递归除了调用自身外没有任何其他多余的操作,所以它在进行到递归出口的时候,获得一个返回值,进行回溯的每一个函数的返回值都是它的调用的另一个规模缩小的函数,也就是说:函数在压栈的时候,压到栈顶函数,获得一个返回值,退栈,当前栈顶获得返回值,这个值是退栈的那个元素的返回值,依次类推,直到所有函数退栈,获得的返回值都是一个值,也就是递归出口的那个值.
    • 用例子来表示,即是回溯过程中,ci(1,5,8)获得了返回值5,ci(2,3,5)的返回值是ci(1,5,8),也就是5,ci(3,2,3)的返回值是ci(2,3,5),也就是5,ci(4,1,2)的返回值也是5;
    • 从尾递归的流程中可以看出,尾递归的回溯的过程是完全没用的,直到递归出口就已经获得了想要的值了.
    • 递归的过程也只是相当于循环而已,ci(4,1,2),4是要求斐波那契变体的第4项,1是第一项,2是第二项,从4减到1起到一个计数作用,1和2也是作为递推的起点
    • 所以,在很多语言中,尾递归可被优化成和循环(递推)一样的效率.

      总结

    • 递归有两个过程,递归和回溯,递归到最深处获得一个返回值,由这个返回值回溯推出想要求的函数的返回值,起到缩小规模计算的作用.
    • 尾递归与递归的不同处在于尾递归在return处除了调用自身外没有其他操作,导致回溯的过程是完全浪费的.
    • 尾递归在一些语言中可以优化成和循环一样的执行效率.
      *下图是普通递归和尾递归的执行图示:
      图片描述
      图片描述

    转载于:https://www.cnblogs.com/fanqieya/p/10823200.html

    展开全文
  • 解释型语言和编译型语言区别 标签: 解释型语言和编译型语言区别解释型语言和编译型语言编译型语言和解释型语言区别 2013-11-24 17:58 13702人阅读 评论(11) 收藏 举报 分类: ...
  • 自己字节码编译器和解释器 如何使用 使用Gradle: dependencies { compile 'com.github.bloodshura:venusscript:1.3.0' } 使用Maven: <groupId>com.github.bloodshura</groupId> <artifactId>venusscript ...
  • 总结了下本人在长期项目中使用xlC编译选项,为了自己查询方便,也同时为了给爱好同类技术朋友一个资料。如果您发现还有非常有用选项,请给我留言。不胜感激。虽然这个总结应该属于C&C++类别。但我认为该...
  • 金星脚本 ...自己字节码编译器和解释器 如何使用 使用Gradle: dependencies { compile 'com.github.bloodshura:venusscript:1.3.0' } 使用Maven: <groupId>com.github.bloodshura</groupId>
  • this(),首先说明只能在自己类中使用,也就是说多个构造函数时,想调用同类另一个构造函数时就可以用this base(),是让子类来调用父类中构造方法,这样就可以减少一些代码书写 下面用代码将两个不同之处列...
  • 为满足煤田地质和地球物理教学实验需要,根据煤田三维地震资料解释方法和原理,设计开发了基于Windows平台煤田地震解释教学软件系统.该系统采用4层架构体系结构设计,包括数据层、基础框架层、应用框架层和应用分析...
  • 虽然从大一就开始学习面向对象语言C++,但认为...回顾:用abstract关键词修饰的类,抽象类的往往用于同类的一般化,抽象类不可以被实例化。比如:可以将Animal这个类定义为抽象类:public abstract Animal。还有它跟接
  • 命令选项和参数带[]是表示可能省略带<...是表示同类内容可以出现多次------------------------------------------------------------------------------------------------------------------------------...
  • 根据百度百科上的解释: 如果后验分布与先验分布属于同类(分布簇),则先验分布与后验分布被称为共轭分布,而先验分布被称为似然函数的共轭先验。 上面这个定义有点复杂,我们待会儿再回过头来看这个定义 P(θ∣x)...
  • 多买几本书同类的书——因为每个作者的出发点是不一样的,哪怕对同一个概念都有不同的解释说明。理解知识的重要过程之一就如牛的反刍一样,要嚼一遍、咽下去、再吐出来、再嚼一遍、再咽下去……所以,既然一本书可以...
  • 乔治敦大学继续研究学院数据科学证书的同类群组23顶点项目 团队成员:Griffin,Ermina,Yephet和Aidan 自述内容 完成后添加内容并带有指向各节链接 抽象 添加摘要 背景资料 说明项目背景 资料采购 谈谈我们在...
  • Task与Activity详解 标签: candroid 2011-02-22 20:47 7556人阅读 评论(5) ...作者同类文章X 版权声明:本文为博主原创文章,未经博主允许不得转载。 1. Task是包
  • 常规使用springAOP功能,就是对一个serviceB方法进行切入记录日志,AOP能起作用。但是假如B方法被service中A方法调用,切入会失效,无法记录日志(这里切入失效是指对B切入...解释,要求熟悉动态代理原理 ...
  • 解释事件冒泡机制?

    2019-10-06 18:48:16
    a、在一个对象上触发某类... 父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次最顶层,即document对象(有些浏览器是window) b、冒泡型事件:事件按照从最特...
  • 直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次最顶层,即document对象(有些浏览器是window)。 如何来阻止Jquery事件冒泡? 通过一个小例子来解释 <!DOCTYPE ...
  • 一、通俗的解释: 问题提出:还是以iris的数据为例,有A、B、C三种花,每一类的特征都用4维特征向量表示。现在已知一个特征向量,要求对应的类别,而我们人可以直接通过眼睛看而作出分类的是在一维二维三维空间,而...
  • [名词解释:竞业禁止] 竞业禁止又称同业竞止,是指特定地位人或掌握原从业公司(企业)商业秘密人,在解除雇佣、劳动关系后在一定期限内(公司应付补偿金),不得实施其所服务营业具有竞争性质行为。...
  • 下次遇到和这个字符串同类的字符串,我们只需要判断是否符合特征,就知道这个字符串是不是同类的。举个例子:每个地方都有邮政编码。邮政编码就是按照一定的特征组织的。一共六位数。我们可以把它抽象成一个正则...
  • 下次遇到和这个字符串同类的字符串,我们只需要判断是否符合特征,就知道这个字符串是不是同类的。举个例子:每个地方都有邮政编码。邮政编码就是按照一定的特征组织的。一共六位数。我们可以把它抽象成一个正则...
  • 下次遇到和这个字符串同类的字符串,我们只需要判断是否符合特征,就知道这个字符串是不是同类的。举个例子:每个地方都有邮政编码。邮政编码就是按照一定的特征组织的。一共六位数。我们可以把它抽象成一个正则...
  • 一、通俗的解释:问题提出:还是以iris的数据为例,有A、B、C三种花,每一类的特征都用4维特征向量表示。现在已知一个特征向量,要求对应的类别,而我们人可以直接通过眼睛看而作出分类的是在一维二维三维空间,而不...
  • 题目链接 1137. 第 N 个泰波那契数 泰波那契序列 Tn 定义如下: ...解释: T_3 = 0 + 1 + 1 = 2 T_4 = 1 + 1 + 2 = 4 示例 2: 输入:n = 25 输出:1389537 提示: 0 <= n <= 37 答案保证是一个 32
  • 历史上曾经多次出现因输入错误而导致大规模技术宕机及严重损失。 Amazon Web Services在经历严重S3服务宕机之后进行了全面检查,而原因则被归结为一点:输入错误。...云巨头在对服务宕机事件进行解释...
  • 保险术语解释(五)

    千次阅读 2005-08-14 09:30:00
    海上保险承担危险主要是指因航海而发生危险或与航海有关危险,即海上灾害、火灾、战争、海盗、抢夺、盗窃、被捕,主权者扣押、限制和扣留、抛弃、船员不法行为及同类或保险单所特定其他危险。...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 327
精华内容 130
关键字:

同类的解释