TensorFlow入门

TensorFlow入门(一)

一、步骤:

①准备数据:采集大量“特征/标签”数据
②搭建网络:搭建神经网络结构
③优化参数:训练网络获取最佳参数(反传)
④应用网络:将网络保存为模型,输入新数据,输出分类或预测结果(前传)

二、鸢尾花分类

1、采集大量数据对(花萼长、花萼宽、花瓣长、花瓣宽,对应的类别)构成数据集。 输入特征 标签
把数据集喂入搭建好的神经网络结构,网络优化参数得到模型,模型读入新输入特征,输出识别结果。
2、输入层四个节点(四个输入特征),输出层三个节点(三种类别)。
3、前向传播:,其中y为1 x 3的输出矩阵,x为1 x 4的输入特征矩阵,w为 4 x 3的权重矩阵,b为1 x 3的偏置项矩阵(3个输出层节点)。
4、损失函数loss:预测值y与标准答案y_的差距。可以定量判断w和b的优劣,当损失函数输出最小时,参数w、b会出现最优值。
5、均方误差
TensorFlow入门_第1张图片
6、梯度下降:
目的:找到一组参数w和b,使得损失函数最小。
梯度:函数对各参数求偏导后的向量。函数梯度下降的方向是函数减小的方向。
梯度下降法:沿损失函数梯度下降的方向,寻找损失函数的最小值,得到最优参数。
学习率lr:当学习率设置的过小时,收敛过程将变得十分缓慢。过大时,梯度可能会在最小值附近来回震荡,甚至无法收敛。
TensorFlow入门_第2张图片
反向传播:从后向前,逐层求损失函数对每层神经元参数的偏导数,迭代更新所有参数。
TensorFlow入门_第3张图片
代码如下:

import tensorflow as tf

w = tf.Variable(tf.constant(value=[5], shape=(1, 1), dtype=tf.dtypes.float32)) # 生成权重张量,tf.Variable设定为可训练
lr = 0.2 # 初始化学习率
epoch = 50 # 迭代的轮数

for i in range(epoch):
    with tf.GradientTape() as tape: # 梯度计算框架
        loss = tf.square(w + 1) # 损失函数,square为平方函数
        grads = tape.gradient(loss, w) # 梯度:损失函数loss对w求导
        pass
    w.assign_sub(lr*grads) # 自减,相当于: w -= lr*grads
    print("After %s epoch,w is %f,loss is %f" % (epoch, w.numpy(), loss)) # w.numpy()将张量形式转化为numpy格式,相关代码如下。
    pass

a = tf.Variable(tf.constant([[1, 2, 3], [2, 3, 4]], shape=[2, 3], dtype=tf.dtypes.float32))
print(a)
# 
# array([[1., 2., 3.],
#        [2., 3., 4.]], dtype=float32)>
print(a.numpy())
# [[1. 2. 3.]
#  [2. 3. 4.]]
print(type(a.numpy()))
# 

三、常用函数

1、创建张量

a = tf.Variable(tf.constant(5.0))
b = tf.Variable(tf.constant([5.0]))
c = tf.Variable(tf.constant([[5.0]]))
d = tf.Variable(tf.constant([5.0], shape=(1, 1)))
e = tf.Variable(tf.constant([5.0], shape=(1)))
# 注意差别
print(a) # 
print(b) # 
print(c) # 
print(d) # 
print(e) # 

2、类型转换及最值

a = tf.constant([1, 2], shape=(1, 2), dtype=tf.dtypes.float32, name='a')

# 强制转换类型
b = tf.cast(x=a, dtype=tf.dtypes.int32) # tf.cast(张量名, dtype=数据类型)
print(a) # tf.Tensor([[1. 2.]], shape=(1, 2), dtype=float32)
print(b) # tf.Tensor([[1 2]], shape=(1, 2), dtype=int32)

# 计算张量维度上元素的最小值
print(tf.reduce_min(input_tensor=a)) # tf.Tensor(1.0, shape=(), dtype=float32)

# 计算张量维度上元素的最大值
print(tf.reduce_max(input_tensor=a)) # tf.Tensor(2.0, shape=(), dtype=float32)

3、参数axis:在一个二维张量中,可以通过调整axis等与0或1控制执行维度。axis=0代表跨行(经度,down),axis=1代表跨列(纬度,across),不指定的话则所有元素参与计算。

a = tf.constant([[1, 2, 3],
                 [2, 3, 4]], dtype=tf.dtypes.float32, shape=(2, 3), name='a')

# 计算张量沿指定维度的平均值
b = tf.reduce_mean(input_tensor=a, axis=0)
c = tf.reduce_mean(input_tensor=a, axis=1)
print(b) # tf.Tensor([1.5 2.5 3.5], shape=(3,), dtype=float32)
print(c) # tf.Tensor([2. 3.], shape=(2,), dtype=float32)

# 计算张量沿指定维度的和
d = tf.reduce_sum(input_tensor=a, axis=0)
e = tf.reduce_sum(input_tensor=a, axis=1)
print(d) # tf.Tensor([3. 5. 7.], shape=(3,), dtype=float32)
print(e) # tf.Tensor([6. 9.], shape=(2,), dtype=float32)

