Archive for the ‘Algorithm’ category

sklearn 典型的回归模型

September 14th, 2017

回归模型中线性回归是最最基本的模型,也是在数据处理中运用最多的模型。sklearn提供了一套完备的工具集,可以对数据进行拟合和预测。

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression,RidgeCV,LassoCV,ElaticNetCV
from sklearn.preprocessing.PolynomialFeatures import PolynomialFeatures
models = [Pipeline([  
        ('poly', PolynomialFeatures()),  
        ('linear', LinearRegression(fit_intercept=False))]),  
        Pipeline([  
            ('poly', PolynomialFeatures()),  
            ('linear', RidgeCV(alphas=np.logspace(-3, 2, 50), fit_intercept=False))]),  
        Pipeline([  
            ('poly', PolynomialFeatures()),  
            ('linear', LassoCV(alphas=np.logspace(-3, 2, 50), fit_intercept=False))]),  
        Pipeline([  
            ('poly', PolynomialFeatures()),  
            ('linear', ElasticNetCV(alphas=np.logspace(-3, 2, 50), l1_ratio=[.1, .5, .7, .9, .95, .99, 1],  
                                    fit_intercept=False))])  
    ]  

模型中的fit_intercept代表是否存在截距,默认是开启的,normalize:标准化开关,默认关闭。

通过上面的头文件就可以看出来除了提供最最基本的LinearRegression以外,还提供带有L1 L2范数的LassoCV和RidgeCV。

LinearRegression的损失函数为J(θ)=1/2(Xθ−Y)T(Xθ−Y) 。优化方法为梯度下降和最小二乘法,scikit中采用最小二乘
。只要数据线性相关,LinearRegression就是首选,如果发现拟合或者预测的不够好,再考虑其他的线性回归库。

LassoCV的损失函数为J(θ)=1/2m(Xθ−Y)T(Xθ−Y)+α||θ|| 。即 线性回归LineaRegression的损失函数+L1(1范式的正则化项α||θ||) ,Lasso回归可以使得一些特征的系数变小,甚至还使一些绝对值较小的系数直接变为0,从而增强模型的泛化能力,因此对于高维的特征数据,尤其是线性关系是稀疏的,就采用Lasso回归,或者是要在一堆特征里面找出主要的特征。

RidgeCV的损失函数为J(θ)=1/2(Xθ−Y)T(Xθ−Y)+1/2(α||θ||^2)。即线性回归LineaRegression的损失函数+L2(2范式的正则化项1/2(α||θ||^2))),其中a为超参数 alphas=np.logspace(-3, 2, 50) 从给定的超参数a中选择一个最优的,logspace用于创建等比数列 本例中 开始点为10的-3次幂,结束点10的2次幂,元素个数为50.并且从这50个数中选择一个最优的超参数。Ridge回归中超参数a和回归系数θ的关系,a越大,正则项惩罚的就越厉害,得到的回归系数θ就越小,最终趋近与0。如果a越小,即正则化项越小,那么回归系数θ就越来越接近于普通的线性回归系数。
#使用场景:只要数据线性相关,用LinearRegression拟合的不是很好,需要正则化,可以考虑使用RidgeCV回归。

ElaticNetCV的损失函数为J(θ)=1/2m(Xθ−Y)T(Xθ−Y)+αρ||θ||1+α(1−ρ)/2||θ||22 其中α为正则化超参数,ρ为范数权重超参数 。乍一看就是Lasso和Ridge损失函数的合体。其中alphas=np.logspace(-3, 2, 50), l1_ratio=[.1, .5, .7, .9, .95, .99, 1] 。ElasticNetCV会从中选出最优的 a和p 。ElasticNetCV类对超参数a和p使用交叉验证,帮助选择合适的a和p,使用场景:ElasticNetCV类在我们发现用Lasso回归太过(太多特征被稀疏为0),而Ridge回归也正则化的不够(回归系数衰减太慢)的时候。

