tf 损失函数_【TF2.1学习笔记7】激活函数、损失函数和优化器

大纲指数衰减学习率

激活函数

损失函数

缓解过拟合

优化器

1. 指数衰减学习率

思想:先用较大的学习率快速得到近似解,然后逐步减小学习率,使算法在迭代后期稳定下来。计算公式为:

指数衰减学习率=初始学习率*学习率衰减率^(单前轮数/多少轮衰减一次),其中,单前轮数可以指opoch数,也可以指global steps。

例子:

import tensorflow as tf

epoch=40

lr_base=0.2

lr_decay=0.99

lr_step=1

w = tf.Variable(tf.constant(5, dtype=tf.float32))

for epoch in range(epoch):

lr=lr_base*lr_decay**(epoch/lr_step)

with tf.GradientTape() as tape:

loss=tf.square(w+1)

grads=tape.gradient(loss,w)

w.assign_sub(lr*grads)

print("after%spoch, w is%f, loss if%f, lr is%f" %(epoch,w.numpy(),loss,lr))

outputs:

after 0 poch, w is 2.600000, loss if 36.000000, lr is 0.200000

after 1 poch, w is 1.174400, loss if 12.959999, lr is 0.198000

after 2 poch, w is 0.321948, loss if 4.728015, lr is 0.196020

after 3 poch, w is -0.191126, loss if 1.747547, lr is 0.194060

after 4 poch, w is -0.501926, loss if 0.654277, lr is 0.192119

after 5 poch, w is -0.691392, loss if 0.248077, lr is 0.190198

after 6 poch, w is -0.807611, loss if 0.095239, lr is 0.188296

after 7 poch, w is -0.879339, loss if 0.037014, lr is 0.186413

after 8 poch, w is -0.923874, loss if 0.014559, lr is 0.184549

after 9 poch, w is -0.951691, loss if 0.005795, lr is 0.182703

2. 激活函数tf.math.sigmoid(x):数学形式为

,输出范围为[0,1]。特点:(1)大部分梯度接近于0,易造成梯度消失;(2)输出非0均值,收敛慢;(3)幂运算复杂,计算量大。

tf.math.tanh(x):数学形式为

,输出范围为[-1,1]。特点:大部分梯度接近于0,易造成梯度消失;(2)输出0均值;(3)幂运算复杂,计算量大。

tf.nn.relu(x):数学形式为

。优点是:解决了梯度消失问题,运算简单,收录速度远快于sigmoid和tanh。缺点是:输出非0均值,收敛慢;某些神经元的激活值为0,梯度也为0,导致这些神经元的参数永远不会被更新,即Dead relu问题。

tf.nn.leaky_relu(x):数学形式为

。理论上来讲,leaky_relu有relu的所有优点,并且不存在Dead relu问题。

建议:首选relu激活函数

学习率设置为较小的值

输入特征标准化,让输入特征满足0均值,1标注差的正太分布

输出参数中心化,让随机生成的参数满足0均值,

标准差的正太分布,n指当前层输入特征个数。

3. 损失函数

损失函数指预测值y与已知答案y_之间的差距。均方误差

loss_mse=tf.math.reduce_mean(tf.math.square(y_-y))

例子:

import tensorflow as tf

import numpy as np

SEED=23455

rdm=np.random.RandomState(SEED)

x=rdm.rand(32,2)

y_=[[x1+x2+(rdm.rand()/10.-0.05)] for (x1,x2) in x]

x=tf.cast(x,dtype=tf.float32) #tf.cast能对numpy数据进行操作,返回Tensor

#print(x)

w1=tf.Variable(tf.random.normal([2,1],stddev=1,seed=1))

epoch=15000

lr=0.002

for epoch in range(epoch):

with tf.GradientTape() as tape:

y=tf.linalg.matmul(x,w1)

loss_mse=tf.math.reduce_mean(tf.math.square(y-y_)) #Tensor居然能直接减去列表

grads=tape.gradient(loss_mse,w1)

w1.assign_sub(lr*grads)

if epoch%500==0:

print("after%dtraining steps, w1 is" % (epoch))

print(w1.numpy(),"\n")

outputs:

after 14500 training steps, w1 is

[[1.0002553 ]

[0.99838644]]交叉熵

表示两个概率分布之间的距离。交叉熵越大,两个概率分布越远;交叉熵越小,两个概率分布越近。计算公式为:

式中,y_指标准答案,y指网络预测值。

实现方法:tf.losses.categorical_corssentropy(y_,y)

例子:

