CV&NLP基础6之手写数字识别代码体验

总流程(思路)预览

在这里插入图片描述

x是输入的图片y是图片对应的label

在这里插入图片描述

关于训练数据集的说明

在这里插入图片描述

搭建计算网络层

这里输入x是[60000, 784],输出的label y是10分类。像上一篇文章一样,写出各层的变化。
第一层: h1 = relu(x @ w1 + b1)
       其中,w1: [784, 512],b1: [512],h1: [784, 512]

第二层: h2 = relu(h1 @ w2 + b2)
       其中,w2: [512, 256],b2: [256],h2: [784, 256]

第三层: out = relu(h2 @ w3 + b3)
       其中,w3: [256, 10],b3: [10],out: [784, 10]

在这里插入图片描述

下面详情视频清晰版: 链接: https://pan.baidu.com/s/1LibA6jI0bHylwo6qyGp4bA?pwd=njcw 提取码: njcw

CVNLP基础文章6搭建计算网络层概述

计算损失值loss

x.shape[0]是图片数。这里计算loss算的是“平均损失”,没有使用总损失,两者都可,目标都是缩小loss值
在这里插入图片描述

下面详情视频清晰版: 链接: https://pan.baidu.com/s/1GVaP6S2sJ0qkeAL7MOUmcg?pwd=ffd4 提取码: ffd4

CVNLP基础文章6计算损失值loss

优化损失值loss(minimize loss)

在这里插入图片描述

下面详情视频清晰版: 链接: https://pan.baidu.com/s/1IVt75gRfln_KnF0Yt4auyw?pwd=tyhc 提取码: tyhc

CVNLP基础文章6优化损失值loss

手写数字初体验代码

代码

导入各种包

import os # “os”是系统包
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # TensorFlow的最小打印日志的等级为2。
# TensorFlow集成了深度学习环境,每次运行都会显示一些电脑环境信息,设置了这个值,就可以隐藏一些不紧要的输出,更简洁。
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers, datasets

获取数据

(x, y), (x_val, y_val) = datasets.mnist.load_data() 
# (x,y)是训练集;(x_val, y_val)是验证集。
# 注: 这里写“(x_val, y_val)”只是为了更全一点,如果用不到验证集,用“_”代替便可
# 目前数据还是“数字类型”,需要将数据转换成深度学习里面的变量类型“tensor”
x = tf.convert_to_tensor(x, dtype=tf.float32) / 255 # x是图片数据,让矩阵元素是浮点数构成。除以255是处理图像的习惯,让矩阵中的值在0~1或者-1~0之间

y = tf.convert_to_tensor(y, dtype=tf.int32) # y是标签,此时y是0~9中的一个数,不会有小数点,是哪一类就是哪一类,用整数型就可以了

# 现在我们不想让“y”是单个数字形式。现在采用“独热编码one-hot”处理“label y”,关于独热编码见“CV&NLP基础文章5”。
y = tf.one_hot(y, depth=10) # depth就是标签y有几类,数字图片一共有10种。此时y从“一维单个数字”转换成了“十维向量”。
                            # 例: y是2的话,就用[0,0,1,0,0,0,0,0,0,0]表示。y是7的话,就用[0,0,0,0,0,0,1,0,0,0]表示。

print(f"6万张训练数据集的数据格式为: {x.shape}, {y.shape}")
print(tf.reduce_max(x), tf.reduce_min(x)) #上面除以255以后,“28*28维矩阵x”中最大的元素是1.0,最小的元素是0.0

数据预处理(切片)

train_dataset = tf.data.Dataset.from_tensor_slices((x, y)).batch(100) 
#以100个为一组对6万张训练集切片。此时一共有600组,每组各100张图片

搭建计算模型(这一步只是搭建框架,没有实际的输入输出)

model = keras.Sequential([
    layers.Dense(512, activation='relu'),
    layers.Dense(256, activation='relu'),
    layers.Dense(10, activation='relu')
])
optimizer = optimizers.SGD(learning_rate=0.0001)
# 以上详情见本篇文章“搭建计算机网络层”视频
# 下面两行代码只是用来看看这个框架都有些什么参数
model.build(input_shape=(None, 784)) # None意思是没有输入图片, 仅是测试而已
model.summary() # 用来看框架内部结构的函数

