计算机系统应用教程网站

网站首页 > 技术文章 正文

使用低级的TensorFlow Core创建卷积神经网络(ConvNet)模型

btikc 2024-10-12 11:10:48 技术文章 6 ℃ 0 评论

本文将演示如何使用低级的TensorFlow Core创建卷积神经网络(ConvNet)模型,而不使用Keras之类的高级api。本教程的目标是更好地理解深层神经网络中的后台进程,并演示如何使用TensorFlow创建自定义代码。

本教程将展示如何将MNIST手写数字数据集加载到数据迭代器中,使用图形和会话,创建一个新的ConvNet体系结构,用不同的选项训练模型,进行预测,并保存训练后的模型。然后将提供完整的代码以及Keras中的等效模型,以便对使用Keras的用户进行直接比较,进一步了解Keras,并展示高级api在创建神经网络方面的强大功能。

MNIST数据集

MNIST是一组28x28灰度图像的手写数字,训练组中有60,000个图像,测试集中有10,000个图像。首先,我将加载并处理MNIST图像。

该模型期望输入形状[batch_size, height, width, channels]。由于图像是灰度(单通道),因此它们具有形状[60000,28,28],因此需要添加通道以具有形状[60000,28,28,1]。它们还具有uint8类型(像素值范围为0-255),因此需要通过除以255将它们缩放到0-1之间。下面显示第一个图像作为示例。Python代码如下:

import tensorflow as tf
import numpy as np
mnist = tf.keras.datasets.mnist
(train_images, train_labels),(test_images, test_labels) = mnist.load_data()
# Normalize and reshape images to [28,28,1]
train_images = np.expand_dims(train_images.astype(np.float32) / 255.0, axis=3)
test_images = np.expand_dims(test_images.astype(np.float32) / 255.0, axis=3)
# View a sample image
import matplotlib.pyplot as plt
plt.figure(dpi=100)
plt.imshow(np.squeeze(train_images[0]), cmap='gray')
plt.title('Number: {}'.format(train_labels[0]))
plt.show()

标签是整数值(例如0,1,2),是分类值,因此需要进行one-hot编码(例如[1,0,0],[0,1,0],[0, 0,1])用于训练。Keras有一个编码器to_categorical,我将使用它来转换标签(Scikit-learn也有一个hotencoder作为另一个选项)。

from keras.utils import to_categorical
train_labels = to_categorical(train_labels)

图和会话

使用TensorFlow创建模型有两个部分:创建图,并在会话中运行图。

图概述了计算数据流。它组织何时以及如何在张量(多维数据阵列)上执行操作。可以在会话内部或外部创建图,但图只能在会话内使用。在会话中,初始化张量,执行操作,并训练模型。

数据迭代器

为了演示数据流图和会话,我将创建一个dataset迭代器。由于MNIST图像和ground truth标签是NumPy数组的切片,因此可以通过将数组传递到方法tf.data. data. from_tensor_sections来创建数据集。然后,我们可以为数据集创建一个迭代器。我们希望它每次运行时返回一个batch_size数量的图像和标签,并重复无限个epochs。

batch_size = 128
dataset = tf.data.Dataset.from_tensor_slices((train_images, train_labels))
iterator = dataset.repeat().batch(batch_size).make_initializable_iterator()
data_batch = iterator.get_next()

我们已经定义了一个数据流图,为了获得新的一批图像和标签,我们可以在会话中运行data_batch。

但是,现在还不是时候。数据流图已经生成,但是图像实际上还没有传入。为此,需要在会话中初始化迭代器。

sess = tf.Session()
sess.run(iterator.initializer)

现在正在运行一个会话,只需运行data_batch就可以检索第一批图像。图像将具有shape [batch_size, height, width, channels],标签具有shape [batch_size, classes]。

batch_images, batch_labels = sess.run(data_batch)
print('Images shape: {}'.format(batch_images.shape))
print('Labels shape: {}'.format(batch_labels.shape))

