政安晨:【Keras机器学习示例演绎】(四)—— 利用迁移学习进行关键点检测

本文主要是介绍政安晨:【Keras机器学习示例演绎】(四)—— 利用迁移学习进行关键点检测,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

数据收集

导入

定义超参数

加载数据

可视化数据

准备数据生成器

定义增强变换

创建训练和验证分割

数据生成器调查

模型构建

模型编译和训练

进行预测并将其可视化

更进一步


政安晨的个人主页政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏: TensorFlow与Keras机器学习实战

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正!

本文目标:利用数据增强和迁移学习训练关键点检测器。

关键点检测包括对物体关键部位的定位。例如,人脸的关键部位包括鼻尖、眉毛、眼角等。这些部分有助于以特征丰富的方式表示底层对象。关键点检测的应用包括姿势估计、人脸检测等。

在本例中,我们将使用斯坦福 Extra 数据集,利用迁移学习建立一个关键点检测器。

本示例需要 TensorFlow 2.4 或更高版本,以及 imgaug 库,可使用以下命令安装:

!pip install -q -U imgaug

数据收集


StanfordExtra 数据集包含 12,000 张狗的图像以及关键点和分割图。该数据集由斯坦福狗数据集发展而来。

可通过以下命令下载:

!wget -q http://vision.stanford.edu/aditya86/ImageNetDogs/images.tar

注释在 StanfordExtra 数据集中以单个 JSON 文件的形式提供,用户需要填写此表格才能访问该文件。

作者明确指示用户不要共享 JSON 文件,本示例也尊重这一愿望:您应自行获取 JSON 文件。

JSON 文件的本地版本为 stanfordextra_v12.zip。
下载文件后,我们可以解压缩。

!tar xf images.tar
!unzip -qq ~/stanfordextra_v12.zip

导入

from keras import layers
import kerasfrom imgaug.augmentables.kps import KeypointsOnImage
from imgaug.augmentables.kps import Keypoint
import imgaug.augmenters as iaafrom PIL import Image
from sklearn.model_selection import train_test_split
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
import json
import os

定义超参数

IMG_SIZE = 224
BATCH_SIZE = 64
EPOCHS = 5
NUM_KEYPOINTS = 24 * 2  # 24 pairs each having x and y coordinates

加载数据


作者还提供了一个元数据文件,其中指定了有关关键点的其他信息,如颜色信息、动物姿势名称等。我们将在 pandas 数据框中加载该文件,以提取信息用于可视化目的。

IMG_DIR = "Images"
JSON = "StanfordExtra_V12/StanfordExtra_v12.json"
KEYPOINT_DEF = ("https://github.com/benjiebob/StanfordExtra/raw/master/keypoint_definitions.csv"
)# Load the ground-truth annotations.
with open(JSON) as infile:json_data = json.load(infile)# Set up a dictionary, mapping all the ground-truth information
# with respect to the path of the image.
json_dict = {i["img_path"]: i for i in json_data}

json_dict 的单个条目如下所示:

'n02085782-Japanese_spaniel/n02085782_2886.jpg':
{'img_bbox': [205, 20, 116, 201],'img_height': 272,'img_path': 'n02085782-Japanese_spaniel/n02085782_2886.jpg','img_width': 350,'is_multiple_dogs': False,'joints': [[108.66666666666667, 252.0, 1],[147.66666666666666, 229.0, 1],[163.5, 208.5, 1],[0, 0, 0],[0, 0, 0],[0, 0, 0],[54.0, 244.0, 1],[77.33333333333333, 225.33333333333334, 1],[79.0, 196.5, 1],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[150.66666666666666, 86.66666666666667, 1],[88.66666666666667, 73.0, 1],[116.0, 106.33333333333333, 1],[109.0, 123.33333333333333, 1],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0]],'seg': ...}

在这个例子中,我们感兴趣的键是:

  • img_path
  • joints

关节中总共有 24 个条目。

每个条目有 3 个值:


x 坐标
y 坐标
关键点的可见性标志(1 表示可见,0 表示不可见)


我们可以看到,关节点包含多个 [0, 0, 0] 条目,表示这些关键点没有被标记。

在本例中,我们将同时考虑非可见和未标记的关键点,以便进行迷你批量学习。

# Load the metdata definition file and preview it.
keypoint_def = pd.read_csv(KEYPOINT_DEF)
keypoint_def.head()# Extract the colours and labels.
colours = keypoint_def["Hex colour"].values.tolist()
colours = ["#" + colour for colour in colours]
labels = keypoint_def["Name"].values.tolist()# Utility for reading an image and for getting its annotations.
def get_dog(name):data = json_dict[name]img_data = plt.imread(os.path.join(IMG_DIR, data["img_path"]))# If the image is RGBA convert it to RGB.if img_data.shape[-1] == 4:img_data = img_data.astype(np.uint8)img_data = Image.fromarray(img_data)img_data = np.array(img_data.convert("RGB"))data["img_data"] = img_datareturn data

