在TensorFlow中编写自定义卷积神经网络指南
bigegpt 2024-10-07 06:35 12 浏览
本文将演示如何使用低级的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开发人员来说,许多步骤可能是黑盒,本教程的目的是帮助展示在后台发生了什么。
相关推荐
- 当Frida来“敲”门(frida是什么)
-
0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...
- 服务端性能测试实战3-性能测试脚本开发
-
前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...
- Springboot整合Apache Ftpserver拓展功能及业务讲解(三)
-
今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...
- Linux和Windows下:Python Crypto模块安装方式区别
-
一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...
- Python 3 加密简介(python des加密解密)
-
Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...
- 怎样从零开始编译一个魔兽世界开源服务端Windows
-
第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...
- 附1-Conda部署安装及基本使用(conda安装教程)
-
Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...
- 如何配置全世界最小的 MySQL 服务器
-
配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...
- 如何使用Github Action来自动化编译PolarDB-PG数据库
-
随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...
- 面向NDK开发者的Android 7.0变更(ndk android.mk)
-
订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...
- 信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要
-
问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...
- OpenSSH 安全漏洞,修补操作一手掌握
-
1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...
- Linux:lsof命令详解(linux lsof命令详解)
-
介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...
- 幻隐说固态第一期:固态硬盘接口类别
-
前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...
- 新品轰炸 影驰SSD多款产品登Computex
-
分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...
- 一周热门
- 最近发表
-
- 当Frida来“敲”门(frida是什么)
- 服务端性能测试实战3-性能测试脚本开发
- Springboot整合Apache Ftpserver拓展功能及业务讲解(三)
- Linux和Windows下:Python Crypto模块安装方式区别
- Python 3 加密简介(python des加密解密)
- 怎样从零开始编译一个魔兽世界开源服务端Windows
- 附1-Conda部署安装及基本使用(conda安装教程)
- 如何配置全世界最小的 MySQL 服务器
- 如何使用Github Action来自动化编译PolarDB-PG数据库
- 面向NDK开发者的Android 7.0变更(ndk android.mk)
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)