tensorflow中Adam优化器运用

tensorflow中Adam优化器运用

Adam优化器引用API:tensorflow.keras.optimizers.Adam

代码实现:

#Adam

#求一阶动量和二阶动量

m_w = beta1 * m_w + (1 - beta1) * grads[0] #求一阶动量m_w,和SGDM一阶动量表达式一样

m_b = beta1 * m_b + (1 - beta1) * grads[1] #求一阶动量m_b,和SGDM一阶动量表达式一样

v_w = beta2 * v_w + (1 - beta2) * tf.square(grads[0]) #求二阶动量v_w,和RMSprop的二阶动量表达式一样

v_b = beta2 * v_b + (1 - beta2) * tf.square(grads[1]) #求二阶动量b_b,和RMSprop的二阶动量表达式一样

#求修正项

m_w_correction = m_w / (1 -tf.pow(beta1, int(global_step))) #对一阶动量m_w除以一个式子得到修正项m_w_correction

m_b_correction = m_w / (1 -tf.pow(beta1, int(global_step))) #对一阶动量m_b除以一个式子得到修正项m_b_correction

v_w_correction = v_w / (1 -tf.pow(beta2, int(global_step))) #对一阶动量v_w除以一个式子得到修正项v_w_correction

v_b_correction = v_b / (1 -tf.pow(beta2, int(global_step))) #对一阶动量v_b除以一个式子得到修正项v_w_correction

#参数自更新

w1.assign_sub(learning_rate * m_w_correction / tf.sqrt(v_w_correction)) #参数w1自更新

b1.assign_sub(learning_rate * m_b_correction / tf.sqrt(v_b_correction)) #参数b1自更新)

Adam优化器实现iris数据集分类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#导入模块
import tensorflow as tf #导入tensorflow模块

from sklearn import datasets #导入sklearn中的datasets模块,方便下载内置的iris数据集

from matplotlib import pyplot as plt #导入matplotlib中的pyplot,待会画图

import numpy as np #导入numpy模块做数学运算

import time #导入时间模块,用来计时

#导入数据
x_data = datasets.load_iris().data #导入iris数据集的特征

y_data = datasets.load_iris().target #导入iris数据集的标签

#随机打乱顺序,使训练更具准确性
np.random.seed(120)#调用numpy中的random方法里的seed方法,赋值120,使输入特征和标签能够一一对应

np.random.shuffle(x_data) #调用numpy中的random方法里的shuffle方法,将训练集x_data里的特征值乱序

np.random.seed(120)#调用numpy中的random方法里的seed方法,赋值120,使输入特征和标签能够一一对应

np.random.shuffle(y_data) #调用numpy中的random方法里的shuffle方法,将测试集y_data里的标签乱序

tf.random.set_seed(120)#调用tensorflow中的random方法里的set_seed方法,赋值120

#划分数据集
x_train = x_data[:-30] #将iris数据集(特征,共150行,此时已打乱)前120行作为训练集x_train

y_train = y_data[:-30] #将iris数据集(标签,共150行,此时已打乱)前120行作为训练集y_train

x_test = x_data[-30:] #将iris数据集(特征,共150行,此时已打乱)最后30行作为测试集x_test

y_test = y_data[-30:] #将iris数据集(标签,共150行,此时已打乱)最后30行作为测试集y_test

#转换特征值的数据类型,使之与后面数据运算时数据类型一致
x_train = tf.cast(x_train, dtype = tf.float32) #调用tensorflow中的cast方法,将x_train中的特征值类型转换为float32

x_test = tf.cast(x_test, dtype = tf.float32) #调用tensorflow中的cast方法,将x_test中的特征值类型转换为float32

#用from_tensor_slices方法将特征值和标签值配对
train_data_batch = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)#将训练集的特征x_train和标签y_train配对,用batch方法将120个训练数据分成32个为一组的批次

