1,825 次浏览

tensorflow2学习(四)

这一篇是使用tensorflow2进行mnist数据集的分类。

MLP分类mnist

import numpy as np
import tensorflow as tf
import tensorflow.keras as keras
import matplotlib.pyplot as plt

# load mnist dataset
(train_x, train_y), (test_x, test_y) = keras.datasets.mnist.load_data(path='mnist.npz')

# show a picture of number
# number = train_x[0]
# plt.figure()
# plt.title('handwritten numberal')
# plt.imshow(number)
# plt.show()

# define parameters of neural network
ninput = 784  # input units, 28 * 28
nhidden1 = 256  # hidden units
nhidden2 = 128  # hidden units
noutput = 10  # output units

# construct a three-layers neural network, aka. MLP
model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(nhidden1, activation='relu'),
    keras.layers.Dense(nhidden2, activation='relu'),
    keras.layers.Dense(noutput)
])
model.compile(optimizer=keras.optimizers.SGD(0.001),
        loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

model.fit(train_x, train_y, epochs=10)

test_loss, test_acc = model.evaluate(test_x,  test_y, verbose=2)
print('loss', test_loss, '\naccuracy: ',test_acc)

上面代码使用的是一个多层感知机进行识别mnist数据集。(一般tensorflow数据存储在.keras/datasets文件夹中,直接使用tensorflow的api下载可能比较慢,可以提前下载好数据放入.keras/datasets文件夹中)

输入使用的是keras.layers.Flatten将图片矩阵装换成MLP所要求的数据输入,这个Flatten相当于如下代码功能(tensorflow提供的数据类型是numpy.ndarray):

lens = train_x.shape[0]
train_x.reshape((lens, -1))

然后两个隐藏层使用Dense(全连接)层,激活函数使用relu,最终输出一个10长度的概率分布,然后取出概率最大的作为最终的结果。

CNN分类mnist

CNN,卷积神经网络,一个十分经典的神经网络,这里就不赘述了,主要需要知道的就是:
1. 卷积操作,通过filter进行提取局部特征
2. 池化层,压缩提取的特征大小,也可以成为下采样
3. pad,提取图片边缘的特征
4. 步长
假设输入的图片是\(\)\(W*H*D\)\(\)(长,宽,channel),filter的个数\(\)\(K\)\(\),filter大小为\(\)\(F*F\)\(\),padding为\(\)\(P\)\(\),步长为\(\)\(S\)\(\),就可以得到隐藏层的输入为:\(\)\(W_1 = (W+2P-F)/S + 1\)\(\),\(\)\(H_1 = (H+2P-F)/S + 1\)\(\),\(\)\(D_1 = K\)\(\)

import numpy as np
import tensorflow as tf
import tensorflow.keras as keras
import matplotlib.pyplot as plt

# load mnist dataset
(train_x, train_y), (test_x, test_y) = keras.datasets.mnist.load_data(path='mnist.npz')
# Normalize
train_x, test_x = train_x / 255.0, test_x / 255.0
train_x, test_x = train_x[:, :, :, np.newaxis], test_x[:, :, :, np.newaxis]

# show a picture of number
# number = train_x[0]
# plt.figure()
# plt.title('handwritten numberal')
# plt.imshow(number)
# plt.show()

model = keras.models.Sequential([
    keras.layers.Conv2D(28, (3, 3), strides=1, padding='same', activation='relu', input_shape=(28, 28, 1)),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.Flatten(),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dense(10)
])
# model.summary()
model.compile(optimizer='SGD',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.fit(train_x, train_y, epochs=10, validation_data=(test_x, test_y))

test_loss, test_acc = model.evaluate(test_x,  test_y, verbose=2)
print('loss', test_loss, '\naccuracy: ',test_acc)

使用tf.keras.layers.Conv操作要知道Conv1D与Conv2D的区别,简单的说Conv1D只进行纵向的移动提取特征,Conv2D则是横向以及纵向的移动来提取特征。(reference4),所以对数据进行一个升维处理。考虑到mnist数据集一张图片内的值变化较大(0-255),做了一个标准化处理。

整个模型的架构就是,一层卷积一层池化一层卷积一层池化,然后数据是3D的(tf.keras.layers.Conv2D第一个参数就是filter的个数,也即输入到下一层隐藏层的特征深度),则需要将其展开为一维的,经过两个全连接层最后输出。

建立好模型后则可以使用model.summary()来查看构建的模型。然后就可以训练以及预测了。

系列:
Morvan博客-tensorflow2学习(一)
Morvan博客-tensorflow2学习(二)
Morvan博客-tensorflow2学习(三)
tensorflow2学习(四)

reference
1. https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-16-transfer-learning/
2. https://tensorflow.google.cn/guide
3. https://tensorflow.google.cn/tutorials/keras/classification
4.conv1d与conv2d区别 https://blog.csdn.net/Elva_23/article/details/83826587
5. CNN中feature map、卷积核、卷积核个数、filter、channel的概念解释,以及CNN 学习过程中卷积核更新的理解