所以综上排名:LinearRegression > LassoCV(稀疏) >  ElaticNetCV  > RidgeCV(稠密) 

model = models[t]  
model.set_params(poly__degree=d) #设置多项式回归的阶
model.fit(x, y.ravel()) 
lin = model.get_params('linear')['linear'] 
if hasattr(lin, 'alpha_'): 
  ...
if hasattr(lin, 'l1_ratio_'): # 根据交叉验证结果,从输入l1_ratio(list)中选择的最优l1_ratio_(float) 
  ...
print output, lin.coef_.ravel(),lin.intercept_ 
y_hat = model.predict(x_hat)  
s = model.score(x, y)  

sklearn中提供了pipeline,只要把模型定义好,就可以直接利用fit对数据进行拟合,拟合完毕后使用predict进行预测。其中通过get_params可以获取某个模型,然后就能访问该回归模型的coef_和intercept_ ,如果模型设置的fit_intercept=false,那么打印出的lin.coef_中第一项就是截距,后面的为各个相关系数,lin.intercept_为0。如果置为true,那么lin.intercept_为截距值。

model.score主要用来衡量模型的拟合程度,Returns the coefficient of determination R^2 of the prediction.

R^2就是1-RSS/TSS,R^2越大,拟合效果越好。如果预测值为样本期望,那么R^2为0。

附sklearn工具类

参数列表 类别 fit方法有用 说明
sklearn.preprocessing StandardScaler 特征 无监督 Y 标准化
sklearn.preprocessing MinMaxScaler 特征 无监督 Y 区间缩放
sklearn.preprocessing Normalizer 特征 无信息 N 归一化
sklearn.preprocessing Binarizer 特征 无信息 N 定量特征二值化
sklearn.preprocessing OneHotEncoder 特征 无监督 Y 定性特征编码
sklearn.preprocessing Imputer 特征 无监督 Y 缺失值计算
sklearn.preprocessing PolynomialFeatures 特征 无信息 N 多项式变换(fit方法仅仅生成了多项式的表达式)
sklearn.preprocessing FunctionTransformer 特征 无信息 N 自定义函数变换(自定义函数在transform方法中调用)
sklearn.feature_selection VarianceThreshold 特征 无监督 Y 方差选择法
sklearn.feature_selection SelectKBest 特征/特征+目标值 无监督/有监督 Y 自定义特征评分选择法
sklearn.feature_selection SelectKBest+chi2 特征+目标值 有监督 Y 卡方检验选择法
sklearn.feature_selection RFE 特征+目标值 有监督 Y 递归特征消除法
sklearn.feature_selection SelectFromModel 特征+目标值 有监督 Y 自定义模型训练选择法
sklearn.decomposition PCA 特征 无监督 Y PCA降维
sklearn.lda LDA 特征+目标值 有监督 Y LDA降维

参考

http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.RidgeCV.html

numpy,Pandas 使用小结

August 31st, 2017

Update 2017-9-20

最近被一些生活上的事搞得焦头烂额,博客又有些荒废了,继续更…..

网络上有大段的numpy和Pandas博文,我就不一一阐述了,只记录我最近使用出现的坑….

numpy和Pandas配合matplotlib使用,可以快速绘制各类图表,我们可以方便的使用pandas读取xlsx,csv格式的数据.例如我们读取xlsx格式的数据,我们可以在read_excel定义表格是否存在header,便于跳过。pandas读取返回数据类型是dataFrame,而dataframe的每一行数据又是一个ndarray类型,在知道数据表头的前提下,可以将data看成一个大的数组,data[‘列名’]打印某列数据。data每列的列名就是一个key,列数据就是一个value,通过这种方式可以对某几列进行计算。

    pd.set_option('display.width', 200)
    data = pd.read_excel('sales.xlsx', sheetname='sheet1', header=0)
    print 'data.head() = \n', data.head()
    print 'data.tail() = \n', data.tail()
    print 'data.dtypes = \n', data.dtypes
    print 'data.columns = \n', data.columns
    for c in data.columns:
        print c,
    print
    data['total'] = data['Jan'] + data['Feb'] + data['Mar']
    print data.head()
    print data['Jan'].sum()
    print data['Jan'].min()
    print data['Jan'].max()
    print data['Jan'].mean()

