新课题1——深度学习世界的hello world(python识别mnist数据集)

mnist数据集是一款比较经典的各种手写数字体的集合,一般被初学者用来练手

我使用的框架为tensorflow,前面主要未解决的问题是BP神经网络的反向传播,所以在这里使用了tf框架。

下面开始我的项目搭建过程。

步骤:

0加载数据集的数据

import numpy as np
import matplotlib.pyplot as plt
from keras.datasets import mnist

(X_train_orig, Y_train_orig), (X_test_orig, Y_test_orig) = mnist.load_data()

print(X_train_orig.shape)
print(Y_train_orig.shape)
#(60000, 28, 28)
#(60000,)

0.1对数据的相关处理

说明:用python识别mnist的项目本质上是一个分类器项目,通过识别不同图片内部的特征,将其归类,所以,在最后我们输出的是[10,?]的一个张量,?代表样本数量,10是0-9的十个分类的个数。

这里需要对标签进行one-hot编码。

def one_hot_matrix(lables,C):
    """
    创建一个矩阵,其中第i行对应第i个类号,第j列对应第j个训练样本
    所以如果第j个样本对应着第i个标签,那么entry (i,j)将会是1

    参数:
        lables - 标签向量
        C - 分类数

    返回:
        one_hot - 独热矩阵

    """

    #创建一个tf.constant,赋值为C,名字叫C
    C = tf.constant(C,name="C")

    #使用tf.one_hot,注意一下axis
    one_hot_matrix = tf.one_hot(indices=lables , depth=C , axis=0)

    #创建一个session
    sess = tf.Session()

    #运行session
    one_hot = sess.run(one_hot_matrix)

    #关闭session
    sess.close()

    return one_hot
X_train_flatten = X_train_orig.reshape(X_train_orig.shape[0],-1).T #每一列就是一个样本
X_test_flatten = X_test_orig.reshape(X_test_orig.shape[0],-1).T

#归一化数据
X_train = X_train_flatten / 255
X_test = X_test_flatten / 255

#转换为独热矩阵
Y_train = one_hot_matrix(Y_train_orig,10)
Y_test = one_hot_matrix(Y_test_orig,10)

print("训练集样本数 = " + str(X_train.shape[1]))
print("测试集样本数 = " + str(X_test.shape[1]))
print("X_train.shape: " + str(X_train.shape))
print("Y_train.shape: " + str(Y_train.shape))
print("X_test.shape: " + str(X_test.shape))
print("Y_test.shape: " + str(Y_test.shape))

#训练集样本数 = 60000
#测试集样本数 = 10000
#X_train.shape: (784, 60000)
#Y_train.shape: (10, 60000)
#X_test.shape: (784, 10000)
#Y_test.shape: (10, 10000)

 

1 初始化网络参数

1.1 

layers_dims = [784, 100, 50, 10]
def initialize_parameters(layers_dims):
    parameters = {}
    L = len(layers_dims)
    for l in range(1, L):
        parameters["W" + str(l)] = tf.get_variable("W"+str(l),[layers_dims[l],layers_dims[l-1]],initializer=tf.contrib.layers.xavier_initializer(seed=1))
        parameters["b" + str(l)] = tf.get_variable("b"+str(l),[layers_dims[l],1],initializer=tf.zeros_initializer())
        
        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#包含的参数为(W,b)

这里用tf的相关函数保证了数据类型的一致?这里我不确定,但前面用常规的初始化确实遇到了数据不匹配的问题。

这里神经网络的层数可以根据layers_dims中数量的变化来发生变化,比较灵活。

当然,也有直接定义几层参数的方法,三层神经网络的权重初始化如下代码所示:

def initialize_parameters():
    """
    初始化神经网络的参数,参数的维度如下:
        W1 : [25, 784]
        b1 : [25, 1]
        W2 : [12, 25]
        b2 : [12, 1]
        W3 : [10, 12]
        b3 : [10, 1]

    返回:
        parameters - 包含了W和b的字典


    """

    tf.set_random_seed(1) #指定随机种子

    W1 = tf.get_variable("W1",[25,784],initializer=tf.contrib.layers.xavier_initializer(seed=1))
    b1 = tf.get_variable("b1",[25,1],initializer=tf.zeros_initializer())
    W2 = tf.get_variable("W2", [12, 25], initializer = tf.contrib.layers.xavier_initializer(seed=1))
    b2 = tf.get_variable("b2", [12, 1], initializer = tf.zeros_initializer())
    W3 = tf.get_variable("W3", [10, 12], initializer = tf.contrib.layers.xavier_initializer(seed=1))
    b3 = tf.get_variable("b3", [10, 1], initializer = tf.zeros_initializer())

    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2,
                  "W3": W3,
                  "b3": b3}

    return parameters