可视化数据


现在,我们编写一个实用程序来可视化图像及其关键点。

# Parts of this code come from here:
# https://github.com/benjiebob/StanfordExtra/blob/master/demo.ipynb
def visualize_keypoints(images, keypoints):fig, axes = plt.subplots(nrows=len(images), ncols=2, figsize=(16, 12))[ax.axis("off") for ax in np.ravel(axes)]for (ax_orig, ax_all), image, current_keypoint in zip(axes, images, keypoints):ax_orig.imshow(image)ax_all.imshow(image)# If the keypoints were formed by `imgaug` then the coordinates need# to be iterated differently.if isinstance(current_keypoint, KeypointsOnImage):for idx, kp in enumerate(current_keypoint.keypoints):ax_all.scatter([kp.x],[kp.y],c=colours[idx],marker="x",s=50,linewidths=5,)else:current_keypoint = np.array(current_keypoint)# Since the last entry is the visibility flag, we discard it.current_keypoint = current_keypoint[:, :2]for idx, (x, y) in enumerate(current_keypoint):ax_all.scatter([x], [y], c=colours[idx], marker="x", s=50, linewidths=5)plt.tight_layout(pad=2.0)plt.show()# Select four samples randomly for visualization.
samples = list(json_dict.keys())
num_samples = 4
selected_samples = np.random.choice(samples, num_samples, replace=False)images, keypoints = [], []for sample in selected_samples:data = get_dog(sample)image = data["img_data"]keypoint = data["joints"]images.append(image)keypoints.append(keypoint)visualize_keypoints(images, keypoints)

从图中可以看出,我们的图像大小并不均匀,这在现实世界的大多数情况下都是意料之中的。

但是,如果我们将这些图像的大小调整为统一形状(例如 (224 x 224)),它们的地面实况注释也会受到影响。

如果我们对图像进行任何几何变换(例如水平翻转),情况也是一样。幸运的是,imgaug 提供了可以处理这个问题的实用程序。

在后文中,我们将编写一个继承 keras.utils.Sequence 类的数据生成器,使用 imgaug 对成批数据进行数据增强。

准备数据生成器

class KeyPointsDataset(keras.utils.PyDataset):def __init__(self, image_keys, aug, batch_size=BATCH_SIZE, train=True, **kwargs):super().__init__(**kwargs)self.image_keys = image_keysself.aug = augself.batch_size = batch_sizeself.train = trainself.on_epoch_end()def __len__(self):return len(self.image_keys) // self.batch_sizedef on_epoch_end(self):self.indexes = np.arange(len(self.image_keys))if self.train:np.random.shuffle(self.indexes)def __getitem__(self, index):indexes = self.indexes[index * self.batch_size : (index + 1) * self.batch_size]image_keys_temp = [self.image_keys[k] for k in indexes](images, keypoints) = self.__data_generation(image_keys_temp)return (images, keypoints)def __data_generation(self, image_keys_temp):batch_images = np.empty((self.batch_size, IMG_SIZE, IMG_SIZE, 3), dtype="int")batch_keypoints = np.empty((self.batch_size, 1, 1, NUM_KEYPOINTS), dtype="float32")for i, key in enumerate(image_keys_temp):data = get_dog(key)current_keypoint = np.array(data["joints"])[:, :2]kps = []# To apply our data augmentation pipeline, we first need to# form Keypoint objects with the original coordinates.for j in range(0, len(current_keypoint)):kps.append(Keypoint(x=current_keypoint[j][0], y=current_keypoint[j][1]))# We then project the original image and its keypoint coordinates.current_image = data["img_data"]kps_obj = KeypointsOnImage(kps, shape=current_image.shape)# Apply the augmentation pipeline.(new_image, new_kps_obj) = self.aug(image=current_image, keypoints=kps_obj)batch_images[i,] = new_image# Parse the coordinates from the new keypoint object.kp_temp = []for keypoint in new_kps_obj:kp_temp.append(np.nan_to_num(keypoint.x))kp_temp.append(np.nan_to_num(keypoint.y))# More on why this reshaping later.batch_keypoints[i,] = np.array(kp_temp).reshape(1, 1, 24 * 2)# Scale the coordinates to [0, 1] range.batch_keypoints = batch_keypoints / IMG_SIZEreturn (batch_images, batch_keypoints)

要进一步了解如何在 imgaug 中使用关键点,请查看本文。

定义增强变换

