想要一个网站,北京seo相关,公司怎样做网络推广,遵义直播遵义新闻官网前言
按照进度, 学习theano中的卷积操作
国际惯例, 来一波参考网址
Convolutional Neural Networks (LeNet)
卷积神经网络如何应用在彩色图像上#xff1f;
卷积小知识
三大特性#xff1a;局部感知(稀疏连接), 权值共享, 池化 上图很重要, 描述的是前一个隐层m-1具有四…前言
按照进度, 学习theano中的卷积操作
国际惯例, 来一波参考网址
Convolutional Neural Networks (LeNet)
卷积神经网络如何应用在彩色图像上
卷积小知识
三大特性局部感知(稀疏连接), 权值共享, 池化 上图很重要, 描述的是前一个隐层m-1具有四个特征图, 第m个隐层具有两个特征图, 四个权重框代表的是第m-1层的所有特征图与第m层的第一个特征图的连接,注意前一层的所有特征图与后一层第二个特征图的权重并没有画出来, 所以说, 由第m-1层映射到第m层, 总共需要4*28个不同的权重矩阵, 而不是四个.
代码实现
前面折腾过各种函数,其中就有conv2d, 然后我们就用它来尝试一下2D卷积需要注意的是定义的输入、输出、卷积核矩阵它们每个维度都代表什么详细可以戳我前面的【theano-windows】学习笔记十一——theano中与神经网络相关函数, 这里也写一下:
对于输入:是一个4D张量分别代表 [批大小,输入特征数(即通道数),图像高度,图像宽度]
对于卷积核: 是一个4D张量分别代表(第mm层的特征图数目,第m−1m-1层的特征图数目,卷积核高,卷积核宽)
无反向传播的卷积网络
其实这个代码与第一篇关于theano的博客一样,戳这里
写一遍便于理解, 顺序就是
定义输入张量 import theano
import theano.tensor as T
import numpy as np#随机数种子初始化rngnp.random.RandomState(23455)
inputT.tensor4(nameinput)#定义输入张量初始化权重张量
#初始化权重张量w_shp(2,3,9,9)#下一层两个特征图,上一层三个特征图,卷积核大小9*9
w_boundnp.sqrt(3*9*9)
Wtheano.shared(np.asarray(rng.uniform(low-1.0/w_bound,high1.0/w_bound,sizew_shp),dtypeinput.dtype),nameW)初始化偏置张量
#初始化偏置,如果需要训练,一般设置为0,此处模仿训练好的偏置b_shp(2,)
btheano.shared(np.asarray(rng.uniform(low-.5,high.5,sizeb_shp),dtypeinput.dtype),nameb)卷积并用sigmoid激活
#卷积操作conv_outT.nnet.conv2d(input,W)#用sigmoid激活outputT.nnet.sigmoid(conv_outb.dimshuffle(x,0,x,x))丢入到function中供后续使用
#整个操作的函数ftheano.function([input],output)读取并处理图片:需要注意的是图片必须改成(批大小,通道,高,宽)
############################注意事项#################################### 图片的原始数据是一个3D数据【高宽通道数量】 # 经过数据置换(transpose(2,0,1))之后变成了【通道数量高宽】 # 因为f中传入参数需要4D因此需要将图片数据reshape成为一个【1, 通道数量, 高, 宽】这样的4D张量 # reshape的参数一定要注意1就是最外的那一维度3就是通道数量然后是【高】和【宽】 # 这样结果的 img_.shape 【1, 3, 宽, 高】 # # 为什么reshape为这样的size呢因为调用f时需要传入一个input而这个input就是4D最终的这个input是传入到 # conv2d中的第一个参数而那个参数的格式是什么呢[mini-batch size特征图的数量图像高度图像宽度] # 这样就串起来了吧第一个参数是batch size据我所知应该是指卷积核的数量吧但是不知道为什么这里是1 # 第二个参数代表输入层的特征图数量这个地方是3其实就是把一张彩色图片按照3个通道作为3个特征图进行输入 # 最后两个是图像的高度和宽度正好一一对应。 #使用此函数对一张图片进行操作import pylab
from PIL import Imageimg Image.open(F:\\Photo\\2.jpg)#读取图片
img_w,img_himg.size#图像的宽和高
imgnp.asarray(img,dtypeinput.dtype)/256.
img_img.transpose(2,0,1).reshape(1,3,img_h,img_w)
filtered_imgf(img_) 可视化结果 pylab.subplot(1,3,1);pylab.axis(off);pylab.imshow(img)
pylab.gray();
pylab.subplot(1,3,2);pylab.axis(off);pylab.imshow(filtered_img[0,0,:,:])
pylab.subplot(1,3,3);pylab.axis(off);pylab.imshow(filtered_img[0,1,:,:])
pylab.show() 最大值池化
是卷积中非常重要的非线性下采样方法,它将图像分成不重叠的块,对每一块选择最大值输出
两个理由告诉你为什么最大值池化重要:
通过消除非极大值,可以降低高层的计算提供了平移不变性, 图像中的每个像素就有8个平移自由度, 如果将最大值池化级联到卷积层,假设是2*2的池化区域, 8种平移可能有3个相同结果, 但是如果用3×33\times3的池化区域,就可能有5种相同结果(这个原因还在探索中)
函数调用格式是:
theano.tensor.signal.pool.pool_2d(input, wsNone, ignore_borderNone, strideNone, pad(0, 0), modemax, dsNone, stNone, paddingNone)
参数说明:
input: N维的图片输入张量ws:长度为2的元组, 缩减因子,在每个维度上将图像减半ignore_border: 若为true, 则(5,5)的输入经过ws(2,2)得到(2,2)的输出, 否则是(3,3)的输出stride:步长, 池化操作在行/列上移动的长度,如果是None,那么与ws相同pad:两个int型元组,或者两个int型的theano向量,大小为2, 用于填充图像的四个边界第一个是上下填充大小, 第二个是左右填充大小mode是每个池化窗口的操作方法,包括max,’sum’,’average_inc_pad’,’average_exc_pad’ds,st,padding丢弃使用了,分别用ws,stride,pad代替
此处我们就不用官方的例子了直接把上面的图片进行池化操作:
import theano
import theano.tensor as T
import numpy as np
import pylab
from PIL import Image
#随机数种子初始化
rngnp.random.RandomState(23455)
inputT.dtensor4(nameinput)#定义输入张量
img Image.open(F:\\Photo\\2.jpg)#读取图片
img_w,img_himg.size#图像的宽和高
imgnp.asarray(img,dtypeinput.dtype)/256.
img_img.transpose(2,0,1).reshape(1,3,img_h,img_w)
maxpool_shape(2,2)
pool_outT.signal.pool.pool_2d(input,maxpool_shape,ignore_borderFalse)
f_pooltheano.function([input],pool_out)
pool_imgf_pool(img_)
img_poolpool_img[0,:,:,:].transpose(1,2,0)print img.shape
print img_pool.shapepylab.subplot(1,2,1);pylab.axis(off);pylab.imshow(img)
pylab.subplot(1,2,2);pylab.axis(off);pylab.imshow(img_pool)
pylab.show()
输出 上述程序一定要注意定义的容器input的数据类型,我刚开始写的程序如下:
#错误写法
import theano
import theano.tensor as T
import numpy as np
import pylab
from PIL import Image
#随机数种子初始化
rngnp.random.RandomState(23455)
inputT.tensor4(nameinput)#定义输入张量
img Image.open(F:\\Photo\\2.jpg)#读取图片
img_w,img_himg.size#图像的宽和高
imgnp.asarray(img,dtypeinput.dtype)/256.
img_img.transpose(2,0,1).reshape(1,3,img_h,img_w)
maxpool_shape(2,2)
pool_outT.signal.pool.pool_2d(input,maxpool_shape,ignore_borderFalse)
f_pooltheano.function([input],pool_out)
print input.dtype#float32
print img_.dtype#float32
pool_imgf_pool(img_)
img_poolpool_img[0,:,:,:].transpose(1,2,0)print img.shape
print img_pool.shapepylab.subplot(1,2,1);pylab.axis(off);pylab.imshow(img)
pylab.subplot(1,2,2);pylab.axis(off);pylab.imshow(img_pool)
pylab.show()
虽然我们的input容器和img输入都是float32,但是不知道为什么一直出现下列错误:
ValueError: GpuDownsampleFactorMax: last dimention size of 600 is bigger then 512. This case is not implemented.
Apply node that caused the error: GpuDownsampleFactorMax{(2, 2),False}(GpuFromHost.0)
Toposort index: 1
Inputs types: [CudaNdarrayType(float32, 4D)]
Inputs shapes: [(1, 3, 800, 1200)]
Inputs strides: [(0, 960000, 1200, 1)]
Inputs values: [not shown]
Outputs clients: [[HostFromGpu(GpuDownsampleFactorMax{(2, 2),False}.0)]]HINT: Re-running with most Theano optimization disabled could give you a back-trace of when this node was created. This can be done with by setting the Theano flag optimizerfast_compile. If that does not work, Theano optimizations can be disabled with optimizerNone.
HINT: Use the Theano flag exception_verbosityhigh for a debugprint and storage map footprint of this apply node.
网上的解释戳这里,它的意思是池化以后的矩阵的最后一个维度(第四个维度)不支持大于512的维度,建议翻转一下后两个维度. 但是如果我们的图片长宽都大于1024,那么翻转就没用了这时候只要把input容器变成dtensor,而非tensor就可以运行了,很神奇,卡了我好几个小时, 原理在于dtensor是在CPU上运行, 而CPU的内存交换没有GPU那么小,tensor是运行在GPU上的.
另一种可以处理任意维度的数据的方法是使用theano.sandbox.cuda.dnn.dnn_pool,详细介绍戳这里, 代码如下
#错误写法
import theano
import theano.tensor as T
import numpy as np
import pylab
from PIL import Image
#random seeds
rngnp.random.RandomState(23455)
inputT.tensor4(nameinput,dtypetheano.config.floatX)#input tensor# img Image.open(F:\\Photo\\2.jpg)#read image
# img_w,img_himg.size# with and height of the image
# imgnp.asarray(img,dtypetheano.config.floatX)/256. #normalize
# img_img.transpose(2,0,1).reshape(1,3,img_h,img_w) #reshape for inputimgnp.random.RandomState(1).rand(5000, 5000,3)
img_np.asarray(img,dtypetheano.config.floatX)
img_img.transpose(2,0,1).reshape(1,3,img_.shape[0],img_.shape[1])
img_np.asarray(img_,dtypetheano.config.floatX)print img_.shape
maxpool_shape(2,2)
# pool_outT.signal.pool.pool_2d(input,maxpool_shape,ignore_borderFalse)#limited by 512
pool_outtheano.sandbox.cuda.dnn.dnn_pool(input,maxpool_shape)# non-limitedf_pooltheano.function([input],pool_out)
print input.dtype#float32
print img_.dtype#float32
pool_imgf_pool(img_)pool_imgnp.asarray(pool_img,dtypetheano.config.floatX)
img_poolpool_img[0,:,:,:].transpose(1,2,0)print img.shape
print img_pool.shapepylab.subplot(1,2,1);pylab.axis(off);pylab.imshow(img)
pylab.subplot(1,2,2);pylab.axis(off);pylab.imshow(img_pool)
pylab.show()
Lenet分类模型
模型结构如下: 如此就可以按照顺序依次搭建: 卷积池化, 全连接中间隐层, softmax
读数据
这个没什么好说的,跟前面博客一样, 重点是记得把数据放入到共享区域
#引入相关库
import theano
import theano.tensor as T
import numpy as np
import os
import cPickle,gzip
import timeit#定义读数据的函数,把数据丢入到共享区域
def load_data(dataset):data_dir,data_fileos.path.split(dataset)if os.path.isfile(dataset):with gzip.open(dataset,rb) as f:train_set,valid_set,test_setcPickle.load(f)#共享数据集def shared_dataset(data_xy,borrowTrue):data_x,data_ydata_xyshared_xtheano.shared(np.asarray(data_x,dtypetheano.config.floatX),borrowborrow)shared_ytheano.shared(np.asarray(data_y,dtypetheano.config.floatX),borrowborrow)return shared_x,T.cast(shared_y,int32)#定义三个元组分别存储训练集,验证集,测试集train_set_x,train_set_yshared_dataset(train_set)valid_set_x,valid_set_yshared_dataset(valid_set)test_set_x,test_set_yshared_dataset(test_set)rval[(train_set_x,train_set_y),(valid_set_x,valid_set_y),(test_set_x,test_set_y)]return rval
定义卷积池化层
使用的fan_in,fan_out权重初始化准则, 具体公式戳这里, 前提是需要知道对于每个隐单元有fan_in(输入特征图个数×卷积核高×卷积核宽)fan\_in=(输入特征图个数\times 卷积核高\times 卷积核宽)个连接,对于低层的每个单元接受的梯度来自fan_out(输出特征图个数×卷积核高×卷积核宽)/池化大小fan\_out=(输出特征图个数\times 卷积核高\times 卷积核宽)/池化大小.
实现此层过程就是, 先定义并初始化权重和偏置, 随后进行卷积操作, 池化, 激活, (貌似正常情况下是卷积-激活-池化).
#定义卷积和最大池化
class ConvPool(object):def __init__(self,rng,input,filter_shape,img_shape,pool_shape):#input是容器,img_shape是(批大小,输入特征图数,高,宽)self.inputinput#初始化参数按照fan_in,fan_out准则#对于每个隐单元,有(输入特征图*高*宽)个输入神经元fan_innp.prod(filter_shape[1:])#对于低层隐单元接收(输出特征图*滤波器高*滤波器宽)/池化大小的梯度fan_out(filter_shape[0]*np.prod(filter_shape[2:])//np.prod(pool_shape))#随机初始化权重W_boundnp.sqrt(6./(fan_infan_out))self.Wtheano.shared(np.asarray(rng.uniform(low-W_bound,highW_bound,sizefilter_shape),dtypetheano.config.floatX),borrowTrue)#初始化偏置全零b_valuesnp.zeros((filter_shape[0],),dtypetheano.config.floatX)self.btheano.shared(valueb_values,borrowTrue)#定义卷积操作conv_outT.nnet.conv2d(inputinput,filtersself.W,filter_shapefilter_shape,input_shapeimg_shape)#定义池化操作pool_outT.signal.pool.pool_2d(inputconv_out,wspool_shape,ignore_borderTrue)#激活函数self.outputT.tanh(pool_outself.b.dimshuffle(x,0,x,x))#存储参数self.params[self.W,self.b]#更新输出self.inputinput
定义隐层
这一个可以戳前面的博客, 大概过程也是: 定义并初始化权重和偏置, 乘积激活
#定义隐层
class HiddenLayer(object):def __init__(self,rng,input,n_in,n_out,WNone,bNone,activitationT.tanh):self.inputinput #输入#根据fan_in,fan_out初始化权重if W is None:W_valuesnp.asarray(rng.uniform(low- np.sqrt(6./(n_inn_out)),highnp.sqrt(6./(n_inn_out)),size(n_in,n_out)),dtypetheano.config.floatX)if activitationT.nnet.sigmoid:W_values*4if b is None:b_valuesnp.zeros((n_out,),dtypetheano.config.floatX)#将权重和偏置放入到共享变量中Wtheano.shared(valueW_values,nameW,borrowTrue)btheano.shared(valueb_values,nameb,borrowTrue)self.WWself.bbself.params[self.W,self.b]#激活lin_ouputT.dot(input,self.W)self.bself.output(lin_ouput if activitation is None else activitation(lin_ouput))
定义softmax层
过程是: 定义并初始化权重, 定义损失函数, 定义测试误差函数
#定义输出层,softmax
class SoftMax(object):def __init__(self,rng,input,n_in,n_out):#定义权重W_valuesnp.asarray(rng.uniform(low-np.sqrt(6./(n_inn_out)),highnp.sqrt(6./(n_inn_out)),size(n_in,n_out)),dtypetheano.config.floatX)#定义偏置b_valuesnp.zeros((n_out,),dtypetheano.config.floatX)#共享变量self.Wtheano.shared(valueW_values,borrowTrue,nameW)self.btheano.shared(valueb_values,borrowTrue,nameb)#softmax函数值self.p_y_given_xT.nnet.softmax(T.dot(input,self.W)self.b)#预测值self.y_predT.argmax(self.p_y_given_x,axis1)self.params[self.W,self.b]self.inputinputdef negative_log_likelihood(self,y):#定义对数似然return - T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]),y])def errors(self,y):#定义误差if y.ndim!self.y_pred.ndim:raise TypeError(y should have the same shape as self.y_pred,(y,y.type,y_pred,self.y_pred.type))if y.dtype.startswith(int):return T.mean(T.neq(self.y_pred,y))else:raise NotImplementedError()
搭建网络
所需要的层已经定义完毕, 然后按照上面的图中所示的网络结构搭建.
需要注意的问题有:
原始图片存储方法为每一行代表一张图片,所以在丢入到卷积层之前需要重新组织成(批大小, 通道数, 图片高, 图片宽), 因为是灰度图,所以通道为1,图片大小是标准的mnist手写数字大小(28\times28)最好事先推导一下每层卷积的特征图大小, 全连接层单元数, 因为定义的网络需要输入特征图大小, 我刚开始想的是取出第一层卷积过后得到的ouput, 然后用shape自动得到第二层所需要的分别得到下一个卷积所需要的特征图大小, 但是死活取不出来这个值, 尴了个尬.存储模型的方法还是沿用上一篇博客介绍的方法,存储为pkl格式
#定义整个训练和测试过程
def test_ConvPool(learning_rate0.1,n_epoches200,datasetmnist.pkl.gz,nkerns[20,50],n_hidden100,batch_size500):datasetsload_data(datasetdataset)train_set_x,train_set_ydatasets[0]valide_set_x,valide_set_ydatasets[1]test_set_x,test_set_ydatasets[2]#计算小批数据的批数n_train_batchestrain_set_x.get_value(borrowTrue).shape[0]//batch_sizen_valid_batchesvalide_set_x.get_value(borrowTrue).shape[0]//batch_sizen_test_batchestest_set_x.get_value(borrowTrue).shape[0]//batch_size#小批数据的索引print 建立模型...indexT.iscalar()#批索引xT.matrix(x)yT.ivector(y)rngnp.random.RandomState(123455)layer0_inputx.reshape((batch_size,1,28,28))ClassifierLenet(rng,batch_sizebatch_size,inputlayer0_input,n_hiddenn_hidden,nkernsnkerns,n_out10)#损失函数costClassifier.negative_log_likelihood(y)#梯度计算gradsT.grad(cost,Classifier.params)#梯度更新updates[(params_i,params_i-learning_rate*grad_i)for params_i,grad_i in zip(Classifier.params,grads)]#训练模型train_modeltheano.function([index],cost,updatesupdates,givens{x:train_set_x[index*batch_size:(index1)*batch_size],y:train_set_y[index*batch_size:(index1)*batch_size]})#验证模型valid_modeltheano.function([index],Classifier.layer3.errors(y),givens{x:valide_set_x[index*batch_size:(index1)*batch_size],y:valide_set_y[index*batch_size:(index1)*batch_size]})#测试模型test_modeltheano.function([index],Classifier.layer3.errors(y),givens{x:test_set_x[index*batch_size:(index1)*batch_size],y:test_set_y[index*batch_size:(index1)*batch_size]})#使用提前停止方法训练模型print(训练模型...)patiences10000patiences_increase2improvement_threshold0.995validation_frequencymin(n_train_batches,patiences//2)best_validation_lossnp.infbest_iter0test_score0start_timetimeit.default_timer()epoch0done_loopFalsewhile(epochn_epoches) and (not done_loop):epochepoch1for minibatch_index in range(n_train_batches):minibatch_avg_costtrain_model(minibatch_index)iter(epoch-1)*n_train_batchesminibatch_indexif (iter1)%validation_frequency0:validation_loss[valid_model(i) for i in range(n_valid_batches)]this_validateion_lossnp.mean(validation_loss)print (epoch %i,minibatch %i/%i,validation error %f %%%(epoch,minibatch_index1,n_train_batches,this_validateion_loss*100.))if this_validateion_lossbest_validation_loss:if this_validateion_lossbest_validation_loss*improvement_threshold:patiencesmax(patiences,iter*patiences_increase)best_validation_lossthis_validateion_lossbest_iteritertest_losses[test_model(i) for i in range(n_test_batches)]test_scorenp.mean(test_losses)print((epoch %i, minibatch %i/%i, test error of best model %f %%) %(epoch, minibatch_index 1,n_train_batches,test_score * 100.))#保存最优模型save_fileopen(best_model_Conv.pkl,wb)model[Classifier.layer0,Classifier.layer1,Classifier.layer2,Classifier.layer3]cPickle.dump( model,save_file)if patiencesiter:done_loopTruebreakendtimetimeit.default_timer()print(优化结束)print(Best validation score of %f %% obtained at iteration %i, with test performance %f %% %(best_validation_loss * 100., best_iter 1, test_score * 100.))
其实如果你用pycharm之类的工具调试以后,可以发现这个best_model_Conv.pkl存储的就是四个层的模型参数 测试网络
首先是载入模型
mnist_classcPickle.load(open(best_model_Conv.pkl))
然后构建一个前向网络
xT.matrix(x)
single_inputx.reshape((1,1,28,28))
hidden_nummnist_class[2].b.container.data.shape[0];
kerns_num[mnist_class[1].W.container.data.shape[0],mnist_class[1].W.container.data.shape[1]]
classifier_testLenet(rngnp.random.RandomState(1234),batch_size1,inputsingle_input,n_hiddenhidden_num,nkernskerns_num,n_out10)
给网络参数赋值
#逐层赋值
#第一层卷积
classifier_test.layer0.W.set_value(mnist_class[0].W.get_value())
classifier_test.layer0.b.set_value(mnist_class[0].b.get_value())
#第二层卷积
classifier_test.layer1.W.set_value(mnist_class[1].W.get_value())
classifier_test.layer1.b.set_value(mnist_class[1].b.get_value())
#第三层全连接-隐层
classifier_test.layer2.W.set_value(mnist_class[2].W.get_value())
classifier_test.layer2.b.set_value(mnist_class[2].b.get_value())
#第四层softmax
classifier_test.layer3.W.set_value(mnist_class[3].W.get_value())
classifier_test.layer3.b.set_value(mnist_class[3].b.get_value())
定义前向计算的操作
#前向计算
forward_computetheano.function([single_input],classifier_test.layer3.y_pred)
测试网络,这里我们使用前面学习caffe时候手工制作的mnist数据集戳这里下载, 密码是bead.当然也可以按照MLP中的方法采用mnist原始数据集.
from PIL import Image
import pylab
imgImage.open(E:\\code_test\\theano\\binarybmp\\9.bmp)
img_w,img_himg.size#图像的宽和高
imgnp.asarray(img,dtypefloat32)
pylab.imshow(img)
pylab.show()
#原始图片是28*28要增加两个维度
imgimg.reshape((1,1,28,28)) 识别结果输出
label_preforward_compute(img)
print label_pre
#9
目前就是0识别成6, 6识别成5剩下的几个全对
博客code打包链接: https://pan.baidu.com/s/1i5xipiH 密码: rvit
后记
通过池化那部分的研究我们发现关于卷积的实现在theano.tensor.nnet戳这里以及theano.sandbox.cuda.dnn戳这里中也有对应实现。这里要注意, 我们以后使用卷积是否要研究后者的使用而非前者。