小白的树莓派Tensorflow2.0 opencv 学习笔记(三)

正式进入TensorFlow2.0模块

TensorFlow2.0 基础部分

TensorFlow2.0 数值类型

TensorFlow2.0 的张量类型有:

  1. 标量(单个实数) 如1、2、3 等 维度数(秩)为0,shape为[]
  2. 向量(n个实数的有序集合)通过中括号包裹 如[1,2] 维度数为1,长度不定,shape为[n]
  3. 矩阵 n行m列实数的有序集合,如[[1,2],[3,4]],维度数为2,shape为[n,m]
  4. 张量 维度数大于2的数组,如果表示图片数据的话有,图片数量,图片高度,图片宽度,图片通道数四个维度

在TensorFlow2.0中一般把标量、向量、矩阵也统称为张量,不做区分

TensorFlow2.0中创建数值必须用其规定方法,不能用Python语言的标准变量创建方式。
比如

a = tf.constant(1.2,dtype=tf.float32) #创建一个精度为32bit、值为1.2的标量

此外TF2也支持字符串、布尔类型的数据.
可以利用tf.cast函数进行数据类型转换
tf.Variable 用以创建待优化张量,也就是所谓的变量

TF2创建已知分布的张量

在卷积神经网络中,卷积核初始化可以通过创建已知分布的张量来进行,下面是两种常见的分布

利用tf.random.normal([n,m],mean=1,stddev=2)创建一个二维矩阵,其中的数值从均值为1,标准差为2的正态分布中随机取出
以 a = tf.random.normal([2,3],mean=1,stddev=2)为例
a的值为
array([[1.4210551, 1.6179423, 2.4991584],
[0.8452484, 2.7406826, 1.1655676]], dtype=float32)>
其中id为内部索引对象的编号

利用tf.random.uniform([n,m],minval=a,maxval=b,dtype=tf.int32)可以创建二维矩阵,其中的元素为区间[a,b]内的整数

创建序列

在循环计算或者索引张量时需要创建一段连续的整型序列(类似于Python中 for i in range(100) 循环中的range)可以通过tf.range函数实现,函数原型
tf.range(a,b,delta=k) [a,b)步长为2的序列

Reshape

张量的存储和视图概念,比如shape为[2,4,4,3]的张量A,可以理解为两张4行4列,每个位置有RGB3个通道的数据的图像。TF在进行矩阵运算的时候会自动调用Broadcasting使得矩阵的维数对应。这在神经网络中非常常见,调用tf.reshape()函数也能改变张量的维数。
例如

#[1,28,28]->[1,28*28] 三维降二维
x = tf.zeros([1,28,28])
x = tf.reshape(x,[1,28*28])
数学运算

TF重载了±*/运算符,所以可以不利用函数直接使用运算符运算,乘方也与Python一致,指数用tf.exp(),对数tf.math.log()只能计算以10为底的函数值,可以配合换底公式使用改变底数

TF2的语法变化

而TensorFlow 2.0相比于1.X改进还是非常多的,很多“反人类”的操作都被移除了。
比如:not sessions 下面是实现 计算3*5的TF代码对比

#TF1.x
a = tf.constant(5)
b = tf.constant(3)
c = a*b
with tf.Session() as sess:
    print(sess.run(c))

#TF2
a = tf.constant(5)
b = tf.constant(3)
c = a*b
print(c)

可以看出TensorFlow2.0更加贴近Python

此外TensorFlow 2.0推荐使用Keras构建和训练深度学习模型,它更加方便使用,模块化易组合的特点也更易于扩展

简单分类网络模型

了解了张量的常用操作之后,最后用一个完整的张量方式实现的分类网络模型收尾。

TF中的keras.datasets模块提供了常用的经典数据集的自动下载、管理、加载并提供了tf.data.Dataset数据集对象,方便实现多线程,预处理和批训练等常用功能。这里以MNIST_data为例,MNIST_data的下载问题先到http://yann.lecun.com/exdb/mnist/下载mnist.npz然后解压放在python\Lib\site-packages\tensorflow_core\python\keras\datasets目录下再修改mnist.py中def load_data函数中path的路径并将下载的相应代码去掉即可