# 下面输出解读:
# 第一列Layer层:这里是Dense函数产生的层
# 第二列就是每道工序的“输出维度”
# 第三列的参数就是 w、b的个数,以第一层工序举例: 第一层的输入是[None ,784],
# 那么第一层的“W参数”就是[784, 512],“b参数”就是[512],所以784*512+512=401920个参数

开始训练

# 大循环,形参epoch是执行几轮“600次循环”的次数,多次训练数据集可以让计算机不断学习,降低loss值
# 每一轮大循环都是训练6万张图片极其标签,有“epoch”次大循环
def train_epoch(epoch): 
    
    # 小循环,只为训练6万张数据。根据切片,一共600次循环,每一次循环处理100张图片(x)和图片的标签(y)
    for step, (x, y) in enumerate(train_dataset): 
        
        # 计算loss
        with tf.GradientTape() as tape:
            # [b, 28, 28] => [b, 784]
            x = tf.reshape(x, (-1, 784))
            
            # [b, 784] => [b, 10]
            out = model(x) # 将输入x送入模型,得到out
            
            # x.shape[0]是输入的图片数,这里应为 100
            loss = tf.reduce_sum(tf.square(out-y)) / x.shape[0] 
            
        # 计算梯度,“model.trainable_variables”里面是各个w、b,更新w、b后也放入其中 
        # grads 里面是 w、b的梯度
        grads = tape.gradient(loss, model.trainable_variables)
        
        # 更新梯度 w' = w - learning rate * grad w      b' = b - learning rate * grad b
        optimizer.apply_gradients(zip(grads, model.trainable_variables))
        
        if step%50 == 0: # 小循环是600轮,每格50轮输出看看loss值,loss是tensor类型,需要转换成numpy类型来更好地查看
            print('epoch: {}, step: {}, loss: {}'.format(epoch, step, loss.numpy()))
def train():
    #每一轮大循环都换在训练6万张图片
    for epoch in range(10):
        print('当前是第 ', epoch, " 次 大循环")
        train_epoch(epoch)

train()

JupyterLab运行截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

tf.convert_to_tensor函数的使用

函数描述:
将各种类型的python对象转化为tensor对象

将给定value转换为Tensor。
此函数将各种类型的Python对象转换为Tensor 对象。它接受Tensor对象,numpy数组,Python列表和Python标量。
参数:
value:需要转换的
dtype:返回张量的可选元素类型。如果缺少,则从value的类型推断出类型。
name:如果Tensor创建了new,则使用可选名称。
返回:
一个基于value的输出操作(ops),输出一个tensor(自己的理解)

convert_to_tensor(
    value,
    dtype=None,
    name=None,
    preferred_dtype=None
)

示例:

a = np.array([1,2,3])
b = tf.convert_to_tensor(a)
print(type(a)) # <class 'numpy.ndarray'>
print(type(b)) # <class 'tensorflow.python.framework.ops.Tensor'>

补充:tensorflow的reshape操作tf.reshape()

  1. 在处理图像数据的时候总会遇到输入图像的维数不符合的情况,此时tensorflow中reshape()就很好的解决了这个问题

  2. numpy.reshape()与tensorflow,reshape()相似

  3. 格式: tf.reshape(tensor,shape,name=None)

  4. 函数的作用是将tensor变换为参数shape形式,其中的shape为一个列表形式,特殊的是列表可以实现逆序的遍历,即list(-1)。-1所代表的含义是我们不用亲自去指定这一维的大小,函数会自动进行计算,但是列表中只能存在一个-1。(如果存在多个-1,就是一个存在多解的方程)

实际操作中,有如下效果:我创建了一个一维的数组:

>>>import numpy as np
>>>a= np.array([1,2,3,4,5,6,7,8])
>>>a
array([1,2,3,4,5,6,7,8])

