TensorFlow零基础入门,实现手写数字识别

2023-11-03

TensorFlow 是一个用于人工智能的开源神器 ,主要为深度学习算法提供了很多函数,以及独特的运算支持。

废话不多说直接上干货。

我的环境:

python3.7

tensorflow==1.13.2

numpy==1.20.2

1、入门示例

import tensorflow as tf

# 第一步:定义计算(计算图)
a = tf.constant([1, 2])
b = tf.constant([2, 3])
res = a+b
print(res)

# 第二步:执行计算(会话中)
sess = tf.Session()    # 启动会话
res1 = sess.run(res)
sess.close()   # 关闭会话

print(res1)

输出:

>>>res
<tf.Tensor 'add:0' shape=(2,) dtype=int32>
>>>res1
array([3, 5])

res为一个叫Tensor的数据类型,也就是张量

可以看到TensorFlow定义的量只有进入到会话中才会被运算。

TensorFlow分为定义计算和执行计算两步,要求参与运算的数据类型完全相同。

2、TensorFlow数据类型

TensorFlow的数据类型其实就是tensor,就是一个数据流。

细分为两类:

  • 常量:constant,常量就是不变的量。
  • 变量:Variable,在TensorFlow中定义的变量就是我们之后训练模型要训练的量。

下面通过一个小例子来演示如何用TensorFlow来训练一个模型

2.1 利用TensorFlow构建线性模型

步骤包括以下几步:

  1. 导入100个样本数据
  2. 构造一个线性模型
  3. 定义损失函数
  4. 定义训练函数
  5. 启动图
  6. 初始化变量
  7. 开始训练

先设定线性模型的结构如下:

image.png

数据信息如下,包括输入值x1,x2和结果y
在这里插入图片描述

​ 训练模型的意义就是定义变量a,b,c.然后训练这三个变量,使得 y = a x 1 + b x 2 + c y=ax_1+bx_2+c y=ax1+bx2+c成立,如果你对神经网络有所了解的话就可以知道,这里的a和b其实对应的就是x1和x2的权值,而c对应的就是阈值了。

先进行第一步导入100个样本数据。在这之前要先导入相关的库。

数据链接:样本数据集.

import numpy as np
import tensorflow as tf


data = np.float32(np.load('line_fit_data.npy'))  # 导入100个样本数据
x_data = data[:, :2]   # 样本自变量
y_data = data[:, 2:]   # 样本实际值

输出:

>>>data.shape
(100, 3)

​ 可以看到这是一个二维数组,有100行3列。

第二步:构造一个线性模型

w = tf.Variable(tf.zeros([2, 1]))
bias = tf.Variable(tf.zeros([1]))
y = tf.matmul(x_data, w) + bias   # 构造一个线性模型

​ 先声明两个变量a,b,并附初始值0.因为是两个变量所以就声明为一个两行一列的数组,而c就声明为一个一维数组。之所以要这样声明是为了方便后面的矩阵运算。

matmul:就是一个矩阵乘法函数

>>>tf.matmul(x_data, w)
<tf.Tensor 'MatMul:0' shape=(100, 1) dtype=float32>

​ 可以看到在进行了矩阵乘法之后和结构为一个100*1的矩阵,在加上bias也就是c,就得到了模型的预测值。

第三步:定义损失函数

​ 那么如何判断模型的预测值和实际结果之间的差距呢,也就是怎么判断预测值和实际值有多像。

​ 这里需要定义一个损失函数。

loss = tf.reduce_mean(tf.square(y_data - y))  # 定义损失函数,均方误差

​ 这个损失函数的意思就是把模型的每一组预测值和每一组实际值做对比,求出均方误差。均方误差越小就表明模型越精确。

第四步:定义训练函数

​ 训练函数要做的就是将损失函数的值不断变小,从而达到预测越来越精确地目的。

optimizer = tf.train.GradientDescentOptimizer(0.5)   # 构建梯度下降法优化器

​ 这里用到了梯度下降算法。TensorFlow自带有这个函数,里面的参数指的是学习的速率。

​ 先解释一下什么是梯度下降算法,这个算法的作用是使某个函数的函数值在训练后不断减小,原理和函数的梯度有关,如果把一个函数的每一个变量看作一个维度,那么一个函数的梯度就是这个函数增加最快的一个方向向量,那么与梯度方向相反的方向就是这个函数的值减小最快的方向。

​ 下面以一个二维函数举例子,高维同样可以这样理解。