Images shape: (128, 28, 28, 1)

Labels shape: (128, 10)

我们可以通过运行data_batch两次显示前两批中的第一张图像。

# Get the first batch of images and display first image
batch_images, batch_labels = sess.run(data_batch)
plt.subplot(1, 2, 1)
plt.imshow(np.squeeze(batch_images)[0], cmap='gray')
# Get a second batch of images and display first image
batch_images, batch_labels = sess.run(data_batch)
plt.subplot(1, 2, 2)
plt.imshow(np.squeeze(batch_images)[0], cmap='gray')
plt.show()

在第一批中,第一批图像为5。在第二批中,第一批图像为1。

然后可以关闭会话sess.close()。但请注意,会话结束时信息将丢失。例如,如果我们关闭并重新启动会话,如下所示,数据迭代器将从头开始重新启动。(注意,迭代器需要在每个会话中初始化。)

# New session
sess = tf.Session()
sess.run(iterator.initializer)
# Get the first batch of images and display first image
batch_images, batch_labels = sess.run(data_batch)
plt.subplot(1, 2, 1)
plt.imshow(np.squeeze(batch_images)[0], cmap='gray')
# Close and restart session
sess.close()
sess = tf.Session()
sess.run(iterator.initializer)
# Get a second batch of images and display first image
batch_images, batch_labels = sess.run(data_batch)
plt.subplot(1, 2, 2)
plt.imshow(np.squeeze(batch_images)[0], cmap='gray')
plt.show()

由于会话已关闭并且创建了新会话,因此数据迭代器从头开始重新启动并再次显示相同的图像。

with

会话也可以通过“with”语句启动并自动关闭。在“with”块的末尾,会话按指示关闭。

with tf.Session() as sess:
 sess.run(iterator.initializer)
 
 for _ in range(2):
 batch_images, batch_labels = sess.run(data_batch)
 img = np.squeeze(batch_images)[0]
 plt.imshow(img, cmap='gray')
 plt.show()
 
# sess is closed

ConvNet模型

以下将演示如何使用TensorFlow构建此基本ConvNet:

该架构有四个卷积层。前两层有16个filters,后两个有32个filters,所有filters大小为3x3。四个卷积层中的每一个还具有偏差和relu激活。最后两层是全连接(dense)层。

权重和偏差

ConvNet中的初始权重需要随机值,以便网络能够学习。我们可以使用带有tf.get_variable的初始化器来为层创建权重。每个卷积层都有形状为[filter_height, filter_width, in_channels, out_channels]的filters。由于dense层是全连接的,并且没有3x3 filters,所以它们的形状只是[in_channels, out_channels]每个偏差的大小都与对应层的out_channels相同,并使用0初始化。

创建weights和biases词典。

因为MNIST图像是灰度的,所以第一层的in_channels是1。输出层需要将out_channels设为10,因为有10个类。其他层中的filters数量可以根据性能或速度进行调优,但是每个in_channels需要与前一层的out_channels相同。第一个dense层的尺寸为7*7*32。

卷积层

TensorFlow具有tf.nn.conv2d函数,可以用来将张量与权值进行卷积。为了简化卷积层,我将创建一个函数,该函数接收输入数据x并应用带有权重的2D卷积W,添加偏差b,使用relu激活。

#Define 2D convolutional function
def conv2d(x, W, b, strides=1):
 x = tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME')
 x = tf.nn.bias_add(x, b)
 return tf.nn.relu(x)

模型图

另一个函数可用于制作模型图。这将接受MNIST图像作为数据,并使用不同层的权重和偏差。

在第二和第四卷积层之后,层的高度和宽度减小。最大池将滑动一个窗口,并只在区域内使用最大值。通过使用2x2窗口(ksize=[1,2,2,1])和步幅2(strides=[1,2,2,1]),尺寸将减少一半。这有助于减少模型大小,同时保留最重要的特征。对于奇数输入大小,输出形状由除以2后的上限确定(例如7/2 = 4)。