ce1=tf.losses.categorical_crossentropy([1,0],[0.6,0.4])

ce2=tf.losses.categorical_crossentropy([1,0],[0.8,0.2])

print(ce1)

print(ce2)

outputs:

tf.Tensor(0.5108256, shape=(), dtype=float32)

tf.Tensor(0.22314353, shape=(), dtype=float32)softmax和交叉熵结合

tf.nn.softmax_cross_entropy_with_logits(y_, y)

下面例子说明了softmax_cross_entropy_with_logits等价于softmax和categorical_crossentropy:

y_=np.array([[1,0,0],

[0,1,0],

[0,0,1],

[1,0,0]])

y=np.array([[12,3,2],

[3,10,1],

[1,2,5],

[4,6.5,1]])

y_pred=tf.nn.softmax(y)

loss1=tf.losses.categorical_crossentropy(y_,y_pred)

loss2=tf.nn.softmax_cross_entropy_with_logits(y_,y)

print(loss1)

print(loss2)

outputs:

tf.Tensor([1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58265938e+00], shape=(4,), dtype=float64)

tf.Tensor([1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58265938e+00], shape=(4,), dtype=float64)自定义

mse和交叉熵不一定是最优的loss,有时候可自定义loss。

4. 缓解过拟合正则化

正则化在损失函数中引入模型复杂度指标,利用给w加权值,弱化了训练数据的噪声(一般不正则化b)。数学形式为:

权值w的正则化一般有L1和L2正则化:

正则化的选择:

(1)L1正则化大概率会使很多参数变为0,因此它通过稀疏参数减少参数的数量,降低复杂度。

(2)L2正则化会使很多参数接近于0但不为0,因此它通过减小参数大小降低复杂度。

例子:

import tensorflow as tf

import numpy as np

from matplotlib import pyplot as plt

import pandas as pd

# 读入数据和标签

df=pd.read_csv('dot.csv')

x_data=np.array(df[['x1','x2']]) #shape (300,2)

y_data=np.array(df['y_c']) #shape (300,)

y_data=y_data.reshape(-1,1) #shape (300,1)

Y_c=[['red' if y else 'blue'] for y in y_data]

# 转换数据类型,否则后面矩阵相乘时会因数据类型问题报错

x_train=tf.cast(x_data,tf.float32) #tf函数能直接处理numpy数据,很有趣

y_train=tf.cast(y_data,tf.float32)

# 配对数据,切分数据

train_db=tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)

# 生成神经网络的参数,并保证参数可训练

w1=tf.Variable(tf.random.normal([2,11]),dtype=tf.float32)

b1=tf.Variable(tf.constant(0.01,shape=[11])) #突然间觉得对constant很陌生

w2=tf.Variable(tf.random.normal([11,1]),dtype=tf.float32)

b2=tf.Variable(tf.constant(0.01,shape=[1]))

lr=0.005

epoch=800

# 训练部分

for epoch in range(epoch):

for step,(x_train,y_train) in enumerate(train_db):

with tf.GradientTape() as tape:

h1=tf.linalg.matmul(x_train,w1)+b1

h1=tf.nn.relu(h1)

y=tf.linalg.matmul(h1,w2)+b2

#mse

loss_mse=tf.math.reduce_mean(tf.math.square(y_train-y))

#正则化

loss_regularization=[]

#tf.nn.l2_loss(w1)=sum(w**2)/2,输出一个scalar。使用tf.losses里面很多函数是不求和的,需要注意。

loss_regularization.append(tf.nn.l2_loss(w1))

loss_regularization.append(tf.nn.l2_loss(w2))

loss_regularization=tf.math.reduce_sum(loss_regularization)

loss=loss_mse+0.03*loss_regularization

#求梯度

variables=[w1,b1,w2,b2]

grads=tape.gradient(loss,variables)

# 更新梯度

w1.assign_sub(lr * grads[0])

b1.assign_sub(lr * grads[1])

w2.assign_sub(lr * grads[2])

b2.assign_sub(lr * grads[3])

if epoch%20==0:

print('epoch:',epoch, 'loss:',float(loss))

# 预测部分

print('******************predict*****************')

#xx在-3到3之间以步长为0.1,yy在-3到3之间以步长为0.1,生成间隔数值点

xx,yy=np.mgrid[-3:3:.1,-3:3:.1]

# 将xx和yy拉直,并合并配对为二维张量,生成二维坐标点

grid=np.c_[xx.ravel(),yy.ravel()]

grid=tf.cast(grid,tf.float32)

# 将网格点喂入神经网络进行预测

