Fork me on GitHub

Neural Network 学习2.1 forward 加上test测试环节

import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets

# 加载数据集
# x:[60k,28,28] x_test:[10k,28,28]
# y:[60k] y_test:[10k]
(x, y), (x_test, y_test) = datasets.mnist.load_data()

# x:[0-255]==>[0,1.]因为范围在0-1之间比较好优化
x = tf.convert_to_tensor(x, dtype=tf.float32) / 255.
y = tf.convert_to_tensor(y, dtype=tf.int32)
x_test = tf.convert_to_tensor(x_test, dtype=tf.float32) / 255.
y_test = tf.convert_to_tensor(y_test, dtype=tf.int32)

# 创建数据集可以一次性训练一个batch
train_db = tf.data.Dataset.from_tensor_slices((x, y)).batch(60)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(60)
train_iter = iter(train_db) # 迭代器
sample = next(train_iter)
print('batch:', sample[0].shape, sample[1].shape) # sample[0]是一个batch的x的大小;sample[1]是一个batch的y的大小

# [b,784]==>[b,256]==>[b,128]==>[b,10]
# w的维度[dim_in,dim_out]
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1)) # 一定要加tf.Variable,不然梯度下降那里会说类型是none
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1)) # 如果默认方差为1.就会导致梯度爆炸
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))

lr = 1e-3 # learning_rate=0.001
for epoch in range(100): # 对整个数据集迭代10次
for step, (x, y) in enumerate(train_db): # 对每一个batch进行训练,每一个batch运算叫一个step,为的是有目的的打印,告诉你当前是哪一个step
# x:[128,28,28]
x = tf.reshape(x, [60, -1])

with tf.GradientTape() as tape: # 梯度求解
# y:[128]
# h1=x@w+b,希望x的shape是[128,28*28],所以对x的shape进行reshape
h1 = x @ w1 + b1 # [b,784]@[784,256]+[256]=[b,256]
h1 = tf.nn.relu(h1) # 非线性转换
h2 = h1 @ w2 + b2 # [b,256]@[256,128]+[128]=[b,128]
h2 = tf.nn.relu(h2)
out = h2 @ w3 + b3 # [b,128]@[b,10]+[10]=[b,10] 最后一层不加非线性转换

# 计算误差 compute loss
y_onehot = tf.one_hot(y, depth=10) # [b]==>[b,10]

# 均方差 mes=mean(sum(y-out)^2)
loss = tf.square(y_onehot - out) # 得到的shape[b,10]
loss = tf.reduce_mean(loss) # 得到一个标量scalar

# 计算梯度 compute gradient
grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
# w1 = w1 - lr * dw
w1.assign_sub(lr * grads[0]) # 原地更新,保持Variable类型
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])

if step % 100 == 0:
print(epoch, step, 'loss:', float(loss))

# 在每一个数据集循环之后进行测试,不能用之前train的样本,而要用test样本,不然会数据泄露
# test/evluation
# 用当前最新的一个[w1,b1,w2,b2,w3,b3]
total_correct ,total_number= 0,0 # 先都初始化为0
for step, (x, y) in enumerate(test_db):
# [b,28,28]--->[b,28*28]
x = tf.reshape(x, [-1, 28 * 28])

# [b,784]==>[b,256]==>[b,128]==>[b,10]
h1 = tf.nn.relu(x @ w1 + b1)
h2 = tf.nn.relu(h1 @ w2 + b2)
out = h2 @ w3 + b3

# out: [b,10] ~R 实数范围
# prob: [b,10] ~[0,1] 的范围
prob = tf.nn.softmax(out, axis=1) # softmax函数就是一个映射的函数,并能保证和为1
# 得到的prob shape还是[b,10]
# pred 的数据类型是int64!!!
pred =tf.cast(tf.argmax(prob, axis=1),dtype=tf.int32)
# 得到[b,1]的预测值
# [b], int32

correct = tf.reduce_sum(tf.cast(tf.equal(pred,y),dtype=tf.int32))
# 计算总的对的个数,但correct是一个tensor,先转化为一个numpy类型
total_correct +=int(correct)
# 计算总的测试个数 就是b
total_number += x.shape[0]

#在循环结束之后
acc = float(total_correct/total_number)
print('acc:',acc)
posted @ 2020-11-08 10:15  我们都会有美好的未来  阅读(202)  评论(0)    收藏  举报