TensorFlow 2.0,大大简化了TensorFlow 1 的纷繁复杂的API,使用Keras(号称DeepLearning for human)和eager execution(命令行模式),号称能像Numpy一样畅爽运行,快速、可扩展、可投入生产。
这只是一个自己写着复习的笔记,更简单粗暴入门建议可以看北大李锡涵的 《简单粗暴 TensorFlow 2》 与 GitHub传送门
强烈推荐
本项笔记与素材学习自: 慕课,北京大学,曹健老师: 《人工智能实践:TensorFlow笔记》
TensorFlow 2.0 可在任意平台实现稳健的模型部署,不论服务器,PC,网页,边缘设备,不论何种语言,都可以通过标准化交换格式实现跨平台,跨语言部署。
(1)需要掌握一点点python编程:,如import、赋值、运算、条件、循环、file、面向对象即可。
python教程——廖雪峰
(2)with结构;
(3)Numpy 科学计算库 以及简单的 matplotlib库的应用;
如果只个运行在Windows的人电脑上,只需安装CPU版:
1.安装 Python环境;
2.安装Python的IDEpycharm,或者用其他编辑器,个人比较喜欢用jupyter,好看;
3.在cmd中输入:
pip install tensorflow
## 如果安装不了可以试试升级pip版本:
python -m pip install --upgrade pip
首先,需要准备数据:且数据量越大越好,要构成特征和标签对,如果想识别猫就要有大量猫的图片和该图为猫的标签,即构成标签对;
然后,搭建神经网络的网络结构;
再后,通过反向传播,优化连接的权重,直到模型识别准确率达到要求,得到最优连线权重,保存模型;
最后,用保存的模型,输入为被训练的新数据,网络会前向传播,输出分类概率结果。
人们通过经验总结出了规律:通过测量花的花萼长、花萼宽、花瓣长、花瓣宽,可以得出鸢尾花的类别。
(如:花萼长>花萼宽 且 花瓣长/花瓣宽>2 则为 1杂色鸢尾)
若是采用 if…case 语句——专家系统 把专家的经验告诉计算机,计算机执行逻辑运算给出分类。
但是鸢尾花的种植者在识别鸢尾花的时候,并不需要如此理性逻辑的计算,更多的是依靠经验和感性思维,一眼便能看出是哪种鸢尾花,且随着经验越多,识别率越准确,这就是基于连接主义神经网络要模拟出的鸢尾花辨识方法。
输入: 1行4列的数据:花萼长,花萼宽,花瓣长,花瓣宽
输出: 0,1,2,三个种类的可能性大小
这个网络中,每一个具有计算功能的“粉色球”就是一个神经元,神经元的计算模型为:
为了方便理解将MP模型中的非线性函数去掉:
喂入数据:[5.8, 4.0, 1.2, 0.2] 和 其对应的标签 [0] 狗尾草鸢尾
神经网络执行前向传播 : y = w x + b y=wx+b y=wx+b
可以看出,此时的分类最大可能性为1类 杂色鸢尾,这是因为网络的权重 w w w和偏置 b b b都是随机产生的,当然答案也就是“瞎蒙”的。
损失函数: 预测值(y)与标签(y_)的差距。损失函数可以定量判断 w , b w,b w,b的优劣,当损失函数输出最小时,参数 w w w和 b b b会出现最优值。
损失函数的定义有多种方法,如均方误差
均方误差: M S E ( y , y ^ ) = ∑ i = 1 n ( y − y ^ ) 2 n MSE(y,\hat{y}) =\frac{ \sum_{i=1}^n{(y-\hat{y})}^2}{n} MSE(y,y^)=n∑i=1n(y−y^)2
——表征网络前向传播推理和标准答案之间的差距
目的: 是寻找一组参数 w 和 b w和b w和b使得损失函数最小;
梯度: 损失函数的梯度表示损失函数对各参数求偏导后的向量,函数梯度下降的方向是函数减小的方向。
梯度下降法:沿损失函数梯度下降的方向,寻找损失函数的最小值,得到最优参数的方法。
学习率(learning rate, l r lr lr): 监督学习以及深度学习中重要的超参,其决定着目标函数能否收敛到局部最小值以及何时收敛到最小值。当学习率设置的过小时,收敛过程将变得十分缓慢。而当学习率设置的过大时,梯度可能会在最小值附近来回震荡,甚至可能无法收敛。
Tensorflow中的Tensor就是张量,是多维数据(列表),用阶表示张量的维度
维数 | 阶 | 名字 | 举例 |
---|---|---|---|
0-D | 0 | 标量 scalar | s=123 |
1-D | 1 | 标量 vector | v=[1,2,3] |
2-D | 2 | 标量 matrix | m=[[1,2,3],[2,3,4],[3,4,5]] |
n-D | 3 | 张量 tensor | [[[ (n个括号) |
张量表示0阶到n阶的数组(列表)
tf.int , tf.float
tf.int32 , tf.int64, tf.float32 , tf.float64
tf.bool
tf.constant([Ture,False])
tf,string
tf.constant("Hellow,world!")
# 创建一个张量
# tf.constant(张量内容, dtype=数据类型(可选))
import tensorflow as tf
a = tf.constant([[1, 5],[2,3]], dtype = tf.int64)
print(a) # 输出张量所有信息(内容、形状、数据类型)
print(a.dtype) # 张量的数据类型
print(a.shape) # shape的逗号隔开几个数字,说明该张量是几维的
运行结果:
tf.Tensor(
[[1 5]
[2 3]], shape=(2, 2), dtype=int64)
(2, 2)
将numpy的数据类型转换为Tensor数据类型
# 创建一个张量
# tf.convert_to_tensor(数据名, dtype=数据类型(可选))
import tensorflow as tf
import numpy as np
a = np.arange(0, 5)
b = tf.convert_to_tensor(a, dtype = tf.int64)
print(a)
print(b)
运行结果:
[0 1 2 3 4]
tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64)
# 创建全为0的张量
tf.zeros([3,4])
# 创建全为1的张量
tf.ones(5)
# 创建全为指定值的张量
tf.fill([3,3],1.5)
运行结果:
tf.Tensor(
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]], shape=(3, 4), dtype=float32)
tf.Tensor([1. 1. 1. 1. 1.], shape=(5,), dtype=float32)
tf.Tensor(
[[1.5 1.5 1.5]
[1.5 1.5 1.5]
[1.5 1.5 1.5]], shape=(3, 3), dtype=float32)
# 生成正态分布的随机数,默认均值为0,标准差为1
tf.random.normal(维数, mean = 均值, stddev = 标准差)
# 生成截断式正态分布的随机数,保证生成的随机数在 μ±2σ 之内
tf.random.truncated_normal(维数, mean = 均值, stddev = 标准差)
# 生成均匀分布随机数 [minval ,maxval),前闭后开
tf.random.uniform(维数, minval = 最小值, maxval = 最大值)
a = tf.constant([1, 2, 3], dtype = tf.float64)
# 强制类型转换 tf.cast(张量名, dtype = 数据类型)
a1 = tf.cast(a, tf.int64)
# 张量维度上元素的最小值 tf.reduce_min(张量名)
a1_min = tf.reduce_min(a1)
# 张量维度上元素的最小值 tf.reduce_max(张量名)
a1_max = tf.reduce_max(a1)
print(a)
print(a1)
print(a1_min)
print(a1_max)
运行结果:
tf.Tensor([1. 2. 3.], shape=(3,), dtype=float64)
tf.Tensor([1 2 3], shape=(3,), dtype=int64)
tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(3, shape=(), dtype=int64)
在一个二维张量或数组中,可以通过 axis = 0 或 axis = 1 控制执行维度。
col0 | col1 | col2 | col3 | col4 | col5 | |
---|---|---|---|---|---|---|
row0 | + | → | → | → | → | axis = 1方向 |
row1 | ↓ | |||||
row2 | ↓ | |||||
row3 | ↓ | |||||
row3 | axis = 0方向 |
## 方向如何使用:
x=tf.constant( [ [ 2, 3, 7],[3, 4, 5] ], dtype = tf.float64)
print(x)
print(tf.reduce_mean( x )) # mean 求均值
print(tf.reduce_sum( x, axis=1 )) # sum 求和
运行结果:
tf.Tensor(
[[2. 3. 7.]
[3. 4. 5.]], shape=(2, 3), dtype=float64)
tf.Tensor(4.0, shape=(), dtype=float64)
tf.Tensor([12. 12.], shape=(2,), dtype=float64)
tf.Variable()将变量标记为“可训练的”,被标记的变量会在反向传播中记录梯度信息。神经网络训练中,常用该函数标记带训练参数。
tf.Variable(initial_value,trainable,validate_shape,name)
initial_value 默认为 None,可以搭配 tensorflow 随机生成函数来初始化参数;
trainable 默认为 True,表示可以后期被算法优化的,如果不想该变量被优化,即改为 False;
validate_shape 默认为 True,形状不接受更改,如果需要更改, validate_shape=False;
name 默认为 None,给变量确定名称。
神经网络在训练时,是把输入特征和标签配对后,喂入网络的
features = tf.constant([12,23,10,17])
labels = tf.constant([0, 1, 1, 0])
dataset = tf.data.Dataset.from_tensor_slices((features, labels))
print(dataset)
for element in dataset:
print(element)
运行结果:(将输入与标签配对了)
(, )
(, )
(, )
(, )
with tf.GradientTape( ) as tape:
w = tf.Variable(tf.constant(3.0))
loss = tf.pow(w,2) #loss = w^2
grad = tape.gradient(loss,w)
print(grad)
运算结果:
tf.Tensor(6.0, shape=(), dtype=float32)
seq = ['one', 'two', 'three']
for i, element in enumerate(seq):
print(i, element)
运算结果:
0 one
1 two
2 three
类别 | 0狗尾鸢尾 | 1杂色鸢尾 | 2弗吉尼亚鸢尾 |
---|---|---|---|
独热码 | (0. | 1. | 0.) |
# output = tf.one_hot( 待转换数据, depth = 几分类 )
classes = 3
labels = tf.constant([1,0,2])
output = tf.one_hot( labels, depth = classes ) # 待转换数据中元素应小于depth
print(output)
运行结果:
tf.Tensor(
[[0. 1. 0.]
[1. 0. 0.]
[0. 0. 1.]], shape=(3, 3), dtype=float32)
tf.one_hot()独热码的对比
classes = 3
labels = tf.constant([0,1,2])
output = tf.one_hot( labels, depth = classes )
print(output)
运行结果:
tf.Tensor(
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]], shape=(3, 3), dtype=float32)
对于分类问题,神经网络完成前向传播,计算出了每种类型的可能性大小:
类别 | 0狗尾鸢尾 | 1杂色鸢尾 | 2弗吉尼亚鸢尾 |
---|---|---|---|
输出y | 1.01 | 2.01 | -0.66 |
计算 | e y 0 e y 0 + e y 1 + e y 2 \frac{ {e}^{y_0}}{ {e}^{y_0}+{e}^{y_1}+{e}^{y_2}} ey0+ey1+ey2ey0 | e y 1 e y 0 + e y 1 + e y 2 \frac{ {e}^{y_1}}{ {e}^{y_0}+{e}^{y_1}+{e}^{y_2}} ey0+ey1+ey2ey1 | e y 2 e y 0 + e y 1 + e y 2 \frac{ {e}^{y_2}}{ {e}^{y_0}+{e}^{y_1}+{e}^{y_2}} ey0+ey1+ey2ey2 |
结果 | 2.75 10.73 \frac{2.75}{10.73} 10.732.75 | 7.46 10.73 \frac{7.46}{10.73} 10.737.46 | 0.52 10.73 \frac{0.52}{10.73} 10.730.52 |
概率 | 0.256 | 0.695 | 0.048 |
这些数字只有符合概率分布后,才能与独热码的标签作比较:
s o f t m a x ( y i ) = e y i ∑ j = 1 n e y i softmax(y_i) = \frac{ {e}^{y_i}}{ \sum_{j=1}^n {e}^{y_i}} softmax(yi)=∑j=1neyieyi
y = tf.constant ( [1.01, 2.01, -0.66] )
y_pro = tf.nn.softmax(y)
print(y_pro)
运行结果:
tf.Tensor([0.25598174 0.69583046 0.04818781], shape=(3,), dtype=float32)
w = tf.Variable(4)
w.assign_sub(1) # w = w - 1
print(w)
运行结果:
test = np.array([[1, 2, 3], [2, 3, 4], [4, 5, 6], [5, 6, 7]])
print(test)
print( tf.argmax (test, axis=0)) # 返回每一列(经度)最大值的索引
print( tf.argmax (test, axis=1)) # 返回每一行(纬度)最大值的索引
运行结果:
[[1 2 3]
[2 3 4]
[4 5 6]
[5 6 7]]
tf.Tensor([3 3 3], shape=(3,), dtype=int64)
tf.Tensor([2 2 2 2], shape=(4,), dtype=int64)
类别 | 狗尾鸢尾 | 杂色鸢尾 | 弗吉尼亚鸢尾 |
---|---|---|---|
对应 | 0 | 1 | 2 |
from sklearn import datasets
from pandas import DataFrame
import pandas as pd
import tensorflow as tf
import numpy as np
x_data = datasets.load_iris().data # 从datasets中加载_iris.data数据
y_data = datasets.load_iris().target # 从datasets中加载_iris.target数据
# 用DataFrame将数据变为表格形式,每列增加中文标签
x_data = DataFrame(x_data, columns = ['花萼长', '花萼宽', '花瓣长', '花瓣宽'])
# 设置对齐
pd.set_option('display.unicode.east_asian_width', True)
x_data['类别'] = y_data # 表格中增加y_data列 标签为类别
x_data # 将x_data 显示出来(jupyter)
在jupyter中运行可以得到直观的x_data:
编号 | 花萼长 | 花萼宽 | 花瓣长 | 花瓣宽 | 类别 |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | 0 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | 0 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | 0 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | 0 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | 0 |
… | … | … | … | … | … |
145 | 6.7 | 3.0 | 5.2 | 2.3 | 2 |
146 | 6.3 | 2.5 | 5.0 | 1.9 | 2 |
147 | 6.5 | 3.0 | 5.2 | 2.0 | 2 |
148 | 6.2 | 3.4 | 5.4 | 2.3 | 2 |
149 | 5.9 | 3.0 | 5.1 | 1.8 | 2 |
150 rows × 5 columns
# 接上部分
del x_data, y_data
np.random.seed(116)
np.random.shuffle(x_data) # 在设定的种子下,对x_data第一维(也就是行)数据乱序
np.random.seed(116)
np.random.shuffle(y_data) # 在相同的种子下,对y_data乱序,保证x_data和t_data对应关系不变
np.random.seed(116)
# 前120组为训练集
x_train = x_data[:-30]
y_train = y_data[:-30]
# 后30组为测试集
x_test = x_data[-30:]
y_test = y_data[-30:]
# 数据类型转换为一致,否则矩阵相乘报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# from_tensor_slices() 组成特征&标签对, batch()打包成32个为1撮
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
test_db = tf.data.Dataset.from_tensor_slices((x_test , y_test )).batch(32)
# 生成神经网络参数,4个输入特征,故输入层为4个节点;3分类故输出层为3个神经元
# tf.Variable()标记为可训练
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1))
r = 0.1 # 学习率为0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中, 为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
for epoch in range(epoch): #数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): #batch级别的循环 ,每个step循环一个batch
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.square(y_ - y)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all += loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads = tape.gradient(loss, [w1, b1])
# 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad
w1.assign_sub(lr * grads[0]) # 参数w1自更新
b1.assign_sub(lr * grads[1]) # 参数b自更新
# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all/4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
# 绘制 loss 曲线
plt.figure(num = 1, figsize = (10, 6),dpi = 180)
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
# 绘制 Accuracy 曲线
plt.figure(num = 1, figsize = (10, 6),dpi = 180)
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()