zoukankan      html  css  js  c++  java
  • [北京大学]TensorFlow 2.0 学习笔记(1)-鸢尾花分类

    使用TensorFlow 2.1 对鸢尾花进行分类

    说明:这个系列课程是北京大学的TensorFlow2.0的精品课,讲的细致,干货很多。
    B站传送门
    评论区有代码和PPT课件

    1 安装TensorFlow 2.1和显卡支持

    1.1 安装miniconda或者anaconda

    创建虚拟环境

    conda create -n AI python=3.7
    

    进入虚拟环境

    conda activate AI

    1.1 安装英伟达GPU加速包和TensorFlow 2.1

    conda install cudatoolkit=10.1
    conda install cudnn=7.6
    pip install tensorflow==2.1
    

    1.2 测试TensorFlow是否安装成功

    import tensorflow as tf # 导入tf
    tf.test.is_gpu_available()	# 测试GPU功能是否开启,如果返回True说明没有问题
    

    2 训练鸢尾花分类

    输入数据集特征为['花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度'],标签为:Setosa Iris(狗尾草 鸢尾),Versicolour Iris(杂色鸢尾),Virginica Iris(弗吉尼亚鸢尾)三类,分别用数字0,1,2表示。

    网络模型为:

    训练模型为:

    参数为:w和b

    2.1 导入模块

    # 导入所需模块
    import tensorflow as tf
    from sklearn import datasets
    from matplotlib import pyplot as plt
    import numpy as np
    

    2.1 加载数据集

    使用sklearn加载训练数据集。

    # 导入数据,分别为输入特征和标签
    x_data = datasets.load_iris().data	# (150,3)
    y_data = datasets.load_iris().target # (150)
    

    使用下面的语句输出数据集的shape和dtype

    print("x_data shape:{}, dtype={}".format(x_data.shape, x_data.dtype))
    print("y_data shape:{}, dtype={}".format(y_data.shape, y_data.dtype))
    

    结果:

    x_data shape:(150, 4), dtype=float64	# 特征
    y_data shape:(150,), dtype=int32	# 标签
    

    2.2 数据集乱序

    # 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
    # seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
    np.random.seed(116)  # 使用相同的seed,保证输入特征和标签一一对应
    np.random.shuffle(x_data)
    np.random.seed(116)
    np.random.shuffle(y_data)
    tf.random.set_seed(116)
    

    2.3 分成训练集和数据集

    # 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
    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)
    

    2.4 配成[输入特征,标签]对,每次喂入一小撮(batch)

    # from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次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)
    

    2.5 搭建神经网络,定义神经网络中所有可训练参数

    生成截断式正态分布的随机数

    tf.random.truncated_normal (维度,mean=均值,stddev=标准差)

    在tf.truncated_normal中如果随机生成数据的取值在(μ-2σ,μ+2σ)之外 则重新进行生成,保证了生成值在均值附近。

    μ:均值, σ:标准差

    # 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
    # 用tf.Variable()标记参数可训练
    # 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
    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))
    

    2.6 定义保存数据和学习率等参数

    lr = 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的和
    

    2.7 嵌套循环迭代,with结构更新参数,显示当前loss(训练部分)

    tf.on_hot(x, depth=num)

    对x求独热码,分为num类。比如将一个人分为到【男,女】类别中,那么这个人只能分到其中1类中,那么如果是则为1,不是则为0,那么分类情况就有两种,[0,1]和[1,0],这个就是独热码。三分类就是[0,0,1],[0,1,0],[1,0,0]。

    tf.nn.sotfmax(x)

    使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)

    import tensorflow as tf
    
    a = tf.constant([1,1,1], dtype=tf.float32)
    a_ = tf.nn.softmax(a)
    print(a)
    print(a_)
    

    上面代码输出为:

    tf.Tensor([1. 1. 1.], shape=(3,), dtype=float32)
    tf.Tensor([0.33333334 0.33333334 0.33333334], shape=(3,), dtype=float32)
    

    输出的概率和为1,并且符合概率分布。

    均方误差(MSE)

    是各数据偏离真实值 差值的平方和 的平均数

    # 训练部分
    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做准备
        #(测试部分.....)
    

    2.8 算当前参数前向传播后的准确率,显示当前acc(测试部分)

    for epoch in range(epoch):  #数据集级别的循环,每个epoch循环一次数据集
        #(训练部分.....)
        # 测试部分
        # 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("--------------------------")
    

    2.9 数据可视化loss和acc

    # 绘制 loss 曲线
    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()  # 画出曲线图标
    plt.show()  # 画出图像
    
    # 绘制 Accuracy 曲线
    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()
    
    

    2.10 完整代码

    # -*- coding: UTF-8 -*-
    # 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
    
    # 导入所需模块
    import tensorflow as tf
    from sklearn import datasets
    from matplotlib import pyplot as plt
    import numpy as np
    
    # 导入数据,分别为输入特征和标签
    x_data = datasets.load_iris().data
    y_data = datasets.load_iris().target
    
    # 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
    # seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
    np.random.seed(116)  # 使用相同的seed,保证输入特征和标签一一对应
    np.random.shuffle(x_data)
    np.random.seed(116)
    np.random.shuffle(y_data)
    tf.random.set_seed(116)
    
    # 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
    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)
    
    # from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次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)
    
    # 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
    # 用tf.Variable()标记参数可训练
    # 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
    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 = []  # 将每轮的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.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()  # 画出曲线图标
    plt.show()  # 画出图像
    
    # 绘制 Accuracy 曲线
    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()
    
    

    3 运行结果


  • 相关阅读:
    8.耍杂技的牛 推公式
    内联函数分析
    类的静态成员变量
    操作符重载的概念
    数组本质分析
    动态内存分配
    函数重载分析
    指针本质分析
    单引号和双引号
    内存操作经典问题分析
  • 原文地址:https://www.cnblogs.com/jlxa162hhf/p/14906513.html
Copyright © 2011-2022 走看看