4、tf.Variable()函数将变量标记为“可训练”,被标记的变量会在反向传播中记录梯度信息。神经网络训练中,常用该函数标记待训练参数。
5、数学运算:

a = tf.constant(value=[1, 2, 3], dtype=tf.dtypes.float32, shape=(1, 3), name='a')
b = tf.constant(value=[2, 3, 4], dtype=tf.dtypes.float32, shape=(1, 3), name='b')

# 对应元素四则运算(维度相同):加、减、乘、除
print(tf.add(x=a, y=b, name='add')) # tf.Tensor([[3. 5. 7.]], shape=(1, 3), dtype=float32)
print(tf.subtract(x=a, y=b, name='subtract')) # tf.Tensor([[-1. -1. -1.]], shape=(1, 3), dtype=float32)
print(tf.multiply(x=a, y=b, name='multiply')) # tf.Tensor([[ 2.  6. 12.]], shape=(1, 3), dtype=float32)
print(tf.divide(x=a, y=b, name='divide')) # tf.Tensor([[0.5       0.6666667 0.75     ]], shape=(1, 3), dtype=float32)

# 平方、n次方与开方
c = tf.fill(dims=(1, 2), value=2., name='c') # 生成1 x 2,值为2的张量
print(tf.square(x=c, name='square')) # tf.Tensor([[4. 4.]], shape=(1, 2), dtype=float32)
print(tf.pow(x=c, y=3, name='pow')) # tf.Tensor([[8. 8.]], shape=(1, 2), dtype=float32)
print(tf.sqrt(x=c, name='sqrt')) # tf.Tensor([[1.4142135 1.4142135]], shape=(1, 2), dtype=float32)

# 矩阵相乘
e = tf.constant([[2, 3, 4],
                 [3, 4, 5]], shape=(2, 3), dtype=tf.dtypes.float32, name='e')
f = tf.constant([[2, 3],
                 [3, 4],
                 [4, 5]], shape=(3, 2), dtype=tf.dtypes.float32, name='f')
print(tf.matmul(a=e, b=f, name='matmul'))
# tf.Tensor(
# [[29. 38.]
#  [38. 50.]], shape=(2, 2), dtype=float32)

6、神经网络在训练时,是把输入特征和标签配对后喂入网络的。tf.data.Dataset.from_tensor_slices()函数,切分传入张量的第一维度,生成输入特征/标签对,构建数据集data=tf.data.Dataset.from_tensor_slices((输入特征, 输出特征)),且NumPy格式和Tensor格式都可用该语句读入数据。

features = tf.constant([12, 23, 10, 17], dtype=tf.dtypes.float32, name='features')
labels = tf.constant([0, 1, 1, 0], dtype=tf.dtypes.int32, name='labels')

datasets = tf.data.Dataset.from_tensor_slices((features, labels))
print(datasets) # 

for element in datasets:
    print(element)
    pass
# (, )
# (, )
# (, )
# (, )

7、函数对指定参数求导

with tf.GradientTape() as tape:
    w = tf.Variable(tf.constant(value=[3.], shape=(1, 1), dtype=tf.dtypes.float32))
    loss = tf.square(w + 1)
    pass
grad = tape.gradient(target=loss, sources=w)

print(grad) # tf.Tensor([[8.]], shape=(1, 1), dtype=float32)

8、enumerate()函数:可遍历每个元素(如列表、元组或字符串),组合为:索引 元素,常在for循环中使用。

list = ['one', 'two', 'three']
for index, element in enumerate(list):
    print(index, element)
    pass
# 0 one
# 1 two
# 2 three

9、独热编码tf.one_hot():在分类问题中,常用独热码做标签,标记类别:1表示是,0表示非。
鸢尾花(标签0表示狗尾草鸢尾,1表示杂色鸢尾,2表示弗吉尼亚鸢尾)
则标签为1表示分类结果为杂色鸢尾,用独热码的形式表示为(0. 1. 0.)

# tf.one_hot(indices=待转换数据, depth=几分类)

classes = 3 # 三分类
labels = tf.constant([1, 0, 2]) # 输入的元素最小为0,最大为2
output = tf.one_hot(indices=labels, depth=classes)

print(output)
# tf.Tensor(
# [[0. 1. 0.] 是/非0
#  [1. 0. 0.] 是/非1
#  [0. 0. 1.]], shape=(3, 3), dtype=float32) 是/非2

10、对于分类问题,神经网络完成前向传播,计算出每种类型的可能性大小,这些数字只有符合概率分布之后,才可以与独热码的标签作比较,此时使用函数tf.nn.softmax(x)是输出符合概率分布。
11、tf.argmax()函数返回沿指定维度最大值的索引

import numpy as np
import tensorflow as tf

