Tensorflow的使用与案例
一:数据类型
tf.int,tf.float…
tf.int32,tf.float32,tf.float64
tf.bool
tf.constant([True,False])
tf.string
tf.constant(“Hello World”)
二:创建Tensor
Tensor意为张量,是多维数组。张量可以表示0阶到n阶数组,阶就是张量的维数。
维数 | 阶 | 名字 | 例子 |
---|---|---|---|
0 | 0 | 标量(scalar) | s = 1 |
1 | 1 | 向量(vector) | v=[1,2,3] |
2 | 2 | 矩阵(matrix) | m=[[1,2,3],[4,5,6],[7,9,9 ]] |
n | n | 张量(tensor) | t=n个列表嵌套而成 |
import tensorflow as tf
ret = tf.constant([1, 2, 3], dtype=tf.int32)
print(ret)
# 结果
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
以上输出中,shape中,用逗号隔开了一个数字,所以它是一个一维张量,数 字3表示有3个元素。
-
将numpy的数据类型转换为Tensor数据类型
tf.convert_to_tensor(数据名,dtype=数据类型)
import tensorflow as tf import numpy as np n = np.arange(0,5) ret = tf.convert_to_tensor(n, dtype=tf.int64) print(ret) # 结果 tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64)
-
创建全为0的张量
tf.zeros(维度)
a = tf.zeros([2, 3]) print(a) # 结果 tf.Tensor( [[0. 0. 0.] [0. 0. 0.]], shape=(2, 3), dtype=float32)
-
创建全为1的张量
tf.ones(维度)
b = tf.ones(4) print(b) # 结果 tf.Tensor([1. 1. 1. 1.], shape=(4,), dtype=float32)
-
创建全为指定值的张量
tf.fill(维度,指定值)
c = tf.fill([2, 2], 9) print(c) # 结果 tf.Tensor( [[9 9] [9 9]], shape=(2, 2), dtype=int32)
注:维度列表中有几个值,则创建一个几维张量
-
生成正态分布的随机数,默认均值为0,标准差为1
tf.random.normal(维度,mean=均值,stddev=标准差)
d = tf.random.normal([2, 3], mean=0.5, stddev=1) print(d) # 结果 tf.Tensor( [[ 2.08641 -0.51270914 1.6858588 ] [ 0.27838406 1.2763277 -0.02637744]], shape=(2, 3), dtype=float32)
-
生成截断式正态分布的随机数
tf.random.truncated_normal(维度,mean=均值,stddev=标准差)
e = tf.random.truncated_normal([2,3], mean=0.5, stddev=1) print(e) # 结果 tf.Tensor( [[ 1.2048004 -0.04421866 0.85759187] [ 0.967208 -1.4424776 1.5051033 ]], shape=(2, 3), dtype=float32)
在tf.random.truncated_normal中,如果随机生成数据的取值在(μ+2σ,μ-2σ)之外,则重新生成,保证了生产值在均值附近。
-
生成均匀分布随机数
tf.random.uniform(维度,minval=最小值,maxval=最大值)
f = tf.random.uniform([2,3], minval=0, maxval=1) print(f) # 结果 tf.Tensor( [[0.03634155 0.28942645 0.11774981] [0.50617504 0.7307261 0.20955396]], shape=(2, 3), dtype=float32)
三:常用函数
-
强制tensor转换为该数据类型
tf.cast(张量名,dtype=数据类型)
x1 = tf.constant([1,2,3], dtype=tf.float64) x2 = tf.cast(x1, dtype=tf.int32) print(x1) print(x2) # 结果 tf.Tensor([1. 2. 3.], shape=(3,), dtype=float64) tf.Tensor([1 2 3], shape=(3,), dtype=int32)
-
计算张量维度上元素的最小值和最大值
tf.reduce_min(张量名)
tf.reduce_max(张量名)
x1 = tf.constant([1,2,3], dtype=tf.float64) ans1 = tf.reduce_min(x1) ans2 = tf.reduce_max(x1) print(ans1) print(ans2) # 结果 tf.Tensor(1.0, shape=(), dtype=float64) tf.Tensor(3.0, shape=(), dtype=float64)
-
axis解析
在一个二维张量或数组中,可以通过调整axis等于0或1控制执行维度。axis=0代表跨行(纵轴),而axis=1代表跨列(横轴)。如果不指定axis,则所有元素参与计算。
-
计算张量沿着指定维度的平均值
tf.reduce_mean(张量名,axis=操作轴)
g = tf.constant([[1,2,3] ,[3,4,5]], dtype=tf.int64) g_mean = tf.reduce_mean(g, axis=0) print(g_mean) # 结果 tf.Tensor([2 3 4], shape=(3,), dtype=int64)
-
计算张量沿着指定维度的和
tf.reduce_sum(张量名,axis=操作轴)
g = tf.constant([[1,2,3] ,[3,4,5]], dtype=tf.int64) g_sum = tf.reduce_sum(g, axis=1) print(g_sum) # 结果 tf.Tensor([ 6 12], shape=(2,), dtype=int64)
-
标记变量为可训练
tf.Variable(初始值)
tf.Variable()将变量标记为“可训练”,被标记的变量会在反向传播中记录梯度信息。神经网络训练中,常用该函数标记待训练参数。
w = tf.Variable(tf.random.normal([2, 3], mean=1, stddev=0))
-
其它函数
-
对应元素四则运算(加减乘除):
tf.add(张量1,张量2)、tf.subtract(张量1,张量2)、tf.multiply(张量1,张量2)、tf.divide(张量1,张量2)
注:只有维度相同的张量才可以做四则运算
-
平方、次方与开方
tf.square(张量名)、tf.pow(张量名,n次方数)、tf.sqrt(张量名)
-
矩阵乘
tf.matmul(矩阵1,矩阵2 )
-
-
特征标签配对函数
tf.data.Dataset.from_tensor_slices((输入特征,标签))
切分传入张量的第一维度,生成输入特征/标签对,构建数据值
注:Numpy和Tensor格式都可以用该语句读入数据
features = tf.constant([12, 23, 10, 17]) labels = tf.constant([0, 1, 1, 0]) dataset = tf.data.Dataset.from_tensor_slices((features,labels)) for element in dataset: print(element) # 结果 (<tf.Tensor: shape=(), dtype=int32, numpy=12>, <tf.Tensor: shape=(), dtype=int32, numpy=0>) (<tf.Tensor: shape=(), dtype=int32, numpy=23>, <tf.Tensor: shape=(), dtype=int32, numpy=1>) (<tf.Tensor: shape=(), dtype=int32, numpy=10>, <tf.Tensor: shape=(), dtype=int32, numpy=1>) (<tf.Tensor: shape=(), dtype=int32, numpy=17>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)
-
with结构
with tf.GradientTape() as tape: 若干个计算过程 grad = tape.gradient(函数,对谁求导)
with结构记录计算过程,gradient求出张量的梯度。我们可以在with结构中使用tf.GradientTape()函数实现某个函数对指定参数的求导运算。配合tf.Variable()函数可以实现损失函数loss对参数w的求导计算过程。
# 创建w^2,并求导 with tf.GradientTape() as tape: w = tf.Variable(tf.constant(3, dtype=tf.float32)) loss = tf.pow(w, 2) grad = tape.gradient(loss, w) print(grad) # 结果 tf.Tensor(6.0, shape=(), dtype=float32)
-
枚举函数(enumerate)
enumerate是python中一个内置函数,它可遍历每个元素(如列表,元组或字符串),结果为一个组合:索引+元素,常在for循环中使用
seq = ["one","two","three"] for i, element in enumerate(seq): print(i,element) # 结果 0 one 1 two 2 three
-
独热编码
tf.one_hot(待转换数据,depth=几分类)
在分类问题中,常用独热码做标签,标记类别为:1表示是,0表示非。
# 独热码 labels = tf.constant([3, 0, 2]) output = tf.one_hot(labels, depth=4) print(output) # 结果 [[0. 0. 0. 1.] [1. 0. 0. 0.] [0. 0. 1. 0.]], shape=(3, 4), dtype=float32)
-
概率分布
tf.nn.softmax(x)
softmax函数的底层计算公式如下:
S o f t m a x ( y i ) = e y i ∑ j = 0 n e y i Softmax(y_i) = \frac{e^{y_i}}{\sum^n_{j=0}e^{y_i}} Softmax(yi)=∑j=0neyieyi其中,yi为神经网络输出值。
softmax函数可以使n个分类的n个输出(y0,y1,…yn)通过softmax()函数符合概率分布,即经过softmax处理过的y值,全部属于0~1,且和为1
y = tf.constant([1.01, 2.01, -0.66]) y_sofa = tf.nn.softmax(y) print(y_sofa) # 结果 tf.Tensor([0.25598174 0.69583046 0.04818781], shape=(3,), dtype=float32)
-
参数自更新
w.assign_sub(w要自减的内容)
常用于参数的自更新,等待自更新的参数w要先被指定为可训练
w = tf.Variable(4) w.assign_sub(1) print(w) # 结果 <tf.Variable 'Variable:0' shape=() dtype=int32, numpy=3>
-
求指定轴最大索引
tf.argmax(张量名,axis=操作轴)
返回张量沿指定维度最大值的索引
text = np.array([[1,2,3],[2,3,4],[5,4,3],[8,7,2]]) ans = tf.argmax(text,axis=0) print(ans) # 结果 tf.Tensor([3 3 1], shape=(3,), dtype=int64)
四:神经网络实现鸢尾花分类
-
步骤
-
准备数据
数据集读入
数据集乱序
生成训练集和测试集
特征和标签配对,每次读入一小撮
-
搭建网络
定义神经网络中所有可训练参数
-
参数优化
嵌套循环迭代,with结构更新参数,显示当前loss
-
测试效果
计算当前参数前向传播后的准确率,显示当前acc(准确率)
-
acc/loss可视化
-
-
代码实现
import pandas as pd import numpy as np import tensorflow as tf import matplotlib.pyplot as plt from sklearn.datasets import load_iris # 读入数据集 x_data = load_iris().data y_data = load_iris().target # iris_df = pd.DataFrame(x_data, columns=["花萼长度", "花萼宽度", "花瓣长度", "花瓣宽度"]) # iris_df["分类"] = y_data # print(iris_df) # 数据集乱序 np.random.seed(116) # 使用相同的seed,使输入特征/标签一一对应 np.random.shuffle(x_data) np.random.seed(116) np.random.shuffle(y_data) np.random.seed(116) # 数据集分出训练集和测试集 x_train = x_data[:-30] y_train = y_data[:-30] x_test = x_data[-30:] y_test = y_data[-30:] # 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错 x_train = tf.cast(x_train, tf.float32) x_test = tf.cast(x_test, tf.float32) # 标签和特征配对,每次向神经网络喂入一个batch的数据 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) # 定义神经网络中所有可训练的参数 w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1)) b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1)) lr = 0.1 # 定义学习率为0.1 train_loss_results = [] # 将每轮的lossj记录在此列表中,为后序loss曲线提供数据 test_acc = [] # 将每轮的acc记录在此列表中,为后序画acc曲线提供数据 epoch = 500 # 循环500轮 loss_all = 0 # 每轮分4个step,loss_all记录4个setp生成的loss和 # 嵌套循环迭代,with结构更新参数,显示当前loss for epoch in range(epoch): # 数据集级别迭代 for setp, (x_train, y_train) in enumerate(train_db): with tf.GradientTape() as tape: # 记录梯度信息 y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算 y = tf.nn.softmax(y) # 使输出的y符合概率分布(此操作后与独热码同量机,可相减求loss) y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为热码格式,方便计算loss loss = tf.reduce_mean(tf.square(y_ - y)) # loss函数为预测值与真实值的均方差 loss_all += loss.numpy() # 将每个step计算出的loss累加,为后序求loss的平均值提供数据 # 计算loss对各个参数的梯度 grads = tape.gradient(loss, [w1, b1]) # 实现梯度更新 w1.assign_sub(lr * grads[0]) # 参数w1自更新 b1.assign_sub(lr * grads[1]) # 参数b1自更新 print(f"Epoch{epoch},loss{loss_all/4}") train_loss_results.append(loss_all/4) loss_all = 0 # 测试部分 # total_corrent为预测对的样本的个数,total_number为测试测总样本数,将这两个变量都初始化为0 total_corrent, 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_corrent += int(correct) # total_number为测试集的样本总数,也就是x_test的行数,shape[0] total_number += x_test.shape[0] # 总的准确率等于total_correct/total_number acc = total_corrent/total_number test_acc.append(acc) print(f"准确率:{acc}") # 绘制loss曲线 plt.title("Loss Function Curve") # 图片标题 plt.xlabel("Epoch") # x轴变量名称 plt.ylabel("Loss") # y轴变量名称 plt.plot(train_loss_results, label="$Loss$") plt.legend() # 画出曲线图标 plt.show() # 绘制Accuracy曲线 plt.title("Acc Curve") plt.xlabel("Epoch") plt.ylabel("ACC") plt.plot(test_acc, label="$Accuracy$") plt.legend() plt.show()
-
图的效果展示: