极市吧 关注:17贴子:87
  • 10回复贴,共1

【极市】万元芳 Prisma算法理论讲解分析与tensorflow复现

取消只看楼主收藏回复

从今天开始,这里将分享极市平台所分享过的关于计算机视觉的干货,欢迎大家围观~~


1楼2017-06-16 11:15回复
    大家好,应极视角的邀请,非常冒昧得给大家来讲一下如何用TensorFlow来复现Prisma App核心算法。先自我介绍一下,我目前是北京化工大学的在读硕士,研究方向是机器学习算法,偏神经网络方向,科技创业团队AG Group的创始人万元芳,大家可以问我怎么看,我都是可以回答的。今天的主题是 prisma 核心算法理论理论讲解分析以及tensorflow的复现,解读的是CVPR2016 的一篇论文。在2015年就有德国的科学家发布了 Image。 2016和2015是一个方法,但是2016上的方法有所改进,所以今天讲的还是prisma的核心算法,也就是如何对图像风格进行转换。
    既然讲风格如何转换,我们先从prisma这个软件是什么开讲。最早Prisma是由四个俄罗斯人开发的App,一发布出来瞬间就在俄罗斯病毒式得传播,然后蔓延到了全世界。Ppt左下角和右边就是用prisma处理的,如果把照片风格处理得很净的话,图片确实会变得特别特别得漂亮,变成艺术品,这也是为什么它这么火的原因。

    这篇文章是我们今天要讲的主要内容,下面的三个作者是最早创造这个算法的德国科学家,这篇文章是他们对前面文章的总结和改进,所以该文献主要讲的仍然是是prisma的核心算法,然后我们今天带来的就是该文献的解读。


    3楼2017-06-18 17:56
    回复

      既然我们提到了卷积神经网络,我们说一下它的大概历史,创始人是 LeCun大神。他在1998年做题目时受到猫的大脑皮层视觉细胞的触发设计出了第一个卷积神经网络,他用这个卷积神经网络做了一个MNIST数据库的字符识别,当时还没有这个数据库,做的是手写数字识别(后来他做得这个工作被整理成了MNIST数据库),从0,1,2,3,4,5,6,7,8,9 有10个字符,我们输入是的32*32的一个手写字符图像,就像ppt上展示的一样,我们输入了一个图像,通过多个卷积层和池化层,再经过三个全连接层,最后的输出层有10个输出,输出的时候10个层只有一个神经元被激活,根据激活的神经元所在的位置(这里使用的是独热编码one hot encoding),根据激活神经元所在位置就可以识别出目前到底手写的是什么数字。
      这个网络结构在现在做神经网络的人看来非常简单,但是在当时的举措是无中生有,很大程度上震动了当时的学界,所以这个网络结构也以他的名字命名,LeNet.这是最早的卷积神经网络模型,但是由于受到当时计算机的计算速度限制,层数非常少,计算性能一般,但是该网络却成了整个卷积神经网络学派的萌芽。
      真正的深度学习流派也就是卷积网络真正崛起是在2012年,bengio大神的一个弟子在参加Imagenet的时候建立的一个网络,由于Lenet的神经网络的计算复杂度比较高,需要一层一层的求导,对比传统的SVM(Support Vector Machine),SVM在极少的运算情况下,仍然能够达到媲美它运算的一个效果,所以当时在科学领域,大家都在推崇SVN 以及决策森林等传统学习方法,而不用神经网络。指导2012年Alexnet 横空出世,这 第一次使用神经网络来参加imagenet,imagenet 是由李飞飞建立的 数据库 最开始是由10个种类图片的数据库,然后进行分类。深度远比lenet要深,它把网络分成了上半部分和下半部分进行计算,两部分进行参数共享,得益于GPU的发展。用了两个GPU进行计算,极大程度上提高了运算速度。
      LeNet时代中央处理器晶体管总数目是10^6个,参与训练的总像素是10^7个,而在2012年的ImageNet大赛时,中央处理器晶体管总数达到了10^9个,参与训练的像素点数目达到了10^14个。
      2012年 Alexnet 问世后,深度学习开始飞速发展。


      4楼2017-06-19 15:38
      回复

        举例计算机是怎么理解图片的,我们人类看到的是图像的内容,在神经网络叫图像层面的理解,比如上图,我们看到的是一只猫,而计算机看到的是一大堆的数字,以矩阵的形式存在,因为是彩色图像而因为有RGB三个通道,这个矩阵是3层的矩阵,矩阵中的值是300*100*3. 300*100是分辨率,3是通道数。
        本文所用到的ppt是斯坦福教授李飞飞老师在2016年斯坦福大学CS231n课用的课件,关注HiTech工坊,查看完整的课件解析。

        简单的说一下利用卷积神经网络做图像的识别,左边输入的图像是车的图片,首先经过第一层卷积层,然后经过一个激活函数(Activation function),这里采用的是RELU,后面再说明为什么采用这个函数。经过卷积层激活,下一层再激活 然后到Pooling层池化层,池化层的作用是降采样,也就是宽和高降低一倍,是一个数据压缩的过程。卷积层卷积层池化层,卷积层 卷积层 池化层,到第三个池化层的时候,图片就已经被压缩到非常小,由于被压缩得非常小,用的卷积核数目会比较多,我这边是输入了一张图片,最后输出了10幅图像。在实际过程中,我们用的卷积核比较多,到最后的一层数目会很多,远不止10副图像,我这边的10幅图像最后采用了卷积手段直接拉成数列的形式,做成一个全连接层的输入后面的FC就是 Full Connection。也就是一个全连接层,大家可以参考MLP,多层感知器那个结构,我把最后卷积层的结果当做输入,经过多层感知器,最后连接一个softmax层进行输出 判断这幅图像的最有可能的类别。像乐村大神的 Lenet ,最后输出层上的10个神经元,有且只有一个神经元会被激活。
        根据这一个被激活的神经元的位置来判定出它到底是哪个种类,比如我们这个是第一个神经元被激活,第一个神经元激活的概率远高于其他神经元,我们就判定我们这个图像属于第一个神经元,也即是判定它是一辆车。


        5楼2017-06-19 15:40
        回复

          从上面的卷积层例子,我们可以看到,前面几层卷积层的过程中,每个卷积核只能看到前一幅图像的一部分,3*3的卷积核只能看到 9个像素点,5*5 看到25个像素点,前面的卷积层提取出来的我们称作Low-levelfeature, 也就是我们看到的是非常低端的特征也就是我们在传统的计算机视觉中使用的,如检测圆,检测直线等,这些只通过一层卷积差不多就可以实现。
          随着卷积层逐步加深的话每个像素点能覆盖原图像的很大部分区域,所以说它后面的卷积层每个神经元所看到的视野不仅仅局限于几个像素点,能够逐渐看到整个图像的一部分甚至最后的神经元可以看到整个图像,能够做到整幅图像的理解。我们以3个卷积层为例,我们就可以看到middle-level的特征,中间这个位置已经可以提出比直线、弧线更高级的东西,它差不多看出车轮的形状以及绗架的结构。
          再往后,在第三个卷积层,几乎每个神经元都能看到原图像中的整幅图像所有像素,他提取的特征定义为high-level feature,高阶的特征,这正是本文需要的特征。随着卷积层加深后,会分析出一些细微的特征,人类通过肉眼几乎无法直接观察到,可以看到图片中越往后是越模糊,但是每副图像都可以观察汽车的每个部件进行特征识别然后三个卷积层之后,我们所提出的特征就是这幅图像几乎是最高级的特征,我们用这些特征来训练我们的分类器,输出层用one hot encoding,独热编码的话,可以用softmax做分类判定最有可能的种类,把对应的神经元激活,然后进行一个分类。

          那么大家从这幅图像中可以看到,为什么往深一层的卷积层可以看到更多的特征呢?我们以3*3的卷积核举例,也就是我的输入层图像。对于第一个卷积层里的像素,因为这个像素是通过输入input图像里3*3也就是9个像素点卷积之后求和得到的一个像素,所以它的像素值反应了输入层里9个像素的值, 从第一层卷积层到第二层卷积层 第二个卷积层的像素点可以看到第一个卷积层里9个像素点的值,第一个卷积层每个像素对应输入层9个像素 第二个卷积层每个像素对应第一个卷积层的9个像素,第二个卷积层一个像素覆盖了输入层的81个像素,所以层数越多,它能看到的东西也就越多,可以这样进行一个全局的理解。


          6楼2017-06-19 15:41
          回复

            这张ppt熟悉神经网络的同学会非常了解,讲的是activation functions,也就是激活函数,神经网络说白了就是线性求和然后激活,就像初中学过的y=kx+b。区别仅仅在于 y是从y0到yn的向量,x从x0到xn的向量,定义的k 可能是从k00到Knn一个矩阵,做的一个比较高维度的y=Kx+b。在求和之后,y不可能直接输出,必须经过一个active方式来将其非线性化。因为神经网络每一个神经元所做的都是直接的乘法和加法,而乘法和加法属于一种线性的算法,学过链式法则的话我们可以知道,乘法和加法都属于线性算法,乘法和加法的组合仍然是线性的,为了保证我们的神经网络有更大的拟合程度,因为我们绝大多数的信号都是非线性信号,所以我们要将它非线性化,所以需要用到一个active function, 这里介绍 三种:sigmoid, tanh,ReLu.
            Sigmoid激活函数是数学中常见的S曲线,不管数据x是从负无穷到正无穷,整个自定义域内,不管x是什么值,总能将值锁定在0和1之间。它在[-5 ,5] 区间性能比较好,但是一旦x<-5或者x>5,它的导数几乎就是0 ,因为神经网络用的都是反向传播,说白了也就是求导,根据导数来优化它的参数。一旦当x的输入比较大或者比较小的话,梯度就会下降不见了,在优化的时候会出现一个饱和的现象,如果采用sigmoid的话,需要对输入数据进行正则化,把输入值尽量压缩在[0,1]区间。
            同理双曲正切(tanh)也像sigmoid函数一样,但是效果比较好的区间要远小于sigmoid,我们也需要把输入值尽量压缩在[-1,1]区间,与sigmoid不同之处是,双曲正切可以将数据压缩在[-1,1],而sigmoid是[0,1]
            本文所用的 Relu是比较新的active方式 由y=x和y=0两段函数拼起来的,如果x>0的话,激活函数是y=x,如果x<0,直接让输出=0。这样的好处是:
            1.不受定义域的影响, 正无穷和负无穷都可以用,不需要进行正则化处理,省略掉一个比较麻烦的步骤。
            2. 它只考虑对神经元起正激励的部分,起负激励的部分就不进行修正,让神经网络往更好的方向发展,如果输入的信号对神经元有激励作用,我会让激励作用放大再放大。然后对于y=x,不管输入x是什么值,导数永远为1.

            这个ppt上写的是max pooling 也就是池化,刚才在简单的介绍卷积网络的时候用到的池化。这里把每4个单元的像素点压缩成一个单元,原图像是4行4列,我们取其中的2行2列,变成了两行两列的图像。我们做的是全局的缩放,图像的基本特征得到保留,同时可以降低图像的维度。我在计算原图像输入的话,它有4*4 有16个像素点,用池化过的图像就只有2*2 4个像素点,这4个像素点还保留着16个像素点的特征。所以说随着卷积层不断的加深,输入图片会越来越多,计算量会增大,在保留图像基本特征的情况下对图像进行降维,这时候用的是max pooling,作用是下采样(down sample),也就是降低图像维度,来减少计算量。

            这幅图像是一个例子。假设这个是我们已经处理过的卷积层输出,它变成了2*2的矩阵,我们把2*2层矩阵拉成1*4的数列作为输入,此时我们给它一个weight权重和bias偏置值,进行上面的y=Kx+b的过程,然后输出层有三个种类,在进行y=kx+b后,第一行的w*x+b 得到-96.8分,同理第二行和第三行可以得到437.9分和61.95分 以此类推,输出层选择的是得分最高的,让那个位置的神经元激活,通过三个输出层的分数可以看到第二个神经元得到了激活,但是很明显这个数据是不对的,第二层代表图像是狗,所以计算错误,首先x 是不能改的,只能改w和b。这是我们初中数学一样,y=kx+b,k和b跑偏了的话,是可以通过y和x的值代进去求,但是因为我们这边参数w和b值太多,我们没办法直接求出来,所以需要用到gradient descent 梯度下降法,用最优化的办法来寻找w和b的最优解。


            7楼2017-06-19 15:44
            回复

              接着上面来,我们在计算种类的时候会根据计算正确错误的时候对w和b 进行的一个修正,神经网络领域叫做学习。然后在处理的过程中,不断地学习,保证w和b达到分类的最优点,输入一幅图像它可以正确激活对应的神经元,比如我输入猫的图像,它激活的是第一第一个神经元激活,证明它是猫。如果网络可以正确激活对应的神经元,此时我们就不低它进行惩罚,认为这个网络已经达到我们的要求。

              OK开始解析我们的文章。这张图片是我们从CVPR那篇文章上的选出的,作者用了5层卷积层,他们把每一层卷积层提取出来的feature进行重构,观察对图像特征的理解,也就是我们前面说的特征,随着层数越来越多,它能够提取的特征也越来越高级。
              对应下面的A BCDE 五幅图像,根据它每一层提取的特征用逆卷积的办法再还原成图片的效果,A和B几乎和原图毫无变化,C略微模糊,D和E由于它提出的特征太高级了,忽略了一些低级的信息,E还原出的图像已经和原始图像跑得特别偏了,所以本文只用到了第4层,y 用来判断是否它是否准确的一句,没有用E层。E层feature跑的太偏了。
              用同样的方法处理style image,就是风格图片。我们看到A提取到的是对应像素点的特征,一直到E提取出的是基于一个全局的特征,然后我们把A 到E每个特征进行一个比对进行特征的迁移,因为最后我们输出的是以content image为主,我们需要把style image 的style 迁移到 content image上面,content image输入的照片具有style image上的风格,风格照片的内容并不进行很大的考量,我们要对比的是尽可能接近它的风格,尽可能使我们输入的图片接近我们输入的图片的样子。

              那么就会有人问,刚才讲的不都是输入和输出已知,也就是分类问题吗?给一个图像,知道了图像的全部也就是x全部固定,知道了图片的种类,根据他的种类反向传播,计算出最匹配他的w和b,求一些参数使计算更准确,可是这个和我们本文用的卷积神经网络有什么关系呢?我们来看一下文章中所要用到的网络。
              这篇文章直接用了出自ppt上图的一个网络, Very deep convolutional netoworks for latge-scale imagerecognition这篇文章是2015年ICLR上牛津大学发表的模型,它用了一个19层的神经模型进行imagenet那个库的训练 我们这个模型叫做VGG19。 VGG模型在神经网络领域是非常权威的,是牛津大学的最高水平,把它进行imagenet所有数据库训练跑出来的一个网络做为本文使用的初始网络。也就是说我们本文所用到所有w和b值全部是经过前人训练好的,我们输入一个图片,我们就可以假设输出的就是正确的分类。
              我们可以看到这个网络的参数,我们所用的是VGG19,也就是E的参数,总共有19个权重层,其中包含 244,244*3的RGB图片,从输入的图片开始,经过卷积层,卷积层,池化层,卷积层,卷积层,池化层,然后 4个卷积层,池化层,再4个卷积层,池化层,再 4个卷积层,池化层,最后连接3个全连接层,最后1000个神经元节点作为输出层。也就是说imagenet从2014年以后从 10个种类变成1000个种类进行分类,有1000个种类图片供大家训练,最后判断分类是否准确。所以VGG19 的输出层有1000个神经元,通过softmax 激活一个神经元,根据神经元的位置判断输出的图像属于哪个类别。


              8楼2017-06-19 15:46
              回复

                那么就会有人问了,你之前不是说优化w和b么,你用人家的网络w和b已经都训练好了啊,再让我们来看这张图,已知x,y,反向求w,b。本文做了一个反转,已知w和b,反向求y和x,求出最有的x,即我们所需要的目标图片。

                这里我们用的方法仍然是计算误差,然后反向传播使用梯度下降法来使误差降到最小。本文定义了3个误差,分别为content loss,用来评估生成图与content图是否接近;style loss,用来反映与style图片风格的接近程度,注意,这里的style loss是分别在每个卷积层输出后求对应style loss最后求和;以及最后的total loss,用来进行反向传播优化生成图,total loss中给定两个参数,用这两个参数来决定输出图像是更偏style图还是content图。

                我们用VGG19来得到content image的feature,输出卷积层4的feature用于后面的反向传播。

                然后相同的方法提取styleimage的feature,输出卷积层1-5的feature用于后面的输出。


                9楼2017-06-19 15:48
                回复

                  然后就是我们的算法了,首先生成一幅与原content尺寸相同的图片,输入VGG19提取feature,然后求total loss,利用梯度下降法使生成图像收敛到我们的目标,即输出的风格迁移图像。

                  既然层数比较深的网络可以提取深层次的feature,那么就有学者就想了,是否可以借此来“愚弄”计算机?左图是原始图像,右图下面给的标注是“掩耳盗铃”,科学家们在原图像中输入了一组噪声生成了右图,但是由于两图的feature完全相同所以成功的欺骗了计算机。

                  于是就有了这个,科学家们成功地用一些奇奇怪怪的图片骗了计算机。

                  然后有同学问我,没有GPU能不能跑这个,然后呢,这个是官方的数据,VGG网络,在用了4块每块差不多6000人民币的显卡,让然需要不间断的训练2-3周,所以,嗯,你可以试试。

                  然后推荐一下TensorFlow,因为tensorflow可以直观的用流程图的方式来表示我们的网络在多GPU下的工作及部署情况,所以我们强烈推荐大家使用TensorFlow来训练自己的神经网络。


                  10楼2017-06-19 15:51
                  回复


                    OK,接下来给大家讲一下怎么用这个neural-style来画自己风格的照片,首先就是把这个工程文件从github(上图)上面clone下来(下图),将其部署在本地。

                    然后这是全部的工程文件。注意直接clone下来的工程里不包含VGG19,需要大家自己下载(图里的那个.mat),有需要的同学可以进我们的资源群,里面有分享。
                    然后让我们来看一下这3个主要的工程文件。


                    然后这个是主文件中的参数,因为我们直接用了VGG19,好多参数都初始化设置好了,不需要我们重新设置,这里我们讲4个参数,--content,--styles,--output还有—iteration。前三个参数是执行这个文件所必须的参数,分别表示content、style、output image的存放路径及格式。Iteration里面是我们的迭代次数,迭代到我们制定的次数然后输出结果,如果不加这个参数则默认迭代次数1000次。

                    然后就是设置我们的用的网络。

                    vgg.py里面还定义了卷积层、池化层还有图像的预处理和还原方法。

                    然后就是把我们用的图片输入建立的网络中。
                    计算content、style image feature。

                    初始化我们生成图片,我们可以看到初始化时候就是个随机图,全是噪声。


                    11楼2017-06-19 15:57
                    回复
                      prisma算法解读视频分享


                      13楼2017-06-20 19:06
                      回复