在这里插入图片描述

​ 所谓梯度下降算法就是在寻找一条最快的“下山”的路。它的参数就是每次“下山”的步长,就是函数往梯度的反方向移动一段距离,所以这个值如果太小,那么学习速率就低,如果太大就会学习不准确。

​ 现在开始训练函数,在这个算法中你可以选择是趋于最小值计算还是趋于最大值计算,我们这里当然是希望我们的损失函数的值越小越好,所以这里的train就如下定义。

train = optimizer.minimize(loss)   # 定义训练函数

第五步:启动图

sess = tf.Session() #启动会话

sess.close()  #关闭会话

​ TensorFlow的运算严格分为定义计算和执行计算两步,定义计算时还要严格要求数据类型,甚至是数据精度都有要求,虽然定义的时候是麻烦了一点,但是这的确能极大地提高运算速度。

​ 所有的运算在定义之后都要放到会话中执行。

第六步:初始化变量

​ 在TensorFlow中只要涉及到变量就要将变量初始化,前面的将变量赋值为0并不是初始化操作,这里的初始化可以理解为激活变量。

sess.run(tf.global_variables_initializer())   # 初始化变量

​ 当然这一步是需要放到会话中执行的。

第七步:训练模型

​ 现在只需要一个循环不停地使用梯度下降算法更新函数值就可以完成模型的训练了。

for i in range(100):
    print('第', i, '轮训练后的模型损失值:', sess.run(loss))
    sess.run(train)   # 开始训练

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

​ 可以看到当训练轮数到达100轮的时候误差以及几乎可以忽略了。也就是模型训练完成。输出一下训练得到的a,b,c

>>>sess.run([w, bias])
[array([[0.09999494],
       [0.19998254]], dtype=float32), array([0.30001214], dtype=float32)]

​ 可以看到值为0.1,0.2,0.3。也就是说模型最终为:y = 0.1x1 + 0.2x2 + 0.3

下面附上完整代码

import numpy as np
import tensorflow as tf


data = np.float32(np.load('line_fit_data.npy'))  # 导入100个样本数据
x_data = data[:, :2]   # 样本自变量
y_data = data[:, 2:]   # 样本实际值

'''
定义计算(计算图)
'''
w = tf.Variable(tf.zeros([2, 1]))
bias = tf.Variable(tf.zeros([1]))
y = tf.matmul(x_data, w) + bias   # 构造一个线性模型
loss = tf.reduce_mean(tf.square(y_data - y))  # 定义损失函数,均方误差

optimizer = tf.train.GradientDescentOptimizer(0.5)   # 构建梯度下降法优化器
train = optimizer.minimize(loss)   # 定义训练函数

'''
执行计算(会话中)
'''
# 启动会话
sess = tf.Session()
sess.run(tf.global_variables_initializer())   # 初始化变量
for i in range(100):
    print('第', i, '轮训练后的模型损失值:', sess.run(loss))
    sess.run(train)   # 开始训练

sess.run([w, bias])# y = 0.1*x1 + 0.2*x2 + 0.3
sess.close()

下面是计算图模型。

在这里插入图片描述

​ x_data,W,biases为模型的输入,结果矩阵乘法运算后得到模型的预测值,预测值和实际值对比将代价函数传入训练模型。

3、手写数字识别

3.1 认识mnist数据集

在这个项目中我用的是mnist数据集。

资源连接:mnist数据集.

这个文件里是处理好的图片文件,资源解压后将整个文件夹放入工程目录。

在这里插入图片描述

​ 这个项目可以算是TensorFlow的helloworld了。

​ 先导入读取文件的库,然后读入数据。

from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data')   # 读取数据

​ 读取训练样本和样本结果

mnist.train.images 
mnist.train.labels
>>>mnist.train.images.shape   # (55000, 784) 55000张图片,每张图片有784个像素值
(55000, 784)
>>>mnist.train.labels.shape   # 一共有55000张图片,每张图片都有一个标签
(55000,)

​ 输出一下这两个样本的结构。可以看到这里的图片格式是一条像素,就是将每一张图片拉成一长条,一共784个像素点,训练样本一共有55000张图片,训练样本的标签就是一维的表示这55000张图片对应的实际的图片的值。

​ 现在来考虑一下我们要如何定义损失函数,也就是我们要怎么表示预测值和实际值的差距。打个比方如果一张图片的实际值为0,而一个模型的预测值为1,另一个模型的预测值为2,现在我问你这两个预测值哪个更加接近实际值呢?

