深度学习算法实践12---卷积神经网络(CNN)实现

转载 2016年09月21日 14:57:39

在搞清楚卷积神经网络(CNN)的原理之后,在本篇博文中,我们将讨论基于Theano的算法实现技术。我们还将以MNIST手写数字识别为例,创建卷积神经网络(CNN),训练该网络,使识别误差达到1%以内。

我们首先需要读入MNIST手写数字识别的训练样本集,为此我们定义了一个工具类:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. from __future__ import print_function  
  2.   
  3. __docformat__ = 'restructedtext en'  
  4.   
  5. import six.moves.cPickle as pickle  
  6. import gzip  
  7. import os  
  8. import sys  
  9. import timeit  
  10.   
  11. import numpy  
  12.   
  13. import theano  
  14. import theano.tensor as T  
  15.   
  16. class MnistLoader(object):  
  17.     def load_data(self, dataset):  
  18.         data_dir, data_file = os.path.split(dataset)  
  19.         if data_dir == "" and not os.path.isfile(dataset):  
  20.             new_path = os.path.join(  
  21.                 os.path.split(__file__)[0],  
  22.                 "..",  
  23.                 "data",  
  24.                 dataset  
  25.             )  
  26.             if os.path.isfile(new_path) or data_file == 'mnist.pkl.gz':  
  27.                 dataset = new_path  
  28.   
  29.         if (not os.path.isfile(dataset)) and data_file == 'mnist.pkl.gz':  
  30.             from six.moves import urllib  
  31.             origin = (  
  32.                 'http://www.iro.umontreal.ca/~lisa/deep/data/mnist/mnist.pkl.gz'  
  33.             )  
  34.             print('Downloading data from %s' % origin)  
  35.             urllib.request.urlretrieve(origin, dataset)  
  36.   
  37.         print('... loading data')  
  38.         # Load the dataset  
  39.         with gzip.open(dataset, 'rb') as f:  
  40.             try:  
  41.                 train_set, valid_set, test_set = pickle.load(f, encoding='latin1')  
  42.             except:  
  43.                 train_set, valid_set, test_set = pickle.load(f)  
  44.         def shared_dataset(data_xy, borrow=True):  
  45.             data_x, data_y = data_xy  
  46.             shared_x = theano.shared(numpy.asarray(data_x,  
  47.                                                dtype=theano.config.floatX),  
  48.                                  borrow=borrow)  
  49.             shared_y = theano.shared(numpy.asarray(data_y,  
  50.                                                dtype=theano.config.floatX),  
  51.                                  borrow=borrow)  
  52.             return shared_x, T.cast(shared_y, 'int32')  
  53.   
  54.         test_set_x, test_set_y = shared_dataset(test_set)  
  55.         valid_set_x, valid_set_y = shared_dataset(valid_set)  
  56.         train_set_x, train_set_y = shared_dataset(train_set)  
  57.   
  58.         rval = [(train_set_x, train_set_y), (valid_set_x, valid_set_y),  
  59.             (test_set_x, test_set_y)]  
  60.         return rval  
这个类在之前我们已经用过,在这里就不详细讲解了。之所以单独定义这个类,是因为如果我们将问题换为其他类型时,我们只需要修改这一个类,就可以实现训练数据的载入了,这样简化了程序修改工作量。