使用reshape()方法来更改数组的形状,使得数组成为一个二维的数组:(数组中元素的个数是2×4=8)

>>>d = a.reshape((2,4))
>>>d
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

进一步提升,可以得到一个三维的数组f:(注意数组中元素的个数时2×2×2=8)

>>>f = a.reshape((2,2,2))
>>>f
array([[[1, 2],
        [3, 4]],
 
       [[5, 6],
        [7, 8]]])

-1 的应用: -1 表示不知道该填什么数字合适的情况下,可以选择,由python通过a和其他的值3推测出来,比如,这里的a 是二维的数组,数组中共有6个元素,当使用reshape()时,6/3=2,所以形成的是3行2列的二维数组,可以看出,利用reshape进行数组形状的转换时,一定要满足(x,y)中x*y=数组的个数。

>>>a = np.array([[1,2,3],[4,5,6]])
>>>np.reshape(a,(3,-1)) 
array([[1, 2],
       [3, 4],
       [5, 6]])
>>> np.reshape(a,(1,-1))
array([[1, 2, 3, 4, 5, 6]])
>>> np.reshape(a,(6,-1))
array([[1],
       [2],
       [3],
       [4],
       [5],
       [6]])
>>> np.reshape(a,(-1,1))
array([[1],
       [2],
       [3],
       [4],
       [5],
       [6]])

下面是两张2×3大小的图片(不知道有几张图片可以用-1代替),如何把所有二维照片给转换成一维的,请看以下三维的数组:

>>>image = np.array([[[1,2,3], [4,5,6]], [[1,1,1], [1,1,1]]])
>>>image.shape
(2,2,3)
>>>image.reshape((-1,6))
array([[1, 2, 3, 4, 5, 6],
       [1, 1, 1, 1, 1, 1]])
>>> a = image.reshape((-1,6))
>>> a.reshape((-1,12))
array([[1, 2, 3, 4, 5, 6, 1, 1, 1, 1, 1, 1]])
a.reshape((12,-1))
array([[1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1]])
>>> a.reshape([-1])
array([1, 2, 3, 4, 5, 6, 1, 1, 1, 1, 1, 1])

最后再给大家呈现一下官方给出的例子:

# tensor 't' is [1, 2, 3, 4, 5, 6, 7, 8, 9]
# tensor 't' has shape [9]
reshape(t, [3, 3]) ==> [[1, 2, 3],
                        [4, 5, 6],
                        [7, 8, 9]]
 
# tensor 't' is [[[1, 1], [2, 2]],
#                [[3, 3], [4, 4]]]
# tensor 't' has shape [2, 2, 2]
reshape(t, [2, 4]) ==> [[1, 1, 2, 2],
                        [3, 3, 4, 4]]
 
# tensor 't' is [[[1, 1, 1],
#                 [2, 2, 2]],
#                [[3, 3, 3],
#                 [4, 4, 4]],
#                [[5, 5, 5],
#                 [6, 6, 6]]]
# tensor 't' has shape [3, 2, 3]
# pass '[-1]' to flatten 't'
reshape(t, [-1]) ==> [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6]
 
# -1 can also be used to infer the shape
 
# -1 is inferred to be 9:
reshape(t, [2, -1]) ==> [[1, 1, 1, 2, 2, 2, 3, 3, 3],
                         [4, 4, 4, 5, 5, 5, 6, 6, 6]]
# -1 is inferred to be 2:
reshape(t, [-1, 9]) ==> [[1, 1, 1, 2, 2, 2, 3, 3, 3],
                         [4, 4, 4, 5, 5, 5, 6, 6, 6]]
# -1 is inferred to be 3:
reshape(t, [ 2, -1, 3]) ==> [[[1, 1, 1],
                              [2, 2, 2],
                              [3, 3, 3]],
                             [[4, 4, 4],
                              [5, 5, 5],
                              [6, 6, 6]]]
 
# tensor 't' is [7]
# shape `[]` reshapes to a scalar
reshape(t, []) ==> 7

猜你喜欢

转载自blog.csdn.net/Waldocsdn/article/details/126167149