​ 那么我可以告诉你这是无法比较的,我们的模型并不会涉及数据的大小比较,所以我们的模型如果只能输出这样的预测值,我们是无法估计要怎样朝着与实际值越来越接近的方向前进的。

​ 那么我们对实际值和预测值换一种表达方式,都表示为一个一维10列的数组,各个位置上对应的数表示值为该位置的概率。

实际值:[1,0,0,0,0,0,0,0,0,0] 表示取0的概率为1,其他概率为0,这样依然可以表示实际值为1.

预测值1:[0.4,0.5,0.1,0,0,0,0,0,0,0]

预测值2:[0,0.4,0.5,0.1,0,0,0,0,0,0]

​ 现在虽然预测值依旧是1和2,但是可以看得出来预测值1明显更接近0。

​ 这种编码格式就是独热编码。其实只需要在读取文件时加一个参数就可以实现。

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)   # 读取数据
mnist.train.labels[2]

​ 这样读取的数据标签就是独热编码格式了。

>>>mnist.train.labels.shape  
(55000, 10)
>>>mnist.train.labels[2]
array([0., 0., 0., 0., 1., 0., 0., 0., 0., 0.])

​ 可以看到现在的标签就是55000*10的数组了。每个图片标签都是独热编码。

​ 具体比较图片的差值就需要引入交叉熵的概念了。

在这里插入图片描述

​ y表示预测值,y’表示实际值,交叉熵越小表示两个实越接近。下面代码实现。

先导入numpy

import numpy as np

real = np.array([1,  0,  0,  0,  0,0,0,0,0,0])
p1 =   np.array([0.4,0.5,0.1,0,  0,0,0,0,0,0])
p2 =   np.array([0,  0.4,0.5,0.1,0,0,0,0,0,0])

-sum(real*np.log(p1+0.0000001))
-sum(real*np.log(p2+0.0000001))

​ 这里要加0.0000001是因为交叉熵公式里有log,log里的值不能是0。

输出:

>>>-sum(real*np.log(p1+0.0000001))
0.9162904818741863
>>>-sum(real*np.log(p2+0.0000001))
16.11809565095832

​ 这里比较就比较直观了,预测值1的交叉熵小。

3.2 代码实现手写数字识别

​ 现在开始实现手写数字识别。

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)   # 读取数据
x_data = tf.placeholder(tf.float32, [None, 784])  # 占位符:样本自变量
y_data = tf.placeholder(tf.float32, [None, 10])   # 占位符:样本目标变量

​ 这里读取数据的时候先保留一个占位符,真正的数据到要运行的时候在传入,相当于保留了一个数据接口,当然这个接口要先定义数据类型,精度和数组的shape,None表示未定,这里的意思就是样本自变量为784列数组,至于多少个,那我不知道,未定。

​ 现在定义网络结构:

w = tf.Variable(tf.zeros([784, 10]))   # 网络权值矩阵
bias = tf.Variable(tf.zeros([10]))     # 网络阈值
y = tf.nn.softmax(tf.matmul(x_data, w) + bias)   # 网络输出

​ 这里在获取网络输出的时候用了softmax函数,这是一个非线性映射函数。具体公式如下:

在这里插入图片描述

​ 这样取值后得到的结果刚好符合独热编码格式,即保证每一项都不为0,相加又刚好为1。

​ 定义损失函数,梯度下降器和训练节点

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_data*tf.log(y), axis=1))  # 交叉熵(损失函数)
optimizer = tf.train.GradientDescentOptimizer(0.003)   # 梯度下降法优化器
train = optimizer.minimize(cross_entropy)   # 训练节点

​ 这里看不懂可以回到前面看看,我前面说明的很详细。这个交叉熵函数里的axis=1表示逐行求交叉熵。tf.reduce_mean表示取均值。

定义一下测试精度:

acc = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(y, axis=1), tf.argmax(y_data, axis=1)), dtype=tf.float32))  # 模型预测值与样本实际值比较的精度

tf.argmax(y, axis=1), tf.argmax(y_data, axis=1)表示逐行取预测值和实际值。

tf.equal表示比较是否相等

tf.cast是将true or false转化为浮点数,true=1.0,false=0.0

最后在取均值就是精度了。

下面就是在会话里运行了。

