训练过程的loss一直是在下降,但是测试过程中的预测准确率却从100%降到0,这是什么原因呢?
环境为python3.7,tensorflow-gpu 2.1
数据集为iris数据集,训练过程采用无监督学习,测试过程采用有监督学习
神经网络为最基本的自编码器:包含输入层,编码隐藏层,解码隐藏层,softmax层用于分类
训练的损失值:
测试的精确度:
import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np
# 导入iris数据集
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
# 打乱数据集
np.random.seed(116)
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 将打乱的数据集构造成训练集和测试集
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)
# 定义分批输入的训练集
train_db = tf.data.Dataset.from_tensor_slices(x_train, ).batch(32)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)
# 定义超参数
input_size = 4
encoder_hidden = 3
decoder_hidden = 3
output_size = input_size
# 构建网络权重和偏置
encoder_w1 = tf.Variable(tf.random.truncated_normal([input_size, encoder_hidden], stddev=0.1))
encoder_b1 = tf.Variable(tf.random.truncated_normal([encoder_hidden], stddev=0.1))
decoder_w1 = tf.Variable(tf.random.truncated_normal([encoder_hidden, output_size], stddev=0.1))
decoder_b1 = tf.Variable(tf.random.truncated_normal([output_size], stddev=0.1))
lr = 0.09 # 学习率为0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 501 # 循环500轮
loss_train_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
# 训练部分
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
for step, (x_train) in enumerate(train_db): # batch级别的循环,每个step循环一次batch
with tf.GradientTape() as tape: # wtih结构记录梯度信息
encoder_hidden_train_output = tf.nn.sigmoid(tf.matmul(x_train, encoder_w1) + encoder_b1)
decoder_hidden_train_output = tf.nn.sigmoid(tf.matmul(encoder_hidden_train_output, decoder_w1) + decoder_b1)
loss_train = tf.reduce_mean(tf.square(x_train - decoder_hidden_train_output))
# 用loss.numpy()取出loss中的值
# 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
loss_train_all += loss_train.numpy()
# 计算loss对各个参数的梯度
grads = tape.gradient(loss_train, [encoder_w1, encoder_b1, decoder_w1, decoder_b1])
# 梯度下降法
# 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad
# tf.assign_sub(ref, value, use_locking=None, name=None)
# 变量 ref 减去 value值,即 ref = ref - value
# ref:变量;value:值;use_locking,默认 False, 若为 True,则受锁保护;name,名称
encoder_w1.assign_sub(lr * grads[0]) # 参数encoder_w1自更新
encoder_b1.assign_sub(lr * grads[1]) # 参数encoder_b1自更新
decoder_w1.assign_sub(lr * grads[2]) # 参数decoder_w1自更新
decoder_b1.assign_sub(lr * grads[3]) # 参数decoder_b1自更新
# 每个epoch打印loss信息
print('Epoch:{}, loss_train:{}'.format(epoch, loss_train_all / 4))
train_loss_results.append(loss_train_all / 4) # 将8个step的loss求平均记录在train_loss_results中
loss_train_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本数,total_number为测试的总样本数,将这两个变量初始化为0
correct = 0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
encoder_hidden_test_output = tf.nn.sigmoid(tf.matmul(x_test, encoder_w1) + encoder_b1)
#decoder_hidden_test_output = tf.nn.sigmoid(tf.matmul(encoder_hidden_test_output, decoder_w1) + decoder_b1)
softmax_hidden_test_output = tf.nn.softmax(encoder_hidden_test_output)
# tf.argmax(array, axis)按行或列返回array中最大元素的索引值
# axis=0表示跨行(经度,搜寻每一列的最大值的索引);axis=1表示跨列(纬度,搜寻每一行的最大值的索引)
# axis不指定的话,所有元素参与运算
y_test_prediction = tf.argmax(softmax_hidden_test_output, axis=1) # 返回decoder_hidden_test_output最大值的索引,即预测的分类
# 将y_test_prediction转换成y_test的数据类型
y_test_prediction = tf.cast(y_test_prediction, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换成int型
correct = tf.cast(tf.equal(y_test, y_test_prediction), 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:{0}, correct:{1}, total_correct:{2}, total_number:{3}".format(acc, correct, total_correct, total_number))
print('--------------------------')
# 绘制loss_train曲线
plt.title("Loss_Train Function Curve") # 图标题
plt.xlabel("Epoch") # x轴名称
plt.ylabel("Loss_Train") # y轴名称
plt.plot(train_loss_results, label='$Loss_train$') # 逐点画出train_loss_results值并连线,连线图标是Loss_train
plt.legend() # 画出曲线图标
plt.show() # 画出图像
# 绘制Accuracy曲线
plt.title("Accuracy Curve")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.plot(test_acc, label='$Accuracy$')
plt.legend()
plt.show()
你训练的数据和测试的数据差异不能太大,而且都是有监督的训练,你不是有标签吗,咋叫无监督的。准确率不高的原因有很多,比如数据太少,模型简单,训练次数不够。