import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
笔记:
下面的这个x_train, x_test = x_train / 255.0, x_test / 255.0 这个归一化操作非常重要 在单层神经网络的训练手写数字识别的时候
我们习惯使用softmax分类函数 这没问题 但是 要考虑一个文艺 softmax的计算是指数形式的 在没有归一化之前 : c是原始数据 d是归一化的
c = np.array(tf.cast(c,dtype=tf.float32)).reshape(1,784)
d = np.array(tf.cast(d,dtype=tf.float32)).reshape(1,784)
y1 = tf.matmul(c,w1)+ b1
print(y1)
y1 = tf.nn.softmax(y1)
print(y1)
y2 = tf.matmul(d,w1)+ b1
print(y2)
y1 = tf.nn.softmax(y2)
print(y2)
执行这段代码 输出之后 你会明显的发现 :
tf.Tensor(
[[ 327.17645 -424.2321 211.14766 624.6971 -870.94885 795.67725
-119.88079 101.743286 53.492374 -17.998362]], shape=(1, 10), dtype=float32)
tf.Tensor([[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]], shape=(1, 10), dtype=float32)
tf.Tensor(
[[ 1.1203 -1.5452155 0.70625913 2.2565136 -3.322827 3.208177
-0.35524258 0.5323045 -0.05956426 -0.05602657]], shape=(1, 10), dtype=float32)
tf.Tensor(
[[ 1.1203 -1.5452155 0.70625913 2.2565136 -3.322827 3.208177
-0.35524258 0.5323045 -0.05956426 -0.05602657]], shape=(1, 10), dtype=float32)
softmax本来是个概率分布函数 但是如果不进行数据归一化 就会产生一个问题 其中有个数值较大
经过softmax进行计算之后 就会出现一个极大的数据 别的数据相对这个数据都非常小了 就会造成一个概率值为1 其余基本为0的问题 这样就会导致
梯度坏死 也就是梯度消失吧 我猜的
#可以认为这个mnist是个py文件吗 还有为啥(x_train,y_train) = mnist.load_data() 得到的x_train就没有相应的shape属性呢
mnist = tf.keras.datasets.mnist
(x_train,y_train),(x_test,y_test) = mnist.load_data()
c = x_train[0]
x_train, x_test = x_train / 255.0, x_test / 255.0
plt.imshow(X= x_train[0])
plt.show()
#注意需要加上 后缀名
a = plt.imread('timg.jpg')
plt.imshow(X=a)
print(y_test.shape)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUYBAT9j-1588224104828)(output_2_0.png)]
(10000,)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-faBzWoTH-1588224104846)(output_2_2.png)]
上面进行了数据的读取 我们可以看到数据的形式   是一个numpy数组的形式 我们需要对数据进行一些基本的处理 比如匹配标签 打乱数据集的顺序 其实这个手写数字集的顺序不需要打乱 本身就是乱序
使用函数tf.convert_to_tensor(img.eval())将numpy数组转换成张量对象。
送入神经网络训练的只能是张量 Tensor Tnesor也具有numpy数据所具备的基本属性 但是Tensor不具备numpy数组的 numpy.flags这个属性
有个重要的问题 就是tensorflow程序的执行流程是什么样的呀
使用type()函数看一个东西是ndarray 还是Tensor
也可以使用使用tf.is_tensor()查看对象是否是一个张量
虽然在搞这个入门级别的东西 但是还是遇到很多BUG 也算费尽心思才解决吧
首先经过(x_train,y_train),(x_test,y_test) = mnist.load_data() 读入的x_train()是一个ndarray 他自然具有ndarray的一切属性
常见的ndarray的属性:
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n 行 m 列
ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtype ndarray 对象的元素类型
ndarray.itemsize ndarray 对象中每个元素的大小,以字节为单位
ndarray.flags ndarray 对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray 元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
这里面 有个属性是ndarray.flags 这个ndarray的属性说的是对象的内存信息
使用print(x_train.flags)
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : False
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
属性 描述
C_CONTIGUOUS (C) 数据是在一个单一的C风格的连续段中
F_CONTIGUOUS (F) 数据是在一个单一的Fortran风格的连续段中
OWNDATA (O) 数组拥有它所使用的内存或从另一个对象中借用它
WRITEABLE (W) 数据区域可以被写入,将该值设置为 False,则数据为只读
ALIGNED (A) 数据和所有元素都适当地对齐到硬件上
UPDATEIFCOPY (U) 这个数组是其它数组的一个副本,当这个数组被释放时,原数组的内容将被更新
我们读出的数据 根据输出的这个属性 我们知道他是只读的所以我们不能对他进行写的操作 但是有个小问题 那就是我觉得np.random.shuffle()这个
乱序函数 并没有对他进行写操作啊 知识乱序一下啊 不过我看了一下 其他代码中shuffle操作的ndarray对象中的flags的属性 确实是可写的 暂时就这 样记下吧!
哎 为自己的知识储备不足感到担忧啊
#那就继续先熟悉一下 数据集乱序
x_train = np.array(x_train)
y_train = np.array(y_train)
np.random.seed(123)
np.random.shuffle(x_train)
np.random.seed(123)
np.random.shuffle(y_train)
tf.random.set_seed(seed=123)
plt.imshow(X=x_train[0].reshape(28,28))
plt.show()
#进行一下数据转换
x_train=tf.cast(x_train,tf.float32)
y_train = tf.cast(y_train,tf.int32)
x_test = tf.cast(x_test,tf.float32)
y_test = tf.cast(y_test,tf.int32)
x_train = np.reshape(x_train,newshape=(60000,784))
x_test = np.reshape(x_test,newshape=(10000,784))
# 将x_train 和y_train进行配对 并且设置每次喂入神经网络的数据
x_train_db = tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32)
x_test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(32)
print(y_test.shape)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zCRZDxQ-1588224104850)(output_4_0.png)]
(10000,)
构造神经网络的参数:
首先 先试用两层的神经网络训练一下试试 单层的话 784的输入 也就是需要784个隐藏神经元 10分类输出 输出需要10个神经元 类似这种
但是我们最后是10分类 也就是10个神经元
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YcB79DVc-1588224104852)(attachment:image.png)]
# w1 = tf.Variable(np.random.normal(size=(784,10)),dtype = tf.float32)
# b1 = tf.Variable(np.random.randn(10),dtype = tf.float32)
w1 = tf.Variable(tf.random.truncated_normal([784, 100], stddev=0.1, seed=1))
b1 = tf.Variable(tf.random.truncated_normal([100], stddev=0.1, seed=1))
w2 = tf.Variable(np.random.normal(size=(100,10)),dtype = tf.float32)
b2 = tf.Variable(np.random.randn(10),dtype = tf.float32)
epoch = 100
LR_BASE = 0.2
LR_DECRY = 0.99
LR_STEP = 1
#定义两个个空的列表 用来存储每次epoch之后的损失值 和 测试的精度
loss_epoch = []
acc_epoch = []
test_acc =[]
acc=0.0
loss=0
print(y_train)
tf.Tensor([4 9 8 ... 0 9 4], shape=(60000,), dtype=int32)
这里面有个东西快把我搞死了
损失函数这个东西 一开使用的最开始的那个MSE 效果还可以 后来感觉在这种多分类单标签的分类中 使用交叉熵损失函数会更好一些
于是乎 使用了 tf.nn.softmax_cross_entropy_with_logits() 这个函数已经过时了 卧槽 反正就是不要使用 坚决不要使用 不能用
在使用tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels)语句时产生。原因是logits和labels在使用时有labels应该少一维的限制。
这个函数的 labels 与前面那个函数不同,这个函数的 labels 是一个索引数值,给出的是这个图片具体属于哪类,而不是一个概率分布。
labels 的 shape 一般都是 [batchsize] ,而 logits 与前面一样,它的 shape 是 [batchsize, numberClass]
y_ = (tf.one_hot(y_train,depth=10))这个独热码的转换会把数据扩充一个维度 需要注意
#训练部分
for epoch in range(10):
lr = LR_BASE * LR_DECRY ** (epoch/LR_STEP)
for step,(x_train,y_train) in enumerate(x_train_db):
with tf.GradientTape() as Tape:
y = tf.matmul(x_train,w1)+ b1
y = tf.nn.relu(y)
y = tf.matmul(y,w2) + b2
y = tf.nn.softmax(y)
y_ = (tf.one_hot(y_train,depth=10))
#loss_mse = tf.reduce_mean(tf.square(y-y_))
loss_mse = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.argmax(y_,axis=1),logits=y))
loss+=loss_mse.numpy()
grad = Tape.gradient(loss_mse,[w1,b1,w2,b2])
#print(grad)
w1.assign_sub(lr*grad[0])
b1.assign_sub(lr*grad[1])
w2.assign_sub(lr*grad[2])
b2.assign_sub(lr*grad[3])
correct = tf.cast(tf.equal(tf.argmax(y,axis=1),tf.argmax(y_,axis=1)),dtype=tf.int32)
acc = tf.cast(tf.reduce_sum(correct),dtype=tf.float32)/32.0
loss_epoch.append(loss_mse)
if(epoch%1==0):
print("after {} 后: loss:{} acc:{}".format(epoch,loss,acc))
loss = 0
#测试部分
total_correct, total_number = 0, 0
for x_test,y_test in x_test_db:
y = tf.matmul(x_test,w1)+b1
y = tf.nn.relu(y)
y = tf.matmul(y,w2)+b2
y = tf.nn.softmax(y)
pred = tf.argmax(y,axis=1)
pred = tf.cast(pred,dtype=y_test.dtype)
correct = tf.cast(tf.equal(pred,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)
if(epoch%1==0):
print("after {} Test_acc:{}".format(epoch,acc))
print("--------------------------")
after 0 后: loss:7.956651736908952 acc:0.96875
after 0 Test_acc:0.9591
--------------------------
after 1 后: loss:7.49035571733134 acc:0.96875
after 1 Test_acc:0.9598
--------------------------
after 2 后: loss:7.089186773868278 acc:0.96875
after 2 Test_acc:0.9606
--------------------------
after 3 后: loss:6.745345288035651 acc:0.96875
after 3 Test_acc:0.9614
--------------------------
after 4 后: loss:6.430445950237981 acc:0.96875
after 4 Test_acc:0.9619
--------------------------
after 5 后: loss:6.144285260919105 acc:0.96875
after 5 Test_acc:0.9628
--------------------------
after 6 后: loss:5.890222105777411 acc:0.96875
after 6 Test_acc:0.9629
--------------------------
after 7 后: loss:5.658413398420862 acc:0.96875
after 7 Test_acc:0.9638
--------------------------
after 8 后: loss:5.450259750040686 acc:0.96875
after 8 Test_acc:0.9643
--------------------------
after 9 后: loss:5.264862050912939 acc:0.96875
after 9 Test_acc:0.9652
--------------------------
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])
model.fit(x_train, y_train, batch_size=32, epochs=10, validation_data=(x_test, y_test), validation_freq=1)
model.summary()
WARNING:tensorflow:From D:\Anaconde\A\envs\tensorflow2_0\lib\site-packages\tensorflow\python\ops\math_grad.py:1250: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
Train on 60000 samples, validate on 10000 samples
Epoch 1/10
60000/60000 [==============================] - 2s 37us/sample - loss: 0.2593 - sparse_categorical_accuracy: 0.9266 - val_loss: 0.1341 - val_sparse_categorical_accuracy: 0.9605
Epoch 2/10
60000/60000 [==============================] - 2s 32us/sample - loss: 0.1107 - sparse_categorical_accuracy: 0.9676 - val_loss: 0.1011 - val_sparse_categorical_accuracy: 0.9688
Epoch 3/10
60000/60000 [==============================] - 2s 34us/sample - loss: 0.0755 - sparse_categorical_accuracy: 0.9774 - val_loss: 0.0927 - val_sparse_categorical_accuracy: 0.9708
Epoch 4/10
60000/60000 [==============================] - 2s 35us/sample - loss: 0.0579 - sparse_categorical_accuracy: 0.9825 - val_loss: 0.0777 - val_sparse_categorical_accuracy: 0.9770
Epoch 5/10
60000/60000 [==============================] - 2s 32us/sample - loss: 0.0438 - sparse_categorical_accuracy: 0.9867 - val_loss: 0.0788 - val_sparse_categorical_accuracy: 0.9750
Epoch 6/10
60000/60000 [==============================] - 2s 31us/sample - loss: 0.0350 - sparse_categorical_accuracy: 0.9893 - val_loss: 0.0742 - val_sparse_categorical_accuracy: 0.9762
Epoch 7/10
60000/60000 [==============================] - 2s 32us/sample - loss: 0.0285 - sparse_categorical_accuracy: 0.9912 - val_loss: 0.0703 - val_sparse_categorical_accuracy: 0.9783
Epoch 8/10
60000/60000 [==============================] - 2s 32us/sample - loss: 0.0216 - sparse_categorical_accuracy: 0.9934 - val_loss: 0.0759 - val_sparse_categorical_accuracy: 0.9780
Epoch 9/10
60000/60000 [==============================] - 2s 34us/sample - loss: 0.0191 - sparse_categorical_accuracy: 0.9941 - val_loss: 0.0839 - val_sparse_categorical_accuracy: 0.9768
Epoch 10/10
60000/60000 [==============================] - 2s 31us/sample - loss: 0.0170 - sparse_categorical_accuracy: 0.9945 - val_loss: 0.0815 - val_sparse_categorical_accuracy: 0.9785
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) multiple 0
_________________________________________________________________
dense (Dense) multiple 100480
_________________________________________________________________
dense_1 (Dense) multiple 1290
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
_________________________________________________________________
训练过程笔记:
一开始有个问题我一直没有明白 记录在这里:
问题:举例来说 手写数字识别是一个10分类单标签的任务 我们假设一次喂入神经网络的参数是32*784 那么经过第一层全连接得到32*10的一个矩阵
这个矩阵每一行中的数据代表了这个数字是几的可能性 y_train经过one_hot编码转换后 变成32*10的形状