在第四卷积层之后,张量需要在全连接层之前被reshape,使其flattened。全连接层的权重不是用于2D卷积,而是矩阵乘法,因此conv2d不使用该函数。

在最后两层之间添加了一个dropout层,以减少过度拟合,其中权重下降的概率为0.2。dropout层应该只在训练中使用,如果模型用于预测,则包含一个training标志来绕过该层。。如果在预测过程中加入dropout层,由于权重的随机下降,模型的输出将不一致,准确度较低。

def conv_net(data, weights, biases, training=False):
 # Convolution layers
 conv1 = conv2d(data, weights['c1'], biases['c1']) # [28,28,16]
 conv2 = conv2d(conv1, weights['c2'], biases['c2']) # [28,28,16]
 pool1 = tf.nn.max_pool(conv2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME') 
 # [14,14,16]
 conv3 = conv2d(pool1, weights['c3'], biases['c3']) # [14,14,32]
 conv4 = conv2d(conv3, weights['c4'], biases['c4']) # [14,14,32]
 pool2 = tf.nn.max_pool(conv4, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME') 
 # [7,7,32]
 # Flatten
 flat = tf.reshape(pool2, [-1, weights['d1'].get_shape().as_list()[0]]) 
 # [7*7*32] = [1568]
 # Fully connected layer
 fc1 = tf.add(tf.matmul(flat, weights['d1']), biases['d1']) # [128]
 fc1 = tf.nn.relu(fc1) # [128]
 # Dropout
 if training:
 fc1 = tf.nn.dropout(fc1, rate=0.2)
 # Output
 out = tf.add(tf.matmul(fc1, weights['out']), biases['out']) # [10]
 return out

代码注释中给出了不同层的形状。从28x28的图像开始,两个最大池化层将大小减半两次,这样它的宽度和高度就减小到(28/2)/2 = 7。在使用Dense层之前,需要对权重进行reshape以使其flattened。由于第四个卷积层中有32个filters,所以flattened层的第一个维数为7x7x32。

构建ConvNet图

接下来,我们可以构建将用于训练模型的数据流图。

一个重要的概念是使用占位符,因此我将首先使用它们创建ConvNet。但是,我还将展示如何在没有占位符的情况下制作模型。

占位符

我们需要定义如何将来自数据迭代器的数据输入模型图。为此,我们可以制作一个占位符,形状[batch_size, height, width, channels]的某个张量将被输入conv_net函数。我们可以将高度和宽度设置为28,通道设置为1,并将批处理大小设置为None,使其保持可变。

现在,我们可以使用带有权值和偏差字典的Xtrain占位符作为conv_net函数的输入,以获得输出logits。

Xtrain = tf.placeholder(tf.float32, shape=(None, 28, 28, 1))
logits = conv_net(Xtrain, weights, biases)

这一步将允许我们通过将图像或批量图像输入Xtrain占位符来训练模型(请参阅下面的“ 喂养图像”)。

损失

该模型基于10个互斥类对图像进行分类。在训练过程中,利用softmax将对数转换为图像属于各个类的相对概率,然后利用softmax交叉熵计算损失。这些都可以用TensorFlow的softmax交叉熵一步完成。由于我们正在测量一批图像的损失,我们可以使用tf.reduce_mean获取批次的平均损失。

我们可以再次使用占位符ytrain作为图,用于输入MNIST标签。回想一下,标签是one-hot 编码的,批次中每个图像都有一个标签,因此形状应该是[batch_size, n_classes]。

ytrain = tf.placeholder(tf.float32, shape=(None, n_classes))
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, 
 labels=ytrain))

优化

损失用于通过反向传播网络中的损失来更新模型权重和偏差。学习率用于缩小更新,从而使权重不会偏离或跳过最佳值。