我们所采用的方法是将图像先接入卷积神经网络,之后再接入BP网络的隐藏层,然后再接入逻辑回归的输出层,因此我们需要先定义多层前向网络的隐藏层和逻辑回归输出层。隐藏层的定义如下所示:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. from __future__ import print_function  
  2.   
  3. __docformat__ = 'restructedtext en'  
  4.   
  5.   
  6. import os  
  7. import sys  
  8. import timeit  
  9.   
  10. import numpy  
  11.   
  12. import theano  
  13. import theano.tensor as T  
  14.   
  15.   
  16. from logistic_regression import LogisticRegression  
  17.   
  18. # start-snippet-1  
  19. class HiddenLayer(object):  
  20.     def __init__(self, rng, input, n_in, n_out, W=None, b=None,  
  21.                  activation=T.tanh):  
  22.         self.input = input  
  23.         if W is None:  
  24.             W_values = numpy.asarray(  
  25.                 rng.uniform(  
  26.                     low=-numpy.sqrt(6. / (n_in + n_out)),  
  27.                     high=numpy.sqrt(6. / (n_in + n_out)),  
  28.                     size=(n_in, n_out)  
  29.                 ),  
  30.                 dtype=theano.config.floatX  
  31.             )  
  32.             if activation == theano.tensor.nnet.sigmoid:  
  33.                 W_values *= 4  
  34.   
  35.             W = theano.shared(value=W_values, name='W', borrow=True)  
  36.   
  37.         if b is None:  
  38.             b_values = numpy.zeros((n_out,), dtype=theano.config.floatX)  
  39.             b = theano.shared(value=b_values, name='b', borrow=True)  
  40.   
  41.         self.W = W  
  42.         self.b = b  
  43.   
  44.         lin_output = T.dot(input, self.W) + self.b  
  45.         self.output = (  
  46.             lin_output if activation is None  
  47.             else activation(lin_output)  
  48.         )  
  49.         # parameters of the model  
  50.         self.params = [self.W, self.b]  
接下来我们定义逻辑回归算法类:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. from __future__ import print_function  
  2.   
  3. __docformat__ = 'restructedtext en'  
  4.   
  5. import six.moves.cPickle as pickle  
  6. import gzip  
  7. import os  
  8. import sys  
  9. import timeit  
  10.   
  11. import numpy  
  12.   
  13. import theano  
  14. import theano.tensor as T  
  15.   
  16. class LogisticRegression(object):    
  17.     def __init__(self, input, n_in, n_out):    
  18.         self.W = theano.shared(    
  19.             value=numpy.zeros(    
  20.                 (n_in, n_out),    
  21.                 dtype=theano.config.floatX    
  22.             ),    
  23.             name='W',    
  24.             borrow=True    
  25.         )    
  26.         self.b = theano.shared(    
  27.             value=numpy.zeros(    
  28.                 (n_out,),    
  29.                 dtype=theano.config.floatX    
  30.             ),    
  31.             name='b',    
  32.             borrow=True    
  33.         )    
  34.         self.p_y_given_x = T.nnet.softmax(T.dot(input, self.W) + self.b)    
  35.         self.y_pred = T.argmax(self.p_y_given_x, axis=1)    
  36.         self.params = [self.W, self.b]    
  37.         self.input = input    
  38.         print("Yantao: ***********************************")  
  39.     
  40.     def negative_log_likelihood(self, y):    
  41.         return -T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]), y])    
  42.     
  43.     def errors(self, y):    
  44.         if y.ndim != self.y_pred.ndim:    
  45.             raise TypeError(    
  46.                 'y should have the same shape as self.y_pred',    
  47.                 ('y', y.type, 'y_pred'self.y_pred.type)    
  48.             )    
  49.         if y.dtype.startswith('int'):    
  50.             return T.mean(T.neq(self.y_pred, y))    
  51.         else:    
  52.             raise NotImplementedError()    

这段代码在逻辑回归博文中已经详细讨论过了,这里就不再重复了,有兴趣的读者可以查看这篇博文(逻辑回归算法实现)。

做完上述准备工作之后,我们就可以开始卷积神经网络(CNN)实现了。