train_aug = iaa.Sequential([iaa.Resize(IMG_SIZE, interpolation="linear"),iaa.Fliplr(0.3),# `Sometimes()` applies a function randomly to the inputs with# a given probability (0.3, in this case).iaa.Sometimes(0.3, iaa.Affine(rotate=10, scale=(0.5, 0.7))),]
)test_aug = iaa.Sequential([iaa.Resize(IMG_SIZE, interpolation="linear")])

创建训练和验证分割

np.random.shuffle(samples)
train_keys, validation_keys = (samples[int(len(samples) * 0.15) :],samples[: int(len(samples) * 0.15)],
)

数据生成器调查

train_dataset = KeyPointsDataset(train_keys, train_aug, workers=2, use_multiprocessing=True
)
validation_dataset = KeyPointsDataset(validation_keys, test_aug, train=False, workers=2, use_multiprocessing=True
)print(f"Total batches in training set: {len(train_dataset)}")
print(f"Total batches in validation set: {len(validation_dataset)}")sample_images, sample_keypoints = next(iter(train_dataset))
assert sample_keypoints.max() == 1.0
assert sample_keypoints.min() == 0.0sample_keypoints = sample_keypoints[:4].reshape(-1, 24, 2) * IMG_SIZE
visualize_keypoints(sample_images[:4], sample_keypoints)

演绎展示:
 

Total batches in training set: 166
Total batches in validation set: 29

模型构建


Stanford dogs 数据集(StanfordExtra 数据集基于该数据集)是使用 ImageNet-1k 数据集构建的。因此,在 ImageNet-1k 数据集上预训练的模型很可能对这项任务有用。我们将使用在该数据集上预先训练好的 MobileNetV2 作为骨干,从图像中提取有意义的特征,然后将这些特征传递给自定义回归头用于预测坐标。

def get_model():# Load the pre-trained weights of MobileNetV2 and freeze the weightsbackbone = keras.applications.MobileNetV2(weights="imagenet",include_top=False,input_shape=(IMG_SIZE, IMG_SIZE, 3),)backbone.trainable = Falseinputs = layers.Input((IMG_SIZE, IMG_SIZE, 3))x = keras.applications.mobilenet_v2.preprocess_input(inputs)x = backbone(x)x = layers.Dropout(0.3)(x)x = layers.SeparableConv2D(NUM_KEYPOINTS, kernel_size=5, strides=1, activation="relu")(x)outputs = layers.SeparableConv2D(NUM_KEYPOINTS, kernel_size=3, strides=1, activation="sigmoid")(x)return keras.Model(inputs, outputs, name="keypoint_detector")

我们定制的网络是全卷积网络,因此与具有全连接密集层的相同版本网络相比,它对参数更加友好。

get_model().summary()

演绎展示:

Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224_no_top.h59406464/9406464 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step

请注意网络的输出形状:(None, 1, 1, 48)。

这就是我们重塑坐标的原因:batch_keypoints[i, :] = np.array(kp_temp).reshape(1, 1, 24 * 2)

模型编译和训练


在本例中,我们只对网络进行 5 个历元的训练。

model = get_model()
model.compile(loss="mse", optimizer=keras.optimizers.Adam(1e-4))
model.fit(train_dataset, validation_data=validation_dataset, epochs=EPOCHS)
Epoch 1/5166/166 ━━━━━━━━━━━━━━━━━━━━ 84s 415ms/step - loss: 0.1110 - val_loss: 0.0959
Epoch 2/5166/166 ━━━━━━━━━━━━━━━━━━━━ 79s 472ms/step - loss: 0.0874 - val_loss: 0.0802
Epoch 3/5166/166 ━━━━━━━━━━━━━━━━━━━━ 78s 463ms/step - loss: 0.0789 - val_loss: 0.0765
Epoch 4/5166/166 ━━━━━━━━━━━━━━━━━━━━ 78s 467ms/step - loss: 0.0769 - val_loss: 0.0731
Epoch 5/5166/166 ━━━━━━━━━━━━━━━━━━━━ 77s 464ms/step - loss: 0.0753 - val_loss: 0.0712<keras.src.callbacks.history.History at 0x7fb5c4299ae0>

进行预测并将其可视化

sample_val_images, sample_val_keypoints = next(iter(validation_dataset))
sample_val_images = sample_val_images[:4]
sample_val_keypoints = sample_val_keypoints[:4].reshape(-1, 24, 2) * IMG_SIZE
predictions = model.predict(sample_val_images).reshape(-1, 24, 2) * IMG_SIZE# Ground-truth
visualize_keypoints(sample_val_images, sample_val_keypoints)# Predictions
visualize_keypoints(sample_val_images, predictions)

演绎展示:

 1/1 ━━━━━━━━━━━━━━━━━━━━ 7s 7s/step

通过更多的训练,预测结果可能会有所改善。

更进一步


尝试使用 imgaug 的其他增强变换,研究其对结果的影响。

在这里,我们从预训练网络中线性转移了特征,也就是说,我们没有对其进行微调。

我们鼓励你在这项任务中对其进行微调,看看是否能提高性能。您还可以尝试不同的架构,看看它们对最终性能有什么影响。


这篇关于政安晨:【Keras机器学习示例演绎】(四)—— 利用迁移学习进行关键点检测的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/920084

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X