Adam优化器是由Adagrad和RMSProp与momentum的组合派生而来的,并且已经被证明可以与ConvNets很好地工作。这里我使用Adam优化器,学习率为1e-4。然后计算梯度,并通过运行minimize方法来更新权重。

optimizer = tf.train.AdamOptimizer(1e-4)
train_op = optimizer.minimize(loss)

train_op现在是训练模型的关键,因为它运行optimizer. minimer。要训练模型,只需将图像输入到图中,然后运行train_op根据损失更新权重。

训练模型

准确性

我们可以使用测试图像来测量训练的准确性。对于每个图像,我们执行模型推理,并使用最大logit值的类作为预测。准确性是预测中正确的部分。我们需要使用整数值而不是one-hot编码来比较预测和标签,所以我们需要使用argmax来转换它们(这就是为什么test_tags没有转换为one-hot编码,否则它将不得不被转换回来)。

可以使用TensorFlow的accuracy运算符测量准确度,该运算符具有两个输出。第一个输出是准确性而不更新指标,第二个输出是我们将使用的输出,它返回更新指标的准确性。

test_predictions = tf.nn.softmax(conv_net(test_images, weights, biases))
acc,acc_op = tf.metrics.accuracy(predictions=tf.argmax(test_predictions,1), 
 labels=tests_labels )

初始化变量

局部变量(如accuracy中的total和count指标等临时变量)和全局变量(如模型权重和偏差)需要初始化,以便在会话中使用。

sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())

喂养图像

回想一下,对于每个batch,都会创建一组新的图像和ground truths,需要将它们输入占位符Xtrain和ytrain。如上所示,我们可以从data_batch获取batch_images和batch_tags。然后,可以通过创建一个以占位符为键、以数据为值的字典来将它们提供给占位符,然后在ssh .run()中运行train_op时将字典传递给feed_dict参数。

batch_images, batch_labels = sess.run(data_batch)
feed_dict = {Xtrain: batch_images, ytrain: batch_labels}
sess.run(train_op, feed_dict=feed_dict)

训练会话

通过调用train_op会话,图中的所有步骤都如上所述运行。我将使用tqdm来查看每个epoch的训练进度。在每个epoch之后,测量并打印出准确度。

from tqdm import tqdm
nepochs = 5
sess = tf.Session()
sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())
sess.run(iterator.initializer)
 
for epoch in range(nepochs):
 for step in tqdm(range(int(len(train_images)/batch_size))):
 
 # Batched data
 batch_images, batch_labels = sess.run(data_batch)
 # Train model
 feed_dict = {Xtrain: batch_images, ytrain: batch_labels}
 sess.run(train_op, feed_dict=feed_dict)
 # Test model
 accuracy = sess.run(acc_op)
 
 print('\nEpoch {} Accuracy: {}'.format(epoch+1, accuracy))

该模型将继续训练所给出的epochs数。在5个epochs之后,该模型具有约0.97的准确度。

没有占位符的训练

上面的例子演示了在图像中填充占位符,但是如果将conv_net中的batch_images和batch_tags直接使用到标签参数tf. nf .softmax_cross_entropy_with_logits_v2中,则可以使这个图更加简洁。然后就可以对模型进行训练,而不需要向图中输入任何张量。

batch_images, batch_labels = iterator.get_next()
logits = conv_net(batch_images, weights, biases, training=True)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, 
 labels=batch_labels))
train_op = optimizer.minimize(loss)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())
sess.run(iterator.initializer)
for epoch in range(nepochs):
 for step in tqdm(range(int(len(train_images)/batch_size)))
 sess.run(train_op)
 accuracy = sess.run(acc_op)
 print('\nEpoch {} Accuracy: {}'.format(epoch+1, accuracy))

访问其他节点

图中的不同节点可以通过在会话中单独调用或在列表中调用来访问。如果运行节点列表,则会给出输出列表。例如,假设我们希望在训练期间看到每个图像批次的损失。这可以通过使用train_op在列表中运行会话中的损失来实现。在这里,我将使用tqdm打印epoch期间每个批次的损失。

