从代码出发:tensorflow手写数据集初探

从代码出发

基础原理

张量

数据维度大于2的数组称为张量。张量是tensorflow的主要数据载体。以MNIST数据集为例,数据集原始数据为图片,为了在计算机中表示图片,需要使用张量 [b,h,w,c] 表示。其中b表示batch,h表示high,w表示weight,c表示Chanel。batch为一批中有多少数据,**[h , w]**用来表示图片中的像素点,c表示每个像素点上的通道。

例如一次训练200张图片,图片像素排布长宽为28*28,图片为黑白图片。则一批数据表示为 张量 [200,28,28,2]。张量为4维数据。使用batch是为了发挥计算机并行计算的效率,一次计算多个数据,这就是为什么深度 智障 学习需要使用大量的计算资源。

batch 与epoch

batch是指一次计算多少数据,以MNIST数据集为例就是,一次计算多少张图片。
epoch是指全部数据计算多少次。

参数梯度

在深度学习中,由于神经网络复杂,多层,其中的参数多则成百上千。所以需要在计算机记录所有神经网络参数的梯度,以便对网络参数进行更新。
记录参数梯度使用以下形式

with tf.GradientTape() as tape:
grads=tape.gradient(loss,[w1 , b1 , w2 , b2 , w3 , b3 ])

在计算中需要对网络模型参数进行保存。以便之后使用

数据初始化

在数据初始化时

  1. 需要将原始数据归一化到[0,1]或[-1,1]之间
  2. 需要将原始数据转换为张量
  3. 需要将数据标签进行one-hot编码
  4. 将数据合并并切片
#数据初始化
'''
初始化时,需将数据集分为训练集和测试集

1.数据归一化
2.数据转换为张量
3.需要将y进行ont-hot编码
4.数据聚合并切片
'''
def _init( ):
    #load数据集
    (x_train,y_train) , (x_test,y_test) = datasets.mnist.load_data()
    #数据转换为张量,并归一化
    x_train=2*tf.convert_to_tensor(x_train,dtype=tf.float32)/255 - 1
    x_test=2*tf.convert_to_tensor(x_test,dtype=tf.float32)/255 - 1
    y_train=tf.convert_to_tensor(y_train,dtype=tf.int32)
    y_test=tf.convert_to_tensor(y_test,dtype=tf.int32)

    #y进行one-hot编码
    y_train=tf.one_hot(y_train,depth=10,on_value=None,off_value=None)
    y_test=tf.one_hot(y_test,depth=10,on_value=None,off_value=None)

    #数据重新聚合
    train_dataset =tf.data.Dataset.from_tensor_slices((x_train,y_train))
    test_dataset=tf.data.Dataset.from_tensor_slices((x_test,y_test))

    #数据集切片
    train_dataset=train_dataset.batch(200)
    test_dataset=test_dataset.batch(200)

    #设置学习率
    # optimizer=optimizers.SGD(learning_rate=0.001)

    #设置精度标尺
    # acc_meter=metrics.Accuracy()

    return train_dataset , test_dataset

创建单层网络

本代码是以最基本的神经网络感知器为基础,具体原理在机器学习入门之感知器一文中有详解。

#获取单层网路参数
def net(in_ , out_):
    w=tf.Variable(tf.random.truncated_normal([in_ , out_], stddev=0.1))
      
    b=tf.Variable(tf.zeros([out_]))
    return w , b

创建三层网络

#获取多层网络参数
def get_netvar(in_1 , in_2 , in_3 , out):
    w1  , b1 = net(in_1 , in_2)
    w2  , b2 = net(in_2 , in_3)
    w3  , b3 = net(in_3 ,  out)
    return w1 , b1  , w2  , b2 ,  w3 , b3

训练与测试