reindex是对这个dataframe重新组织列名,rename则是对某一行的头进行重命名。

pd.reindex(columns=data.columns)
data = data.rename(index={15:'Total'})

除了read_excel外,read_csv可以帮助我们处理cvs格式的数据,当我们接手一个csv数据文件后,要观察这个文件是否存在表头,存在话,可以在data = pd.read_csv(‘xxx’,header=None)跳过,data的数据类型是dataFrame,如果我们想获取某一列数据或者某几列,可以采用iloc[],(这里采用iloc返回的是Seriers类型,如果使用values则转换为np。array类型,而array类型通过tolist则可以转换为 python 内置的list类型)

data = pd.read_csv('wine_data',sep=',',header=None)
x = data.iloc[:,1:].values
y = data.iloc[:,0].vaues

当然也可以生成一个表头,并且在pd.read_csv(‘wine_data’,sep=’,’,header=cols)制定表头是cols,而cols是一个np.array,当读入数据以后,就可以使用表头获取某几列数据x = data[cols[:-1]]

df.loc[1] 获取第二行

df.loc[:,’test1′] 获取test1的那一列,这个冒号的意思是所有行,逗号表示行与列的区分

df.loc[:,[‘test1′,’test2’]] 获取test1列和test2列的数据

df.loc[1,[‘test1′,’test2’]] 获取第二行的test1和test2列的数据

df.at[1,’test1′] 表示取第二行,test1列的数据,和上面的方法类似

df.iloc[0] 获取第一行

df.iloc[0:2,0:2] 获取前两行前两列的数据

df.iloc[[1,2,4],[0,2]] 获取第1,2,4行中的0,2列的数据

apply函数是对某一行或者某一列使用定义的函数进行处理,例如函数find_state_code,在python,numpy和pandas中axis是一个比较难以理解的概念,stackoverflow给出了非常好的解释翻译过来就是axis=0沿着列的方向,axis=1沿着行的方向。下面代码就是沿着行的方向把每个行中列名为state的元素进行修改!

def find_state_code(row):
    if row['state'] != 0:
        print process.extractOne(row['state'], states, score_cutoff=80)

data.apply(find_state_code, axis=1)

pandas.cut将值放入某个bin中,并将bin赋值给这列数据。

>>> pd.cut(np.array([.2, 1.4, 2.5, 6.2, 9.7, 2.1]), 3,labels=["good","medium","bad"])
[good, good, good, medium, bad, good]
Categories (3, object): [good < medium < bad]

numpy中提供np.linalg.svd函数,对图像进行奇异值分解,然后我们可以将得到的特征值和特征向量相乘复原这张图像,例如一张图高282px 宽218px rgb,那么分解出来就是u 是282×282 v是218×218 sigma 218.那么u[:, k]代表第k列reshape成为mx1形状的矩阵,v[k]代表k行reshape成为1xn形状的矩阵,二者通过np.dot(uk, vk)做矩阵点乘,再乘sigma即可还原图像。

a = np.array(A)

u_r, sigma_r, v_r = np.linalg.svd(a[:, :, 0])
u_g, sigma_g, v_g = np.linalg.svd(a[:, :, 1])
u_b, sigma_b, v_b = np.linalg.svd(a[:, :, 2])
=====
def restore1(sigma, u, v, K):  # 奇异值、左特征向量、右特征向量
    m = len(u)
    n = len(v[0])
    a = np.zeros((m, n))
    for k in range(K):
        uk = u[:, k].reshape(m, 1)
        vk = v[k].reshape(1, n)
        a += sigma[k] * np.dot(uk, vk)
    a[a &lt; 0] = 0 a[a &gt; 255] = 255
    # a = a.clip(0, 255)
    return np.rint(a).astype('uint8')

