深入探索:TensorFlow的机制与卷积神经网络
一、TensorFlow Estimators的使用
在使用TensorFlow进行机器学习任务时,Estimators是一个非常实用的工具。下面我们将介绍如何使用Estimators进行MNIST手写数字分类,以及如何将Keras模型转换为Estimator。
1. 使用Estimators进行MNIST手写数字分类
- 步骤一:导入模块并设置超参数
import tensorflow_datasets as tfds
import tensorflow as tf
import numpy as np
BUFFER_SIZE = 10000
BATCH_SIZE = 64
NUM_EPOCHS = 20
steps_per_epoch = np.ceil(60000 / BATCH_SIZE)
这里,
BUFFER_SIZE
用于打乱数据集,
BATCH_SIZE
是小批量的大小,
NUM_EPOCHS
是训练的轮数,
steps_per_epoch
确定了每一轮的迭代次数。
- 步骤二:定义预处理函数
def preprocess(item):
image = item['image']
label = item['label']
image = tf.image.convert_image_dtype(image, tf.float32)
image = tf.reshape(image, (-1,))
return {'image-pixels':image}, label[..., tf.newaxis]
该函数将输入图像的类型从
uint8
转换为
tf.float32
,并将其展平。
- 步骤三:定义输入函数
def train_input_fn():
datasets = tfds.load(name='mnist')
mnist_train = datasets['train']
dataset = mnist_train.map(preprocess)
dataset = dataset.shuffle(BUFFER_SIZE)
dataset = dataset.batch(BATCH_SIZE)
return dataset.repeat()
def eval_input_fn():
datasets = tfds.load(name='mnist')
mnist_test = datasets['test']
dataset = mnist_test.map(preprocess).batch(BATCH_SIZE)
return dataset
train_input_fn
用于训练,
eval_input_fn
用于评估。
- 步骤四:定义特征列
image_feature_column = tf.feature_column.numeric_column(
key='image-pixels', shape=(28*28))
这里定义了大小为784(28×28)的特征列,这是MNIST图像展平后的大小。
- 步骤五:创建Estimator
dnn_classifier = tf.estimator.DNNClassifier(
feature_columns=[image_feature_column],
hidden_units=[32, 16],
n_classes=10,
model_dir='models/mnist-dnn/')
我们指定了两个隐藏层,第一个隐藏层有32个单元,第二个有16个单元,并且指定了类别数为10。
- 步骤六:训练和评估
dnn_classifier.train(
input_fn=train_input_fn,
steps=NUM_EPOCHS * steps_per_epoch)
eval_result = dnn_classifier.evaluate(
input_fn=eval_input_fn)
print(eval_result)
运行结果如下:
{'accuracy': 0.8957, 'average_loss': 0.3876346, 'loss': 0.38815108, 'global_step': 18760}
2. 将Keras模型转换为Estimator
- 步骤一:生成数据并划分数据集
tf.random.set_seed(1)
np.random.seed(1)
x = np.random.uniform(low=-1, high=1, size=(200, 2))
y = np.ones(len(x))
y[x[:, 0] * x[:, 1]<0] = 0
x_train = x[:100, :]
y_train = y[:100]
x_valid = x[100:, :]
y_valid = y[100:]
- 步骤二:构建Keras模型
model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(2,), name='input-features'),
tf.keras.layers.Dense(units=4, activation='relu'),
tf.keras.layers.Dense(units=4, activation='relu'),
tf.keras.layers.Dense(units=4, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
- 步骤三:定义输入函数
def train_input_fn(x_train, y_train, batch_size=8):
dataset = tf.data.Dataset.from_tensor_slices(
({'input-features':x_train}, y_train.reshape(-1, 1)))
return dataset.shuffle(100).repeat().batch(batch_size)
def eval_input_fn(x_test, y_test=None, batch_size=8):
if y_test is None:
dataset = tf.data.Dataset.from_tensor_slices(
{'input-features':x_test})
else:
dataset = tf.data.Dataset.from_tensor_slices(
({'input-features':x_test}, y_test.reshape(-1, 1)))
return dataset.batch(batch_size)
- 步骤四:定义特征列
features = [
tf.feature_column.numeric_column(
key='input-features:', shape=(2,))
]
- 步骤五:编译模型并转换为Estimator
model.compile(optimizer=tf.keras.optimizers.SGD(),
loss=tf.keras.losses.BinaryCrossentropy(),
metrics=[tf.keras.metrics.BinaryAccuracy()])
my_estimator = tf.keras.estimator.model_to_estimator(
keras_model=model,
model_dir='models/estimator-for-XOR/')
- 步骤六:训练和评估
num_epochs = 200
batch_size = 2
steps_per_epoch = np.ceil(len(x_train) / batch_size)
my_estimator.train(
input_fn=lambda: train_input_fn(x_train, y_train, batch_size),
steps=num_epochs * steps_per_epoch)
my_estimator.evaluate(
input_fn=lambda: eval_input_fn(x_valid, y_valid, batch_size))
运行结果如下:
{'binary_accuracy': 0.96, 'loss': 0.081909806, 'global_step': 10000}
二、卷积神经网络(CNNs)简介
CNNs是一类受人类视觉皮层启发的模型,在图像分类任务中表现出色。下面我们将介绍CNN的基本概念和卷积操作。
1. CNN的基本概念
- 特征提取 :CNN的早期层从原始数据中提取低级特征,如边缘和斑点,后期层(通常是全连接层)使用这些特征进行预测。
- 特征层次结构 :CNN通过逐层组合低级特征形成高级特征,例如在处理图像时,低级特征可以组合成更复杂的形状。
- 稀疏连接和参数共享 :CNN的特征图中的单个元素只连接到输入图像的一小部分像素,并且不同的图像块使用相同的权重,这减少了网络中的参数数量,提高了捕捉显著特征的能力。
CNN通常由多个卷积层和下采样层(池化层)组成,最后是一个或多个全连接层。池化层没有可学习的参数,而卷积层和全连接层有需要在训练过程中优化的权重和偏置。
2. 离散卷积操作
离散卷积是CNN中的基本操作,下面我们将介绍一维离散卷积的数学定义和计算方法。
-
数学定义 :对于两个向量 $x$ 和 $w$,离散卷积 $y = x * w$ 定义为:
$y[i] = \sum_{k=-\infty}^{+\infty} x[i - k] w[k]$
在实际应用中,由于我们处理的是有限特征向量,需要对 $x$ 进行零填充,以解决索引范围为 $-\infty$ 到 $+\infty$ 的问题。假设原始输入 $x$ 有 $n$ 个元素,滤波器 $w$ 有 $m$ 个元素($m \leq n$),填充后的向量 $x_p$ 的大小为 $n + 2p$,则实际的计算公式为:
$y[i] = \sum_{k=0}^{m - 1} x_p[i + m - k] w[k]$ -
计算方法 :计算离散卷积时,需要注意 $x$ 和 $w$ 的索引方向不同。可以通过翻转其中一个向量,然后计算它们的点积来实现。例如,翻转滤波器 $w$ 得到 $w_r$,计算 $x[i: i + m]$ 和 $w_r$ 的点积得到 $y[i]$,然后使用滑动窗口方法计算所有输出元素。
下面是一个计算一维离散卷积的示例:
输入向量 $x = [3, 2, 1, 7, 1, 2, 5, 4]$,滤波器 $w = [1, 2, 3, 4, 1, 1, 4]$,通过上述方法可以计算出输出向量的前三个元素。
通过以上内容,我们了解了如何使用TensorFlow的Estimators进行分类任务,以及如何将Keras模型转换为Estimator。同时,我们还介绍了卷积神经网络的基本概念和离散卷积操作,这些知识为我们进一步深入学习和应用CNN奠定了基础。
三、二维离散卷积操作
在实际的图像数据处理中,二维离散卷积更为常见。接下来我们详细介绍二维离散卷积的数学定义和计算方法。
1. 数学定义
对于二维矩阵 (X_{n_1\times n_2}) 和二维滤波器 (W_{m_1\times m_2})(其中 (m_1\leq n_1) 且 (m_2\leq n_2)),二维离散卷积 (Y = X * W) 的元素 (Y[i,j]) 定义为:
[Y[i,j]=\sum_{k_1 =-\infty}^{+\infty}\sum_{k_2=-\infty}^{+\infty}X[i - k_1,j - k_2]W[k_1,k_2]]
同样,在实际应用中,为了解决无限索引的问题,需要对矩阵 (X) 进行零填充。假设在两个维度上分别填充 (p_1) 和 (p_2) 个零,填充后的矩阵 (X_p) 的大小为 ((n_1 + 2p_1)\times(n_2+ 2p_2)),则实际计算公式为:
[Y[i,j]=\sum_{k_1 = 0}^{m_1 - 1}\sum_{k_2=0}^{m_2 - 1}X_p[i + m_1 - k_1,j + m_2 - k_2]W[k_1,k_2]]
2. 计算方法
与一维离散卷积类似,计算二维离散卷积时,需要注意 (X) 和 (W) 的索引方向。可以通过翻转滤波器 (W)(在两个维度上都进行翻转)得到 (W_r),然后将 (W_r) 与 (X) 的对应子矩阵进行点积运算。具体步骤如下:
1. 对输入矩阵 (X) 进行零填充。
2. 翻转滤波器 (W) 得到 (W_r)。
3. 将 (W_r) 依次滑过 (X) 的每个位置,计算对应子矩阵与 (W_r) 的点积,得到输出矩阵 (Y) 的元素。
以下为计算二维离散卷积的示例:
假设输入矩阵 (X=\begin{bmatrix}
1 & 2 & 3\
4 & 5 & 6\
7 & 8 & 9
\end{bmatrix}),滤波器 (W=\begin{bmatrix}
1 & 0\
0 & 1
\end{bmatrix}),通过上述方法可以计算出输出矩阵 (Y)。
四、在TensorFlow中实现深度CNN
在了解了CNN的基本概念和卷积操作后,我们可以在TensorFlow中实现深度CNN。下面以MNIST手写数字分类为例,介绍具体的实现步骤。
1. 数据加载与预处理
import tensorflow as tf
import tensorflow_datasets as tfds
# 加载MNIST数据集
(ds_train, ds_test), ds_info = tfds.load(
'mnist',
split=['train', 'test'],
shuffle_files=True,
as_supervised=True,
with_info=True
)
# 数据预处理函数
def normalize_img(image, label):
return tf.cast(image, tf.float32) / 255., label
# 应用预处理函数
ds_train = ds_train.map(
normalize_img, num_parallel_calls=tf.data.AUTOTUNE)
ds_train = ds_train.cache()
ds_train = ds_train.shuffle(ds_info.splits['train'].num_examples)
ds_train = ds_train.batch(128)
ds_train = ds_train.prefetch(tf.data.AUTOTUNE)
ds_test = ds_test.map(
normalize_img, num_parallel_calls=tf.data.AUTOTUNE)
ds_test = ds_test.batch(128)
ds_test = ds_test.cache()
ds_test = ds_test.prefetch(tf.data.AUTOTUNE)
2. 构建CNN模型
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
在这个模型中,我们使用了两个卷积层和两个最大池化层,最后是一个全连接层和一个输出层。
3. 编译和训练模型
model.compile(
optimizer=tf.keras.optimizers.Adam(0.001),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()],
)
model.fit(
ds_train,
epochs=6,
validation_data=ds_test,
)
4. 评估模型
test_loss, test_acc = model.evaluate(ds_test)
print(f'Test accuracy: {test_acc}')
五、数据增强技术
数据增强是提高模型泛化性能的有效方法,通过对训练数据进行随机变换,可以增加数据的多样性,从而使模型能够学习到更鲁棒的特征。以下是一些常见的数据增强技术及其在TensorFlow中的实现。
1. 随机翻转
data_augmentation = tf.keras.Sequential([
tf.keras.layers.RandomFlip('horizontal'),
])
2. 随机旋转
data_augmentation.add(tf.keras.layers.RandomRotation(0.1))
3. 随机缩放
data_augmentation.add(tf.keras.layers.RandomZoom(0.1))
可以将数据增强层添加到模型的开头,例如:
model = tf.keras.models.Sequential([
data_augmentation,
tf.keras.layers.Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=(28, 28, 1)),
# 其他层...
])
六、实现基于人脸图像的CNN分类器
我们可以使用上述知识实现一个基于人脸图像的CNN分类器,用于预测人的性别。以下是大致的实现步骤:
- 数据收集 :收集包含人脸图像和对应性别标签的数据集。
- 数据预处理 :对图像进行归一化、裁剪等操作。
- 构建CNN模型 :参考前面的示例,构建一个适合人脸图像分类的CNN模型。
- 数据增强 :应用数据增强技术提高模型的泛化性能。
- 训练模型 :使用训练数据对模型进行训练。
- 评估模型 :使用测试数据评估模型的性能。
通过以上步骤,我们可以实现一个简单的基于人脸图像的CNN分类器。在实际应用中,还可以根据具体需求对模型进行优化和调整。
综上所述,我们深入探讨了TensorFlow的Estimators的使用、卷积神经网络的基本概念和操作、在TensorFlow中实现深度CNN、数据增强技术以及基于人脸图像的CNN分类器的实现。这些知识为我们在图像分类等领域的应用提供了坚实的基础。
超级会员免费看
858

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



