
这个过程有点类似Flink、Spark的算子计算过程,通过各种算子,将RDD转化成目标数据。这里本质也是通过各种算子将图片转化为目标数据。
import os
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers, datasets
class MNISTLoader():
def __init__(self):
mnist = tf.keras.datasets.mnist
(self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()
#MNIST中的图像默认为uint8(0-255的数字)。以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道
self.train_data = np.expand_dims(self.train_data.astype(np.float32)/255.0, axis=-1) # [60000, 28, 28, 1]#在最后位置,增加一维度,与reshape类似
self.test_data = np.expand_dims(self.test_data.astype(np.float32) / 255.0, axis=-1) # [10000, 28, 28, 1]
self.train_label = self.train_label.astype(np.int32) # [60000]
self.test_label = self.test_label.astype(np.int32) # [10000]
self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]
def get_batch(self, batch_size):
#生产随机索引
index = np.random.randint(0, self.num_train_data, batch_size)
#根据随机索引返回对应内容
return self.train_data[index, :], self.train_label[index] #随机获取50条数据
#多层感知机模型
class MLP(tf.keras.Model):
# 初始化
def __init__(self):
super().__init__()
#定义网络机构,以及对应的函数
self.flatten = tf.keras.layers.Flatten() #Flatten层将除第一维(batch_size)以外的维度展平
self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)
self.dense2 = tf.keras.layers.Dense(units=10)
def call(self, inputs):
# print(inputs.shape) #(50, 28, 28, 1)
#调用
x = self.flatten(inputs) #压平层,用于将多维张量压成一维
x = self.dense1(x)
x = self.dense2(x)
output = tf.nn.softmax(x)
return output
#卷积神经网络模型
class CNN(tf.keras.Model):
# 初始化
def __init__(self):
super().__init__()
#第一层卷积
self.conv1 = tf.keras.layers.Conv2D(
filters=32, #卷积层神经元(卷积核)数目,设置神经元(卷积核)数目32,则输出(batchsize,28,28,32),32个神经元输出数据整合到一起
kernel_size=[5,5], #感受野大小,卷积核大小,就是那个小方块的大小,通常为奇数正方形,比如3*3,5*5
padding='same', # padding策略(vaild 或 same)
activation=tf.nn.relu #激活函数
)
#加一个池化层,用区域最大值池化,本质也是降维
self.pool1 = tf.keras.layers.MaxPool2D(pool_size=[2,2],strides=2)
#第二层卷积
self.conv2 = tf.keras.layers.Conv2D(
filters=64, # 卷积层神经元(卷积核)数目,这个数据是啥?
kernel_size=[5, 5], # 感受野大小,卷积核大小,就是那个小方块的大小,通常为奇数正方形,比如3*3,5*5
padding='same', # padding策略(vaild 或 same)
activation=tf.nn.relu # 激活函数
)
#再池化一次
self.pool2 = tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2)
#压平,就是resharp
self.flatten = tf.keras.layers.Reshape(target_shape=(7 * 7 * 64,))
#全连接层,输出1024
self.dense1 = tf.keras.layers.Dense(units=1024, activation=tf.nn.relu)
#全连接层,输出10,10就是最终输出各分类的概率
self.dense2 = tf.keras.layers.Dense(units=10)
def call(self, inputs): #输入数据[batch_size,28,28,1]
x = self.conv1(inputs) # [batch_size, 28, 28, 32]
x = self.pool1(x) # [batch_size, 14, 14, 32]
x = self.conv2(x) # [batch_size, 14, 14, 64]
x = self.pool2(x) # [batch_size, 7, 7, 64]
x = self.flatten(x) # [batch_size, 7 * 7 * 64]
x = self.dense1(x) # [batch_size, 1024]
x = self.dense2(x) # [batch_size, 10]
output = tf.nn.softmax(x) #取出最大概率的那个分类
return output
#超参数
num_epochs = 5 #循环5次
batch_size = 50 #每次读取的数据量
learning_rate = 0.001 #学习率
#模型
model = MLP() #准确率97%
# model = CNN() #准确率99%
#载入数据
data_loader = MNISTLoader()
#优化,Adam代替了GD梯度算法
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
#一共循环的次数 1200 * 5
num_batches = int(data_loader.num_train_data // batch_size * num_epochs)
for batch_index in range(num_batches):
X, y = data_loader.get_batch(batch_size)
with tf.GradientTape() as tape:
y_pred = model(X)
#损失函数,交叉熵作为损失函数,代替了MSE,在分类问题中被广泛应用。其离散形式为 H(y, \hat{y}) = -\sum_{i=1}^{n}y_i \log(\hat{y_i}) ,其中 y 为真实概率分布, \hat{y} 为预测概率分布, n 为分类任务的类别个数。预测概率分布与真实分布越接近,则交叉熵的值越小,反之则越大。
loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred)
loss = tf.reduce_mean(loss)
print("batch %d: loss %f" %(batch_index, loss.numpy()))
#计算模型的梯度,然后进行训练优化,相当于迭代过程中的自动优化
grads = tape.gradient(loss, model.variables) #对这些参数求导
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables)) #应用优化
print("final variables", model.variables)
#模型的评估
sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
num_batches = int(data_loader.num_test_data / batch_size)
for batch_index in range(num_batches):
start_index, end_index = batch_index * batch_size , (batch_index + 1) * batch_size
y_pred = model.predict(data_loader.test_data[start_index:end_index])
sparse_categorical_accuracy.update_state(y_true=data_loader.test_label[start_index:end_index], y_pred=y_pred)
print("test accuracy: %f" %(sparse_categorical_accuracy.result()))
效果非常好:
Model: "cnn"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) multiple 832
_________________________________________________________________
max_pooling2d (MaxPooling2D) multiple 0
_________________________________________________________________
conv2d_1 (Conv2D) multiple 51264
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 multiple 0
_________________________________________________________________
reshape (Reshape) multiple 0
_________________________________________________________________
dense (Dense) multiple 3212288
_________________________________________________________________
dense_1 (Dense) multiple 10250
=================================================================
Total params: 3,274,634
Trainable params: 3,274,634
Non-trainable params: 0
_________________________________________________________________
test accuracy: 0.992183
test accuracy: 0.992222
test accuracy: 0.992261
test accuracy: 0.992300

被折叠的 条评论
为什么被折叠?



