• Convolution Neural Network (CNN) 原理与实现


    本文结合Deep learning的一个应用,Convolution Neural Network 进行一些基本应用,参考Lecun的Document 0.1进行部分拓展,与结果展示(in python)。

    分为以下几部分:

    1. Convolution(卷积)

    2. Pooling(降采样过程)

    3. CNN结构

    4.  跑实验

    下面分别介绍。

    PS:本篇blog为ese机器学习短期班参考资料(20140516课程),本文只是简要讲最naive最simple的思想,重在实践部分,原理课上详述。

     

    1. Convolution(卷积)

    类似于高斯卷积,对imagebatch中的所有image进行卷积。对于一张图,其所有feature map用一个filter卷成一张feature map。 如下面的代码,对一个imagebatch(含两张图)进行操作,每个图初始有3张feature map(R,G,B), 用两个9*9的filter进行卷积,结果是,每张图得到两个feature map。

    卷积操作由theano的conv.conv2d实现,这里我们用随机参数W,b。结果有点像edge detector是不是?

    Code: (详见注释)

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. # -*- coding: utf-8 -*-  
    2. """ 
    3. Created on Sat May 10 18:55:26 2014 
    4.  
    5. @author: rachel 
    6.  
    7. Function: convolution option of two pictures with same size (width,height) 
    8. input: 3 feature maps (3 channels <RGB> of a picture) 
    9. convolution: two 9*9 convolutional filters 
    10. """  
    11.   
    12. from theano.tensor.nnet import conv  
    13. import theano.tensor as T  
    14. import numpy, theano  
    15.   
    16.   
    17. rng = numpy.random.RandomState(23455)  
    18.   
    19. # symbol variable  
    20. input = T.tensor4(name = 'input')  
    21.   
    22. # initial weights  
    23. w_shape = (2,3,9,9) #2 convolutional filters, 3 channels, filter shape: 9*9  
    24. w_bound = numpy.sqrt(3*9*9)  
    25. W = theano.shared(numpy.asarray(rng.uniform(low = -1.0/w_bound, high = 1.0/w_bound,size = w_shape),  
    26.                                 dtype = input.dtype),name = 'W')  
    27.   
    28. b_shape = (2,)  
    29. b = theano.shared(numpy.asarray(rng.uniform(low = -.5, high = .5, size = b_shape),  
    30.                                 dtype = input.dtype),name = 'b')  
    31.                                   
    32. conv_out = conv.conv2d(input,W)  
    33.   
    34. #T.TensorVariable.dimshuffle() can reshape or broadcast (add dimension)  
    35. #dimshuffle(self,*pattern)  
    36. # >>>b1 = b.dimshuffle('x',0,'x','x')  
    37. # >>>b1.shape.eval()  
    38. # array([1,2,1,1])  
    39. output = T.nnet.sigmoid(conv_out + b.dimshuffle('x',0,'x','x'))  
    40. f = theano.function([input],output)  
    41.   
    42.   
    43.   
    44.   
    45.   
    46. # demo  
    47. import pylab  
    48. from PIL import Image  
    49. #minibatch_img = T.tensor4(name = 'minibatch_img')  
    50.   
    51. #-------------img1---------------  
    52. img1 = Image.open(open('//home//rachel//Documents//ZJU_Projects//DL//Dataset//rachel.jpg'))  
    53. width1,height1 = img1.size  
    54. img1 = numpy.asarray(img1, dtype = 'float32')/256. # (height, width, 3)  
    55.   
    56. # put image in 4D tensor of shape (1,3,height,width)  
    57. img1_rgb = img1.swapaxes(0,2).swapaxes(1,2).reshape(1,3,height1,width1) #(3,height,width)  
    58.   
    59.   
    60. #-------------img2---------------  
    61. img2 = Image.open(open('//home//rachel//Documents//ZJU_Projects//DL//Dataset//rachel1.jpg'))  
    62. width2,height2 = img2.size  
    63. img2 = numpy.asarray(img2,dtype = 'float32')/256.  
    64. img2_rgb = img2.swapaxes(0,2).swapaxes(1,2).reshape(1,3,height2,width2) #(3,height,width)  
    65.   
    66.   
    67.   
    68. #minibatch_img = T.join(0,img1_rgb,img2_rgb)  
    69. minibatch_img = numpy.concatenate((img1_rgb,img2_rgb),axis = 0)  
    70. filtered_img = f(minibatch_img)  
    71.   
    72.   
    73. # plot original image and two convoluted results  
    74. pylab.subplot(2,3,1);pylab.axis('off');  
    75. pylab.imshow(img1)  
    76.   
    77. pylab.subplot(2,3,4);pylab.axis('off');  
    78. pylab.imshow(img2)  
    79.   
    80. pylab.gray()  
    81. pylab.subplot(2,3,2); pylab.axis("off")  
    82. pylab.imshow(filtered_img[0,0,:,:]) #0:minibatch_index; 0:1-st filter  
    83.   
    84. pylab.subplot(2,3,3); pylab.axis("off")  
    85. pylab.imshow(filtered_img[0,1,:,:]) #0:minibatch_index; 1:1-st filter  
    86.   
    87. pylab.subplot(2,3,5); pylab.axis("off")  
    88. pylab.imshow(filtered_img[1,0,:,:]) #0:minibatch_index; 0:1-st filter  
    89.   
    90. pylab.subplot(2,3,6); pylab.axis("off")  
    91. pylab.imshow(filtered_img[1,1,:,:]) #0:minibatch_index; 1:1-st filter  
    92. pylab.show()  

    2. Pooling(降采样过程)

    最常用的Maxpooling. 解决了两个问题:

    1. 减少计算量

    2. 旋转不变性 (原因自己悟)

         PS:对于旋转不变性,回忆下SIFT,LBP:采用主方向;HOG:选择不同方向的模版

    Maxpooling的降采样过程会将feature map的长宽各减半。(下面结果图中没有体现出来,python自动给拉到一样大了,但实际上像素数是减半的)

    Code: (详见注释)

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. # -*- coding: utf-8 -*-  
    2. """ 
    3. Created on Sat May 10 18:55:26 2014 
    4.  
    5. @author: rachel 
    6.  
    7. Function: convolution option  
    8. input: 3 feature maps (3 channels <RGB> of a picture) 
    9. convolution: two 9*9 convolutional filters 
    10. """  
    11.   
    12. from theano.tensor.nnet import conv  
    13. import theano.tensor as T  
    14. import numpy, theano  
    15.   
    16.   
    17. rng = numpy.random.RandomState(23455)  
    18.   
    19. # symbol variable  
    20. input = T.tensor4(name = 'input')  
    21.   
    22. # initial weights  
    23. w_shape = (2,3,9,9) #2 convolutional filters, 3 channels, filter shape: 9*9  
    24. w_bound = numpy.sqrt(3*9*9)  
    25. W = theano.shared(numpy.asarray(rng.uniform(low = -1.0/w_bound, high = 1.0/w_bound,size = w_shape),  
    26.                                 dtype = input.dtype),name = 'W')  
    27.   
    28. b_shape = (2,)  
    29. b = theano.shared(numpy.asarray(rng.uniform(low = -.5, high = .5, size = b_shape),  
    30.                                 dtype = input.dtype),name = 'b')  
    31.                                   
    32. conv_out = conv.conv2d(input,W)  
    33.   
    34. #T.TensorVariable.dimshuffle() can reshape or broadcast (add dimension)  
    35. #dimshuffle(self,*pattern)  
    36. # >>>b1 = b.dimshuffle('x',0,'x','x')  
    37. # >>>b1.shape.eval()  
    38. # array([1,2,1,1])  
    39. output = T.nnet.sigmoid(conv_out + b.dimshuffle('x',0,'x','x'))  
    40. f = theano.function([input],output)  
    41.   
    42.   
    43.   
    44.   
    45.   
    46. # demo  
    47. import pylab  
    48. from PIL import Image  
    49. from matplotlib.pyplot import *  
    50.   
    51. #open random image  
    52. img = Image.open(open('//home//rachel//Documents//ZJU_Projects//DL//Dataset//rachel.jpg'))  
    53. width,height = img.size  
    54. img = numpy.asarray(img, dtype = 'float32')/256. # (height, width, 3)  
    55.   
    56.   
    57. # put image in 4D tensor of shape (1,3,height,width)  
    58. img_rgb = img.swapaxes(0,2).swapaxes(1,2) #(3,height,width)  
    59. minibatch_img = img_rgb.reshape(1,3,height,width)  
    60. filtered_img = f(minibatch_img)  
    61.   
    62.   
    63. # plot original image and two convoluted results  
    64. pylab.figure(1)  
    65. pylab.subplot(1,3,1);pylab.axis('off');  
    66. pylab.imshow(img)  
    67. title('origin image')  
    68.   
    69. pylab.gray()  
    70. pylab.subplot(2,3,2); pylab.axis("off")  
    71. pylab.imshow(filtered_img[0,0,:,:]) #0:minibatch_index; 0:1-st filter  
    72. title('convolution 1')  
    73.   
    74. pylab.subplot(2,3,3); pylab.axis("off")  
    75. pylab.imshow(filtered_img[0,1,:,:]) #0:minibatch_index; 1:1-st filter  
    76. title('convolution 2')  
    77.   
    78. #pylab.show()  
    79.   
    80.   
    81.   
    82.   
    83. # maxpooling  
    84. from theano.tensor.signal import downsample  
    85.   
    86. input = T.tensor4('input')  
    87. maxpool_shape = (2,2)  
    88. pooled_img = downsample.max_pool_2d(input,maxpool_shape,ignore_border = False)  
    89.   
    90. maxpool = theano.function(inputs = [input],  
    91.                           outputs = [pooled_img])  
    92.   
    93. pooled_res = numpy.squeeze(maxpool(filtered_img))                
    94. #pylab.figure(2)  
    95. pylab.subplot(235);pylab.axis('off');  
    96. pylab.imshow(pooled_res[0,:,:])  
    97. title('down sampled 1')  
    98.   
    99. pylab.subplot(236);pylab.axis('off');  
    100. pylab.imshow(pooled_res[1,:,:])  
    101. title('down sampled 2')  
    102.   
    103. pylab.show()  


    3. CNN结构

    想必大家随便google下CNN的图都滥大街了,这里拖出来那时候学CNN的时候一张图,自认为陪上讲解的话画得还易懂(<!--囧-->)

    废话不多说了,直接上Lenet结构图:(从下往上顺着箭头看,最下面为底层original input)

    4. CNN代码

    资源里下载吧,我放上去了喔~(in python)
     
    这里贴少部分代码,仅表示建模的NN:

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. rng = numpy.random.RandomState(23455)  
    2.   
    3.     # transfrom x from (batchsize, 28*28) to (batchsize,feature,28,28))  
    4.     # I_shape = (28,28),F_shape = (5,5),  
    5.     N_filters_0 = 20  
    6.     D_features_0= 1  
    7.     layer0_input = x.reshape((batch_size,D_features_0,28,28))  
    8.     layer0 = LeNetConvPoolLayer(rng, input = layer0_input, filter_shape = (N_filters_0,D_features_0,5,5),  
    9.                                 image_shape = (batch_size,1,28,28))  
    10.     #layer0.output: (batch_size, N_filters_0, (28-5+1)/2, (28-5+1)/2) -> 20*20*12*12  
    11.       
    12.     N_filters_1 = 50  
    13.     D_features_1 = N_filters_0  
    14.     layer1 = LeNetConvPoolLayer(rng,input = layer0.output, filter_shape = (N_filters_1,D_features_1,5,5),  
    15.                                 image_shape = (batch_size,N_filters_0,12,12))  
    16.     # layer1.output: (20,50,4,4)  
    17.       
    18.     layer2_input = layer1.output.flatten(2) # (20,50,4,4)->(20,(50*4*4))  
    19.     layer2 = HiddenLayer(rng,layer2_input,n_in = 50*4*4,n_out = 500, activation = T.tanh)  
    20.       
    21.     layer3 = LogisticRegression(input = layer2.output, n_in = 500, n_out = 10)  

    layer0, layer1 :分别是卷积+降采样

    layer2+layer3:组成一个MLP(ANN)

    训练模型:

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. cost = layer3.negative_log_likelihood(y)  
    2. params = layer3.params + layer2.params + layer1.params + layer0.params  
    3. gparams = T.grad(cost,params)  
    4.   
    5. updates = []  
    6. for par,gpar in zip(params,gparams):  
    7.     updates.append((par, par - learning_rate * gpar))  
    8.   
    9. train_model = theano.function(inputs = [minibatch_index],  
    10.                               outputs = [cost],  
    11.                               updates = updates,  
    12.                               givens = {x: train_set_x[minibatch_index * batch_size : (minibatch_index+1) * batch_size],  
    13.                                         y: train_set_y[minibatch_index * batch_size : (minibatch_index+1) * batch_size]})  


    根据cost(最上层MLP的输出NLL),对所有层的parameters进行训练

    剩下的具体见代码和注释。

    PS:数据为MNIST所有数据



     
     
     
    final result:
    Optimization complete. Best validation score of 0.990000 % obtained at iteration 122500, with test performance 0.950000 %
  • 相关阅读:
    前端 一——介绍
    python知识点拾遗
    python 五——自定义线程池
    python 四——线程、进程、协程
    python 三——列表、字典、元祖、字符串、set
    动态规划法求解0-1背包
    贪心法求解背包问题
    学生成绩管理系统
    [C语言练习]学生学籍管理系统
    [C语言练习]万年历加强版
  • 原文地址:https://www.cnblogs.com/alexanderkun/p/4868783.html
Copyright © 2020-2023  润新知