def load_data(path='D:\\python\\Lib\\site-packages\\tensorflow_core\\python\\keras\\datasets\\mnist.npz'):##主要是这里
  """Loads the MNIST dataset.

  Arguments:
      path: path where to cache the dataset locally
          (relative to ~/.keras/datasets).

  Returns:
      Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.

  License:
      Yann LeCun and Corinna Cortes hold the copyright of MNIST dataset,
      which is a derivative work from original NIST datasets.
      MNIST dataset is made available under the terms of the
      [Creative Commons Attribution-Share Alike 3.0 license.](
      https://creativecommons.org/licenses/by-sa/3.0/)
  
  origin_folder = 'https://storage.googleapis.com/tensorflow/tf-keras-datasets/'
  path = get_file(
      path,
      origin=origin_folder + 'mnist.npz',
      file_hash=
      '731c5ac602752760c8e48fbffcf8c3b850d9dc2a2aedcf2cc48468fc17b673d1')
  """  #防止其尝试下载
  with np.load(path) as f:
    x_train, y_train = f['x_train'], f['y_train']
    x_test, y_test = f['x_test'], f['y_test']

    return (x_train, y_train), (x_test, y_test)

张量分类网络相应代码

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets

def preprocess(x,y):
    #归一化
    x = tf.cast(x, dtype=tf.float32) / 255.
    x = tf.reshape(x, [-1,28*28])#变成二维从而能够进入网络层
    y = tf.cast(y, dtype=tf.int32)
    y = tf.one_hot(y, depth=10)#变成one-hot编码

    return x,y

    
(x, y),(x_test, y_test) = datasets.mnist.load_data()# x为图像,shape为[b,28,28],y为标签,shape为[b]
train_db = tf.data.Dataset.from_tensor_slices((x, y))#将训练图片和标签转换为Dataset对象
train_db = train_db.shuffle(1000)#随机打乱
train_db = train_db.batch(512)#批训练,利用显卡并行计算能力缩短训练时间
train_db = train_db.map(preprocess)#预处理函数为preprocess,map函数可以自动传入参数
train_db = train_db.repeat(20)

test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_db = test_db.shuffle(1000).batch(512).map(preprocess)
x,y = next(iter(train_db))

def main():
    lr = 4e-2
    accs,losses = [], []
    w1, b1 = tf.Variable(tf.random.normal([784,256], stddev=0.1)),tf.Variable(tf.zeros([256]))
    w2, b2 = tf.Variable(tf.random.normal([256,128], stddev=0.1)),tf.Variable(tf.zeros([128]))
    w3, b3 = tf.Variable(tf.random.normal([128,10], stddev=0.1)),tf.Variable(tf.zeros([10]))

    for step,(x,y) in enumerate(train_db):#迭代数据集对象

        x = tf.reshape(x,(-1, 784))
        
        with tf.GradientTape() as tape:
            h1 = x @ w1 + b1
            h1 = tf.nn.relu(h1)
            h2 = h1 @ w2 + b2
            h2 = tf.nn.relu(h2)
            out = h2 @ w3 + b3

            loss = tf.square(y - out)
            loss = tf.reduce_mean(loss)

        grads = tape.gradient(loss, [w1,b1,w2,b2,w3,b3])

        for p,g in zip([w1,b1,w2,b2,w3,b3],grads):
            p.assign_sub(lr * g)

        if step%80 == 0:
            print(step,"loss:",float(loss))#每100次输出一次模型的性能
            losses.append(float(loss))

            total,total_correct = 0.,0

            for x, y in test_db:
                h1 = x @ w1 + b1
                h1 = tf.nn.relu(h1)
                h2 = h1 @ w2 + b2
                h2 = tf.nn.relu(h2)
                out = h2 @ w3 + b3
                pred = tf.argmax(out, axis=1)
                y = tf.argmax(y, axis=1)
                correct = tf.equal(pred, y)
                total_correct += tf.reduce_sum(tf.cast(correct, dtype=tf.int32)).numpy()
                total += x.shape[0]
            
            print(total_correct,total)
            print(step, 'Evaluate Acc:',total_correct/total)
            accs.append(total_correct/total)
    


if __name__ == '__main__':
    main()

最后的准确率只能达到 86.98%,均方误差为0.034,对于一个简单的模型来说,这个结果已经不错了。

你可能感兴趣的:(小白的树莓派Tensorflow2.0 opencv 学习笔记(三))