卷积神经网络:用于图像分类

卷积神经网络用于图像分类,最早可以追溯到Lenet-5,它最早被应用于手写数字的识别,并且取得了不错的分类效果。

因为通常数据集是要求我们自己收集,而且有些数据并不是特别容易收集的,会遇到采集仪器价格昂贵、样本可收集性不高等问题。

这就说明了一个潜在的问题,数据集要多大才能用于分类网络中。

下面,送给大家三句话:

训练集中每个类应有1000张图像;

所用图像应当是具有代表性的高质量图像;

如果图像数量不够,可采用数据增强方法。

对于小样本数据如何处理

1、迁移学习

因为你正在使用是已经查看过大量图像并且学会区分类的网络,所以通常可以教给模型同一领域的新类,只需要几十个数据样本即可。

2、数据增强

博主分享几个自己常用的数据增强代码。

"伽马变换"
img = cv2.imread(file_pathname+'/'+filename, 1)
# 图像归一化
fi = img / 255.0
# 伽马变换
gamma = 0.8  #自己设定
out = np.power(fi, gamma)
out = out * 255
"平移"
def affine(img, a, b, c, d, tx, ty):  #平移
    H,  W,   = img.shape
    tem = img.copy()
    img = np.zeros((H + 2, W + 2, ), dtype=np.float32)
    img[1:H + 1, 1:W + 1] = tem
    H_new = np.round(H * d).astype(np.int)
    W_new = np.round(W * a).astype(np.int)
    out = np.zeros((H_new + 1, W_new + 1, ), dtype=np.float32)
    x_new = np.tile(np.arange(W_new), (H_new, 1))
    y_new = np.arange(H_new).repeat(W_new).reshape(H_new, -1)
    adbc = a * d - b * c
    x = np.round((d * x_new - b * y_new) / adbc).astype(np.int) - tx + 1
    y = np.round((-c * x_new + a * y_new) / adbc).astype(np.int) - ty + 1
    # 避免目标图像对应的原图像中的坐标溢出
    x = np.minimum(np.maximum(x, 0), W + 1).astype(np.int)
    y = np.minimum(np.maximum(y, 0), H + 1).astype(np.int)
    # assgin pixcel to new image
    out[y_new, x_new] = img[y, x]
    out = out[:H_new, :W_new]
    out = out.astype(np.uint8)
    return out
"旋转"
def remote(img, degree):
    height, width = img.shape[:2]
    radians = float(degree / 180 * pi)
    heightNew = int(width * fabs(sin((radians))) + height * fabs(cos((radians))))
    widthNew = int(height * fabs(sin((radians))) + width * fabs(cos((radians))))
    # 得到二维矩阵的旋转的仿射矩阵
    matRotation = cv2.getRotationMatrix2D((width / 2, height / 2), degree, 1)
	# 中心位置的实际平移
    matRotation[0, 2] += (widthNew - width) / 2
    matRotation[1, 2] += (heightNew - height) / 2
    imgRotation = cv2.warpAffine(img, matRotation,
                                 (widthNew, heightNew), borderValue=(0,0,0))
    return imgRotation

3、基于Keras的Data Augmentation方法

代码如下:

from keras.preprocessing.image import ImageDataGenerator
"""
parameters:

rotation_range:整数,数据提升时图片随机转动的角度

width_shift_range:浮点数,图片宽度的某个比例,数据提升时图片水平偏移的幅度

height_shift_range:浮点数,图片高度的某个比例,数据提升时图片竖直偏移的幅度

rescale: 重放缩因子,默认为None. 如果为None或0则不进行放缩,否则会将该数值乘到数据上(在应用其他变换之前)

shear_range:浮点数,剪切强度(逆时针方向的剪切变换角度)

zoom_range:浮点数或形如[lower,upper]的列表,随机缩放的幅度,若为浮点数,则相当于[lower,upper] = [1 - zoom_range, 1+zoom_range]

fill_mode:‘constant’‘nearest’,‘reflect’或‘wrap’之一,当进行变换时超出边界的点将根据本参数给定的方法进行处理

cval:浮点数或整数,当fill_mode=constant时,指定要向超出边界的点填充的值

channel_shift_range: Float. Range for random channel shifts.

horizontal_flip:布尔值,进行随机水平翻转

vertical_flip:布尔值,进行随机竖直翻转

"""

datagen = ImageDataGenerator(
        rotation_range=40,
        width_shift_range=0.2,
        height_shift_range=0.2,
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True,
        fill_mode='nearest',
        cval=0,
        channel_shift_range=0,
        horizontal_flip=False,
        vertical_flip=False,
        rescale=None)

数据增强告一段落,接下来就正式进入卷积神经网络的学习。

AlexNet

alexnet实现手写数字的识别

"直接用代码的形式来表达网络结构"
model = Sequential()
model.add(Conv2D(96, (11, 11), 
          strides=(1, 1), 
          input_shape=(28, 28, 1), 
          padding='same',
          activation='relu',
          kernel_initializer='uniform'))
# 池化层
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
# 第二层加边使用256个5x5的卷积核,加边,激活函数为relu
model.add(Conv2D(256, (5, 5), 
                 strides=(1, 1), 
                 padding='same', 
                 activation='relu', 
                 kernel_initializer='uniform'))
#使用池化层,步长为2
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
# 第三层卷积,大小为3x3的卷积核使用384个
model.add(Conv2D(384, (3, 3), 
                 strides=(1, 1), 
                 padding='same', 
                 activation='relu', 
                 kernel_initializer='uniform'))
# 第四层卷积,同第三层
model.add(Conv2D(384, (3, 3), 
                 strides=(1, 1), 
                 padding='same',
                 activation='relu', 
                 kernel_initializer='uniform'))
# 第五层卷积使用的卷积核为256个,其他同上
model.add(Conv2D(256, (3, 3), 
                 strides=(1, 1), 
                 padding='same', 
                 activation='relu', 
                 kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
model.add(Flatten())
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
model.summary()

VGG

一个5x5的卷积核用两个串联的3x3卷积核来代替

VGG11、13、16、19,SimpleVGG

"VGG13"
model = Sequential()
model.add(Conv2D(64, (3, 3), strides=(1, 1), input_shape=(32, 32, 3), padding='same', activation='relu',
                 kernel_initializer='uniform'))
model.add(Conv2D(64, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(128, (3, 2), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(128, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

GoogLeNet

虽然深度只有22层,但大小却比AlexNet和VGG小很多,GoogleNet参数为500万个,AlexNet参数个数是GoogleNet的12倍,VGGNet参数又是AlexNet的3倍,因此在内存或计算资源有限时,GoogleNet是比较好的选择;从模型结果来看,GoogLeNet的性能却更加优越。

Resnet

ResNet引入了残差网络结构(residual network),通过这种残差网络结构,可以把网络层弄的很深(据说目前可以达到1000多层),并且最终的分类效果也非常好。

Densenet

密集连接:缓解梯度消失问题,加强特征传播,鼓励特征复用,极大的减少了参数量。

总结:上诉神经网络都经常用于图像分类中,并辅之迁移学习。

你可能感兴趣的:(神经网络,深度学习)