# probs=[]

# for x_test in grid:

# h1=tf.linalg.matmul([x_test],w1)+b1 #matmul的操作对象是矩阵,所以需要把x_test转换为矩阵

# h1=tf.nn.relu(h1)

# y=tf.linalg.matmul(h1,w2)+b2

# probs.append(y)

h1=tf.linalg.matmul(grid,w1)+b1

h1=tf.nn.relu(h1)

probs=tf.linalg.matmul(h1,w2)+b2

x1=x_data[:,0]

x2=x_data[:,1]

probs=np.array(probs).reshape(xx.shape) #Tensor可直接转换为numpy数据

plt.scatter(x1,x2,color=np.squeeze(Y_c))

plt.contour(xx,yy,probs,levels=[.5])

plt.show()图1 无正则化图2 L2正则化

5. 优化器

神经网络的优化器一般有一下步骤:

Step 1. 计算时刻t损失函数关于当前参数的梯度

Step 2. 计算时刻t的一阶动量

和二阶动量

Step 3. 计算时刻t的下降梯度

Step 4. 计算时刻t+1的参数

不同的优化方法的主要区别在于Step 2。我们来看看5种常见的优化器和它们的实现方法。SGD

SGD的一阶动力和二阶动量分别为

例子:

import tensorflow as tf

import numpy as np

from sklearn import datasets

from matplotlib import pyplot as plt

import time

# 读入数据

x_data=datasets.load_iris().data

y_data=datasets.load_iris().target

# 打乱数据

np.random.seed(116) #使用相同的seed,输出相同的随机数

np.random.shuffle(x_data)

np.random.seed(116)

np.random.shuffle(y_data)

tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样

# 划分训练集和测试集

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)

# 数据集配对

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

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

test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据

epoch = 500 # 循环500轮

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

now_time=time.time()

for epoch in range(epoch):

#训练部分

for step,(x_train,y_train) in enumerate(train_db):

with tf.GradientTape() as tape:

y=tf.linalg.matmul(x_train,w1)+b1

y=tf.nn.softmax(y) # 使输出y符合概率分布

y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy

loss=tf.math.reduce_mean(tf.math.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])

b1.assign_sub(lr*grads[1])

print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据

train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中

loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备

# 测试部分

total_correct, total_number = 0, 0

for x_test,y_test in test_db:

# 使用更新后的参数进行预测

y=tf.linalg.matmul(x_test,w1)+b1

y=tf.nn.softmax(y)

pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类

# 将pred转换为y_test的数据类型

pred=tf.cast(pred,dtype=y_test.dtype)

# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型

correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)

# 将每个batch的correct数加起来

correct=tf.math.reduce_sum(correct)

# 将所有batch中的correct数加起来

total_correct+=int(correct)

# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数

total_number+=x_test.shape[0]

acc=total_correct/total_number

test_acc.append(acc)

print("Test_acc:", acc)

print("--------------------------")

total_time=time.time()-now_time

print('total time',total_time)

# 绘制 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()SGDM(动量梯度下降法)

SGDM的一阶动量和二阶动量分别为:

式中,

是一个接近于1的超参数,一般取0.9。

例子:

import tensorflow as tf

import numpy as np

from sklearn import datasets

from matplotlib import pyplot as plt

import time

# 读入数据

x_data=datasets.load_iris().data

y_data=datasets.load_iris().target

# 打乱数据

np.random.seed(116) #使用相同的seed,输出相同的随机数

np.random.shuffle(x_data)

np.random.seed(116)

np.random.shuffle(y_data)

tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样

# 划分训练集和测试集

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)

# 数据集配对

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

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

test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据

epoch = 500 # 循环500轮

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

# 动量初值

m_w=tf.constant(0,shape=[4,3],dtype=tf.float32)

m_b=tf.constant(0,shape=[3],dtype=tf.float32)

beta=0.9

now_time=time.time()

for epoch in range(epoch):

#训练部分

for step,(x_train,y_train) in enumerate(train_db):

with tf.GradientTape() as tape:

y=tf.linalg.matmul(x_train,w1)+b1

y=tf.nn.softmax(y) # 使输出y符合概率分布

y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy

loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)

loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确

# 计算loss对各个参数的梯度

grads=tape.gradient(loss,[w1,b1])

# sgd-momentum

m_w=beta*m_w+(1-beta)*grads[0]

m_b=beta*m_b+(1-beta)*grads[1]

w1.assign_sub(lr*grads[0])

b1.assign_sub(lr*grads[1])

print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据

train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中

loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备