sess = tf.Session()  # 启动会话
sess.run(tf.global_variables_initializer())  # 执行变量初始化操作
for i in range(20000):
    x_s, y_s = mnist.train.next_batch(100) #取100个样本
    if i%5000 == 0:
        acc_tr = sess.run(acc, feed_dict={x_data: x_s, y_data: y_s})
        print(i, '轮训练的精度', acc_tr)
    sess.run(train, feed_dict={x_data:x_s, y_data:y_s})   # 模型训练

通过mnist.train.next_batch(100)读取随机的100个数据。

 return self._images[start:end], self._labels[start:end]

这是mnist.train.next_batch()函数的返回值。是两个,分别对应x和y

输出一下精度,然后开始训练模型

训练完成后就要输入测试集来看看精度怎么样了。

acc_te = sess.run(acc, feed_dict={x_data:mnist.test.images, y_data:mnist.test.labels})  # 测试集精度
print('模型测试精度:', acc_te)
sess.close()

传入测试集数据。当然不要忘了关闭会话。

0 轮训练的精度 0.13
5000 轮训练的精度 0.88
10000 轮训练的精度 0.9
15000 轮训练的精度 0.9
模型测试精度: 0.9044

打印一下进度可以发现准确率可以达到90%,还是不错的。

整体代码如下:

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)   # 读取数据
x_data = tf.placeholder(tf.float32, [None, 784])  # 占位符:样本自变量
y_data = tf.placeholder(tf.float32, [None, 10])   # 占位符:样本目标变量

w = tf.Variable(tf.zeros([784, 10]))   # 网络权值矩阵
bias = tf.Variable(tf.zeros([10]))     # 网络阈值
y = tf.nn.softmax(tf.matmul(x_data, w) + bias)   # 网络输出

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_data*tf.log(y), axis=1))  # 交叉熵(损失函数)
optimizer = tf.train.GradientDescentOptimizer(0.003)   # 梯度下降法优化器
train = optimizer.minimize(cross_entropy)   # 训练节点
acc = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(y, axis=1), tf.argmax(y_data, axis=1)), dtype=tf.float32))  # 模型预测值与样本实际值比较的精度

sess = tf.Session()  # 启动会话
sess.run(tf.global_variables_initializer())  # 执行变量初始化操作
for i in range(20000):
    x_s, y_s = mnist.train.next_batch(100) #取100个样本
    if i%5000 == 0:
        acc_tr = sess.run(acc, feed_dict={x_data: x_s, y_data: y_s})
        print(i, '轮训练的精度', acc_tr)
    sess.run(train, feed_dict={x_data:x_s, y_data:y_s})   # 模型训练

acc_te = sess.run(acc, feed_dict={x_data:mnist.test.images, y_data:mnist.test.labels})  # 测试集精度
print('模型测试精度:', acc_te)
sess.close()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TensorFlow零基础入门,实现手写数字识别 的相关文章