np.loadtxt可以读入格式化数据,然后通过usecols选取某几个特定行。np.convolve是特定针对一维向量做卷积的函数,这个函数开始我很疑惑,因为他和对于图像做卷积很不同,通过查询文档(https://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.convolve.html),了解到第二个参数是卷积核,python内部实现的时候对这个卷积核做了一个反转,然后才对数据做卷积。

stock_max, stock_min, stock_close, stock_amount = np.loadtxt('SH600000.txt', delimiter='\t', skiprows=2, usecols=(2, 3, 4, 5), unpack=True)
stock_sma = np.convolve(stock_close, weight, mode='valid')  # simple moving average
============
np.convolve([1, 2, 3], [0, 1, 0.5])
array([ 0. ,  1. ,  2.5,  4. ,  1.5])

具体计算方法是将[0, 1, 0.5]翻转为[0.5,1,0],对[1,2,3]做卷积,[0,0,1],[0,1,2],[1,2,3],[2,3,0],[3,0,0]分别点乘[0.5,1,0]

0.5*null+1*null+0*1=0
0.5*null+1*1+0*0*2=1
0.5*1+1*2+0*3=2.5
0.5*2+1*3+0*null=4
0.5*3+1*null+0*null=1.5

np.polyfit曲线拟合函数,第三个参数是多项式最高次数,拟合完毕结果返回10次拟合多项式系数, 从高次到低次存放在向量poly中.polyval可求得多项式在t处的值stock_ema_hat,这里的stock_ema,stock_ema_hat 都是向量。

poly = np.polyfit(t, stock_ema, 10)
stock_ema_hat = np.polyval(poly, t)

candlestick_ohlc是专门用于画股市K线图的,这个包来自于from matplotlib.finance import candlestick_ohlc

one-hot编码主要解决许多不连续的值,比如【男,女】【小学,初中,高中,本科,其他】,对于这种数据使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。

自然状态码为:000,001,010,011,100,101

one-hot编码为:000001,000010,000100,001000,010000,100000

可以看出one-hot编码每个编码互斥,每次只有一个激活。数据变成稀疏的。在pandas中直接使用get_dummies()对这些离散值进行one-hot编码,如下代码所示,data[col]特定指某一列离散值。

data = data.join(pd.get_dummies(data[col],prefix=col))
print data

此外sklearn提供LabelEncoder,可以一次性将所有离散值进行编码(非one-hot编码)。

le = LabelEncoder()
for col in data.columns:
    data[col] = le.fit_transform(data[col])

MinMaxScaler,说白了就是归一化,计算方式是特征值减去最小值除以最大值减去最小值。

mms = MinMaxScaler()
data[col] = mms.fit_transform(data[col].values.reshape(-1,1))

pca主成分分析主要用于降维,但是本质上是坐标系的旋转,比如我们使用pca将多维数据降维成2维数据,降维后的坐标轴,其实没有什么实际的意义,但是pca可以让数据更加可视化,便于理解。
采用单变量特征选择(Univariate feature selection)则是在众多变量中选择最重要的变量,抛弃不重要的变量。

pca = PCA(n_components=2,whiten=True,random_state=0)
x = pca.fit_transform(x)
print pca.explained_variance_
print pca.explained_variane_ratio_

fs = SelectKBest(chi2,k=2)
fs.fit(x,y)
idx = fs.get_support(indices=True)//idx 返回选中主要的两列(k=2)

numpy下存在numpy.ravel() 和 numpy.flatten(),两者的功能是一致的(将多维数组降位一维),numpy.flatten()返回一份拷贝,对拷贝所做的修改不会影响(reflects)原始矩阵,而numpy.ravel()返回的是视图(view,也颇有几分C/C++引用reference的意味),会影响(reflects)原始矩阵。

================

附引入包

from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.decomposition import PCA
from sklearn.feature_selection import SelectKBest, SelectPercentile, chi2
from sklearn.linear_model import LogisticRegressionCV
from sklearn import metrics
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.manifold import TSNE
from matplotlib.finance import candlestick_ohlc
from PIL import Image

 

参考

https://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.convolve.html

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.cut.html

http://blog.csdn.net/ariessurfer/article/details/42526673

http://scikit-learn.org/stable/modules/preprocessing.html#preprocessing

ndarrya用法汇总: http://blog.csdn.net/qingyuanluofeng/article/details/51649789

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html

http://skyrover.me/2016/12/08/Pandas%E4%BD%BF%E7%94%A8%E7%AC%94%E8%AE%B0/

深度残差网络的个人理解

June 21st, 2017

上篇对于三大RCNN算法进行了阐述,算法首要都必须提取整幅图的特征向量,目前性能比较好的神经网络是ResNet。ResNet使用了深度残差网络(Deep Residual Network),这种网络的发明的背景在于网络的层数在不断增加的情况下出现识别率降低的问题。

Deep Residual Network采用在层与层之间添加shortcut,即每层的输出不是传统神经网络当中输入的映射,而是映射和输入的叠加。

网上很多观点都倾向于梯度消失,即对网络做BP推导的话,

本来每个子项就特别小,再乘以更小的子项导致梯度趋近于0,而Deep Residual Network采用添加路径的方式将X1和XL连接起来,导致偏导置于一个比较大的数,在BP过程中,梯度不容易消失。

学术界对于出现这种问题的根源有不同的看法,我倾向这种增加路径的方式非常类似于Dropout,一个是增加路径,一个是随机减少路径,实际上效果来自于训练层数的减少,实际每次训练网络结构层数少于网络最大层数。

目前在我算法里,我使用的是ResNet50,50就是包含50层Conv卷积,ResNet50在网上有现成的model和weights,不过这里为了加深理解提供部分基于Keras的模型代码和模型结构图示。

    x = ZeroPadding2D((3, 3))(img_input)

    x = Convolution2D(64, (7, 7), strides=(2, 2), name='conv1', trainable = trainable)(x)
    x = FixedBatchNormalization(axis=bn_axis, name='bn_conv1')(x)
    x = Activation('relu')(x)
    x = MaxPooling2D((3, 3), strides=(2, 2))(x)

    x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1), trainable = trainable)
    x = identity_block(x, 3, [64, 64, 256], stage=2, block='b', trainable = trainable)
    x = identity_block(x, 3, [64, 64, 256], stage=2, block='c', trainable = trainable)

    x = conv_block(x, 3, [128, 128, 512], stage=3, block='a', trainable = trainable)
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='b', trainable = trainable)
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='c', trainable = trainable)
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='d', trainable = trainable)

    x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a', trainable = trainable)
    x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b', trainable = trainable)
    x = identity_block(x, 3, [256, 256, 1024], stage=4, block='c', trainable = trainable)
    x = identity_block(x, 3, [256, 256, 1024], stage=4, block='d', trainable = trainable)
    x = identity_block(x, 3, [256, 256, 1024], stage=4, block='e', trainable = trainable)
    x = identity_block(x, 3, [256, 256, 1024], stage=4, block='f', trainable = trainable)