test_data_batch = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)#将测试集的特征x_test和标签y_test配对,用batch方法将30个训练数据分成32个为一组的批次

#用truncated_normal方法构建神经网络,并用Variable方法标记可训练数据
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev = 0.1, seed = 1))#用truncated_normal方法,构建4个输入特征,3个分类的神经网络结构,标准差为0.1的正态分布,随机种子为1

b1 = tf.Variable(tf.random.truncated_normal([3], stddev = 0.1, seed = 1))#用truncated_normal方法,因为b1和w1的分类维度要一样,所以是3,标准差为0.1的正态分布,随机种子为1

#设置变量
learnRate = 0.1 #学习率为0.1

train_loss_results = [] #将每轮的loss记录在此列表中,为后面画loss曲线时提供数据

test_accuracy = [] #将每轮的精度accuracy记录在此列表中,为后面画精度accuracy曲线提供数据

epoch = 500 #循环500轮

loss_all = 0 #每轮分4个step,loss_all记录4个step生成的4个loss的和

#############################################################
#SGDM优化器参数设置
# m_w, m_b = 0, 0 #初始化一阶动量m_w, m_b为0
#
# beta = 0.9 #设置超参数为0.9
#############################################################
#############################################################
#Adagrad优化器参数设置
# v_w, v_b = 0, 0 #初始化二阶动量v_w, v_b
#############################################################
#############################################################
#RMSprop优化器参数设置
# v_w, v_b = 0, 0 #初始化二阶动量v_w, v_b
# beta = 0.9 #初始化超参数为0.9
#############################################################
#############################################################
#Adam优化器参数设置
m_w, m_b = 0, 0 #初始化一阶动量m_w, m_b
v_w, v_b = 0, 0 #初始化二阶动量v_w, v_b
beta1, beta2 = 0.9, 0.999 #初始化超参数
delta_w, delta_b = 0, 0
global_step = 0 #定义训练的总batch数为global_step
#############################################################

#训练部分
now_time = time.time() #用时间戳记录训练起始时间now_time

for epoch in range(epoch): #遍历数据集,每个epoch循环一次数据集
    for step, (x_train, y_train) in enumerate(train_data_batch): #遍历batch,每个step循环一次batch
        ##########################################
        global_step +=1 #每循环一个btach,global_step自加1
        ############################################
        with tf.GradientTape() as tape: #用上下文管理器记录梯度信息
            y = tf.matmul(x_train, w1) + b1 #神经网络乘加运算,用tensorflow中的matmul方法将训练特征值x_train和w1参数进行矩阵相乘
            y = tf.nn.softmax(y) #用tensorflow中的softmax方法将神经网络乘加运算后得到的输出符合正态分布,输出和为1,可以在之后用来与独热码相减求loss
            y_one_hot = tf.one_hot(y_train, depth = 3) #用tensorflow中的one_hot方法将训练标签y_train转换为独热码格式,因为y输出为3,所以深度为3,方便接下来计算loss的和
            loss = tf.reduce_mean(tf.square(y_one_hot - y)) #用tensorflow中的reduce_mean方法求平均值,用tensorflow中的square方法求平方,这里用均方误差求损失函数loss
            loss_all += loss.numpy() #将每个step计算出的loss累加,后面可以用来求loss平均值,

        #计算loss对各个参数的梯度
        loss_gradient = tape.gradient(loss, [w1, b1])#用tensorflow中的GradientTape方法中的gradient方法求loss对各个参数w1,b1的梯度gradient
        #############################################################
        # Adam优化器,进行梯度更新
        #求一阶动量和二阶动量
        m_w = beta1 * m_w + (1 - beta1) * loss_gradient[0]  #求一阶动量m_w,和SGDM一阶动量表达式一样
        m_b = beta1 * m_b + (1 - beta1) * loss_gradient[1]  #求一阶动量m_b,和SGDM一阶动量表达式一样
        v_w = beta2 * v_w + (1 - beta2) * tf.square(loss_gradient[0])  #求二阶动量v_w,和RMSprop的二阶动量表达式一样
        v_b = beta2 * v_b + (1 - beta2) * tf.square(loss_gradient[1])  #求二阶动量v_b,和RMSprop的二阶动量表达式一样
        #求修正项
        m_w_correction = m_w / (1 - tf.pow(beta1, int(global_step))) #对一阶动量m_w除以一个式子得到修正项m_w_correction
        m_b_correction = m_b / (1 - tf.pow(beta1, int(global_step)))  #对一阶动量m_b除以一个式子得到修正项m_b_correction
        v_w_correction = v_w / (1 - tf.pow(beta2, int(global_step))) #对一阶动量v_w除以一个式子得到修正项v_w_correction
        v_b_correction = v_b / (1 - tf.pow(beta2, int(global_step))) #对一阶动量v_b除以一个式子得到修正项v_w_correction

