深度学习入门案例:使用keras进行二分类实战:从处理数据到训练完成

前几天接到一个需求,需要识别出图像中的图片是一行还是两行。过去,这种问题用传统方法来做的,缺点是鲁棒性很差,尤其是在现实生活中,对数据来源没法严格控制的环境下。一般分类图像类似于这样,偶尔会因为拍摄的原因出现文字倾斜,模糊等问题:

一行 

开始我觉得这是一个很简单的二分类问题,应该一个sigmod分分钟搞定,没曾想最后还是挺曲折的。由于数据还没有到我手上,就先造了一点数据。类似于这样的:       其中涉及几个问题:1.随机生成中文字符 2.随机生成1行或者2行数据 3.第二行数据与第一行数据间距也要随机。具体代码会在最后附上。

大概造了1w张训练集,1千验证集合,和10w测试集。做好准备之后,就开始尝试了。

1.尝试直接全连接分类:

    model = tf.keras.Sequential()
    # Adds a densely-connected layer with 64 units to the model:
    #model.add(layers.Conv2D(64, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(layers.Flatten(input_shape=(40,100,1)))
    model.add(layers.Dense(128, activation='relu'))
    # Add another:
    model.add(layers.Dense(64, activation='relu'))
    # Add a softmax layer with 10 output units:
    model.add(layers.Dense(1, activation='sigmoid'))

中途加入dropout层,并没有卵用,神经网络无法感受到1层和2层的区别。想了一想,可能是因为flatten展开之后,图像的层间关系变得很不明显导致的。所以,考虑加入卷积来提取更加明显的特征试试。这里的准确率最多在0.48左右。

2.尝试加入卷积层:

    model =keras.Sequential()
    # Adds a densely-connected layer with 64 units to the model:
    model.add(Conv2D(64, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(64, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, padding='same', data_format=None))
    model.add(Conv2D(128, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(128, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, padding='same', data_format=None))
    model.add(Conv2D(256, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(256, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(256, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, padding='same', data_format=None))
    model.add(Conv2D(512, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(512, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(512, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, padding='same', data_format=None))
    model.add(Conv2D(512, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(512, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(Conv2D(512, (3, 3), padding='same',input_shape=(40, 100, 1) ,activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, padding='same', data_format=None))
    model.add(Flatten(input_shape=(40,100,512)))
    model.add(Dense(128, activation='relu'))
    # Add another:
    model.add(Dense(64, activation='relu'))
    # Add a softmax layer with 10 output units:
    model.add(Dense(1, activation='sigmoid'))

我尝试模仿vgg的结构来提取特征,可惜的是也只能达到0.6左右的准确率。但是我依然坚信这个问题是深度学习可以解决的,我尝试最后一招,预处理让特征更加明显一点。

3.用opencv预处理:

我的目标是把每一个文字转化成空白,这样的话可以增加目标的像素,减少空白像素。

说干就干:

3.1第一步先把图像转化成灰度图,以前我都误以为颜色对神经网络是没有影响的,主要是通过边界特征来识别,后来才发现并非如此。事实上,颜色信息会干扰梯度计算,影响很大(具体可以在b站看李宏毅老师的课)。灰度处理同时可以用sobel算子边缘检测一下。

    # 1. Sobel算子,x方向求梯度
    sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize = 3)
    # 2. 二值化
    ret, binary = cv2.threshold(sobel, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)

3.2膨胀腐蚀一次,相当于形态学闭运算

    # 3. 膨胀和腐蚀操作的核函数
    element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 9))
    element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (24, 6))
 
    # 4. 膨胀一次,让轮廓突出
    dilation = cv2.dilate(binary, element2, iterations = 1)
 
    # 5. 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
    erosion = cv2.erode(dilation, element1, iterations = 1)

一行的会这样:

两行的就会这样:

然后在通过一个全连接网络,准确率基本达到100%

总结:

1.这个只是第一步尝试,等正真的数据来了,肯定还会有很大的问题需要解决。

2.这个尝试可以证明,神经网络的泛化能力并不是很强。最后通过opencv这种手段来处理到这一步的话,很可能不用神经网络,直方图也可以处理的不错,但是因为需要设置各种阈值,泛化能力更加弱。用神经网络的话还可以在,真正复杂数据来的时候再处理。

3.遇到的一些问题和坑;

3.1 import keras和from tensorflow impot keras两个最好不要混着用,经常出现各种问题。

3.2 用from tensorflow impot keras和import keras,同样的代码结果不一样,有待找出问题。

代码路径:https://github.com/liuzehao/keras-twoclassfication

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值