用深度学习卷积神经网络实现图像识别之猫狗大战

猫狗大战

  • 顾名思义,就是实现猫和狗的分类问题
  • 数据集图像是大小不一的
  • 数据集图像是彩色的

实现思路

  • 处理数据集时,要对图像的大小进行统一缩放
  • 将图片读取为像素矩阵,并转为卷积神经网络可以识别的形状
  • 构建卷积神经网络,有卷积,有池化,有全连接
  • 构建代价函数
  • 构建优化器
  • 迭代求出预测准确率

数据集

在这里插入图片描述
形如上述所示,共计25000张图片,这里做示范选取猫狗各500张。

代码实现

import tensorflow as tf
import numpy as np
import os
import cv2
import random

# 设置随机种子。(5分)
tf.set_random_seed(1)

# 猫狗数据文件夹路径
data_dir = r'data'


# 调用该方法,获取文件夹中猫狗的像素矩阵为数据,并为每条数据添加标签
def load_data(data_dir):
    # 存放所有图片像素矩阵数据
    data_all = []
    # 存放其对应的标签
    labels_all = []
    # i 为每个图片数据的名字
    for i in os.listdir(data_dir):
        # 拼接路径 保证cv2读取正确
        img = cv2.imread(os.path.join(data_dir, i))
        # 将读取到的大小不一的图像进行统一缩放
        img = cv2.resize(img, dsize=(128, 128))
        # 转为数字矩阵
        img_array = np.asarray(img)
        img_array = np.reshape(img_array, (3, 128, 128))
        # 直接对数据进行归一化
        img_array = img_array / 127.5 - 1
        # 将这个数据存放进列表
        data_all.append(img_array)
        # 因为图片的名字为'cat.1.jpg'等类型,所以对名字进行切割,选择第一部分,既是其对应的类型
        label = i.split('.')[0]
        # 将对应的类型,转为0,1,作0,1分类
        if label == 'cat':
            labels_all.append(1)
        else:
            labels_all.append(0)
    # 将列表作为转为数组
    data_all = np.asarray(data_all)
    labels_all = np.asarray(labels_all)
    labels_all = np.vstack(labels_all)
    return data_all, labels_all


# 调用该方法,对数据进行洗牌
def shuffle(data, labels):
    m = len(data)
    o = np.random.permutation(m)
    data = data[o]
    labels = labels[o]
    return data, labels


# 调用该方法对数据进行切分
def data_split(data, labels):
    m = len(data)
    l = int(m * 0.9)
    x_train, x_test = data[0:l], data[l:]
    y_train, y_test = labels[0:l], labels[l:]
    return x_train, x_test, y_train, y_test


# 调用load_data处理数据
data_all, labels_all = load_data(data_dir)

# 调用洗牌函数对数据进行打乱
data_all, labels_all = shuffle(data_all, labels_all)
# 调用数据切分方法,对数据进行切分
x_train, x_test, y_train, y_test = data_split(data_all, labels_all)

# 设置网络的参数,学习率设置为0.0001,训练周期设为100,batch_szie设为100
learning_rate = 0.0001
n_times = 100
batch_size = 100

# 定义网络占位符
X = tf.placeholder(tf.float32, [None, 3, 128, 128])
X_img = tf.transpose(X, perm=[0, 2, 3, 1])
Y = tf.placeholder(tf.float32, [None, 1])
keep_prob = tf.placeholder(tf.float32)

# 定义神经网络结构模型
# 首先构建卷积层,用于特征提取,示例如下,可以调整卷积参数及层数,这里选择两层,激活函数选择relu
conv1 = tf.layers.conv2d(X_img, 32, (3, 3), strides=(1, 1), padding='same', activation=tf.nn.relu)
# 加入batch_normalization防止卷积层过拟合
conv1 = tf.layers.batch_normalization(conv1,momentum=0.9)
pool1 = tf.layers.max_pooling2d(conv1, (2, 2), (2, 2), padding='same')
conv2 = tf.layers.conv2d(pool1, 64, (3, 3), (1, 1), padding='same', activation=tf.nn.relu)
conv2 = tf.layers.batch_normalization(conv2,momentum=0.9)
pool2 = tf.layers.max_pooling2d(conv2, (2, 2), (2, 2), padding='same')
# 将卷积数据展平,用于构建全连接层,用于分类
flatten = tf.layers.flatten(pool2)
fc1 = tf.layers.dense(flatten, 128, activation=tf.nn.relu)
# 全连接层可以加入dropout函数用于切断一些神经元的联系,防止过拟合
fc1 = tf.nn.dropout(fc1, keep_prob=keep_prob)
# 二分类问题,最终归于一个输出即可,激活函数选择sigmoid
fc2 = tf.layers.dense(fc1, 1, activation=tf.nn.sigmoid)
# 编写定义损失函数,网络优化器采用Adam
loss = - tf.reduce_mean(Y * tf.log(fc2) + (1 - Y) * tf.log(1 - fc2))
train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss)
# 预测
predict = tf.cast(fc2 > 0.5, dtype=tf.float32)
# 准确率
accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, Y), dtype=tf.float32))
# 开启会话
with tf.Session() as sess:
    # 创建会话并初始化全局变量
    sess.run(tf.global_variables_initializer())
    # 大循环训练100次
    for n in range(n_times):
        # 起始位置
        start = 0
        # 结束位置
        end_ = batch_size
        # acc_all存放准确率
        acc_all = []
        # 每次分批次循环训练
        for j in range(len(x_train) // batch_size):
            # 获取数据
            # 执行一个逻辑判断,如果下标越界,则重置起始与结束位置
            if start >= len(x_train):
                start = 0
                end_ = batch_size
            # 分批次获取训练数据中的数据
            data_batch, labels_batch = x_train[start:end_], y_train[start:end_]
            # 执行训练
            los, _, acc = sess.run([loss,train_op,accuracy], feed_dict={X: data_batch, Y: labels_batch, keep_prob: 0.9})
            acc_all.append(acc)
        accs = sess.run(accuracy, feed_dict={X: x_test, Y: y_test, keep_prob: 1})
        # 每个大批次训练完毕,打印训练集平均准确率和测试集准确率
        print('大批次', n + 1)
        print('训练集准确率:', np.mean(acc_all))
        print('测试集的准确率:', accs)
    # 测试集中随机抽一个样本并进行测试,输出结果
    r = random.randint(0, len(x_test) - 1)
    print('随机标签', y_test[r])
    print('预测标签', sess.run(predict, feed_dict={X: x_test[r], keep_prob: 1}))

效果总结

项目整体框架可以跑通,由于训练图片较少,大概10次大循环训练集就产生了过拟合,但是测试集准确率徘徊在百分之65,难有提升,这时可以加大数据量,训练一个好的模型。


版权声明:本文为qq872890060原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。