1. 说明
此实例一开始是在 TensorFlow 看到的,不过TensorFlow用高阶API实现,确实是两三行代码就实现了一个服装识别模型。本着学习的精神以让自己对训练神经网络的过程更加熟悉决定手撮一个模型,主要使用的是 Jupyter Notebook 及 IPython 的辅助开发。附上TensorFlow原址:
https://tensorflow.google.cn/tutorials/keras/basic_classification#evaluate_accuracy
最后扯一下,在这个过程中有时候数据的预处理这个还是比较讨人厌的,但这个工作对于一些熟悉 Python 数据处理的人自然是迎刃而解,所以如果要以这个例子来学习的话,我的建议是一些数据的处理等工作可以直接拿来用,涉及到模型实现的先自己来实现,再参照比较差异,这样可以专注于学习模型的建立。
下面给出 TensorFlow 低阶API 改写,主要是介绍 TensorFlow:
点我传送
2. 数据预处理
2.1 准备数据
数据在Github上有(不用翻墙就可以下载),分别是6W的训练集以及1W的测试集。
数据地址: https://github.com/zalandoresearch/fashion-mnist/tree/master/data/fashion
2.2 数据读取、处理及显示
def load_mnist(path, kind='train'):
import os
import gzip
import numpy as np
"""Load MNIST data from `path`"""
labels_path = os.path.join(path,
'%s-labels-idx1-ubyte.gz'
% kind)
images_path = os.path.join(path,
'%s-images-idx3-ubyte.gz'
% kind)
with gzip.open(labels_path, 'rb') as lbpath:
labels = np.frombuffer(lbpath.read(), dtype=np.uint8,
offset=8)
with gzip.open(images_path, 'rb') as imgpath:
images = np.frombuffer(imgpath.read(), dtype=np.uint8,
offset=16).reshape(len(labels), 784)
images = images / 255.0 //像素的取值为0-255为了防止算术溢出,也是必要的处理
images = images.T
labels = labels.reshape(labels.shape[0], 1).T
temp = np.zeros((10, labels.shape[1]))
temp[labels, np.arange(labels.shape[1])] = 1
return images, temp
读取后的格式如下, 784 = 28*28为一张图片的数据, Y的取值范围为0,1,2,…,9即有10类时装,处理成仅有正确的标签一行为1其余为0.
显示图片
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
plt.imshow(X[:, 0].reshape(28, 28), cmap=plt.cm.binary)
plt.xticks([])
plt.yticks([])
plt.xlabel(class_names[np.argmax(Y[:, 0])])
plt.show()
确定了数据的格式以及正确性之后,便开始实现模型的部分了,大致分为三部分:
- 参数初始化
- 前向传播
- 反向传播
3. 参数初始化
参数初始化问题涉及到网络的规模, 这里取和 TensorFlow 一样的规模,两层神经网络(128, 10),这里使用 “he初始化方法” 参考代码如下:
def initialize_parameters(layers_dims):
"""
参数:
layers_dims -- 指示了每一层的大小
返回:
parameters -- 根据 layers_dims 初始化好的参数
"""
parameters = {}
L = len(layers_dims)
for l in range(1, L):
parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l-1]) * np.sqrt(2/layers_dims[l-1])
parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
assert(parameters['W' + str(l)].shape == (layers_dims[l], layers_dims[l-1]))
assert(parameters['b' + str(l)].shape == (layers_dims[l], 1))
return parameters
4.前向传播
前向传播时,对于每个神经元(结点)来说有两个运算步骤,一是线性运算,二是非线性(激活)运算。
4.1 线性前向传播
def linear_forward(W, b, A):
"""
参数:
W -- 当前层的参数W
b -- 当前层的参数b
A -- 前一层的输出
返回:
Z -- 当前层的线性输出
cache -- 将当前层线性运算所使用到的参数存起来,以便反向传播到当前层时的计算。
"""
Z = np.dot(W, A) + b
assert(Z.shape == (W.shape[0], A.shape[1]))
cache = (W, b, A)
return Z, cache
4.2 激活-前向传播
不同层的结点使用不同的激活函数,这里隐藏层是 relu ,输出层是 softmax。由于激活传播用到了线性前向传播,所以就整合了在一起,如下:
def linear_activation_forward(A_prev, W, b, func = 'relu'):
"""
参数:
A_prev -- 前一层的输出
W, b -- 当前层参数
func --