我们先来定义基于简化版Lenet5的卷积神经网络(CNN)的定义,代码如下所示:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. from __future__ import print_function  
  2.   
  3. import os  
  4. import sys  
  5. import timeit  
  6.   
  7. import numpy  
  8.   
  9. import theano  
  10. import theano.tensor as T  
  11. from theano.tensor.signal import pool  
  12. from theano.tensor.nnet import conv2d  
  13.   
  14.   
  15. class LeNetConvPoolLayer(object):  
  16.     def __init__(self, rng, input, filter_shape, image_shape, poolsize=(22)):  
  17.         assert image_shape[1] == filter_shape[1]  
  18.         self.input = input  
  19.         fan_in = numpy.prod(filter_shape[1:])  
  20.         fan_out = (filter_shape[0] * numpy.prod(filter_shape[2:]) //  
  21.                    numpy.prod(poolsize))  
  22.         W_bound = numpy.sqrt(6. / (fan_in + fan_out))  
  23.         self.W = theano.shared(  
  24.             numpy.asarray(  
  25.                 rng.uniform(low=-W_bound, high=W_bound, size=filter_shape),  
  26.                 dtype=theano.config.floatX  
  27.             ),  
  28.             borrow=True  
  29.         )  
  30.         b_values = numpy.zeros((filter_shape[0],), dtype=theano.config.floatX)  
  31.         self.b = theano.shared(value=b_values, borrow=True)  
  32.         conv_out = conv2d(  
  33.             input=input,  
  34.             filters=self.W,  
  35.             filter_shape=filter_shape,  
  36.             input_shape=image_shape  
  37.         )  
  38.         pooled_out = pool.pool_2d(  
  39.             input=conv_out,  
  40.             ds=poolsize,  
  41.             ignore_border=True  
  42.         )  
  43.         self.output = T.tanh(pooled_out + self.b.dimshuffle('x'0'x''x'))  
  44.         self.params = [self.W, self.b]  
  45.         self.input = input  
 上面代码实现了对输入信号的卷积操作,并对结果进行最大化池化。

下面我们来看怎样初始化Lenet层,怎样将Lenet层输出信号转为MLP网络隐藏层的输入信号,具体代码如下所示:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. layer0 = LeNetConvPoolLayer(  
  2.         rng,  
  3.         input=layer0_input,  
  4.         image_shape=(batch_size, 12828),  
  5.         filter_shape=(nkerns[0], 155),  
  6.         poolsize=(22)  
  7.     )  
如上所示,我们的输入信号是28*28的黑白图像,而且我们采用的批量学习,因此输入图像就定义为(batch_size, 1, 28, 28),我们对图像进行5*5卷积操作,根据卷积操作定义,最终得到的卷积输出层为(28-5+1,28-5+1)=(24,24)的“图像”,我们采用2*2的最大池化操作,即取2*2区域像素的最大值作为新的像素点的值,则最终输出层得到12*12的输出信号。

接下来,我们将输出信号继续输入一个Lenet卷积池化层,代码如下所示:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. layer1 = LeNetConvPoolLayer(  
  2.     rng,  
  3.     input=layer0.output,  
  4.     image_shape=(batch_size, nkerns[0], 1212),  
  5.     filter_shape=(nkerns[1], nkerns[0], 55),  
  6.     poolsize=(22)  
  7. )  
如上所示,这时输入信号变化为12*12的图像,我们还使用5*5的卷积核,可以得到(12-5+1, 12-5+1)=(8,8)的图像,采用2*2最大池化操作后,得到(4,4)图像。可以通过调用layer1.output.flatten(2)将其变为一维信号,从而输入MLP的隐藏层。