def train_test (train_dataset ,test_dataset, lr , epoch    ):
    w1 , b1  , w2  , b2 ,  w3 , b3 = get_netvar(784,256,128,10)
    epoch_sumloss = []
    epoch_acc = []
    for inter in range(epoch):
        sum_loss=[]
        sum_acc=[]
        total_correct=0
        #训练,更新网络参数
        for step,(x,y) in enumerate(train_dataset):
            #记录下所有可训练变量的梯度,以便下一步更新
            with tf.GradientTape() as tape:
                x=tf.reshape(x,(-1,28*28))

                h1 =tf.nn.relu( x@w1+b1)
                h2 = tf.nn.relu( h1@w2+b2 )
                out_ = h2@w3+b3
                
                #计算单个方差
                loss=tf.square(out_-y)
                #张量求和,也就是计算所有图片的均方误差和,计算均方差
                loss=tf.reduce_mean(loss)
                #记录loss
                sum_loss.append(loss.numpy())
            #获取每个变量对应的梯度值
            grads=tape.gradient(loss,[w1 , b1 , w2 , b2 , w3 , b3 ])

            #更新网络参数
            w1.assign_sub(lr*grads[0])
            b1.assign_sub(lr*grads[1])
            w2.assign_sub(lr*grads[2])
            b2.assign_sub(lr*grads[3])
            w3.assign_sub(lr*grads[4])
            b3.assign_sub(lr*grads[5])
        epoch_sumloss.append(sum(sum_loss)/ len(sum_loss))
        #测试准确率
        for step,(x,y) in enumerate(test_dataset):
                x=tf.reshape(x,(-1,28*28))
                h1 =tf.nn.relu( x@w1+b1)
                h2 = tf.nn.relu( h1@w2+b2 )
                out_ = h2@w3+b3
                #选取概率最大的类别
                pred=tf.argmax(out_ , axis=1)
                #one-hot编码逆过程
                y=tf.argmax(y,axis=1)
                #比较两者结果是否相等
                correct = tf.equal(pred , y)
                # print(correct)
                total_correct=tf.reduce_sum(tf.cast(correct , dtype=tf.int32)).numpy()
                # print(total_correct , len(correct),total_correct/len(correct))
                sum_acc.append(total_correct/len(correct))
                
        epoch_acc.append(sum(sum_acc)/len(sum_acc))

        print('epoch:' , inter , 'step' , step , 'loss:'  , loss.numpy() , 'acc:' ,sum(sum_acc)/len(sum_acc) )

    return  epoch_sumloss  , epoch_acc

画图

def draw(epoch_sumloss , epoch_acc):
    x=[i for i in range(len(epoch_sumloss))]
    #左纵坐标
    fig , ax1 = plt.subplots()
    color = 'red'
    ax1.set_xlabel('epoch')
    ax1.set_ylabel('loss' , color=color)
    ax1.plot(x , epoch_sumloss , color=color)
    ax1.tick_params(axis='y', labelcolor= color)

    ax2=ax1.twinx()
    color1='blue'
    ax2.set_ylabel('acc',color=color1)
    ax2.plot(x , epoch_acc , color=color1)
    ax2.tick_params(axis='y' , labelcolor=color1)

    fig.tight_layout()
    plt.show()

主函数

if __name__ == '__main__' :
    train_dataset , test_dataset = _init()
    epoch_sumloss  , epoch_acc = train_test(train_dataset , test_dataset , 0.01 , 40)
    draw(epoch_sumloss , epoch_acc)

代码结果

在这里插入图片描述

总结

代码准确率在88%左右,没能达到更高的精度是因为使用固定的学习率进行计算,同时如果训练次数增加的话,按照精度曲线应该还有上升的空间。

全部代码

'''
created by young_monkeysun  2020 9 22
 '''
import os
import tensorflow as tf
import matplotlib.pyplot as plt
import tensorflow.keras.datasets as datasets

#数据初始化
'''
初始化时,需将数据集分为训练集和测试集

1.数据归一化
2.数据转换为张量
3.需要将y进行ont-hot编码
4.数据聚合并切片
'''
def _init( ):
    #load数据集
    (x_train,y_train) , (x_test,y_test) = datasets.mnist.load_data()
    #数据转换为张量,并归一化
    x_train=2*tf.convert_to_tensor(x_train,dtype=tf.float32)/255 - 1
    x_test=2*tf.convert_to_tensor(x_test,dtype=tf.float32)/255 - 1
    y_train=tf.convert_to_tensor(y_train,dtype=tf.int32)
    y_test=tf.convert_to_tensor(y_test,dtype=tf.int32)

    #y进行one-hot编码
    y_train=tf.one_hot(y_train,depth=10,on_value=None,off_value=None)
    y_test=tf.one_hot(y_test,depth=10,on_value=None,off_value=None)

    #数据重新聚合
    train_dataset =tf.data.Dataset.from_tensor_slices((x_train,y_train))
    test_dataset=tf.data.Dataset.from_tensor_slices((x_test,y_test))

    #数据集切片
    train_dataset=train_dataset.batch(200)
    test_dataset=test_dataset.batch(200)

    #设置学习率
    # optimizer=optimizers.SGD(learning_rate=0.001)

    #设置精度标尺
    # acc_meter=metrics.Accuracy()

    return train_dataset , test_dataset  