tf.reset_default_graph() #用于清除默认图形堆栈并重置全局默认图形。 

with tf.Session() as sess:
    parameters = initialize_parameters(layers_dims)
    print("W1 = " + str(parameters["W1"]))
    print("b1 = " + str(parameters["b1"]))
    print("W2 = " + str(parameters["W2"]))
    print("b2 = " + str(parameters["b2"]))

#W1 = <tf.Variable 'W1:0' shape=(100, 784) dtype=float32_ref>
#b1 = <tf.Variable 'b1:0' shape=(100, 1) dtype=float32_ref>
#W2 = <tf.Variable 'W2:0' shape=(50, 100) dtype=float32_ref>
#b2 = <tf.Variable 'b2:0' shape=(50, 1) dtype=float32_ref>

#向前传播第一次初始化的输出

2 向前传播

def forward_propagation(X,parameters):
    """
    实现一个模型的前向传播,模型结构为LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SOFTMAX

    参数:
        X - 输入数据的占位符,维度为(输入节点数量,样本数量)
        parameters - 包含了W和b的参数的字典

    返回:
        Z3 - 最后一个LINEAR节点的输出

    """

    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']
    W3 = parameters['W3']
    b3 = parameters['b3']

    Z1 = tf.add(tf.matmul(W1,X),b1)        # Z1 = np.dot(W1, X) + b1
    #Z1 = tf.matmul(W1,X) + b1             #也可以这样写
    A1 = tf.nn.relu(Z1)                    # A1 = relu(Z1)
    Z2 = tf.add(tf.matmul(W2, A1), b2)     # Z2 = np.dot(W2, a1) + b2
    A2 = tf.nn.relu(Z2)                    # A2 = relu(Z2)
    Z3 = tf.add(tf.matmul(W3, A2), b3)     # Z3 = np.dot(W3,Z2) + b3


    return Z3
tf.reset_default_graph() #用于清除默认图形堆栈并重置全局默认图形。 
with tf.Session() as sess:
    X,Y = create_placeholders(784,10)
    parameters = initialize_parameters(layers_dims)
    Z3 = forward_propagation(X,parameters)
    print("Z3 = " + str(Z3))

3 计算误差

def compute_cost(Z3,Y):
    """
    计算成本

    参数:
        Z3 - 前向传播的结果
        Y - 标签,一个占位符,和Z3的维度相同

    返回:
        cost - 成本值


    """
    logits = tf.transpose(Z3) #转置
    labels = tf.transpose(Y)  #转置
    
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=labels))
    #这里进行softmax激活函数的处理了。

    return cost
tf.reset_default_graph()

with tf.Session() as sess:
    X,Y = create_placeholders(784,10)
    parameters = initialize_parameters(layers_dims)
    Z3 = forward_propagation(X,parameters)
    print("Z3 = " + str(Z3))
    print("Y = " + str(Y))
    cost = compute_cost(Z3,Y)
    print("cost = " + str(cost))

4 反向传播,最小化损失函数

optimizer = tf.train.GradientDescentOptimizer(learning_rate = learning_rate).minimize(cost)

_ , c = sess.run([optimizer,cost],feed_dict={X:mini_batch_X,Y:mini_batch_Y})

5 构建神经网络,训练参数

#小批量训练
def random_mini_batches(X, Y, mini_batch_size = 64, seed = 0):
    """
    Creates a list of random minibatches from (X, Y)

    Arguments:
    X -- input data, of shape (input size, number of examples)
    Y -- true "label" vector (containing 0 if cat, 1 if non-cat), of shape (1, number of examples)
    mini_batch_size - size of the mini-batches, integer
    seed -- this is only for the purpose of grading, so that you're "random minibatches are the same as ours.

    Returns:
    mini_batches -- list of synchronous (mini_batch_X, mini_batch_Y)
    """

    m = X.shape[1]                  # number of training examples
    mini_batches = []
    np.random.seed(seed)

    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m))
    shuffled_X = X[:, permutation]
    shuffled_Y = Y[:, permutation].reshape((Y.shape[0],m))

    # Step 2: Partition (shuffled_X, shuffled_Y). Minus the end case.
    num_complete_minibatches = math.floor(m/mini_batch_size) # number of mini batches of size mini_batch_size in your partitionning
    for k in range(0, num_complete_minibatches):
        mini_batch_X = shuffled_X[:, k * mini_batch_size : k * mini_batch_size + mini_batch_size]
        mini_batch_Y = shuffled_Y[:, k * mini_batch_size : k * mini_batch_size + mini_batch_size]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

    # Handling the end case (last mini-batch < mini_batch_size)
    if m % mini_batch_size != 0:
        mini_batch_X = shuffled_X[:, num_complete_minibatches * mini_batch_size : m]
        mini_batch_Y = shuffled_Y[:, num_complete_minibatches * mini_batch_size : m]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

    return mini_batches

 

