CNN框架的搭建及各个参数的调节
本文代码下载地址:我的github
本文主要讲解将CNN应用于人脸识别的流程,程序基于Python+numpy+theano+PIL开发,采用类似LeNet5的CNN模型,应用于olivettifaces人脸数据库,实现人脸识别的功能,模型的误差降到了5%以下。本程序只是个人学习过程的一个toy implement,样本很小,模型随时都会过拟合。
但是,本文意在理清程序开发CNN模型的具体步骤,特别是针对图像识别,从拿到图像数据库,到实现一个针对这个图像数据库的CNN模型,我觉得本文对这些流程的实现具有参考意义。
《本文目录》
一、olivettifaces人脸数据库介绍
二、CNN的基本“构件”(LogisticRegression、HiddenLayer、LeNetConvPoolLayer)
三、组建CNN模型,设置优化算法,应用于Olivetti Faces进行人脸识别
四、训练结果以及参数设置的讨论
五、利用训练好的参数初始化模型
六、一些需要说明的
一、olivettifaces人脸数据库介绍
本文所用的训练数据就是这张图片,400个样本,40个类别,乍一看样本好像比较小,用CNN效果会好吗?先别下结论,请往下看。
- """
- 加载图像数据的函数,dataset_path即图像olivettifaces的路径
- 加载olivettifaces后,划分为train_data,valid_data,test_data三个数据集
- 函数返回train_data,valid_data,test_data以及对应的label
- """
- def load_data(dataset_path):
- img = Image.open(dataset_path)
- img_ndarray = numpy.asarray(img, dtype='float64')/256
- faces=numpy.empty((400,2679))
- for row in range(20):
- for column in range(20):
- faces[row*20+column]=numpy.ndarray.flatten(img_ndarray [row*57:(row+1)*57,column*47:(column+1)*47])
- label=numpy.empty(400)
- for i in range(40):
- label[i*10:i*10+10]=i
- label=label.astype(numpy.int)
- #分成训练集、验证集、测试集,大小如下
- train_data=numpy.empty((320,2679))
- train_label=numpy.empty(320)
- valid_data=numpy.empty((40,2679))
- valid_label=numpy.empty(40)
- test_data=numpy.empty((40,2679))
- test_label=numpy.empty(40)
- for i in range(40):
- train_data[i*8:i*8+8]=faces[i*10:i*10+8]
- train_label[i*8:i*8+8]=label[i*10:i*10+8]
- valid_data[i]=faces[i*10+8]
- valid_label[i]=label[i*10+8]
- test_data[i]=faces[i*10+9]
- test_label[i]=label[i*10+9]
- #将数据集定义成shared类型,才能将数据复制进GPU,利用GPU加速程序。
- def shared_dataset(data_x, data_y, borrow=True):
- shared_x = theano.shared(numpy.asarray(data_x,
- dtype=theano.config.floatX),
- borrow=borrow)
- shared_y = theano.shared(numpy.asarray(data_y,
- dtype=theano.config.floatX),
- borrow=borrow)
- return shared_x, T.cast(shared_y, 'int32')
- train_set_x, train_set_y = shared_dataset(train_data,train_label)
- valid_set_x, valid_set_y = shared_dataset(valid_data,valid_label)
- test_set_x, test_set_y = shared_dataset(test_data,test_label)
- rval = [(train_set_x, train_set_y), (valid_set_x, valid_set_y),
- (test_set_x, test_set_y)]
- return rval
二、CNN的基本“构件”(LogisticRegression、HiddenLayer、LeNetConvPoolLayer)
代码太长,就不贴具体的了,只给出框架,具体可以下载我的代码看看:
- #分类器,即CNN最后一层,采用逻辑回归(softmax)
- class LogisticRegression(object):
- def __init__(self, input, n_in, n_out):
- self.W = ....
- self.b = ....
- self.p_y_given_x = ...
- self.y_pred = ...
- self.params = ...
- def negative_log_likelihood(self, y):
- def errors(self, y):
- #全连接层,分类器前一层
- class HiddenLayer(object):
- def __init__(self, rng, input, n_in, n_out, W=None, b=None,activation=T.tanh):
- self.input = input
- self.W = ...
- self.b = ...
- lin_output = ...
- self.params = [self.W, self.b]
- #卷积+采样层(conv+maxpooling)
- class LeNetConvPoolLayer(object):
- def __init__(self, rng, input, filter_shape, image_shape, poolsize=(2, 2)):
- self.input = input
- self.W = ...
- self.b = ...
- # 卷积
- conv_out = ...
- # 子采样
- pooled_out =...
- self.output = ...
- self.params = [self.W, self.b]
三、组建CNN模型,设置优化算法,应用于Olivetti Faces进行人脸识别
- def evaluate_olivettifaces(learning_rate=0.05, n_epochs=200,
- dataset='olivettifaces.gif',
- nkerns=[5, 10], batch_size=40):
- #随机数生成器,用于初始化参数....
- #加载数据.....
- #计算各数据集的batch个数....
- #定义几个变量,x代表人脸数据,作为layer0的输入......
- ######################
- #建立CNN模型:
- #input+layer0(LeNetConvPoolLayer)+layer1(LeNetConvPoolLayer)+layer2(HiddenLayer)+layer3(LogisticRegression)
- ######################
- ...
- ....
- ......
- #########################
- # 定义优化算法的一些基本要素:代价函数,训练、验证、测试model、参数更新规则(即梯度下降)
- #########################
- ...
- ....
- ......
- #########################
- # 训练CNN阶段,寻找最优的参数。
- ########################
- ...
- .....
- .......
另外,值得一提的是,在训练CNN阶段,我们必须定时地保存模型的参数,这是在训练机器学习算法时一个经常会做的事情,这一部分的详细介绍我之前写过一篇文章《DeepLearning tutorial(2)机器学习算法在训练过程中保存参数》。简单来说,我们要保存CNN模型中layer0、layer1、layer2、layer3的参数,所以在“训练CNN阶段”这部分下面,有一句代码:
- save_params(layer0.params,layer1.params,layer2.params,layer3.params)
这个函数具体定义为:
- #保存训练参数的函数
- def save_params(param1,param2,param3,param4):
- import cPickle
- write_file = open('params.pkl', 'wb')
- cPickle.dump(param1, write_file, -1)
- cPickle.dump(param2, write_file, -1)
- cPickle.dump(param3, write_file, -1)
- cPickle.dump(param4, write_file, -1)
- write_file.close()
如果在其他算法中,你要保存的参数有五个六个甚至更多,那么改一下这个函数的参数就行啦。
四、训练结果以及参数设置的讨论
- 调节learning_rate
学习速率learning_rate就是运用SGD算法时梯度前面的系数,非常重要,设得太大的话算法可能永远都优化不了,设得太小会使算法优化得太慢,而且可能还会掉入局部最优。可以形象地将learning_rate比喻成走路时步子的大小,想象一下要从一个U形的山谷的一边走到山谷最低点,如果步子特别大,像巨人那么大,那会直接从一边跨到另一边,然后又跨回这边,如此往复。如果太小了,可能你走着走着就掉入了某些小坑,因为山路总是凹凸不平的(局部最优),掉入这些小坑后,如果步子还是不变,就永远走不出那个坑。
(2)nkerns=[20, 50], batch_size=40,poolsize=(2,2),learning_rate=0.01时,训练到epoch 60多时,validation-error降到5%,test-error降到15%
(3)nkerns=[20, 50], batch_size=40,poolsize=(2,2),learning_rate=0.05时,训练到epoch 36时,validation-error降到2.5%,test-error降到5%
PS:学习速率应该自适应地减小,是有专门的一些算法的,本程序没有实现这个功能,有时间再研究一下。
- 调节batch_size
因为我们采用minibatch SGD算法来优化,所以是一个batch一个batch地将数据输入CNN模型中,然后计算这个batch的所有样本的平均损失,即代价函数是所有样本的平均。而batch_size就是一个batch的所包含的样本数,显然batch_size将影响到模型的优化程度和速度。
回到本文的模型,首先因为我们train_dataset是320,valid_dataset和test_dataset都是40,所以batch_size最好都是40的因子,也就是能让40整除,比如40、20、10、5、2、1,否则会浪费一些样本,比如设置为30,则320/30=10,余数时20,这20个样本是没被利用的。并且,如果batch_size设置为30,则得出的validation-error和test-error只是30个样本的错误率,并不是全部40个样本的错误率。这是设置batch_size要注意的。特别是样本比较少的时候。
下面是我实验时的记录,固定其他参数,改变batch_size:
batch_size=1、2、5、10、20时,validation-error一直是97.5%,没降下来。我觉得可能是样本类别覆盖率过小,因为我们的数据是按类别排的,每个类别10个样本是连续排在一起的,batch_size等于20时其实只包含了两个类别,这样优化会很慢。
因此最后我将batch_size设为40,也就是valid_dataset和test_dataset的大小了,没办法,原始数据集样本太少了。一般我们都不会让batch_size达到valid_dataset和test_dataset的大小的。
- 关于n_epochs
n_epochs也就是最大的训练步数,比如设为200,那训练过程最多遍历你的数据集200遍,当遍历了200遍你的dataset时,程序会停止。n_epochs就相当于一个停止程序的控制参数,并不会影响CNN模型的优化程度和速度,只是一个控制程序结束的参数。
- nkerns=[20, 50]
20表示第一个卷积层的卷积核的个数,50表示第二个卷积层的卷积核的个数。这个我也是瞎调的,暂时没什么经验可以总结。
不过从理论上来说,卷积核的个数其实就代表了特征的个数,你提取的特征越多,可能最后分类就越准。但是,特征太多(卷积核太多),会增加参数的规模,加大了计算复杂度,而且有时候卷积核也不是越多越好,应根据具体的应用对象来确定。所以我觉得,CNN虽号称自动提取特征,免去复杂的特征工程,但是很多参数比如这里的nkerns还是需要去调节的,还是需要一些“人工”的。
下面是我的实验记录,固定batch_size=40,learning_rate=0.05,poolsize=(2,2):
(1)nkerns=[20, 50]时,训练到epoch 36时,validation-error降到2.5%,test-error降到5%
(2)nkerns=[10, 30]时,训练到epoch 46时,validation-error降到5%,test-error降到5%
(3)nkerns=[5, 10]时,训练到epoch 38时,validation-error降到5%,test-error降到7.5%
- poolsize=(2, 2)
poolzize在本程序中是设置为(2,2),即从一个2*2的区域里maxpooling出1个像素,说白了就算4和像素保留成1个像素。本例程中人脸图像大小是57*47,对这种小图像来说,(2,2)时比较合理的。如果你用的图像比较大,可以把poolsize设的大一点。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++分割线+++++++++++++++++++++++++++++++++++++++++++
上面部分介绍完了CNN模型构建以及模型训练的过程,代码都在train_CNN_olivettifaces.py里面,训练完可以得到一个params.pkl文件,这个文件保存的就是最后的模型的参数,方便你以后直接使用这个模型。以后只需利用这些保存下来的参数来初始化CNN模型,就得到一个可以使用的CNN系统,将人脸图输入这个CNN系统,预测人脸图的类别。
接下来就介绍怎么使用训练好的参数的方法,这部分的代码放在use_CNN_olivettifaces.py文件中。
五、利用训练好的参数初始化模型
- self.W = params_W
- self.b = params_b
params_W,params_b就是从params.pkl文件中读取来的,读取的函数:
- #读取之前保存的训练参数
- #layer0_params~layer3_params都是包含W和b的,layer*_params[0]是W,layer*_params[1]是b
- def load_params(params_file):
- f=open(params_file,'rb')
- layer0_params=cPickle.load(f)
- layer1_params=cPickle.load(f)
- layer2_params=cPickle.load(f)
- layer3_params=cPickle.load(f)
- f.close()
- return layer0_params,layer1_params,layer2_params,layer3_params
六、一些需要说明的
@author:wepon
@blog:http://blog.csdn.net/u012162613/article/details/43277187
本文代码下载地址:我的github
本文主要讲解将CNN应用于人脸识别的流程,程序基于Python+numpy+theano+PIL开发,采用类似LeNet5的CNN模型,应用于olivettifaces人脸数据库,实现人脸识别的功能,模型的误差降到了5%以下。本程序只是个人学习过程的一个toy implement,样本很小,模型随时都会过拟合。
但是,本文意在理清程序开发CNN模型的具体步骤,特别是针对图像识别,从拿到图像数据库,到实现一个针对这个图像数据库的CNN模型,我觉得本文对这些流程的实现具有参考意义。
《本文目录》
一、olivettifaces人脸数据库介绍
二、CNN的基本“构件”(LogisticRegression、HiddenLayer、LeNetConvPoolLayer)
三、组建CNN模型,设置优化算法,应用于Olivetti Faces进行人脸识别
四、训练结果以及参数设置的讨论
五、利用训练好的参数初始化模型
六、一些需要说明的
一、olivettifaces人脸数据库介绍
本文所用的训练数据就是这张图片,400个样本,40个类别,乍一看样本好像比较小,用CNN效果会好吗?先别下结论,请往下看。
- """
- 加载图像数据的函数,dataset_path即图像olivettifaces的路径
- 加载olivettifaces后,划分为train_data,valid_data,test_data三个数据集
- 函数返回train_data,valid_data,test_data以及对应的label
- """
- def load_data(dataset_path):
- img = Image.open(dataset_path)
- img_ndarray = numpy.asarray(img, dtype='float64')/256
- faces=numpy.empty((400,2679))
- for row in range(20):
- for column in range(20):
- faces[row*20+column]=numpy.ndarray.flatten(img_ndarray [row*57:(row+1)*57,column*47:(column+1)*47])
- label=numpy.empty(400)
- for i in range(40):
- label[i*10:i*10+10]=i
- label=label.astype(numpy.int)
- #分成训练集、验证集、测试集,大小如下
- train_data=numpy.empty((320,2679))
- train_label=numpy.empty(320)
- valid_data=numpy.empty((40,2679))
- valid_label=numpy.empty(40)
- test_data=numpy.empty((40,2679))
- test_label=numpy.empty(40)
- for i in range(40):
- train_data[i*8:i*8+8]=faces[i*10:i*10+8]
- train_label[i*8:i*8+8]=label[i*10:i*10+8]
- valid_data[i]=faces[i*10+8]
- valid_label[i]=label[i*10+8]
- test_data[i]=faces[i*10+9]
- test_label[i]=label[i*10+9]
- #将数据集定义成shared类型,才能将数据复制进GPU,利用GPU加速程序。
- def shared_dataset(data_x, data_y, borrow=True):
- shared_x = theano.shared(numpy.asarray(data_x,
- dtype=theano.config.floatX),
- borrow=borrow)
- shared_y = theano.shared(numpy.asarray(data_y,
- dtype=theano.config.floatX),
- borrow=borrow)
- return shared_x, T.cast(shared_y, 'int32')
- train_set_x, train_set_y = shared_dataset(train_data,train_label)
- valid_set_x, valid_set_y = shared_dataset(valid_data,valid_label)
- test_set_x, test_set_y = shared_dataset(test_data,test_label)
- rval = [(train_set_x, train_set_y), (valid_set_x, valid_set_y),
- (test_set_x, test_set_y)]
- return rval
二、CNN的基本“构件”(LogisticRegression、HiddenLayer、LeNetConvPoolLayer)
代码太长,就不贴具体的了,只给出框架,具体可以下载我的代码看看:
- #分类器,即CNN最后一层,采用逻辑回归(softmax)
- class LogisticRegression(object):
- def __init__(self, input, n_in, n_out):
- self.W = ....
- self.b = ....
- self.p_y_given_x = ...
- self.y_pred = ...
- self.params = ...
- def negative_log_likelihood(self, y):
- def errors(self, y):
- #全连接层,分类器前一层
- class HiddenLayer(object):
- def __init__(self, rng, input, n_in, n_out, W=None, b=None,activation=T.tanh):
- self.input = input
- self.W = ...
- self.b = ...
- lin_output = ...
- self.params = [self.W, self.b]
- #卷积+采样层(conv+maxpooling)
- class LeNetConvPoolLayer(object):
- def __init__(self, rng, input, filter_shape, image_shape, poolsize=(2, 2)):
- self.input = input
- self.W = ...
- self.b = ...
- # 卷积
- conv_out = ...
- # 子采样
- pooled_out =...
- self.output = ...
- self.params = [self.W, self.b]
三、组建CNN模型,设置优化算法,应用于Olivetti Faces进行人脸识别
- def evaluate_olivettifaces(learning_rate=0.05, n_epochs=200,
- dataset='olivettifaces.gif',
- nkerns=[5, 10], batch_size=40):
- #随机数生成器,用于初始化参数....
- #加载数据.....
- #计算各数据集的batch个数....
- #定义几个变量,x代表人脸数据,作为layer0的输入......
- ######################
- #建立CNN模型:
- #input+layer0(LeNetConvPoolLayer)+layer1(LeNetConvPoolLayer)+layer2(HiddenLayer)+layer3(LogisticRegression)
- ######################
- ...
- ....
- ......
- #########################
- # 定义优化算法的一些基本要素:代价函数,训练、验证、测试model、参数更新规则(即梯度下降)
- #########################
- ...
- ....
- ......
- #########################
- # 训练CNN阶段,寻找最优的参数。
- ########################
- ...
- .....
- .......
另外,值得一提的是,在训练CNN阶段,我们必须定时地保存模型的参数,这是在训练机器学习算法时一个经常会做的事情,这一部分的详细介绍我之前写过一篇文章《DeepLearning tutorial(2)机器学习算法在训练过程中保存参数》。简单来说,我们要保存CNN模型中layer0、layer1、layer2、layer3的参数,所以在“训练CNN阶段”这部分下面,有一句代码:
- save_params(layer0.params,layer1.params,layer2.params,layer3.params)
这个函数具体定义为:
- #保存训练参数的函数
- def save_params(param1,param2,param3,param4):
- import cPickle
- write_file = open('params.pkl', 'wb')
- cPickle.dump(param1, write_file, -1)
- cPickle.dump(param2, write_file, -1)
- cPickle.dump(param3, write_file, -1)
- cPickle.dump(param4, write_file, -1)
- write_file.close()
如果在其他算法中,你要保存的参数有五个六个甚至更多,那么改一下这个函数的参数就行啦。
四、训练结果以及参数设置的讨论
- 调节learning_rate
学习速率learning_rate就是运用SGD算法时梯度前面的系数,非常重要,设得太大的话算法可能永远都优化不了,设得太小会使算法优化得太慢,而且可能还会掉入局部最优。可以形象地将learning_rate比喻成走路时步子的大小,想象一下要从一个U形的山谷的一边走到山谷最低点,如果步子特别大,像巨人那么大,那会直接从一边跨到另一边,然后又跨回这边,如此往复。如果太小了,可能你走着走着就掉入了某些小坑,因为山路总是凹凸不平的(局部最优),掉入这些小坑后,如果步子还是不变,就永远走不出那个坑。
(2)nkerns=[20, 50], batch_size=40,poolsize=(2,2),learning_rate=0.01时,训练到epoch 60多时,validation-error降到5%,test-error降到15%
(3)nkerns=[20, 50], batch_size=40,poolsize=(2,2),learning_rate=0.05时,训练到epoch 36时,validation-error降到2.5%,test-error降到5%
PS:学习速率应该自适应地减小,是有专门的一些算法的,本程序没有实现这个功能,有时间再研究一下。
- 调节batch_size
因为我们采用minibatch SGD算法来优化,所以是一个batch一个batch地将数据输入CNN模型中,然后计算这个batch的所有样本的平均损失,即代价函数是所有样本的平均。而batch_size就是一个batch的所包含的样本数,显然batch_size将影响到模型的优化程度和速度。
回到本文的模型,首先因为我们train_dataset是320,valid_dataset和test_dataset都是40,所以batch_size最好都是40的因子,也就是能让40整除,比如40、20、10、5、2、1,否则会浪费一些样本,比如设置为30,则320/30=10,余数时20,这20个样本是没被利用的。并且,如果batch_size设置为30,则得出的validation-error和test-error只是30个样本的错误率,并不是全部40个样本的错误率。这是设置batch_size要注意的。特别是样本比较少的时候。
下面是我实验时的记录,固定其他参数,改变batch_size:
batch_size=1、2、5、10、20时,validation-error一直是97.5%,没降下来。我觉得可能是样本类别覆盖率过小,因为我们的数据是按类别排的,每个类别10个样本是连续排在一起的,batch_size等于20时其实只包含了两个类别,这样优化会很慢。
因此最后我将batch_size设为40,也就是valid_dataset和test_dataset的大小了,没办法,原始数据集样本太少了。一般我们都不会让batch_size达到valid_dataset和test_dataset的大小的。
- 关于n_epochs
n_epochs也就是最大的训练步数,比如设为200,那训练过程最多遍历你的数据集200遍,当遍历了200遍你的dataset时,程序会停止。n_epochs就相当于一个停止程序的控制参数,并不会影响CNN模型的优化程度和速度,只是一个控制程序结束的参数。
- nkerns=[20, 50]
20表示第一个卷积层的卷积核的个数,50表示第二个卷积层的卷积核的个数。这个我也是瞎调的,暂时没什么经验可以总结。
不过从理论上来说,卷积核的个数其实就代表了特征的个数,你提取的特征越多,可能最后分类就越准。但是,特征太多(卷积核太多),会增加参数的规模,加大了计算复杂度,而且有时候卷积核也不是越多越好,应根据具体的应用对象来确定。所以我觉得,CNN虽号称自动提取特征,免去复杂的特征工程,但是很多参数比如这里的nkerns还是需要去调节的,还是需要一些“人工”的。
下面是我的实验记录,固定batch_size=40,learning_rate=0.05,poolsize=(2,2):
(1)nkerns=[20, 50]时,训练到epoch 36时,validation-error降到2.5%,test-error降到5%
(2)nkerns=[10, 30]时,训练到epoch 46时,validation-error降到5%,test-error降到5%
(3)nkerns=[5, 10]时,训练到epoch 38时,validation-error降到5%,test-error降到7.5%
- poolsize=(2, 2)
poolzize在本程序中是设置为(2,2),即从一个2*2的区域里maxpooling出1个像素,说白了就算4和像素保留成1个像素。本例程中人脸图像大小是57*47,对这种小图像来说,(2,2)时比较合理的。如果你用的图像比较大,可以把poolsize设的大一点。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++分割线+++++++++++++++++++++++++++++++++++++++++++
上面部分介绍完了CNN模型构建以及模型训练的过程,代码都在train_CNN_olivettifaces.py里面,训练完可以得到一个params.pkl文件,这个文件保存的就是最后的模型的参数,方便你以后直接使用这个模型。以后只需利用这些保存下来的参数来初始化CNN模型,就得到一个可以使用的CNN系统,将人脸图输入这个CNN系统,预测人脸图的类别。
接下来就介绍怎么使用训练好的参数的方法,这部分的代码放在use_CNN_olivettifaces.py文件中。
五、利用训练好的参数初始化模型
- self.W = params_W
- self.b = params_b
params_W,params_b就是从params.pkl文件中读取来的,读取的函数:
- #读取之前保存的训练参数
- #layer0_params~layer3_params都是包含W和b的,layer*_params[0]是W,layer*_params[1]是b
- def load_params(params_file):
- f=open(params_file,'rb')
- layer0_params=cPickle.load(f)
- layer1_params=cPickle.load(f)
- layer2_params=cPickle.load(f)
- layer3_params=cPickle.load(f)
- f.close()
- return layer0_params,layer1_params,layer2_params,layer3_params
六、一些需要说明的
CNN框架的搭建及各个参数的调节相关推荐
- 【人工智能实验】卷积神经网络CNN框架的实现与应用-手写数字识别
目录 实验六 卷积神经网络CNN框架的实现与应用 一.实验目的 二.实验原理 三.实验结果 1.调整学习率.epochs以及bacth_size这三个参数,分别观察参数的变化对于实验结果的影响. 2. ...
- idea ssm框架 mysql_idea搭建简单ssm框架的最详细教程(新)
为开发一个测试程序,特搭建一个简单的ssm框架,因为网上看到很多都是比较老旧的教程,很多包都不能用了,eclipes搭建并且其中还附带了很多的其他东西,所以特此记录一下mac中idea搭建过程. 另: ...
- 为了鉴别世界名画,我死磕CNN后终于搭建了自己的模型
各位看官想必对大名鼎鼎的 "卷积神经网络"(CNN)一定不陌生.在<用Python实现深度学习框架>的第8章中,我们用自己实现的框架 MatrixSlow 搭建卷积神经 ...
- mvc框架自个儿搭建
mvc 框架 自己搭建 php框架 个人觉得根据自己需求,选中最佳最适合自己MVC框架,并在开发中能够体现出敏捷开发的效果就OK了,作为一个PHPer要提高自己的对PHP和MVC的框架的认识,所以自己 ...
- SSM框架的搭建(idea)
SSM框架的搭建(idea) 首先建立项目: 一路下一步即可 导入依赖(context,mysql,mybatis,druid) <dependency><groupId>or ...
- 腾讯 tars java_腾讯 Tars 基础框架手动搭建——填掉官方 Guide 的坑
背景 Tars 简介 腾讯 Tars 是腾讯内部使用的 TAF(Tencent Application Framework)的对外开源版,去掉了许多冗杂多余的部分.该框架集开发.运维.微服务.RPC ...
- CLion之C++框架篇-安装工具,基础框架的搭建(一)
CLion之C++框架篇-安装工具,基础框架的搭建(一) 背景 日常学习C++,也就是看看书.在vim里写写代码.在日常项目开发中,也是边看书(一是系统性理解.二是找找有什么更好的代码编写方式)边写代 ...
- 基于Maven的Springboot+Mybatis+Druid+Swagger2+mybatis-generator框架环境搭建
首页 Android Java 服务器 标签云 作品 关于 赞助列表 <a href="https://github.com/RayeWang" class="f ...
- CNN网络的搭建(Lenet5与ResNet18)
CNN介绍 这里给出维基百科中对于卷积神经网络简介 卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单 ...
最新文章
- Metasploit设置HttpTrace参数技巧
- java+mysql中文乱码问题
- 如何Docker化任意一个应用
- Extjs Window用法详解 3 打印具体应用,是否关掉打印预览的界面
- 二层交换机、三层交换机和路由器的基本工作原理和三者之间的主要区别
- 基于JavaSwing+Mysql点餐系统设计和实现
- python qtextedit设置光标位置_Python基础命令学习——就这一篇文章就够了
- 目前高产的稻麦品种的光能利用效率仅为()左右_枣树高产优质高效栽培关键技术...
- 解决每次git pull、git push都需要输入账号和密码的问题
- 频繁刷新页面websocket会报错_代码优化:Node+WebSocket+Vue聊天室
- vsftpd单用户多目录配置
- 电脑计算机无法安3.5,win10 net framework 3.5安装不了的完美解决办法
- ASP.NET2.0 GridView小技巧汇粹 (转)
- 复制百度文库内容chrome插件
- nginx请求转发被拒绝_nginx实现请求转发
- pl2303hxa串口线驱动_pl2303hx驱动下载
- c语言16进制转2进制代码
- Gym - 101964E -Fishermen(二分+差分求前缀和)
- html alert属性可以自定义,Html自定义alert,confirm弹窗
- 特征值 是 系数行列式等于0时的 解
热门文章
- 北京市中 高英语听说计算机考,2021年北京高考首次英语听说机考时间确定,共五种题型...
- C++ 内存基本构件 placement new
- 【C++grammar】继承与构造test1代码附录
- python 抓取网页链接_从Python中的网页抓取链接
- 商业模式新生代_业务分析基础 - 商业模式新生代01篇
- hadoop put命令的格式_HDFS常用命令
- uva 1433——Garlands
- Mooc的Python3学习笔记
- 把student a am i 变成 i am a student(两种方法)
- C++ STL 容器之queue