for epoch in range(nepochs):
 
 prog_bar = tqdm(range(int(len(train_images)/batch_size)))
 
 for step in prog_bar:
 _,cost = sess.run([train_op,loss])
 
 prog_bar.set_description("cost: {}".format(cost))
 accuracy = sess.run(acc_op)
 
 print('\nEpoch {} Accuracy: {}'.format(epoch+1, accuracy))

预测

测试预测

我们可以使用来自测试准确度的test_prediction来可视化一些示例图像进行分类的性能。在这里,我将显示前25张测试图像,并使用整数预测作为标题。

onehot_predictions = sess.run(test_predictions)
predictions = np.argmax(np.squeeze(onehot_predictions), axis=1)
f, axarr = plt.subplots(5, 5, figsize=(25,25))
for idx in range(25):
 axarr[int(idx/5), idx%5].imshow(np.squeeze(test_images[idx]), cmap='gray')
 axarr[int(idx/5), idx%5].set_title(str(predictions[idx]),fontsize=50)

预测新的图像批次

如果希望预测一组新的图像,只需在会话中的一批图像上运行conv_net函数即可进行预测。例如,下面可以用来得到测试集中前25幅图像的预测:

predictions = sess.run(tf.argmax(conv_net(test_images[:25], weights, biases), axis=1))

然后这些predictions就可以像上面一样用于显示图像。

预测单个图像

回想一下,模型期望输入具有形状[batch_size, height, width, channels]。这意味着,如果对单个图像进行预测,则图像需要扩展其尺寸以使第一维(batch_size)为1。这里预测了测试集中的第1000个图像。

img = test_images[1000]
print(img.shape) # [28, 28, 1]
img = np.expand_dims(img, 0)
print(img.shape) # [1, 28, 28, 1]
prediction = sess.run(tf.argmax(conv_net(img, weights, biases), axis=1))
plt.imshow(np.squeeze(img), cmap='gray')
plt.title(np.squeeze(prediction), fontsize=40)

预测概率

预测的归一化概率分布可以用softmax对conv_net模型的对数进行计算。

idx = 1000
img = np.expand_dims(test_images[idx], 0)
plt.imshow(np.squeeze(img), cmap='gray')
# Predict value
prediction = conv_net(img, weights, biases)
probabilities = tf.nn.softmax(prediction)
probs = sess.run(probabilities)
probs = np.squeeze(probs)
# Plot probabilities
plt.figure(dpi=150)
plt.bar(range(10), probs)
for i in range(10):
 plt.text(i-0.3, probs[i]+0.05, s='{:.2f}'.format(probs[i]), size=10)
plt.ylim([0,1.1])
plt.xticks(range(10))
plt.ylabel('Probability')
plt.xlabel('Predicted Number')

该模型很可能预测该数字为9。

对于模型来说,有些数字并不容易预测。例如,这是测试集中的另一个图像(idx=3062)。

虽然模型预测最可能的类别是8,但它的概率只有0.48,而且还有其他几个数字的概率更高。

这是一个不正确的预测(idx=259)的例子:

模型错误地预测为0,数字6是第二高的预测。

保存模型

如上所述,只要会话仍处于打开状态,就可以进行预测。如果会话结束,则训练的权重和偏差将丢失。会话和模型图以及训练的权重和偏差可以使用tf.train.Saver保存为检查点。

saver = tf.train.Saver() 
saver.save(sess, './model.ckpt')

完整的Python代码示例

下面将是一个示例脚本,用于创建,训练和保存ConvNet并显示手写数字样本的预测。