上图只是针对其中一个conv_block,conv_block分出两个分支,一个分支卷积一次,一个分支卷积3次,然后在res2a处将两个分支Add。identity_block则是直接将输入和三次卷积结果Add。

 

http://blog.csdn.net/superCally/article/details/55671064

https://my.oschina.net/yilian/blog/667900

https://arxiv.org/pdf/1605.06431.pdf

 

RCNN、Fast RCNN和Faster RCNN的个人理解

June 1st, 2017

最近在使用Keras对我定义的目标进行训练和目标检测,目前最火的目标检测框架就是Faster RCNN了,Faster RCNN克服了他的前辈RCNN和Fast RCNN固有的一些问题,提升了检测速度,使得在视频领域的目标检测成为可能。

RCNN算法这里简单提一下:

  • 区域提名:通过Selective Search从原始图片提取2000个左右区域候选框;
  • 区域大小归一化:把所有侯选框缩放成固定大小(原文采用227×227)
  • 特征提取:通过CNN网络,提取特征;
  • 分类与回归:在特征层的基础上添加两个全连接层,再用SVM分类来做识别,用线性回归来微调边框位置与大小,其中每个类别单独训练一个边框回归器。

RCNN最大弊端就是拥有太多的候选框,这个导致每个候选框都要分别通过CNN提取特征,计算量依然很大,其中有不少其实是重复计算,最终这个也使得目标识别非常慢