#获取单层网路参数
def net(in_ , out_):
    w=tf.Variable(tf.random.truncated_normal([in_ , out_], stddev=0.1))
      
    b=tf.Variable(tf.zeros([out_]))
    return w , b

#获取多层网络参数
def get_netvar(in_1 , in_2 , in_3 , out):
    w1  , b1 = net(in_1 , in_2)
    w2  , b2 = net(in_2 , in_3)
    w3  , b3 = net(in_3 ,  out)
    return w1 , b1  , w2  , b2 ,  w3 , b3 



def train_test (train_dataset ,test_dataset, lr , epoch    ):
    w1 , b1  , w2  , b2 ,  w3 , b3 = get_netvar(784,256,128,10)
    epoch_sumloss = []
    epoch_acc = []
    for inter in range(epoch):
        sum_loss=[]
        sum_acc=[]
        total_correct=0
        #训练,更新网络参数
        for step,(x,y) in enumerate(train_dataset):
            #记录下所有可训练变量的梯度,以便下一步更新
            with tf.GradientTape() as tape:
                x=tf.reshape(x,(-1,28*28))

                h1 =tf.nn.relu( x@w1+b1)
                h2 = tf.nn.relu( h1@w2+b2 )
                out_ = h2@w3+b3
                
                #计算单个方差
                loss=tf.square(out_-y)
                #张量求和,也就是计算所有图片的均方误差和,计算均方差
                loss=tf.reduce_mean(loss)
                #记录loss
                sum_loss.append(loss.numpy())
            #获取每个变量对应的梯度值
            grads=tape.gradient(loss,[w1 , b1 , w2 , b2 , w3 , b3 ])

            #更新网络参数
            w1.assign_sub(lr*grads[0])
            b1.assign_sub(lr*grads[1])
            w2.assign_sub(lr*grads[2])
            b2.assign_sub(lr*grads[3])
            w3.assign_sub(lr*grads[4])
            b3.assign_sub(lr*grads[5])
        epoch_sumloss.append(sum(sum_loss)/ len(sum_loss))
        #测试准确率
        for step,(x,y) in enumerate(test_dataset):
                x=tf.reshape(x,(-1,28*28))
                h1 =tf.nn.relu( x@w1+b1)
                h2 = tf.nn.relu( h1@w2+b2 )
                out_ = h2@w3+b3
                #选取概率最大的类别
                pred=tf.argmax(out_ , axis=1)
                #one-hot编码逆过程
                y=tf.argmax(y,axis=1)
                #比较两者结果是否相等
                correct = tf.equal(pred , y)
                # print(correct)
                total_correct=tf.reduce_sum(tf.cast(correct , dtype=tf.int32)).numpy()
                # print(total_correct , len(correct),total_correct/len(correct))
                sum_acc.append(total_correct/len(correct))
                
        epoch_acc.append(sum(sum_acc)/len(sum_acc))

        print('epoch:' , inter , 'step' , step , 'loss:'  , loss.numpy() , 'acc:' ,sum(sum_acc)/len(sum_acc) )

    return  epoch_sumloss  , epoch_acc

    
def draw(epoch_sumloss , epoch_acc):
    x=[i for i in range(len(epoch_sumloss))]
    #左纵坐标
    fig , ax1 = plt.subplots()
    color = 'red'
    ax1.set_xlabel('epoch')
    ax1.set_ylabel('loss' , color=color)
    ax1.plot(x , epoch_sumloss , color=color)
    ax1.tick_params(axis='y', labelcolor= color)

    ax2=ax1.twinx()
    color1='blue'
    ax2.set_ylabel('acc',color=color1)
    ax2.plot(x , epoch_acc , color=color1)
    ax2.tick_params(axis='y' , labelcolor=color1)

    fig.tight_layout()
    plt.show()

if __name__ == '__main__' :
    train_dataset , test_dataset = _init()
    epoch_sumloss  , epoch_acc = train_test(train_dataset , test_dataset , 0.01 , 40)
    draw(epoch_sumloss , epoch_acc)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值