import tensorflow as tf
import numpy as np
from tqdm import tqdm
from keras.datasets import mnist
from keras.utils import to_categorical
import matplotlib.pyplot as plt
# MNIST Dataset
(train_images, train_labels),(test_images, test_labels) = mnist.load_data()
train_images = np.expand_dims(train_images.astype(np.float32) / 255.0, axis=3)
test_images = np.expand_dims(test_images.astype(np.float32) / 255.0, axis=3)
train_labels = to_categorical(train_labels)
# Training parameters
batch_size = 128
n_epochs = 5
n_classes = 10
learning_rate = 1e-4
# 2D Convolutional Function
def conv2d(x, W, b, strides=1):
 x = tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME')
 x = tf.nn.bias_add(x, b)
 return tf.nn.relu(x)
# Define Weights and Biases
weights = {
 # Convolution Layers
 'c1': tf.get_variable('W1', shape=(3,3,1,16), \
 initializer=tf.contrib.layers.xavier_initializer()), 
 'c2': tf.get_variable('W2', shape=(3,3,16,16), \
 initializer=tf.contrib.layers.xavier_initializer()),
 'c3': tf.get_variable('W3', shape=(3,3,16,32), \
 initializer=tf.contrib.layers.xavier_initializer()),
 'c4': tf.get_variable('W4', shape=(3,3,32,32), \
 initializer=tf.contrib.layers.xavier_initializer()),
 
 # Dense Layers
 'd1': tf.get_variable('W5', shape=(7*7*32,128), 
 initializer=tf.contrib.layers.xavier_initializer()),
 'out': tf.get_variable('W6', shape=(128,n_classes), 
 initializer=tf.contrib.layers.xavier_initializer()),
}
biases = {
 # Convolution Layers
 'c1': tf.get_variable('B1', shape=(16), initializer=tf.zeros_initializer()),
 'c2': tf.get_variable('B2', shape=(16), initializer=tf.zeros_initializer()),
 'c3': tf.get_variable('B3', shape=(32), initializer=tf.zeros_initializer()),
 'c4': tf.get_variable('B4', shape=(32), initializer=tf.zeros_initializer()),
 
 # Dense Layers
 'd1': tf.get_variable('B5', shape=(128), initializer=tf.zeros_initializer()),
 'out': tf.get_variable('B6', shape=(n_classes), initializer=tf.zeros_initializer()),
}
# Model Function
def conv_net(data, weights, biases, training=False):
 # Convolution layers
 conv1 = conv2d(data, weights['c1'], biases['c1']) # [28,28,16]
 conv2 = conv2d(conv1, weights['c2'], biases['c2']) # [28,28,16]
 pool1 = tf.nn.max_pool(conv2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME') 
 # [14,14,16]
 conv3 = conv2d(pool1, weights['c3'], biases['c3']) # [14,14,32]
 conv4 = conv2d(conv3, weights['c4'], biases['c4']) # [14,14,32]
 pool2 = tf.nn.max_pool(conv4, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME') 
 # [7,7,32]
 # Flatten
 flat = tf.reshape(pool2, [-1, weights['d1'].get_shape().as_list()[0]]) 
 # [7*7*32] = [1568]
 # Fully connected layer
 fc1 = tf.add(tf.matmul(flat, weights['d1']), biases['d1']) # [128]
 fc1 = tf.nn.relu(fc1) # [128]
 # Dropout
 if training:
 fc1 = tf.nn.dropout(fc1, rate=0.2)
 # Output
 out = tf.add(tf.matmul(fc1, weights['out']), biases['out']) # [10]
 return out
# Dataflow Graph
dataset = tf.data.Dataset.from_tensor_slices((train_images,train_labels)).repeat().batch(batch_size)
iterator = dataset.make_initializable_iterator()
batch_images, batch_labels = iterator.get_next()
logits = conv_net(batch_images, weights, biases, training=True)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=batch_labels))
optimizer = tf.train.AdamOptimizer(learning_rate)
train_op = optimizer.minimize(loss)
test_predictions = tf.nn.softmax(conv_net(test_images, weights, biases))
acc,acc_op = tf.metrics.accuracy(predictions=tf.argmax(test_predictions,1), labels=test_labels)
# Run Session
with tf.Session() as sess:
 # Initialize Variables
 sess.run(tf.global_variables_initializer())
 sess.run(tf.local_variables_initializer())
 sess.run(iterator.initializer)
 # Train the Model
 for epoch in range(n_epochs):
 prog_bar = tqdm(range(int(len(train_images)/batch_size)))
 for step in prog_bar:
 _,cost = sess.run([train_op,loss])
 prog_bar.set_description("cost: {:.3f}".format(cost))
 accuracy = sess.run(acc_op)
 print('\nEpoch {} Accuracy: {:.3f}'.format(epoch+1, accuracy))
 # Show Sample Predictions
 predictions = sess.run(tf.argmax(conv_net(test_images[:25], weights, biases), axis=1))
 f, axarr = plt.subplots(5, 5, figsize=(25,25))
 for idx in range(25):
 axarr[int(idx/5), idx%5].imshow(np.squeeze(test_images[idx]), cmap='gray')
 axarr[int(idx/5), idx%5].set_title(str(predictions[idx]),fontsize=50)
 
 # Save Model
 saver = tf.train.Saver() 
 saver.save(sess, './model.ckpt')

