Press "Enter" to skip to content

猫还是狗?让AI瞅瞅!

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

有没有开过一个脑洞,自己动手搭建一个模型可以分辨阿猫阿狗?别害羞了,现在就教你,快上车!

阿猫还是阿狗?

上有个叫 Dogs VS Cats 的挑战赛(https://www.kaggle.com/c/dogs-vs-cats),我们今天所有的数据就来自这个挑战赛的数据集,包含25000张标记了的阿狗阿猫的图像,如下所示:

我们看看具体的图像。每张图像都可以用 3 维数组表示出来,我们会将所有的训练图像重新调整为 50 X 50 像素大小。举个栗子:

此外,我们还会去掉图像的所有色彩,将它们变成黑白照片。

首先最要紧的是准备我们需要的编程环境。

设置

从 Kaggle(https://www.kaggle.com/c/dogs-vs-cats/data)上下载训练和测试模型用的图像压缩文件,并将它们提取到我们当前的工作目录中。

import cv2import numpy as npimport os         from random import shuffle from tqdm import tqdm      import tensorflow as tfimport matplotlib.pyplot as pltimport tflearnfrom tflearn.layers.conv import conv_2d, max_pool_2dfrom tflearn.layers.core import input_data, dropout, fully_connectedfrom tflearn.layers.estimator import regression%matplotlib inlineTRAIN_DIR = 'train'TEST_DIR = 'test'IMG_SIZE = 50LR = 1e-3MODEL_NAME = 'dogs-vs-cats-convnet'

图像预处理

我们有 25000 张图像用于训练模型,12500 张图像用于测试模型。我们创建一个函数,用它来编码训练图像的标签:

def create_label(image_name):    """ Create an one-hot encoded vector from image name """    word_label = image_name.split('.')[-3]    if word_label == 'cat':        return np.array([1,0])    elif word_label == 'dog':        return np.array([0,1])

现在我们看看训练和测试数据的实际读数。每张图像会被重新调整为 50 X 50 像素大小,读取为灰度模式:

def create_train_data():    training_data = []    for img in tqdm(os.listdir(TRAIN_DIR)):        path = os.path.join(TRAIN_DIR, img)        img_data = cv2.imread(path, cv2.IMREAD_GRAYSCALE)        img_data = cv2.resize(img_data, (IMG_SIZE, IMG_SIZE))        training_data.append([np.array(img_data), create_label(img)])    shuffle(training_data)    np.save('train_data.npy', training_data)    return training_datadef create_test_data():    testing_data = []    for img in tqdm(os.listdir(TEST_DIR)):        path = os.path.join(TEST_DIR,img)        img_num = img.split('.')[0]        img_data = cv2.imread(path, cv2.IMREAD_GRAYSCALE)        img_data = cv2.resize(img_data, (IMG_SIZE, IMG_SIZE))        testing_data.append([np.array(img_data), img_num])     shuffle(testing_data)    np.save('test_data.npy', testing_data)return testing_data

现在我们分拆数据。24500 张图像用于训练模型,500 张图像用于测试模型。我们还需要重新调整数据大小,以适应 TensorFlow:

# 如果没有创建数据集:train_data = create_train_data()test_data = create_test_data()# 如果已创建数据集:# train_data = np.load('train_data.npy')# test_data = np.load('test_data.npy')train = train_data[:-500]test = train_data[-500:]X_train = np.array([i[0] for i in train]).reshape(-1, IMG_SIZE, IMG_SIZE, 1)y_train = [i[1] for i in train]X_test = np.array([i[0] for i in test]).reshape(-1, IMG_SIZE, IMG_SIZE, 1)y_test = [i[1] for i in test]

卷积神经网络

我们该怎么分辨汪星人和喵星人呢?是不是很难?别担心,我们有神器——卷积神经网络 !

在以前,人们不得不考虑编写可能和手头工作相关的不同的特征。在我们识别阿猫阿狗的例子里,就是耳朵、尾巴、毛发、胡须等这些特征。不过,现在我们有了卷积神经网络,这些都不再是事儿,它能够从初始数据中学习。

关于卷积网络的工作原理,如果不是很了解,墙裂推荐我站的这篇讲解:

https://jizhi.im/blog/post/intuitive_explanation_cnn

应该能明白卷积神经网络是怎么一回事了吧?你可以把卷积当成一些很小的可以滑动的晶体(比方说 5 X 5 大小),当它们放在与它们相似的一些特征上面时,就会被“激活”。这样以来,卷积可以弄明白图像更大范围的内容,而不仅仅只有一个像素。

搭建我们的模型

最终,有趣的地方到了!我们会用 tflearn(http://tflearn.org/)搭建我们的卷积神经网络,会额外再用一个丢弃层。这是我们的模型:

tf.reset_default_graph()convnet = input_data(shape=[None, IMG_SIZE, IMG_SIZE, 1], name='input')convnet = conv_2d(convnet, 32, 5, activation='relu')convnet = max_pool_2d(convnet, 5)convnet = conv_2d(convnet, 64, 5, activation='relu')convnet = max_pool_2d(convnet, 5)convnet = fully_connected(convnet, 1024, activation='relu')convnet = dropout(convnet, 0.8)convnet = fully_connected(convnet, 2, activation='softmax')convnet = regression(convnet, optimizer='adam', learning_rate=LR, loss='categorical_crossentropy', name='targets')model = tflearn.DNN(convnet, tensorboard_dir='log', tensorboard_verbose=0)model.fit({'input': X_train}, {'targets': y_train}, n_epoch=10,           validation_set=({'input': X_test}, {'targets': y_test}),           snapshot_step=500, show_metric=True, run_id=MODEL_NAME)

结果为:

Training Step: 3829  | total loss: [1m[32m11.45499[0m[0m | time: 35.818s| Adam | epoch: 010 | loss: 11.45499 - acc: 0.5025 -- iter: 24448/24500Training Step: 3830  | total loss: [1m[32m11.49676[0m[0m | time: 36.938s| Adam | epoch: 010 | loss: 11.49676 - acc: 0.5007 | val_loss: 11.60503 - val_acc: 0.4960 -- iter: 24500/24500--

我们将图像大小重新调整为 50 X 50 X 1 矩阵,这是我们在用的输入图像的尺寸。

接着,创建一个有 32 个过滤器和步幅为 5 的卷积层,激活函数为 ReLU。然后,添加一个最大池化层。以 64 个过滤器重复这个过程。

接下来,添加一个有 1024 个神经元的全连接层。最后使用一个概率保持为 0.8 的丢弃层,完成模型的搭建。

我们使用 Adam 为优化器,学习率设为 0.001。我们的损失函数为分类交叉熵损失。

最终,我们将搭建的深度学习模型训练 10 个周期。

一切进展不错,但我们的验证准确率似乎不是很好。所以我们接着搭建一个更大更好一点的模型。

搭建更好的模型

tf.reset_default_graph()convnet = input_data(shape=[None, IMG_SIZE, IMG_SIZE, 1], name='input')convnet = conv_2d(convnet, 32, 5, activation='relu')convnet = max_pool_2d(convnet, 5)convnet = conv_2d(convnet, 64, 5, activation='relu')convnet = max_pool_2d(convnet, 5)convnet = conv_2d(convnet, 128, 5, activation='relu')convnet = max_pool_2d(convnet, 5)convnet = conv_2d(convnet, 64, 5, activation='relu')convnet = max_pool_2d(convnet, 5)convnet = conv_2d(convnet, 32, 5, activation='relu')convnet = max_pool_2d(convnet, 5)convnet = fully_connected(convnet, 1024, activation='relu')convnet = dropout(convnet, 0.8)convnet = fully_connected(convnet, 2, activation='softmax')convnet = regression(convnet, optimizer='adam', learning_rate=LR, loss='categorical_crossentropy', name='
;targets')model = tflearn.DNN(convnet, tensorboard_dir='log', tensorboard_verbose=0)model.fit({'input': X_train}, {'targets': y_train}, n_epoch=10,           validation_set=({'input': X_test}, {'targets': y_test}),           snapshot_step=500, show_metric=True, run_id=MODEL_NAME)

结果为:

Training Step: 3829  | total loss: [1m[32m0.34434[0m[0m | time: 44.501s| Adam | epoch: 010 | loss: 0.34434 - acc: 0.8466 -- iter: 24448/24500Training Step: 3830  | total loss: [1m[32m0.35046[0m[0m | time: 45.619s| Adam | epoch: 010 | loss: 0.35046 - acc: 0.8432 | val_loss: 0.50006 - val_acc: 0.7860 -- iter: 24500/24500--

这一步搭建的模型和之前的模型非常像,不同之处就是我们添加了更多的卷积层和最大池化层。所以我们的模型有了更多的参数,可以学习更复杂的函数。我们也可以看到验证准确率达到了 80 %。现在让模型开始干活!

我们看看模型分辨一张图像的结果:

d = test_data[0]img_data, img_num = ddata = img_data.reshape(IMG_SIZE, IMG_SIZE, 1)prediction = model.predict([data])[0]fig = plt.figure(figsize=(6, 6))ax = fig.add_subplot(111)ax.imshow(img_data, cmap="gray")print(f"cat: {prediction[0]}, dog: {prediction[1]}")

cat: 0.8773844838142395, dog: 0.12261549383401871

看起来不对,那再让它看看更多的图像:

fig=plt.figure(figsize=(16, 12))for num, data in enumerate(test_data[:16]):     img_num = data[1]    img_data = data[0]     y = fig.add_subplot(4, 4, num+1)    orig = img_data    data = img_data.reshape(IMG_SIZE, IMG_SIZE, 1)    model_out = model.predict([data])[0]     if np.argmax(model_out) == 1:         str_label='Dog'    else:        str_label='Cat'     y.imshow(orig, cmap='gray')    plt.title(str_label)    y.axes.get_xaxis().set_visible(False)    y.axes.get_yaxis().set_visible(False)plt.show()

我们可以看到,模型正确的分辨出了上面的阿猫阿狗!

结语

本文我们用卷积神经网络搭建了一个 AI 模型,只用原始像素(也就是只经过了少许预处理)就能分辨出图像中是猫还是狗。重要的是,在比较老旧的机器上,模型的训练速度也很快!

可以试着自己操作一番,看看 AI 能否认出你家的汪星人和喵星人!

参考资料:

https://medium.com/@curiousily/tensorflow-for-hackers-part-iii-convolutional-neural-networks-c077618e590b

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注