test = np.array([[1, 2, 3], [2, 3, 4], [5, 4, 3], [8, 7, 2]])
print("test:\n", test)
print("每一列的最大值的索引:", tf.argmax(test, axis=0))  # 跨行,即每一列最大值
print("每一行的最大值的索引", tf.argmax(test, axis=1))  # 跨列,即每一行最大值
# 每一列的最大值的索引: tf.Tensor([3 3 1], shape=(3,), dtype=int64)
# 每一行的最大值的索引 tf.Tensor([2 2 0 0], shape=(4,), dtype=int64)

四、神经网络实现鸢尾花分类

1、鸢尾花数据集读入:直接从sklearn包datasets读入数据集,语法为:

from sklearn import datasets

feature_data = datasets.load_iris().data
label_data = datasets.load_iris().target

2、步骤:
①准备数据:数据集读入、数据集乱序、生成训练集和测试集、配对、每次读入一小撮。
②搭建网络:定义神经网络中所有可训练参数。
③参数优化:嵌套循环迭代,with结构更新参数,显示当前loss
④测试效果:计算当前参数前向传播后的准确率,显示当前accuracy
⑤accuracy/loss可视化

import tensorflow as tf
from sklearn import datasets # 数据集导入
from matplotlib import pyplot as plt # 可视化
import numpy as np

# 数据集读入
feature_data = datasets.load_iris().data # 输入特征
label_data = datasets.load_iris().target # 标签

# 数据集乱序(原始数据有顺序,不打乱会影响准确率)
seed = 110 # 设置同一个随机种子,保证在乱序后输入特征和标签一一对应
np.random.seed(seed=seed)
np.random.shuffle(feature_data)
np.random.seed(seed=seed)
np.random.shuffle(label_data)
tf.random.set_seed(seed=seed)

# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
feature_train = feature_data[:-30]
label_train = label_data[:-30]
feature_test = feature_data[-30:]
label_test = label_data[-30:]

# 强制转变特征数据类型,防止矩阵相乘时报错
feature_train = tf.cast(x=feature_train, dtype=tf.dtypes.float32)
feature_test = tf.cast(x=feature_test, dtype=tf.dtypes.float32)

# 配成[输入特征, 标签]对,每次喂入一个batch
train_db = tf.data.Dataset.from_tensor_slices(tensors=(feature_train, label_train)).batch(32)
test_db = tf.data.Dataset.from_tensor_slices(tensors=(feature_test, label_test)).batch(32)

# 生成神经网络的参数,4个输入特征,故输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
w = tf.Variable(tf.random.truncated_normal(shape=[4, 3], stddev=0.1))
b = tf.Variable(tf.random.truncated_normal(shape=[1, 3], stddev=0.1))

lr = 0.1 # 学习率设置为0.1
train_loss_result = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_accuracy = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 5000 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和

# 训练
for i in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
    for step, (feature_train, label_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
        with tf.GradientTape() as tape:
            y = tf.nn.softmax(tf.matmul(feature_train, w) + b) # 执行前向传播,并使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
            y_ = tf.one_hot(indices=label_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
            loss = tf.reduce_mean(tf.square(y - y_)) # 均方误差损失函数
            loss_all += loss.numpy()
            pass
        grads = tape.gradient(target=loss, sources=[w, b])

        # 梯度下降 反向传播更新参数
        w.assign_sub(lr * grads[0])
        b.assign_sub(lr * grads[1])
        pass

    # 每个epoch,打印loss信息
    print("Epoch {}, loss: {}".format(i + 1, loss_all / 4))
    train_loss_result.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 feature_test, label_test in test_db:
        # 使用更新后的参数进行预测
        y = tf.nn.softmax(tf.matmul(feature_test, w) + b) # 30 x 3
        # 返回预测结果中每行最大值的索引,数值上等于预测的分类
        index = tf.argmax(input=y, axis=1) 
        index = tf.cast(x=index, dtype=label_test.dtype) # 转换为label_test的数据类型
        # 若分类正确,则correct=True,否则为False,并将bool型的结果转换为int型
        correct = tf.cast(tf.equal(index, label_test), dtype=tf.dtypes.int32)
        # 将每个batch的correct数加起来
        correct = tf.reduce_sum(correct)
        # 将所有batch中的correct数加起来
        total_correct += int(correct)
        # total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
        total_number += feature_test.shape[0]
        pass
    # 总的准确率等于total_correct/total_number
    accuracy = total_correct / total_number
    test_accuracy.append(accuracy)
    print("Test_accuracy:", accuracy)
    print("--------------------------")
    pass

# 绘制 loss 曲线
plt.title('Loss Function Curve')  # 图片标题
plt.xlabel('Epoch')  # x轴变量名称
plt.ylabel('Loss')  # y轴变量名称
plt.plot(train_loss_result, label="$Loss$")  # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend()  # 画出曲线图标
plt.show()  # 画出图像

# 绘制 Accuracy 曲线
plt.title('Acc Curve')  # 图片标题
plt.xlabel('Epoch')  # x轴变量名称
plt.ylabel('Acc')  # y轴变量名称
plt.plot(test_accuracy, label="$Accuracy$")  # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()

你可能感兴趣的:(神经网络,tensorflow,python)