def model(X_train,Y_train,X_test,Y_test,
        learning_rate=0.0001,num_epochs=1500,minibatch_size=32,
        print_cost=True,is_plot=True):
    """
    实现一个三层的TensorFlow神经网络:LINEAR->RELU->LINEAR->RELU->LINEAR->SOFTMAX

    参数:
        X_train - 训练集,维度为(输入大小(输入节点数量) = 12288, 样本数量 = 1080)
        Y_train - 训练集分类数量,维度为(输出大小(输出节点数量) = 6, 样本数量 = 1080)
        X_test - 测试集,维度为(输入大小(输入节点数量) = 12288, 样本数量 = 120)
        Y_test - 测试集分类数量,维度为(输出大小(输出节点数量) = 6, 样本数量 = 120)
        learning_rate - 学习速率
        num_epochs - 整个训练集的遍历次数
        mini_batch_size - 每个小批量数据集的大小
        print_cost - 是否打印成本,每100代打印一次
        is_plot - 是否绘制曲线图

    返回:
        parameters - 学习后的参数

    """
    ops.reset_default_graph()                #能够重新运行模型而不覆盖tf变量
    tf.set_random_seed(1)
    seed = 3
    (n_x , m)  = X_train.shape               #获取输入节点数量和样本数
    n_y = Y_train.shape[0]                   #获取输出节点数量
    costs = []                               #成本集

    #给X和Y创建placeholder
    X,Y = create_placeholders(n_x,n_y)

    #初始化参数
    parameters = initialize_parameters(layers_dims)

    #前向传播
    Z3 = forward_propagation(X,parameters)

    #计算成本
    cost = compute_cost(Z3,Y)

    #反向传播,使用Adam优化
    optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

    #初始化所有的变量
    init = tf.global_variables_initializer()

    #开始会话并计算
    with tf.Session() as sess:
        #初始化
        sess.run(init)

        #正常训练的循环
        for epoch in range(num_epochs):

            epoch_cost = 0  #每代的成本
            num_minibatches = int(m / minibatch_size)    #minibatch的总数量
            seed = seed + 1
            minibatches = random_mini_batches(X_train,Y_train,minibatch_size,seed)

            for minibatch in minibatches:

                #选择一个minibatch
                (minibatch_X,minibatch_Y) = minibatch

                #数据已经准备好了,开始运行session
                _ , minibatch_cost = sess.run([optimizer,cost],feed_dict={X:minibatch_X,Y:minibatch_Y})

                #计算这个minibatch在这一代中所占的误差
                epoch_cost = epoch_cost + minibatch_cost / num_minibatches

            #记录并打印成本
            ## 记录成本
            if epoch % 5 == 0:
                costs.append(epoch_cost)
                #是否打印:
                if print_cost and epoch % 5 == 0:
                        print("epoch = " + str(epoch) + "    epoch_cost = " + str(epoch_cost))

        #是否绘制图谱
        if is_plot:
            plt.plot(np.squeeze(costs))
            plt.ylabel('cost')
            plt.xlabel('iterations (per tens)')
            plt.title("Learning rate =" + str(learning_rate))
            plt.show()

        #保存学习后的参数
        parameters = sess.run(parameters)
        print("参数已经保存到session。")

        #计算当前的预测结果
        correct_prediction = tf.equal(tf.argmax(Z3),tf.argmax(Y))

        #计算准确率
        accuracy = tf.reduce_mean(tf.cast(correct_prediction,"float"))

        print("训练集的准确率:", accuracy.eval({X: X_train, Y: Y_train}))
        print("测试集的准确率:", accuracy.eval({X: X_test, Y: Y_test}))

        return parameters
#开始时间
start_time = time.clock()
#开始训练
parameters = model(X_train, Y_train, X_test, Y_test,num_epochs=150, minibatch_size=512)
#结束时间
end_time = time.clock()
#计算时差
print("CPU的执行时间 = " + str(end_time - start_time) + " 秒" )