随机推荐

  • 解决idea项目中没有蓝色方块

    当遇到Idea项目中没有蓝色方块时候 打开右边Maven 点击 然后选中pom xml 点击后即变蓝
  • 在Windows下使用CMake GUI

    由于供应商代码使用了CMake 所以也尝试使用CMake VS来编译C CMake的安装和使用入门在下面blog中有详细讲解可供参考 https blog csdn net yaoyuanyylyy article details 7902
  • 释放租赁红利,中国长租公寓行业创新模式探讨和分析

    超过万亿的巨大市场前景 九部委联合印发住房租赁新政 提出将采取多种措施加快推进租赁住房建设 培育和发展住房租赁市场 长租公寓尤其让众多资本机构觊觎 正在用惊人的扩张速度勾勒出一幅蓝图盛景 对于被称为 下一个风口 的公寓行业 各方有不同的解读
  • 总结一下2021年全国大学生电子设计大赛A题用到的MSP432P401开发板

    作者 嵌入式历练者 ID Eterlove 记下相关笔记 记录我的学习生活 站在巨人的肩上Standing on Shoulders of Giants 该文章为原创 转载请注明出处和作者 https blog csdn net Eterl
  • 求数组中数对之差的最大值

    数组中的一个数字减去它右边子数组中的一个数字可以得到一个差值 求所有可能的差值中的最大值 例如 数组 1 4 17 3 2 9 中 最大的差值为17 2 15 动态规划法 我们用变量dif来记录前i 1个数组成的序列的最大数对差 用变量ma
  • 【华为OD机试】求字符串中所有整数的最小和【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 输入字符串s 输出s中包含所有整数的最小和 说明 字符串s 只包含 a z A Z 合法的整数包括 1 正整数 一个或者多个0 9组成 如 0 2 3 002 102
  • 页面结构分析

  • 关于解决Win10家庭中文版没有组策略编辑器的问题

    今天在使用远程桌面连接服务器的时候发生了一些列的问题 首先是突然间出现了凭据不工作问题 但自己的用户名及密码都没有错误 最后查询发现需要修改在凭据管理中修改相应信息 呢么修改则需要在组策略编辑器中修改 但是呢win10家庭版又无法进入 以下
  • 【华为OD机试真题 python】最大数字【2023 Q1

    题目描述 最大数字 给定一个由纯数字组成以字符串表示的数值 现要求字符串中的每个数字最多只能出现2次 超过的需要进行删除 删除某个重复的数字后 其它数字相对位置保持不变 如 34533 数字3重复超过2次 需要删除其中一个3 删除第一个3后
  • idea读取数据库乱码,Navicat正常(解决)

    乱码问题困扰了我2天 菜的抠脚 先说说问题吧 你如果不想看这些废话就直接去下面解决 我先创建了数据库 拷贝了sql语句运行之后 Navicat正常显示 但是页面显示乱码 其实是中文latin1编码 debug跟进程序 发现在hibernat
  • msvcp140_1.dll丢失怎样修复?快速修复dll文件缺失

    msvcp140 1 dll丢失怎样修复 关于msvcp140 1 dll丢失 其实和其他dll文件的修复方法是一模一样的 你缺失了什么dll文件 那么你就在百度搜索这个dll文件 然后放到指定的文件夹就好了 解决起来还是非常的简单的 ms
  • Cocos Creator资源管理AssetManager细说一二

    关于AssetManager Asset Manager 是 Creator 在 v2 4 新推出的资源管理器 用于替代之前的 cc loader 新的 Asset Manager 资源管理模块具备加载资源 查找资源 销毁资源 缓存资源 A
  • VUE搭建项目,配置本地IP地址其他人可访问项目(整理)

    1 首先找到config文件夹目录下的 index js文件 Various Dev Server settings host localhost 将localhost进行替换成 0 0 0 0 host 0 0 0 0 can be ov
  • 如何使用USB接口对C51单片机下载固件

    使用USB转UART芯片对单片机下载固件时会遇到的问题 C51系列单片机在下载固件的时候需要断电重启 在使用RS232接口的时候不会遇到什么困难 因为RS232不需要进行识别 但是现在使用USB转UART的芯片时会遇到问题 因为USB设备在
  • CIFAR-10训练模型(ResNet18)

    1 搭建环境 环境在实验进行时已经搭建完毕 具体步骤就不过多赘述 参考 https blog csdn net weixin 39574469 article details 117454061 接下来只需导入所需的包即可 import n
  • python中列表数据汇总和平均值_如何从记录列表中计算平均值

    所以我正在做一个作业 当从一个数据列表中计算一个平均值 数据是从一个外部的 txt文件中读取的 时 我似乎遇到了麻烦 具体来说 我要做的是从下面的数据列表中读取数据记录 在1 2 2014 Frankton 42305 67 23 12 4
  • 高德地图API INVALID_USER_SCODE问题以及keystore问题

    转载地址 http m blog csdn net article details id 50448014 请尊重原创 今天这篇文章会给大家介绍三个问题 1 接入API时出现invalid user scode问题 首先进行第一个大问题 接
  • python连接数据库设置编码_python连接mysql数据库——编码问题

    编码问题 1 连接数据库语句 在利用pycharm连接本地的mysql数据库时 要考虑到的是将数据库语句填写完整 困扰了一下午的问题就是连接语句并没有加入编码设置 db pymysql connect host localhost user
  • 如何利用计算机打印较大的字,如何在一张A4纸上打印一个超大字?

    是不是很想打印超大字 要是硬件上去了 就什么话也不用说了 可惜的是 手中只有一个A4的打印机 怎么办 还是有办法的 用Microsoft Office 2003就可以 我由于学校工作的原因 打印机只能打A4的纸 有时又想打超大字 不得不用现
  • TensorFlow零基础入门,实现手写数字识别

    TensorFlow 是一个用于人工智能的开源神器 主要为深度学习算法提供了很多函数 以及独特的运算支持 废话不多说直接上干货 我的环境 python3 7 tensorflow 1 13 2 numpy 1 20 2 1 入门示例 imp