0
点赞
收藏
分享

微信扫一扫

Tensorflow2.0学习教程Class2.6_神经网络参数优化器对比

朱小落 2022-03-31 阅读 45

详细学习视频链接:
北京大学
几中优化器的对比实验都基于Class1.2_鸢尾花分类代码:
Tensorflow2.0学习教程Class1.2(实现鸢尾花分类__iris数据集)详细注释

神经网络参数优化器简介
在这里插入图片描述
SGD优化器
在这里插入图片描述
在这里插入图片描述
效果:total_time 6.422186613082886
在这里插入图片描述
在这里插入图片描述

SGDM优化器
在这里插入图片描述
在这里插入图片描述
效果:total_time 6.045186758041382
在这里插入图片描述
在这里插入图片描述

Adagrad优化器
在这里插入图片描述
在这里插入图片描述
效果:total_time 6.311020135879517
在这里插入图片描述
在这里插入图片描述

RMSProp优化器
在这里插入图片描述
在这里插入图片描述
效果:total_time 6.230712890625
在这里插入图片描述
在这里插入图片描述

Adam优化器
在这里插入图片描述
在这里插入图片描述
效果:total_time 7.851320028305054
在这里插入图片描述
在这里插入图片描述

结论:Adam优化器的效果最好

几种优化器的代码如下:可直接运行Adam优化器,其他几种优化器的实现在注释中,去掉注释即可

# TF2 实现利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线
from sklearn import datasets
from pandas import DataFrame
import pandas as pd
import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
import time  ##1##
'''
准备数据:
    1.数据集读入
    2.数据集乱序
    3.生成训练集和测试集(x_train/y_train,x_test/y_train)
    4.配对(输入特征,标签),每次读入一小撮(batch)
'''
# 1.数据集读入
# 从sklearn包datasets读入数据集
x_data=datasets.load_iris().data#.data返回iris数据集的所有输出特征
y_data=datasets.load_iris().target#.target返回iris数据集的所有标签
# print(x_data)
# print(y_data)

# # 为表格增加行索引(左侧)和列标签(上方)
# x_data=DataFrame(x_data,columns=['花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度'])
# # 设置列名对齐
# pd.set_option('display.unicode.east_asian_width', True)
# # print(x_data)
#
# # 新加一列,列标签为‘类别’,数据为y_data
# x_data['类别']=y_data
# print(x_data)
#类型维度不确定时,建议用print函数打印出来确认效果

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

# 3.生成训练集和测试集(x_train/y_train,x_test/y_train)\
# 训练集和测试集没有交集
x_train=x_data[:-30]
y_train=y_data[:-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)

# 4.配对(输入特征,标签),每次读入一小撮(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)
w=tf.Variable(tf.random.truncated_normal([4,3],stddev=0.1))
b=tf.Variable(tf.random.truncated_normal([3],stddev=0.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的和

##########################################################################
#SGDM优化器
#m_w, m_b = 0, 0#一阶栋梁初始值为0
#beta = 0.9#超参数,(经验值)
##########################################################################
#Adagrad优化器
#v_w, v_b = 0, 0#二阶动量初始值为0
##########################################################################
#RMSProp优化器
# v_w, v_b = 0, 0
# beta = 0.9
##########################################################################
#Adam优化器
m_w, m_b = 0, 0
v_w, v_b = 0, 0
beta1, beta2 = 0.9, 0.999
delta_w, delta_b = 0, 0
global_step = 0
##########################################################################

'''
参数优化:
    嵌套循环迭代,with结构更新参数,显示当前loss
'''
now_time = time.time() #Class2_优化器
for epoch in range(epoch):#整个数据集循环500次
    for step,(x_train,y_train) in enumerate(train_db):#batch级别的循环 ,每个step循环一个batch
        ##########################################################################
        global_step += 1#Adam优化器
        ##########################################################################
        with tf.GradientTape() as tape:# with结构记录梯度信息
            y=tf.matmul(x_train,w)+b# 神经网络乘加运算
            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对各个参数的梯度
        grad=tape.gradient(loss,[w,b])#对loss求导并带入w,b的值
        # 实现梯度更新 w = w - lr * w_grad    b = b - lr * b_grad
        #########################################################
        # # SGD优化器
        # w.assign_sub(lr*grad[0])
        # b.assign_sub(lr*grad[1])
        #########################################################
        # # SGD-momentun优化器(SGDM)
        # m_w = beta * m_w + (1 - beta) * grad[0]
        # m_b = beta * m_b + (1 - beta) * grad[1]
        # w.assign_sub(lr * m_w)
        # b.assign_sub(lr * m_b)
        #########################################################
        # Adagrad优化器
        # v_w += tf.square(grad[0])
        # v_b += tf.square(grad[1])
        # w.assign_sub(lr * grad[0] / tf.sqrt(v_w))
        # b.assign_sub(lr * grad[1] / tf.sqrt(v_b))
        #########################################################
        # RMSProp
        # v_w = beta * v_w + (1 - beta) * tf.square(grad[0])
        # v_b = beta * v_b + (1 - beta) * tf.square(grad[1])
        # w.assign_sub(lr * grad[0] / tf.sqrt(v_w))
        # b.assign_sub(lr * grad[1] / tf.sqrt(v_b))
        #########################################################
        # Adam优化器
        m_w = beta1 * m_w + (1 - beta1) * grad[0]
        m_b = beta1 * m_b + (1 - beta1) * grad[1]
        v_w = beta2 * v_w + (1 - beta2) * tf.square(grad[0])
        v_b = beta2 * v_b + (1 - beta2) * tf.square(grad[1])

        m_w_correction = m_w / (1 - tf.pow(beta1, int(global_step)))
        m_b_correction = m_b / (1 - tf.pow(beta1, int(global_step)))
        v_w_correction = v_w / (1 - tf.pow(beta2, int(global_step)))
        v_b_correction = v_b / (1 - tf.pow(beta2, int(global_step)))

        w.assign_sub(lr * m_w_correction / tf.sqrt(v_w_correction))
        b.assign_sub(lr * m_b_correction / tf.sqrt(v_b_correction))
        ##########################################################


    # 每个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做准备

    '''
    测试效果:
        计算当前参数前向传播后的准确率,显示当前acc
    '''
    # total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
    total_correct,total_number=0,0
    for x_test, y_test in test_db:#30个测试样本
        # 使用更新后的参数进行预测
        y = tf.matmul(x_test, w) + b
        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.equal(pred, y_test)
        correct = tf.cast(correct,dtype=tf.int32)
        # 将每个batch的correct数加起来
        correct = tf.reduce_sum(correct)#自增+1
        # 将所有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("--------------------------")
total_time = time.time() - now_time  #Class2_优化器
print("total_time", total_time)  #Class2_优化器

'''
acc/loss可视化
'''
# 绘制 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()
举报

相关推荐

0 条评论