学习kaggle一篇讲的很好的kernel,但是准确率一般般,后面再学习一篇准确度接近最好的kernel。
原kernel链接
首先,简单介绍了一下卷积神经网络,卷积神经网络主要用于图片分类,或者在图片直接识别相似的特征,卷积神经网络接受的有色彩的图片,即是一个立方体,长宽由图片的长宽像素值决定(例如1920×1080),深度为3,分别代表了RGB的值,这所谓的深度也常被人们称为 channel。为了简单起见,我们只考虑灰度图像,即黑白图像。
当图片通过卷积神经网络,就想普通的神经网络一样,卷积神经网络识别不同的特征。但不是只关注与一个像素,卷积神经网络每次提取一整块的像素(例如3×3),使之通过一个过滤器,这个过滤器是一个正方体矩阵,大小和上面一整块像素一样。它也被称为卷积核。
引入库
首先引入4个库。
1. Pandas, 用来读取/写入数据
2. Matplotlib ,用来数据可视化
3. Tensorflow Keras models, (这里使用tf-keras 的模型)
4. Tensorflow Keras layers,
CNN 卷积神经网络需要的Layers,
Conv2D,基础的卷积层,这里使用64个神经元的卷积层
Dense,标准的一维全连接层,用于输出结果,一般放在网络的最后,
MaxPooling, 卷积神经网络有Max Pooling的概念,在每一次卷积操作之后,我们从卷积核中获取了一些值,我们只取最大的那个值,即Max Pooling
Flatten,Conv2D 层返回的并不是扁平的,需要Flatten之后再喂给最后的Dense Layer。
编码
导入库,查看input文件夹下的内容
import numpy as np
import pandas as pd
import cv2
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Flatten, Dropout,Activation, Conv2D,MaxPooling2D
import os
print(os.listdir('../input'))
['train', 'test1', 'sampleSubmission.csv']
为了训练模型,我们要检查一下训练数据,发现照片的文件名类似 dog.0, dog.1,cat.0,cat.1 等等,所以我们通过简单的字符串分割即可获取分类标签dog ,cat, 为了便于训练,我们设置dog为0,cat 为 1。
为了计算机读取图片像素,我们将图片像素信息转为数组,这里使用cv2库,来以数组的形式读取图片,并以灰度图像的方式读取。
cv2.imread(os.path.join(path,p),cv2.IMREAD_GRAYSCALE)
我们有不同的图片类型,例如风景照,特写等等,导致图片的大小不同,我们需要把他们变成一样的大小,从而方便分析训练。同样使用cv2库
cv2.resize(img_array,dsize=(80,80))
刚才我们把图片统一成了80×80的大小,为了验证我们是否做的正确,我们需要验证一下。通过matplotlib这个库可以做到,通过下面这行代码显示图片。
plt.imshow(new_img_array,cmap='gray')
运行下面的代码会有更好的理解,可以尝试改成50×50 100×100试试效果。
main_dir = './input/'
train_dir = 'train'
path = os.path.join(main_dir,train_dir)
for p in os.listdir(path):
category = p.split('.')[0]
img_array = cv2.imread(os.path.join(path,p),cv2.IMREAD_GRAYSCALE)
new_img_array = cv2.resize(img_array,dsize=(80,80))
plt.imshow(new_img_array, cmap='gray')
break #only show one pic
好,以上都比较直观,接下来开始真正的编程了。
声明训练数组X,和真值target数组y,X是代表像素的数组,y是0或者1.lambda函数编写转换方法使得 dog 、cat 映射到 0、1。
编写循环方法create_test_data,训练所有的训练数据,将图像转为数组,将图像大小转为80×80,添加图像数组到X,添加类型到y
X = []
y = []
convert = lambda category : int(category == 'dog')
def create_test_data(path):
for p in os.listdir(path):
category = p.split('.')[0]
category = convert(category)
img_array = cv2.imread(os.path.join(path,p),cv2.IMREAD_GRAYSCALE)
new_img_array = cv2.resize(img_array, dsize=(80,80))
X.append(new_img_array)
y.append(category)
接着调用这个方法,然后将X,y数组改成numpy格式的数组
create_test_data(path)
X = np.array(X).reshape(-1,80,80,1)
y = np.array(y)
可以使用pickle这个库,来存储 X,y数据
#import pickle
#pickle.dump(X, open('train_x','wb'))
#pickle.dump(y, open('train_y','wb'))
如果你打印出来X的数据,你会发现每个值都是0-255之间的,这是灰度图像的特质,黑白所占比重不同所致,但是这种宽泛的数据不容易被学习
如何解决? 相信你已经想到了–正则化,我们可以使用Keras的方法使之正则,这里我们已经知道所有的值是0-255,所以只用简单的所有数据都除以255即可,这样所有数据值的范围都是0-1了。
(ps,你可以不用正则化,运行代码看看结果)
#normalize data
X = X / 255
数据预处理告一段落,接下来几步来定义我们的CNN模型。
1. 定义一个序列模型,即 Sequential model
2. 在上面添加layers
3. 首先我们添加Conv2D层,有着64个节点,卷积核的大小为(3,3),你可以尝试不同的节点数,例如 32,128等等。我们需要明确(定义)输入的数据维度(input shape)为X的维度,激活函数这里使用relu。
4. 每一个卷积层(Conv layer)之后都会跟着池化层,我们添加max pooling 大小为(2,2)紧随其后。
5. 我们将继续重复这个组合一次,毕竟2好于1,哈哈,当然也可以3层以上的卷积层,不过会花费更多时间来训练。
6. 接着就添加Flatten layer,为了后面把数据喂给最后的Dense layer。
7. 我命添加有着64个节点的Dense layer,激活函数都是relu,如果不指定激活函数,可能使得模型变得线性化,这不是我们想要的。
8. 最后为了获得我们的结果,使用Dense layer,激活函数可以是sigmoid 或者 softmax ,这里使用sigmoid
9. 最终我们编译模型,需要注意的参数 Loss ,Optimizer,Metrics
Loss:
为了使我们的模型更好,要么最小化损失(loss)要么最大化准确度(accuracy),(神经网络)NN总是最小化损失。为了测量Loss,我们可以使用不同的公式,例如‘categorical_crossentropy’或者 ‘binary_crossentropy’,这里我们使用 ‘binary_crossentropy’
Optimizer:
如果你熟悉一点机器学习的数学,你或许会熟悉”局部最小”、”全局最小”、”损失函数”,为了最小化损失函数,我们使用不同的方法,例如“梯度下降(gradient descent)”、“随机梯度下降(stochstic gradient descent)”,这些都叫做优化函数(Optimizer),我们这里使用默认的一个函数,也就是Adam
Metrics:
用来测量你的模型,可以是准确度accuracy,或者其他的度量(metrics)
model = Sequential()
# add a denselyconnected layer with 64 units to the model:
model.add(Conv2D(64,(3,3), activation = 'relu', input_shape = X.shape[1:]))
model.add(MaxPooling2D(pool_size = (2,2)))
# add another one
model.add(Conv2D(64,(3,3), activation = 'relu'))
model.add(MaxPooling2D(pool_size = (2,2)))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy'])
现在我们通过训练数据fit我们的模型,
Epochs: 我们的模型总共遍历几次数据
Batch size: 一次通过我们模型的数据量
validation_split: 多少数据用来交叉验证损失(在这里我们用20%)
model.fit(X,y, epochs=10,batch_size=32,validation_split=0.2)
运行结果如下
Train on 20000 samples, validate on 5000 samples
Epoch 1/10
20000/20000 [==============================] - 12s 615us/step - loss: 0.6527 - acc: 0.6014 - val_loss: 0.6116 - val_acc: 0.6652
Epoch 2/10
20000/20000 [==============================] - 6s 310us/step - loss: 0.5465 - acc: 0.7262 - val_loss: 0.5132 - val_acc: 0.7472
Epoch 3/10
20000/20000 [==============================] - 6s 307us/step - loss: 0.4863 - acc: 0.7654 - val_loss: 0.4833 - val_acc: 0.7702
Epoch 4/10
20000/20000 [==============================] - 7s 334us/step - loss: 0.4417 - acc: 0.7914 - val_loss: 0.5104 - val_acc: 0.7640
Epoch 5/10
20000/20000 [==============================] - 7s 331us/step - loss: 0.4051 - acc: 0.8137 - val_loss: 0.4921 - val_acc: 0.7622
Epoch 6/10
20000/20000 [==============================] - 7s 328us/step - loss: 0.3687 - acc: 0.8357 - val_loss: 0.4726 - val_acc: 0.7924
Epoch 7/10
20000/20000 [==============================] - 7s 329us/step - loss: 0.3363 - acc: 0.8509 - val_loss: 0.4704 - val_acc: 0.7890
Epoch 8/10
20000/20000 [==============================] - 6s 324us/step - loss: 0.2965 - acc: 0.8687 - val_loss: 0.4846 - val_acc: 0.7956
Epoch 9/10
20000/20000 [==============================] - 6s 325us/step - loss: 0.2595 - acc: 0.8873 - val_loss: 0.4956 - val_acc: 0.7964
Epoch 10/10
20000/20000 [==============================] - 6s 313us/step - loss: 0.2250 - acc: 0.9058 - val_loss: 0.5522 - val_acc: 0.7952
现在模型训练好了,我们将测试数据(test data),也做和训练数据(train data)一样的预处理
train_dir = 'test1'
path = os.path.join(main_dir,train_dir)
X_test = []
id_line = []
def create_test1_data(path):
for p in os.listdir(path):
id_line.append(p.split('.')[0])
img_array = cv2.imread(os.path.join(path,p), cv2.IMREAD_GRAYSCALE)
new_img_array = cv2.resize(img_array, dsize=(80,80))
X_test.append(new_img_array)
create_test1_data(path)
X_test = np.array(X_test).reshape(-1,80,80,1)
X_test = X_test/255
好了,现在我们终于可以使用我们的模型来预测Predict了
predictions = model.predict(X_test)
接着我们需要取整我们的结果
predicted_val = [int(round(p[0])) for p in predictions]
接着构造我们要提交的数据格式
submission_df = pd.DataFrame({'id':id_line, 'label':predicted_val})
写入csv文件
submission_df.to_csv('submission.csv',index=False)
可以把submission.csv提交到kaggle查看准确率了。
完结,撒花。
如果感觉有帮助给我点个赞再走吧,更欢迎留言讨论。