#参数自更新

        #参数自更新
        w1.assign_sub(learnRate * m_w_correction / tf.sqrt(v_w_correction)) #参数w1自更新
        b1.assign_sub(learnRate * m_b_correction / tf.sqrt(v_b_correction)) #参数b1自更新)



        #############################################################
        #############################################################
        # RMSprop优化器,进行梯度更新
        # v_w = beta * v_w + (1 - beta) * tf.square(loss_gradient[0]) #计算二阶动量v_w
        # v_b = beta * v_b + (1 - beta) * tf.square(loss_gradient[1]) #计算二阶动量v_b
        # w1.assign_sub(learnRate * loss_gradient[0] / tf.sqrt(v_w)) #自更新w1
        # b1.assign_sub(learnRate * loss_gradient[1] / tf.sqrt(v_b)) #自更新b1

        #############################################################
        #############################################################
        # Adagrad优化器,进行梯度更新
        # v_w += tf.square(loss_gradient[0]) #求二阶动量v_w,从开始到此刻梯度的平方和
        # v_b += tf.square(loss_gradient[1]) #求二阶动量v_b,从开始到此刻梯度的平方和
        # w1.assign_sub(learnRate * loss_gradient[0] /tf.sqrt(v_w)) #对参数w1进行更新
        # b1.assign_sub(learnRate * loss_gradient[1] / tf.sqrt(v_b)) #对参数b1进行更新

        #############################################################
        #############################################################
        #SGDM优化器,进行梯度更新
        # m_w = beta * m_w + (1 - beta) * loss_gradient[0] #求一阶动量m_w
        # m_b = beta * m_b + (1 - beta) * loss_gradient[1] #求一阶动量m_b
        # w1.assign_sub(learnRate * m_w) #对参数w1进行更新
        # b1.assign_sub(learnRate * m_b) #对参数b1进行更新
        #############################################################

        #############################################################

        # 梯度更新,使用了SGD(无monentum)优化器
        # w1.assign_sub(
        #     learnRate * loss_gradient[0])  # 用assign_sub方法进行自减,实现参数w1的自动更新,等价于w1 = w1 - learn_Rate * loss_gradient[0]
        # b1.assign_sub(
        #     learnRate * loss_gradient[1])  # 用assign_sub方法进行自减,实现参数b1的自动更新,等价于b = b - learn_Rate * loss_gradient[1]

        #############################################################


    # 每个epoch,打印loss信息
    print("epoch: {}, loss: {}".format(epoch,loss_all / 4))  # 每个epoch,打印loss信息,有4个step,所以总loss_all要除以4,求得每次step的平均loss
    train_loss_results.append(loss_all / 4)  # 用append方法将4个step的loss求平均值记录在train_loss_results中
    loss_all = 0  # loss_all归零,为下一个epoch的求loss做准备

    # 测试部分
    total_correct = 0  # total_correct为预测对的样本个数,初始化为0
    total_test_number = 0  # total_number为测试的总样本数,初始化为0

    for x_test, y_test in test_data_batch:  # 遍历训练集的特征值和标签值
        # 用更新后的参数进行预测
        y = tf.matmul(x_test, w1) + b1  # 用tensorflow中的matmul方法来进行乘加运算,再加上b1得到前向传播的结果
        y = tf.nn.softmax(y)  # 用tensorflow中的softmax方法将神经网络乘加运算后得到的前向传播的结果符合正态分布,输出和为1,可以在之后用来与独热码相减求loss
        predict = tf.argmax(y, axis=1)  # 用tensorflow中的argmax方法,返回y中最大值的索引,即预测的标签分类,axis表示按列求值
        predict = tf.cast(predict, dtype=y_test.dtype)  # 将predict的类型转换为测试集标签y_test的数据类型
        correct = tf.cast(tf.equal(predict, y_test),
                          dtype=tf.int32)  # 用tensorflow中的equal方法判断,若分类正确,则值为1,否则为0,并用tensorflow中的cast方法将bool类型转化为int32类型
        correct = tf.reduce_sum(correct)  # 用tensorflow中的reduce_sum方法将每个batch的correct数加起来
        total_correct += int(correct)  # 将所有batch中的correct数转化为int类型,并加起来
        total_test_number += x_test.shape[0]  # 用shape方法返回测试集特征x_test的行数,也就是测试的总样本数

    accuracy = total_correct / total_test_number  # 总的准确率
    test_accuracy.append(accuracy)  # 测试集的准确率添加到列表中来,方便记录
    print("test_accuracy:", accuracy)  # 打印测试集精度准确率
    print("-------------------------------------------------")  # 为每个epoch进行分隔,方便查看