Fast RCNN是RCNN的改进版,借鉴了SPP-Net中对于提取到的卷积层特征的处理,即提出去掉了原始图像上对于ROI区域的crop/warp等操作(也就是把所有的候选框都做归一化),换成了在提取到的卷积特征上的空间金字塔池化层(Spatial Pyramid Pooling,SPP)。因此无论图片大小如何,无论图像向量唯独如何,经过Spatial Pyramid Pooling操作,提取出来的提取出来的维度数据都是一致的,这样就可以统一送至全连接层了。

ROI操作(Spatial Pyramid Pooling,SPP):

通过上图可以看到feature map 经过SPP层被分割成了16个256d+4个256d+1个256d的ROI 特征向量。因此在Fast RCNN中输入的候选框可大可小,然后根据得到的候选框区域投影到整幅图片的特征向量层。

总的Fast RCNN步骤如下:

  • 特征提取:以整张图片为输入利用CNN得到图片的特征层;
  • 区域提名:通过Selective Search等方法从原始图片提取区域候选框,并把这些候选框一一投影到最后的特征层;
  • 区域归一化:针对特征层上的每个区域候选框进行RoI Pooling操作,得到固定大小的特征表示
  • 分类与回归:然后再通过两个全连接层,分别用softmax多分类做目标识别,用回归模型进行边框位置与大小微调。

Faster RCNN在Fast RCNN的基础上更进一部,不再使用Selective Search等方法获取候选框,而是利用RPN(Region Proposal Networks)网络来计算候选框。RPN以一张任意大小的图片为输入,输出一批矩形区域提名,每个区域对应一个目标分数和位置信息。当然RPN和Fast RCNN共用基础的图片特征。

RPN会产生K个Anchor Box,而每个Anchor Box都包括2K个score和4K个坐标点,socre就是这个区域的评分,有多大概率是这个东西?4K就是矩形的是个坐标位置。然后将这些Anchor Box和整幅图的特征向量结合起来(就是Feature Map ——> ROI Feature的操作,就是上面Fast RCNN步骤三,最后产生固定大小的特征表示),得到的固定大小的特征表示可以进行对应区域的classification,分类这个区域是不是那个物体,然后用 k 个回归模型(各自对应不同的Anchor Box)微调候选框位置与大小,最后进行目标真正的分类,判断这个目标是什么东西。

总的步骤:

  • 特征提取:同Fast R-CNN,以整张图片为输入,利用CNN得到图片的特征层;
  • 区域提名:在最终的卷积特征层上利用 k 个不同的矩形框(Anchor Box)进行提名, k 一般取9;
  • 分类与回归:对每个Anchor Box对应的区域进行object/non-object二分类,并用 k 个回归模型(各自对应不同的Anchor Box)微调候选框位置与大小,最后进行目标分类。

Faster RCNN得到区域提名以后,后续操作和Fast RCNN一模一样!事实上只需关注RPN即可,如下图流程(忽略前后的不同….):

梳理了整个算法脉络大白话就是:目标检测分为两大部分:1)区域提名 2)特征回归分类。每个部分都是各大算法进化过来的。

参考文献

[1] R. Girshick, J. Donahue, T. Darrell, J. Malik. Rich feature hierarchies for accurate object detection and semantic segmentation. ImageNet Large-Scale Visual Recognition Challenge workshop, ICCV, 2013.

