没有采用tf.mode.Sequential的方式搭建,打个基础吧。
参考了鸢尾花识别的代码
保证数据维度相同十分重要!!!
注意:tf.onehot中【tf.float32、int8、int16无法用,int32则可以】。或直接.numpy()转为numpy类型,好像dtype指定类型也行??
import tensorflow as tf # 导入 TF 库
from tensorflow import keras # 导入 TF 子库 keras
from tensorflow.keras import layers, optimizers, datasets # 导入 TF 子库等
import matplotlib.pyplot as plt
(x, y), (x_val, y_val) = datasets.mnist.load_data() # 加载 MNIST 数据集
# 样本、验证集打平打平 并取出前20000个作为样本数据集
x = x.reshape(x.shape[0],-1)[0:20000,:]
y = y[0:20000]
x_val = x_val.reshape(x_val.shape[0],-1)
y_val = y_val.reshape(y_val.shape[0],-1)
输入样本x需要转化为tf张量,并归一化
# 转换成tensorflow张量,再转换成float32
# x、x_val归一化
x = tf.convert_to_tensor(x)
x_train = tf.cast(x,tf.float32) / 255
y_train = tf.cast(y,tf.int8)
x_val = tf.convert_to_tensor(x_val)
x_test = tf.cast(x_val,tf.float32) / 255
y_test = tf.cast(y_val,tf.float32)
将batch size设置为256 把数据集分批。分批后数据集(如train_db)是一个可迭代对象,batch size设置为2的n次幂
# 将数据集分批次,并设定每批次个数。并特征与标签一一对应
train_db = tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(256)
test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(256)
初始化参数,随机初始化。注意,要与输入样本的维度对应。每个样本打平后有784个像素,所以,第一层维度需要是784*N。最后一层输出10个类别,所以最后一层为 N*10。
# 生成神经网络参数,设置为三层256,128,10个神经元,10分类
w1 = tf.Variable(tf.random.truncated_normal([784,256],stddev=0.1))
b1 = tf.Variable(tf.random.truncated_normal([256], stddev=0.1))
w2 = tf.Variable(tf.random.truncated_normal([256,128],stddev= 0.1))
b2 = tf.Variable(tf.random.truncated_normal([128], stddev=0.1))
w3 = tf.Variable(tf.random.truncated_normal([128,10],stddev= 0.1))
b3 = tf.Variable(tf.random.truncated_normal([10], stddev=0.1))
初始化参数
lr = 0.1 #学习率
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epochs = 500 # 循环500轮
loss_all = 0 # 每轮分30个step,loss_all记录四个step生成的4个loss的和
循环每个epoch,每个epoch又要循环batch,用with tf.GradientTape() as tape 可以记录图用来求梯度。
loss记录的是平均损失。每次match会记录一个损失,加起来后除以一个epoch中batch的个数,就是一次epoch中的平均损失。
correct记录预测正确的个数,用来计算准确度。但是,tf.equal(tf.reshape(pred,y_test.shape) 使用过程中,如果pred和y_test的shape不相符会出现问题。
例如:pred 的 shape为 [256],y_test 的 shape为 [256,1] 则结果返回一个 [256,256]。
for epoch in range(epochs):
# 循环500eopch,每个epoch将各自batch循环一遍
for step,(x_train,y_train) in enumerate(train_db):
with tf.GradientTape() as tape:
#记录梯度
#神经元计算
#求和指数函数转化为概率
#将标签值转换为one-hot编码
#loss_all += loss.numpy()
#激活函数
y1 = tf.matmul(x_train, w1) + b1
y1 = tf.nn.relu(y1)
y2 = tf.matmul(y1,w2) + b2
y2 = tf.nn.relu(y2)
y3 = tf.matmul(y2,w3) + b3
y3 = tf.nn.softmax(y3)
# y = tf.matmul(x_train, w1) + b1
# y = tf.nn.softmax(y)
y_ = tf.one_hot(y_train,depth=10)
loss = tf.reduce_mean(tf.square(y_ - y3))
loss_all += loss.numpy()
grads = tape.gradient(loss,[w1,b1,w2,b2,w3,b3]) #计算各参数的梯度
w1.assign_sub(lr * grads[0]) 更新各参数
b1.assign_sub(lr * grads[1])
w2.assign_sub(lr * grads[2])
b2.assign_sub(lr * grads[3])
w3.assign_sub(lr * grads[4])
b3.assign_sub(lr * grads[5])
print("Epoch {}, loss: {}".format(epoch, loss_all/79))
train_loss_results.append(loss_all / 79)
loss_all = 0
total_correct, total_number = 0, 0 #用来计算精度
for x_test,y_test in test_db:
# 求取预测值y
# 返回y最大概率的索引即为类别
# 统计正确数量作为精度
y1 = tf.matmul(x_test, w1) + b1
y1 = tf.nn.relu(y1)
y2 = tf.matmul(y1, w2) + b2
y2 = tf.nn.relu(y2)
y3 = tf.matmul(y2, w3) + b3
y3 = tf.nn.softmax(y3)
pred = tf.argmax(y3,axis=1) #返回索引,此处不用在将y_test转化为独热码形式了。
pred = tf.cast(pred,dtype = y_test.dtype)
correct = tf.cast(tf.equal(tf.reshape(pred,y_test.shape), y_test), dtype=tf.int32)
correct = tf.reduce_sum(correct) #统计预测正确的个数
total_correct += int(correct)
total_number += x_test.shape[0] #统计验证样本个数
acc = total_correct / total_number #得到精度
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
loss与accuracy曲线绘制在一张图。
# 绘制 loss 曲线
plt.subplot(2,1,1)
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() # 画出曲线图标
# 绘制 Accuracy 曲线
plt.subplot(2,1,2)
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.tight_layout()
plt.legend()
plt.show()
最后结果如下