# 测试部分

total_correct, total_number = 0, 0

for x_test,y_test in test_db:

# 使用更新后的参数进行预测

y=tf.linalg.matmul(x_test,w1)+b1

y=tf.nn.softmax(y)

pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类

# 将pred转换为y_test的数据类型

pred=tf.cast(pred,dtype=y_test.dtype)

# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型

correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)

# 将每个batch的correct数加起来

correct=tf.math.reduce_sum(correct)

# 将所有batch中的correct数加起来

total_correct+=int(correct)

# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数

total_number+=x_test.shape[0]

acc=total_correct/total_number

test_acc.append(acc)

print("Test_acc:", acc)

print("--------------------------")

total_time=time.time()-now_time

print('total time',total_time)

# 绘制 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()Adagrad

Adagrad在SGD的基础上分配二阶动量,可以对模型中的每一个参数分配自适应学习率。Adagrad的一阶动量和二阶动量分别为:

例子:

import tensorflow as tf

import numpy as np

from sklearn import datasets

from matplotlib import pyplot as plt

import time

# 读入数据

x_data=datasets.load_iris().data

y_data=datasets.load_iris().target

# 打乱数据

np.random.seed(116) #使用相同的seed,输出相同的随机数

np.random.shuffle(x_data)

np.random.seed(116)

np.random.shuffle(y_data)

tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样

# 划分训练集和测试集

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)

# 数据集配对

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

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

test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据

epoch = 500 # 循环500轮

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

# adagrad

v_w=tf.constant(0,shape=[4,3],dtype=tf.float32)

v_b=tf.constant(0,shape=[3],dtype=tf.float32)

now_time=time.time()

for epoch in range(epoch):

#训练部分

for step,(x_train,y_train) in enumerate(train_db):

with tf.GradientTape() as tape:

y=tf.linalg.matmul(x_train,w1)+b1

y=tf.nn.softmax(y) # 使输出y符合概率分布

y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy

loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)

loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确

# 计算loss对各个参数的梯度

grads=tape.gradient(loss,[w1,b1])

# adagrad

v_w+=tf.math.square(grads[0])

v_b+=tf.math.square(grads[1])

w1.assign_sub(lr*grads[0]/tf.math.sqrt(v_w))

b1.assign_sub(lr*grads[1]/tf.math.sqrt(v_b))

print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据

train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中

loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备

# 测试部分

total_correct, total_number = 0, 0

for x_test,y_test in test_db:

# 使用更新后的参数进行预测

y=tf.linalg.matmul(x_test,w1)+b1

y=tf.nn.softmax(y)

pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类

# 将pred转换为y_test的数据类型

pred=tf.cast(pred,dtype=y_test.dtype)

# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型

correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)

# 将每个batch的correct数加起来

correct=tf.math.reduce_sum(correct)

# 将所有batch中的correct数加起来

total_correct+=int(correct)

# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数

total_number+=x_test.shape[0]

acc=total_correct/total_number

test_acc.append(acc)

print("Test_acc:", acc)

print("--------------------------")

total_time=time.time()-now_time

print('total time',total_time)

# 绘制 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()RMSProp

它是在SGD基础上增加二阶动量。RMSProp的一阶动量和二阶动量分别为:

例子:

import tensorflow as tf

import numpy as np

from sklearn import datasets

from matplotlib import pyplot as plt

import time

# 读入数据

x_data=datasets.load_iris().data

y_data=datasets.load_iris().target

# 打乱数据

np.random.seed(116) #使用相同的seed,输出相同的随机数

np.random.shuffle(x_data)

np.random.seed(116)

np.random.shuffle(y_data)

tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样

# 划分训练集和测试集

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)

# 数据集配对

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.001

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

test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据

epoch = 500 # 循环500轮

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

# adagrad

v_w=tf.constant(0,shape=[4,3],dtype=tf.float32)

v_b=tf.constant(0,shape=[3],dtype=tf.float32)

beta=0.9

now_time=time.time()

for epoch in range(epoch):

#训练部分

for step,(x_train,y_train) in enumerate(train_db):

with tf.GradientTape() as tape:

y=tf.linalg.matmul(x_train,w1)+b1

y=tf.nn.softmax(y) # 使输出y符合概率分布

y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy

loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)

loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确

# 计算loss对各个参数的梯度

grads=tape.gradient(loss,[w1,b1])

# rmsprop

v_w=beta*v_w+(1-beta)*tf.math.square(grads[0])

v_b=beta*v_b+(1-beta)*tf.math.square(grads[1])