total_time = time.time() - now_time #用时间戳记录总训练时间total_time

print("total_time:", total_time) #打印总训练时间total_time

# 绘制loss曲线
plt.title('Loss Function Curve')  # 用matplotlib中的title方法标出图片标题
plt.xlabel("Epoch")  # 用matplotlib中的xlabel方法标出x轴变量名称
plt.ylabel("Loss")  # 用matplotlib中的ylabel方法标出y轴变量名称
plt.plot(train_loss_results, label="$Loss$")  # 用matplotlib中的plot方法逐点画出训练集损失值结果train_loss_results值并连线,连线的标签为Loss
plt.legend()  # 用matplotlib中的legend方法画出曲线图标
plt.show()  # 用matplotlib中的show方法画出图像

# 绘制accuracy曲线
plt.title("Accuracy Curve")  # 用matplotlib中的title方法标出图片标题
plt.xlabel("Epoch")  # 用matplotlib中的xlabel方法标出x轴变量名称
plt.ylabel("Accuracy")  # 用matplotlib中的ylabel方法标出y轴变量名称
plt.plot(test_accuracy, label="$Accuracy$")  ##用matplotlib中的plot方法逐点画出测试集精准度test_accuracy值并连线,连线的标签为Accuracy
plt.legend()  # 用matplotlib中的legend方法画出曲线图标
plt.show()  # 用matplotlib中的show方法画出图像

结果为:

E:\Anaconda3\envs\TF2\python.exe C:/Users/Administrator/PycharmProjects/untitled8/iris数据集分类.py
epoch: 0, loss: 0.26738786324858665
test_accuracy: 0.5666666666666667
-------------------------------------------------
epoch: 1, loss: 0.22386804968118668
test_accuracy: 0.6333333333333333
-------------------------------------------------
epoch: 2, loss: 0.17018816992640495
test_accuracy: 0.6333333333333333
-------------------------------------------------
省略........
-------------------------------------------------
epoch: 498, loss: 0.010133910043805372
test_accuracy: 1.0
-------------------------------------------------
epoch: 499, loss: 0.010131825423741248
test_accuracy: 1.0
-------------------------------------------------
total_time: 17.978153705596924