Keras中的等价模型

Keras是一个高级API,可以使用它的序列模型API来极大地简化上述Python代码。

请注意,不需要使用会话。此外,模型权重和偏差不需要在模型外定义。添加图层时会创建它们,并自动计算它们的形状。

from keras.models import Sequential, Model
from keras.layers import Dense, Activation, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, Input
from keras.optimizers import Adam
from keras.datasets import mnist
from keras.utils import to_categorical
import numpy as np
# MNIST Dataset
(train_images, train_labels),(test_images, test_labels) = mnist.load_data()
train_images = np.expand_dims(train_images.astype(np.float32) / 255.0, axis=3)
test_images = np.expand_dims(test_images.astype(np.float32) / 255.0, axis=3)
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
# Training parameters
batch_size = 128
n_epochs = 5
n_classes = 10
# Create the model
model = Sequential()
# Convolution Layers
model.add(Conv2D(16, 3, activation='relu', input_shape=(28, 28, 1), padding='same'))
model.add(Conv2D(16, 3, activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=2, padding='same'))
model.add(Conv2D(32, 3, activation='relu', padding='same'))
model.add(Conv2D(32, 3, activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=2, padding='same'))
# Dense Layers
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(n_classes, activation='softmax'))
# Optimizer
optimizer = Adam(lr=1e-4)
# Compile
model.compile(loss='categorical_crossentropy',
 optimizer=optimizer,
 metrics=['categorical_accuracy'])
# Train model
model.fit(train_images, 
 train_labels,
 epochs=n_epochs,
 batch_size=batch_size,
 validation_data=(test_images, test_labels)
 )
# Show Sample Predictions
predictions = model.predict(test_images[:25])
predictions = np.argmax(predictions, axis=1)
f, axarr = plt.subplots(5, 5, figsize=(25,25))
for idx in range(25):
 axarr[int(idx/5), idx%5].imshow(np.squeeze(test_images[idx]), cmap='gray')
 axarr[int(idx/5), idx%5].set_title(str(predictions[idx]),fontsize=50)
# Save Model
model.save_weights("model.h5")

最后

TensorFlow图创建了用于如何训练模型的计算数据流,会话用于进行实际训练。本文演示了在创建图和在训练会话中运行图时使用的不同步骤和选项。当您对如何创建图并在会话中使用它们有了一个大致的了解之后,开发自定义神经网络和使用TensorFlow Core来满足您的特定需求就变得更加容易了。

可以看出,Keras更加简洁,并且很清楚为什么这个API更适合用于测试新的神经网络。然而,对于新的AI开发人员来说,许多步骤可能是黑盒,本教程的目的是帮助展示在后台发生了什么。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表