'''
epoch = 0    epoch_cost = 1.8048073939788036
epoch = 5    epoch_cost = 0.3332515982990592
epoch = 10    epoch_cost = 0.2444374926834026
epoch = 15    epoch_cost = 0.20180034395466495
epoch = 20    epoch_cost = 0.17208938682690644
epoch = 25    epoch_cost = 0.1487552207122501
epoch = 30    epoch_cost = 0.13145502363769412
epoch = 35    epoch_cost = 0.11671997498498006
epoch = 40    epoch_cost = 0.1042079112978063
epoch = 45    epoch_cost = 0.09372433128519962
epoch = 50    epoch_cost = 0.08588403874100783
epoch = 55    epoch_cost = 0.07700667132297136
epoch = 60    epoch_cost = 0.07071055720249812
epoch = 65    epoch_cost = 0.06447908312528051
epoch = 70    epoch_cost = 0.0591392962851076
epoch = 75    epoch_cost = 0.054782480272090345
epoch = 80    epoch_cost = 0.05065463378261298
epoch = 85    epoch_cost = 0.04652624101274543
epoch = 90    epoch_cost = 0.042965341470817195
epoch = 95    epoch_cost = 0.03951436747661513
epoch = 100    epoch_cost = 0.036161916457817085
epoch = 105    epoch_cost = 0.03350572805437777
epoch = 110    epoch_cost = 0.03098719434924104
epoch = 115    epoch_cost = 0.028340620108139824
epoch = 120    epoch_cost = 0.02633996693910952
epoch = 125    epoch_cost = 0.023921261095784154
epoch = 130    epoch_cost = 0.021953271526811466
epoch = 135    epoch_cost = 0.020309688396051403
epoch = 140    epoch_cost = 0.018723787532912355
epoch = 145    epoch_cost = 0.01693216629294503

参数已经保存到session。
训练集的准确率: 0.9978833
测试集的准确率: 0.9775
CPU的执行时间 = 312.2200849999999 秒
'''

6 预测

import matplotlib.pyplot as plt # plt 用于显示图片
import matplotlib.image as mpimg # mpimg 用于读取图片
import numpy as np

#这是博主自己拍的图片
my_image1 = "0-5.bmp"                                            #定义图片名称
fileName1 = "/Users/weijinqian/Documents/python/test/" + my_image1                      #图片地址
image1 = mpimg.imread(fileName1)                               #读取图片
plt.imshow(image1)                                             #显示图片
my_image1 = image1.reshape(1,28 * 28).T                    #重构图片
my_image_prediction = predict(my_image1, parameters)  #开始预测
print("预测结果: y = " + str(np.squeeze(my_image_prediction)))
plt.show(image1)

预测结果: y = 5

在这里,plt中的show()与imshow()函数出现了一些问题,我暂时还不是很理解。

写到这里就已经完成了识别手写数字体这个简单的项目了。在该过程中用到的数据集为:

10k-labels-idx1-ubyte.gz

train-labels-idx1-ubyte.gz

t10k-images-idx3-ubyte.gz

train-images-idx3-ubyte.gz

网上很容易下载的。

具体加载数据集的函数,大家可以参考keras框架的load_mnist()函数,我对具体实现不太了解,后期可能会去研究。

 

对于项目的优化或者改进,大家可以从以下几个方面进行:

1. 正则化

2. dropout随机失活

3. 优化函数,比如说adam等

4. 各种超参数的调试,比如:学习率,神经网络层数,迭代次数等

5. 可以使用卷积神经网络(CNN)来对数据进行处理。

卷积神经网络的识别数字体项目会在下一个博客中展示,期待以后的更新吧。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么要学习这门课程】深度学习框架如TensorFlow和Pytorch掩盖了深度学习底层实现方法,那能否能用Python代码从零实现来学习深度学习原理呢?本课程就为大家提供了这个可能,有助于深刻理解深度学习原理。左手原理、右手代码,双管齐下!本课程详细讲解深度学习原理并进行Python代码实现深度学习网络。课程内容涵盖感知机、多层感知机、卷积神经网络、循环神经网络,并使用Python 3及Numpy、Matplotlib从零实现上述神经网络。本课程还讲述了神经网络的训练方法与实践技巧,且开展了代码实践演示。课程对于核心内容讲解深入细致,如基于计算图理解反向传播算法,并用数学公式推导反向传播算法;另外还讲述了卷积加速方法im2col。【课程收获】本课程力求使学员通过深度学习原理、算法公式及Python代码的对照学习,摆脱框架而掌握深度学习底层实现原理与方法。本课程将给学员分享深度学习Python实现代码。课程代码通过Jupyter Notebook演示,可在Windows、ubuntu等系统上运行,且不需GPU支持。【优惠说明】 课程正在优惠中!  备注:购课后可加入白勇老师课程学习交流QQ群:957519975【相关课程】学习本课程的前提是会使用Python语言以及Numpy和Matplotlib库。相关课程链接如下:《Python编程的术与道:Python语言入门》https://edu.csdn.net/course/detail/27845《玩转Numpy计算库》https://edu.csdn.net/lecturer/board/28656《玩转Matplotlib数据绘图库》https://edu.csdn.net/lecturer/board/28720【课程内容导图及特色】

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值