w1.assign_sub(lr*grads[0]/tf.math.sqrt(v_w))

b1.assign_sub(lr*grads[1]/tf.math.sqrt(v_b))

print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据

train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中

loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备

# 测试部分

total_correct, total_number = 0, 0

for x_test,y_test in test_db:

# 使用更新后的参数进行预测

y=tf.linalg.matmul(x_test,w1)+b1

y=tf.nn.softmax(y)

pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类

# 将pred转换为y_test的数据类型

pred=tf.cast(pred,dtype=y_test.dtype)

# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型

correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)

# 将每个batch的correct数加起来

correct=tf.math.reduce_sum(correct)

# 将所有batch中的correct数加起来

total_correct+=int(correct)

# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数

total_number+=x_test.shape[0]

acc=total_correct/total_number

test_acc.append(acc)

print("Test_acc:", acc)

print("--------------------------")

total_time=time.time()-now_time

print('total time',total_time)

# 绘制 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()Adam

同时结合了SGDM的一阶动量和RMSProp的二阶动量,即

,并在此基础上增加了两个修正项:

例子:

import tensorflow as tf

import numpy as np

from sklearn import datasets

from matplotlib import pyplot as plt

import time

# 读入数据

x_data=datasets.load_iris().data

y_data=datasets.load_iris().target

# 打乱数据

np.random.seed(116) #使用相同的seed,输出相同的随机数

np.random.shuffle(x_data)

np.random.seed(116)

np.random.shuffle(y_data)

tf.random.set_seed(116) #如果不设置seed,每一次运行结果都不一样

# 划分训练集和测试集

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)

# 数据集配对

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

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

test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据

epoch = 500 # 循环500轮

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

# adam

m_w=tf.constant(0,shape=[4,3],dtype=tf.float32)

m_b=tf.constant(0,shape=[3],dtype=tf.float32)

v_w=tf.constant(0,shape=[4,3],dtype=tf.float32)

v_b=tf.constant(0,shape=[3],dtype=tf.float32)

beta1=0.9

beta2=0.999

global_step=0

now_time=time.time()

for epoch in range(epoch):

#训练部分

for step,(x_train,y_train) in enumerate(train_db):

global_step+=1

with tf.GradientTape() as tape:

y=tf.linalg.matmul(x_train,w1)+b1

y=tf.nn.softmax(y) # 使输出y符合概率分布

y_=tf.one_hot(y_train,depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy

loss=tf.math.reduce_mean(tf.math.square(y-y_)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)

loss_all+=loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确

# 计算loss对各个参数的梯度

grads=tape.gradient(loss,[w1,b1])

# adam

m_w = beta1 * m_w + (1-beta1) * grads[0]

m_b = beta1 * m_b + (1 - beta1) * grads[1]

v_w=beta2*v_w+(1-beta2)*tf.math.square(grads[0])

v_b=beta2*v_b+(1-beta2)*tf.math.square(grads[1])

m_w_correction=m_w/(1-tf.pow(beta1,global_step))

m_b_correction=m_b/(1-tf.pow(beta1,global_step))

v_w_correction=v_w/(1-tf.pow(beta2,global_step))

v_b_correction=v_b/(1-tf.pow(beta2,global_step))

w1.assign_sub(lr*m_w_correction/tf.math.sqrt(v_w_correction))

b1.assign_sub(lr*m_b_correction/tf.math.sqrt(v_b_correction))

print("Epoch {},loss:{}".format(epoch,loss_all/4)) # 训练集有120个数据,每个batch有32个数据

train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中

loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备

# 测试部分

total_correct, total_number = 0, 0

for x_test,y_test in test_db:

# 使用更新后的参数进行预测

y=tf.linalg.matmul(x_test,w1)+b1

y=tf.nn.softmax(y)

pred=tf.math.argmax(y,1) #返回y中最大值的索引,即预测的分类

# 将pred转换为y_test的数据类型

pred=tf.cast(pred,dtype=y_test.dtype)

# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型

correct=tf.cast(tf.math.equal(pred,y_test),dtype=tf.int32)

# 将每个batch的correct数加起来

correct=tf.math.reduce_sum(correct)

# 将所有batch中的correct数加起来

total_correct+=int(correct)

# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数

total_number+=x_test.shape[0]

acc=total_correct/total_number

test_acc.append(acc)

print("Test_acc:", acc)

print("--------------------------")

total_time=time.time()-now_time

print('total time',total_time)

# 绘制 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()

你可能感兴趣的:(tf,损失函数)