下面我们定义Lenet引擎来实现装入数据,定义网络模型,训练网络工作,代码如下所示:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. from __future__ import print_function  
  2.   
  3. import os  
  4. import sys  
  5. import timeit  
  6.   
  7. import numpy  
  8.   
  9. import theano  
  10. import theano.tensor as T  
  11. from theano.tensor.signal import pool  
  12. from theano.tensor.nnet import conv2d  
  13.   
  14. from mnist_loader import MnistLoader  
  15. from logistic_regression import LogisticRegression  
  16. from hidden_layer import HiddenLayer  
  17. from lenet_conv_pool_layer import LeNetConvPoolLayer  
  18.   
  19. class LenetMnistEngine(object):  
  20.     def __init__(self):  
  21.         print("create LenetMnistEngine")  
  22.   
  23.     def train_model(self):  
  24.         learning_rate = 0.1  
  25.         n_epochs = 200  
  26.         dataset = 'mnist.pkl.gz'  
  27.         nkerns = [2050]  
  28.         batch_size = 500  
  29.         (n_train_batches, n_test_batches, n_valid_batches, \  
  30.                     train_model, test_model, validate_model) = \  
  31.                     self.build_model(learning_rate, n_epochs, \  
  32.                         dataset, nkerns, batch_size)  
  33.         self.train(n_epochs, n_train_batches, n_test_batches, \  
  34.                     n_valid_batches, train_model, test_model, \  
  35.                     validate_model)  
  36.   
  37.     def run(self):  
  38.         print("run the model")  
  39.         classifier = pickle.load(open('best_model.pkl''rb'))  
  40.         predict_model = theano.function(  
  41.             inputs=[classifier.input],  
  42.             outputs=classifier.logRegressionLayer.y_pred  
  43.         )  
  44.         dataset='mnist.pkl.gz'  
  45.         loader = MnistLoader()  
  46.         datasets = loader.load_data(dataset)  
  47.         test_set_x, test_set_y = datasets[2]  
  48.         test_set_x = test_set_x.get_value()  
  49.         predicted_values = predict_model(test_set_x[:10])  
  50.         print("Predicted values for the first 10 examples in test set:")  
  51.         print(predicted_values)  
  52.   
  53.     def build_model(self, learning_rate=0.1, n_epochs=200,  
  54.                         dataset='mnist.pkl.gz',  
  55.                         nkerns=[2050], batch_size=500):  
  56.         rng = numpy.random.RandomState(23455)  
  57.         loader = MnistLoader()  
  58.         datasets = loader.load_data(dataset)  
  59.         train_set_x, train_set_y = datasets[0]  
  60.         valid_set_x, valid_set_y = datasets[1]  
  61.         test_set_x, test_set_y = datasets[2]  
  62.         n_train_batches = train_set_x.get_value(borrow=True).shape[0]  
  63.         n_valid_batches = valid_set_x.get_value(borrow=True).shape[0]  
  64.         n_test_batches = test_set_x.get_value(borrow=True).shape[0]  
  65.         n_train_batches //= batch_size  
  66.         n_valid_batches //= batch_size  
  67.         n_test_batches //= batch_size  
  68.         index = T.lscalar()   
  69.         x = T.matrix('x')     
  70.         y = T.ivector('y')   
  71.         print('... building the model')  
  72.         layer0_input = x.reshape((batch_size, 12828))  
  73.         layer0 = LeNetConvPoolLayer(  
  74.             rng,  
  75.             input=layer0_input,  
  76.             image_shape=(batch_size, 12828),  
  77.             filter_shape=(nkerns[0], 155),  
  78.             poolsize=(22)  
  79.         )  
  80.         layer1 = LeNetConvPoolLayer(  
  81.             rng,  
  82.             input=layer0.output,  
  83.             image_shape=(batch_size, nkerns[0], 1212),  
  84.             filter_shape=(nkerns[1], nkerns[0], 55),  
  85.             poolsize=(22)  
  86.         )  
  87.         layer2_input = layer1.output.flatten(2)  
  88.         layer2 = HiddenLayer(  
  89.             rng,  
  90.             input=layer2_input,  
  91.             n_in=nkerns[1] * 4 * 4,  
  92.             n_out=500,  
  93.             activation=T.tanh  
  94.         )  
  95.         layer3 = LogisticRegression(input=layer2.output, n_in=500, n_out=10)  
  96.         cost = layer3.negative_log_likelihood(y)  
  97.         test_model = theano.function(  
  98.             [index],  
  99.             layer3.errors(y),  
  100.             givens={  
  101.                 x: test_set_x[index * batch_size: (index + 1) * batch_size],  
  102.                 y: test_set_y[index * batch_size: (index + 1) * batch_size]  
  103.             }  
  104.         )  
  105.         validate_model = theano.function(  
  106.             [index],  
  107.             layer3.errors(y),  
  108.             givens={  
  109.                 x: valid_set_x[index * batch_size: (index + 1) * batch_size],  
  110.                 y: valid_set_y[index * batch_size: (index + 1) * batch_size]  
  111.             }  
  112.         )  
  113.         params = layer3.params + layer2.params + layer1.params + layer0.params  
  114.         grads = T.grad(cost, params)  
  115.         updates = [  
  116.             (param_i, param_i - learning_rate * grad_i)  
  117.             for param_i, grad_i in zip(params, grads)  
  118.         ]  
  119.         train_model = theano.function(  
  120.             [index],  
  121.             cost,  
  122.             updates=updates,  
  123.             givens={  
  124.                 x: train_set_x[index * batch_size: (index + 1) * batch_size],  
  125.                 y: train_set_y[index * batch_size: (index + 1) * batch_size]  
  126.             }  
  127.         )  
  128.         return (n_train_batches, n_test_batches, n_valid_batches, \  
  129.                     train_model, test_model, validate_model)  
  130.   
  131.     def train(self, n_epochs, n_train_batches, n_test_batches, n_valid_batches,   
  132.                 train_model, test_model, validate_model):  
  133.         print('... training')  
  134.         patience = 10000  
  135.         patience_increase = 2  
  136.         improvement_threshold = 0.995  
  137.         validation_frequency = min(n_train_batches, patience // 2)  
  138.         best_validation_loss = numpy.inf  
  139.         best_iter = 0  
  140.         test_score = 0.  
  141.         start_time = timeit.default_timer()  
  142.         epoch = 0  
  143.         done_looping = False  
  144.         while (epoch < n_epochs) and (not done_looping):  
  145.             epoch = epoch + 1  
  146.             for minibatch_index in range(n_train_batches):  
  147.                 iter = (epoch - 1) * n_train_batches + minibatch_index  
  148.                 if iter % 100 == 0:  
  149.                     print('training @ iter = ', iter)  
  150.                 cost_ij = train_model(minibatch_index)  
  151.                 if (iter + 1) % validation_frequency == 0:  
  152.                     validation_losses = [validate_model(i) for i  
  153.                                          in range(n_valid_batches)]  
  154.                     this_validation_loss = numpy.mean(validation_losses)  
  155.                     print('epoch %i, minibatch %i/%i, validation error %f %%' %  
  156.                           (epoch, minibatch_index + 1, n_train_batches,  
  157.                            this_validation_loss * 100.))  
  158.                     if this_validation_loss < best_validation_loss:  
  159.                         if this_validation_loss < best_validation_loss *  \  
  160.                            improvement_threshold:  
  161.                             patience = max(patience, iter * patience_increase)  
  162.                         best_validation_loss = this_validation_loss  
  163.                         best_iter = iter  
  164.                         test_losses = [  
  165.                             test_model(i)  
  166.                             for i in range(n_test_batches)  
  167.                         ]  
  168.                         test_score = numpy.mean(test_losses)  
  169.                         with open('best_model.pkl''wb') as f:  
  170.                             pickle.dump(classifier, f)  
  171.                         print(('     epoch %i, minibatch %i/%i, test error of '  
  172.                                'best model %f %%') %  
  173.                               (epoch, minibatch_index + 1, n_train_batches,  
  174.                                test_score * 100.))  
  175.                 if patience <= iter:  
  176.                     done_looping = True  
  177.                     break  
  178.         end_time = timeit.default_timer()  
  179.         print('Optimization complete.')  
  180.         print('Best validation score of %f %% obtained at iteration %i, '  
  181.               'with test performance %f %%' %  
  182.               (best_validation_loss * 100., best_iter + 1, test_score * 100.))  
  183.         print(('The code for file ' +  
  184.                os.path.split(__file__)[1] +  
  185.                ' ran for %.2fm' % ((end_time - start_time) / 60.)), file=sys.stderr)  
上述代码与之前的MLP的训练代码类似,这里就不再讨论了。在我的Mac笔记本上,运行大约6个小时,会得到错误率小于1%的结果。

深度学习算法实践12---卷积神经网络(CNN)实现

在搞清楚卷积神经网络(CNN)的原理之后,在本篇博文中,我们将讨论基于Theano的算法实现技术。我们还将以MNIST手写数字识别为例,创建卷积神经网络(CNN),训练该网络,使识别误差达到1%以内。...
  • Yt7589
  • Yt7589
  • 2016年08月30日 12:50
  • 5493

深度学习算法实践12---卷积神经网络(CNN)实现

在搞清楚卷积神经网络(CNN)的原理之后,在本篇博文中,我们将讨论基于Theano的算法实现技术。我们还将以MNIST手写数字识别为例,创建卷积神经网络(CNN),训练该网络,使识别误差达到1%以内。...

深度学习算法实践10---卷积神经网络(CNN)原理

其实从本篇博文开始,我们才算真正进入深度学习领域。在深度学习领域,已经经过验证的成熟算法,目前主要有深度卷积网络(DNN)和递归网络(RNN),在图像识别、视频识别、语音识别领域取得了巨大的成功,正是...
  • Yt7589
  • Yt7589
  • 2016年08月26日 14:46
  • 8252

深度学习算法实践10---卷积神经网络(CNN)原理

好了,转入正题。我们今天将要研究的是卷积网络(CNN),这是深度学习算法应用最成功的领域之一,主要用于图像和视频识别领域。 在讨论卷积网络(CNN)之前,我们先来根据我们的常识,来讨论一下怎样可...

深度学习算法实践11---卷积神经网络(CNN)之卷积操作

卷积神经网络(CNN)主要特性有:稀疏连接和权值共享、卷积操作、池化。在前一篇博文中我们已经讨论了稀疏连接和权值共享,在本篇博文中,我们将介绍卷积操作和池化。正是由于对图像进行卷积操作,卷积神经网络才...

深度学习算法实践11---卷积神经网络(CNN)之卷积操作

卷积神经网络(CNN)主要特性有:稀疏连接和权值共享、卷积操作、池化。在前一篇博文中我们已经讨论了稀疏连接和权值共享,在本篇博文中,我们将介绍卷积操作和池化。正是由于对图像进行卷积操作,卷积神经网络才...

深度学习算法实践11---卷积神经网络(CNN)之卷积操作

卷积神经网络(CNN)主要特性有:稀疏连接和权值共享、卷积操作、池化。在前一篇博文中我们已经讨论了稀疏连接和权值共享,在本篇博文中,我们将介绍卷积操作和池化。正是由于对图像进行卷积操作,卷积神经网络才...
  • Yt7589
  • Yt7589
  • 2016年08月29日 18:20
  • 6163

干货 | 深度学习之卷积神经网络(CNN)的前向传播算法详解

微信公众号 关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第一 【Python】:排名第三 【算法】:排名第四 前言 在(干货 | 深度学习之卷积神经网络(C...
  • Mbx8X9u
  • Mbx8X9u
  • 2017年11月18日 00:00
  • 145

spark深度学习算法(CNN卷积神经网络)的测试与分析

卷积神经网络(Convolutional Neural Network,CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。   关于CNN...

深度学习之卷积神经网络CNN及tensorflow代码实现示例详细介绍

一、CNN的引入 在人工的全连接神经网络中,每相邻两层之间的每个神经元之间都是有边相连的。当输入层的特征维度变得很高时,这时全连接网络需要训练的参数就会增大很多,计算速度就会变得很慢,例如一张黑白的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习算法实践12---卷积神经网络(CNN)实现
举报原因:
原因补充:

(最多只允许输入30个字)