[2] R. Girshick, J. Donahue, T. Darrell, J. Malik. Rich feature hierarchies for accurate object detection and semantic segmentation. IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2014.

[3] R. Girshick, J. Donahue, T. Darrell, J. Malik. Region-Based Convolutional Networks for Accurate Object Detection and Segmentation. IEEE Transactions on Pattern Analysis and Machine Intelligence, May. 2015.

[4] K. He, X. Zhang, S. Ren, and J. Sun. Spatial pyramid pooling in deep convolutional networks for visual recognition. In ECCV. 2014.

[5] S. Ren, K. He, R. Girshick, J. Sun. Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks. Advances in Neural Information Processing Systems 28 (NIPS), 2015.

CNN参数小结

May 11th, 2017

CNN(Convolutional Neural Networks)是当下最火的一种神经网络,主要用来识别图像。CNN由三部分组成:Convolutional Layer, Pooling Layer 和 Fully-Connected Layer,卷积层和池化都是CNN特有的,全连接层是传统的神经网络。

整个网络流程就是 [INPUT – CONV – RELU – POOL – FC],其中CONV-RELU-POOL可以添加很多层,如图所示

举个例子:

  • 输入的数据都是28x28x1的图像,意思就是长宽都是28的pixel,并且是单通道图像。
  • 卷积层中,神经元与输入层中的一个局部区域相连,每个神经元都计算自己与输入层相连的小块区域与自己权重的内积。卷积层会计算所有神经元的输出。如果我们使用25个filter[3x3x25],每个filter是得到的输出数据体的维度就是[26x26x25]。
  • ReLU层将会逐个元素地进行激活函数操作,比如使用以0为阈值的max(0,x)作为激活函数。该层对数据尺寸没有改变,还是[26x26x25]。
  • 汇聚层在在空间维度(宽度和高度)上进行降采样(downsampling)操作,其实也就是POOL层[2×2],数据尺寸变为[13x13x25]。
  • 然后可以再次进行卷积、ReLU和Pool。
  • 全连接层将会计算分类评分,数据尺寸变为[1x1x10],其中10个数字对应的就是CIFAR-10中10个类别的分类评分值,全连接层与常规神经网络一样,其中每个神经元都与前一层中所有神经元相连接。

最开始卷积的维度变化让我很头疼,看了好久才理解。总结下面公式:

  • 输入数据体的尺寸为W1 * H1 * D1
  • 4个参数:
    filter的数量K
    filter的空间尺寸F
    步长stride S
    零填充数量(the amount of zero padding)P
  • 输出数据体的尺寸为W2 * H2 * D2 ,其中:
    W2=(W1-F+2P)/S+1
    H2=(H1-F+2P)/S+1 (宽度和高度的计算方法相同)
    D2=K
    由于参数共享,每个滤波器包含F * F *D1个权重,卷积层一共有F * F * D1  K个权重和K个偏置。

每进行一次卷积,图像的深度就增加一倍,深度与filter的数量K紧密相关!

常见的设置是F=3,S=1,P=1,零填充数量就是为了让输入图像长宽变为偶数(其实就是在图像外围填充0),例如是32、64、128等,而使用S=1的步长,是因为使得空间维度的降采样全部由Pooling层负责,卷积层只负责对输入数据体的深度进行变换。

使用这些参数需要考虑到内存的占用率,比如使用64个尺寸为3×3的滤波器对【224x224x3】的图像进行卷积,零填充为1,步长为1,那么得到的激活数据体尺寸是[224x224x64]。这个数量就是一千万的数据特征,或者就是72MB的内存!

第二次池化后,使用Flatten,压扁这个数据集合,建立二层全连接网络,第一层神经元数100,第二层为10。

 

 

参考:

http://cs231n.github.io/convolutional-networks/

http://cs231n.stanford.edu/syllabus.html

http://cs.stanford.edu/people/karpathy/convnetjs/demo/cifar10.html