Python 机器学习中的数据标注(二)
在本章中,我们开始了对图像标注和分类世界的启发之旅。我们首先通过手动检查掌握创建标注规则的艺术,利用 Python 的广泛功能。这项新技能使我们能够将视觉直觉转化为有价值的数据,这在机器学习的领域中是一种关键资产。随着我们进一步深入,我们探索了大小、宽高比、边界框和多边形及折线标注的复杂性。我们学习了如何根据这些定量图像特征制定标注规则,从而引入了一种系统化和可靠的标注方法。我们的探索扩展到了图像
原文:
annas-archive.org/md5/93bc07c74189036ab895556fd18b8659译者:飞龙
第五章:使用规则标注图像数据
在本章中,我们将探讨专门针对图像分类的数据标注技术,使用 Python 实现。我们的主要目标是阐明你需要采取的路径来为这些图像生成精确的标签,这些标签基于精心设计的规则,这些规则基于各种图像属性。你将获得通过手动检查分解和解析图像的能力,利用强大的 Python 生态系统。
在本章中,你将学习以下内容:
-
如何基于 Python 中对图像可视化的手动检查来创建标注规则
-
如何基于图像的大小和宽高比来创建标注规则
-
如何使用预训练模型如YOLO V3应用迁移学习来标注图像数据
总体目标是赋予你生成精确和可靠数据标签的能力。我们的目标是为你提供一套通用的标注策略,这些策略可以应用于各种机器学习项目。
我们还将介绍用于图像标注的变换,如剪切和翻转。我们将提供所需的知识和技术,以有效地利用这些变换,给你的标注过程带来动态优势。我们将深入研究大小、宽高比、边界框、多边形标注和折线标注的复杂性。你将学习如何根据这些定量图像特征推导出标注规则,提供一种系统且可靠的标注数据的方法。
技术要求
本章中使用的示例的完整代码笔记本可在 GitHub 上找到,网址为github.com/PacktPublishing/Data-Labeling-in-Machine-Learning-with-Python。
本章中使用的样本图像数据集可在 GitHub 上找到,网址为github.com/PacktPublishing/Data-Labeling-in-Machine-Learning-with-Python/tree/main/images。
基于图像可视化的标注规则
图像分类是将图像根据其内容分类到一个或多个类别的过程。由于图像的高度可变性和复杂性,这是一个具有挑战性的任务。近年来,机器学习技术已被成功应用于图像分类。然而,机器学习模型需要大量的标注数据来有效训练。
使用 Snorkel 的规则进行图像标注
Snorkel 是一个开源数据平台,它提供了一种使用弱监督技术生成大量标注数据的方法。弱监督允许你使用噪声或不完整的监督源来标注数据,例如启发式方法、规则或模式。
Snorkel 主要在弱监督范式内运行,而不是传统的半监督学习。Snorkel 是一个为弱监督设计的框架,其中标记过程可能涉及噪声、有限或不精确的规则,而不是大量标记数据。
在 Snorkel 中,用户创建标记函数(LFs),这些函数表达启发式或基于规则的标记策略。这些 LFs 可能并不完美,生成的标签中可能存在冲突或噪声。然后,Snorkel 的标记模型学习去噪和组合这些弱标签,以创建更准确和可靠的训练数据标记。
虽然半监督学习通常涉及少量标记数据和大量未标记数据,但 Snorkel 专注于弱监督场景,使用户能够利用各种噪声或不完整的监督源来训练机器学习模型。
总结来说,Snorkel 更符合弱监督的原则,其中重点在于处理由启发式规则生成的噪声或不精确标签,而不是严格归类为半监督学习框架。
在本节中,我们将探讨弱监督的概念以及如何使用 Snorkel 生成标签。
弱监督
弱监督是一种技术,用于使用噪声或不完整的监督源生成大量标记数据。其思想是使用一组 LFs 为每个数据点生成噪声标签。然后,将这些标签组合起来为每个数据点生成一个最终标签。弱监督的关键优势是它允许你快速且低成本地生成标记数据。
Snorkel 是一个提供使用弱监督生成标签方法的框架。它提供了一套工具来创建 LFs、组合它们,并训练一个模型从生成的标签中学习。Snorkel 使用一种称为数据编程的技术来组合 LFs 并为每个数据点生成一个最终标签。
LF 是一个为数据点生成噪声标签的函数。标签可以是任何值,包括连续或离散值。在图像分类的背景下,LF 是一个如果图像包含感兴趣的对象则输出标签 1,否则输出 0 的函数。
LFs 是通过启发式、规则或模式创建的。关键思想是定义一组规则,以捕获每个数据点的相关信息。
现在,让我们看看如何定义基于手动可视化图像对象颜色规则的规则和 LF,用于植物疾病标记。
基于手动可视化图像对象颜色的规则
在本节中,让我们看看如何使用寻找特定视觉特征的 LF,这些特征是植物叶子图像的典型特征,我们感兴趣的是将其分类为“健康”或“死亡”。例如,我们可以使用一个检查图像是否具有特定颜色分布或是否包含那些图像中常见的特定形状的 LF。
Snorkel 的 LF 可以根据各种属性对图像进行标注,例如某些物体的存在、颜色、纹理和形状。以下是一个使用 Snorkel LF 根据颜色分布检测图像的 Python 代码示例。
基于对图像可视化的手动检查创建标注规则是一个手动过程,通常需要人工标注员的专长。这个过程通常用于没有现有标注数据集的情况,你需要为机器学习或分析任务创建标签。
以下是如何在 Python 中基于对图像可视化的手动检查创建标注规则的一般概述:
-
收集代表性样本: 首先从你的数据集中选择一个代表性的图像样本。这个样本应涵盖你想要分类的变异和类别范围。
-
定义标注标准: 明确定义基于图像视觉属性进行标注的准则或规则。例如,如果你正在根据叶子图像对图像进行分类以识别植物疾病,农业专家会通过视觉检查叶子图像以寻找变色、斑点或异常图案。可以根据症状的外观和位置定义规则。我们将在接下来的演示中使用此示例。
-
创建标注界面: 你可以使用现有的工具或库来创建一个标注界面,让人工标注员可以查看图像并根据定义的准则应用标签。例如,可以使用 Labelbox 和 Supervisely 等库或使用 Python Web 框架(如 Flask 或 Django)自定义界面。
-
标注图像: 让人工标注员手动检查你的样本中的每张图像,并根据定义的准则应用标签。这一步骤涉及人工标注员根据他们的专长和提供的指南对图像进行视觉检查并做出分类决策。
-
收集标注: 收集由人工标注员生成的标注。每张图像应根据视觉检查分配相应的标签或类别。
-
分析和正式化规则: 收集足够的标注后,分析标注员做出的模式和决策。尝试根据标注正式化决策标准。例如,你可能观察到具有某些视觉特征的图像被一致地标注为特定类别。
-
将规则转换为代码:将正式化的决策标准转换为代码,该代码可以根据这些规则自动分类图像。此代码可以用 Python 编写,并集成到您的机器学习管道或分析工作流程中。
-
测试和验证规则:将自动标签规则应用于数据集的更大部分,以确保它们具有良好的泛化能力。如果可用,通过比较自动标签与地面真实标签来验证规则,或者通过手动审查自动标签的子集。
-
迭代和改进:根据反馈、错误分析和必要时进行额外的手动检查,迭代地改进标签规则。这个过程可能包括改进规则、添加更多标准或调整阈值。
基于手动检查创建标签规则是一个劳动密集型过程,但在没有其他选择时,生成标记数据可能是必不可少的。您标记数据集的质量和规则的有效性取决于人工标注员的准确性和一致性,以及定义标准的清晰度。
实际应用
在各种实际应用中,手动检查图像进行分类,以及定义规则或模式是常见的。以下是一些实际示例:
-
医学图像分类:
-
示例:将 X 射线或 MRI 图像分类为“正常”或“异常”。
-
规则/模式:放射科医生通过视觉检查图像以识别异常,如肿瘤、骨折或解剖学上的异常。规则可以基于这些特征的存在、大小或位置。
-
-
植物疾病检测:
-
示例:从叶片图像中识别植物疾病。
-
规则/模式:农业专家通过视觉检查叶片图像以识别褪色、斑点或异常模式。可以根据症状的外观和位置定义规则。
-
-
食品质量检查:
-
示例:从图像中将食品产品分类为“新鲜”或“变质”。
-
规则/模式:食品检查员通过视觉检查水果、蔬菜或包装商品的图像以识别腐烂、霉变或其他质量问题。规则可以基于颜色、质地或形状。
-
-
制造缺陷检测:
-
示例:从图像中检测制造产品的缺陷。
-
规则/模式:质量控制检查员通过视觉检查产品图像以识别缺陷,如裂缝、划痕或缺失部件。可以根据缺陷的位置和特征定义规则。
-
-
交通标志识别:
-
示例:从自动驾驶车辆捕获的图像中识别交通标志。
-
规则/模式:工程师通过视觉检查图像以识别其形状、颜色和符号等特征。可以根据这些视觉线索定义规则。
-
-
野生动物监测:
-
示例:从相机陷阱图像中识别和跟踪动物。
-
规则/模式:野生动物专家通过视觉检查图像以确定特定动物物种的存在、其行为或一天中的时间。规则可以基于动物的外观和上下文。
-
-
历史文档分类:
-
示例:根据内容或时代对历史文档进行分类。
-
规则/模式:档案保管员通过视觉检查扫描的文档的手写风格、语言、内容或视觉元素(如插图)。可以根据这些特征定义规则。
-
-
安全和监控:
-
示例:在监控摄像头录像中识别安全威胁或入侵者。
-
规则/模式:安全人员通过视频流视觉检查异常行为、可疑物体或未经授权的访问。可以根据这些观察结果定义规则。
-
在所有这些例子中,专家或人工标注者通过视觉检查图像,识别相关模式或特征,并定义分类的规则或标准。这些规则通常基于领域知识和经验。一旦建立,这些规则可以用来创建 LF 并自动分类图像,协助决策或优先分析。
植物疾病检测的一个实际例子
让我们看看用于植物疾病检测的示例 LF。在这段代码中,我们创建了一个规则来根据叶子的颜色分布将植物分类为健康或病态。一个规则是如果植物叶子中的black_pixel_percentage大于阈值值,那么我们将该植物分类为病态植物。
下面是两种不同的植物叶子类型。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_05_2_Merged_(2
图 5.1 – 健康和病态植物叶子
我们计算叶子图像中黑色像素的数量,然后计算黑色像素的百分比:
黑色像素百分比 = 叶子图像中黑色像素的数量/叶子图像中总像素数量
我们将使用以下规则:如果一个植物叶子图像中的黑色像素百分比大于阈值值(在这个例子中,10%),那么我们将该植物分类为病态植物,并标记为“病态植物”。
同样,如果黑色像素百分比小于 10%,那么我们将该植物分类为健康植物,并标记为“健康植物”。
以下代码片段展示了如何使用 Python 库计算图像中的黑色像素百分比:
# Convert the image to grayscale
gray_image = cv2.cvtColor(resized_image, cv2.COLOR_BGR2GRAY)
这一行将原始彩色图像转换为灰度图,使用 OpenCV 的cvtColor函数。灰度图像只有一个通道(与彩色图像中的三个通道相比),表示每个像素的强度或亮度。转换为灰度图简化了后续处理:
# Apply thresholding to detect regions with discoloration
_, binary_image = cv2.threshold(gray_image, 150, 255,\
cv2.THRESH_BINARY_INV)
在这一行,对灰度图像gray_image应用了阈值操作。阈值是一种技术,根据像素的强度值将像素分为两类——高于某个阈值的像素和低于阈值的像素。以下是对每个参数的解释:
-
gray_image:要阈值化的灰度图像。 -
150:阈值值。强度值大于或等于 150 的像素将设置为最大值(255),而强度值低于 150 的像素将设置为0。 -
255:高于阈值的像素设置的最大值。 -
cv2.THRESH_BINARY_INV:阈值类型。在这种情况下,它设置为“二值反转”,这意味着高于阈值的像素将变为 0,而低于阈值的像素将变为 255。
此阈值操作的结果存储在binary_image中,这是一个突出显示褪色区域的二值图像:
# Calculate the percentage of black pixels (discoloration) in the image
white_pixel_percentage = \
(cv2.countNonZero(binary_image) / binary_image.size) * 100
cv2.countNonZero(binary_image)函数计算二值图像中非零(白色)像素的数量。由于我们感兴趣的是黑色像素(褪色),我们从图像中的总像素数中减去这个计数。
binary_image.size:这是二值图像中的总像素数,等于宽度乘以高度。
通过将非零(白色)像素的计数除以总像素数并乘以 100,我们得到图像中白色像素的百分比。这个百分比代表了图像中褪色的程度。
要计算黑色像素(褪色)的百分比,可以使用以下代码:
black_pixel_percentage = 100 - white_pixel_percentage
总体来说,这个代码片段是一种简单的方法,通过将其转换为二值图像并计算黑色像素的百分比来定量测量灰度图像褪色的程度。它可以用于检测图像中的缺陷或异常等任务。调整阈值值(在本例中为 150)可以改变检测的灵敏度。
让我们创建一个标记函数,根据叶图像中black_pixel_percentage的阈值值将植物分类为Healthy或Diseased,如下所示。
# Define a labeling function to classify images as "Healthy"
@labeling_function()
def is_healthy(record):
# Define a threshold for discoloration (adjust as needed)
threshold = 10
# Classify as "Healthy" if the percentage of discoloration is below the threshold
if record['black_pixel_percentage'] < threshold:
return 1 # Label as "Healthy"
else:
return 0 # Label as "Diseased"
此 LF 根据图像中黑色像素百分比对标签0(患病植物)或1(健康植物)进行返回。此植物疾病标签的完整工作代码可在 GitHub 仓库中找到。
在下一节中,让我们看看如何使用图像属性(如大小和宽高比)应用标签。
基于属性进行图像标记
让我们看看一个 Python 代码示例,演示如何根据图像属性(如大小和宽高比)使用规则对图像进行分类。
在这里,我们将定义规则,例如,如果叶子中的黑色颜色分布大于 50%,则该植物为病态植物。同样,在检测有行人的自行车时,如果图像的长宽比大于某个阈值,则该图像包含有行人的自行车。
在计算机视觉和图像分类中,长宽比指的是图像或对象宽度与高度的比例。它是衡量对象或图像在水平和垂直维度上拉长或拉伸程度的度量。长宽比常用于图像分析和分类中的特征或标准。值得注意的是,长宽比本身通常不足以进行分类,它通常与其他特征一起使用,如轮廓高度、纹理和边缘,以实现准确的分类结果。边界框、多边形标注和多段线标注等图像属性常用于计算机视觉任务中的对象检测和图像分割。这些属性帮助您在图像中对对象进行标注。以下是每个特征的说明以及演示如何使用它们的 Python 代码示例:
边界框
边界框是包围图像中感兴趣对象的矩形区域。它由四个值定义——(x_min, y_min) 表示左上角,(x_max, y_max) 表示右下角。边界框通常用于对象检测和定位。以下是一个创建和操作边界框的 Python 代码示例:
# Define a bounding box as (x_min, y_min, x_max, y_max)
bounding_box = (100, 50, 300, 200)
# Access individual components
x_min, y_min, x_max, y_max = bounding_box
# Calculate width and height of the bounding box
width = x_max - x_min
height = y_max - y_min
# Check if a point (x, y) is inside the bounding box
x, y = 200, 150
is_inside = x_min <= x <= x_max and y_min <= y <= y_max
print(f"Width: {width}, Height: {height}, Is Inside: {is_inside}")
多边形标注
多边形标注是一组连接的顶点,用于在图像中勾勒出对象的形状。它由表示顶点的 (x, y) 坐标列表定义。多边形标注用于详细的对象分割。以下是一些用于处理多边形标注的 Python 代码示例:
# Define a polygon annotation as a list of (x, y) coordinates
polygon = [(100, 50), (200, 50), (250, 150), (150, 200)]
# Calculate the area of the polygon (using shoelace formula)
def polygon_area(vertices):
n = len(vertices)
area = 0
for i in range(n):
j = (i + 1) % n
area += (vertices[i][0] * vertices[j][1]) - \
(vertices[j][0] * vertices[i][1])
area = abs(area) / 2
return area
area = polygon_area(polygon)
print(f"Polygon Area: {area}")
多段线标注
多段线标注是由每个顶点的 (x, y) 坐标列表定义的一系列连接线段。多段线通常用于表示由多个线段组成的形状,如道路或路径。以下是一些用于处理多段线标注的 Python 代码示例:
# Define a polyline annotation as a list of (x, y) coordinates
polyline = [(100, 50), (200, 50), (250, 150), (150, 200)]
# Calculate the total length of the polyline
def polyline_length(vertices):
length = 0
for i in range(1, len(vertices)):
x1, y1 = vertices[i - 1]
x2, y2 = vertices[i]
length += ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
return length
length = polyline_length(polyline)
print(f"Polyline Length: {length}")
这些代码示例展示了如何在 Python 中处理边界框、多边形标注和多段线标注。您可以使用这些概念来创建规则,在计算机视觉应用中对图像进行标注。
现在,让我们看看以下示例,了解我们如何使用轮廓高度来区分图像中是否包含骑自行车的行人或仅显示自行车的图像。
示例 1 – 图像分类 – 有无行人的自行车
轮廓高度,在图像处理和计算机视觉的背景下,指的是测量图像中对象轮廓或轮廓的垂直范围或尺寸。它通常通过找到对象的边界或轮廓的最小和最大垂直位置(即最高点和最低点)来计算。
这里是如何通常确定轮廓高度的:
-
轮廓检测:第一步是在图像中检测对象的轮廓。轮廓基本上是分离对象与其背景的边界。
-
边界矩形:一旦检测到轮廓,就会在轮廓周围绘制一个边界矩形(通常称为“边界框”)。这个矩形包含了整个对象。
-
测量:为了计算轮廓高度,测量边界矩形的垂直范围。这是通过找到边界矩形的顶部和底部边界的 y 坐标(垂直位置)之间的差异来完成的。
总结来说,轮廓高度提供了关于图像中对象垂直尺寸的信息。它可以是各种计算机视觉任务的有用特征,例如物体识别、跟踪和尺寸估计。
让我们看看我们将如何使用 Python 函数根据轮廓高度检测以下图像。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_05_2_Merged_(1g)
a: 有人的自行车 b: 无人的自行车
图 5.2 – 关于轮廓高度的两种图像的比较
在这里,图像中骑自行车的轮廓高度(图 5*.2a*)大于无人的自行车图像的轮廓高度(图 5*.2b*)。
让我们使用 Python 库 CV2 Canny 边缘检测器来检测给定图像的最大轮廓高度,如下所示:
# Define a function to find the contour height of an object using the Canny edge detector
def canny_contour_height(image):
此函数接受一个图像作为输入,并返回使用 Canny 边缘检测器找到的最大轮廓高度:
# Convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply the Canny edge detector with low and high threshold values
edges = cv2.Canny(gray, 100, 200)
# Find the contours of the edges
contours, _ = cv2.findContours(edges, \
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Initialize the maximum height as zero
max_height = 0
# Loop through each contour
for cnt in contours:
# Find the bounding rectangle of the contour
x, y, w, h = cv2.boundingRect(cnt)
# Update the maximum height if the current height is larger
if h > max_height:
max_height = h
# Return the maximum height
return max_height
在这里,使用 Python 函数来找到图像的轮廓高度。如图像所示,结果显示骑自行车的图像的轮廓高度大于无人的自行车图像的轮廓高度。因此,我们可以通过使用轮廓高度的某个阈值来对这些图像进行分类;如果大于该阈值,则将这些图像分类为带人的自行车;否则,如果轮廓高度小于该阈值,则将这些图像分类为仅显示自行车。
如前所述的 LF 所示,(我们在第二章中学习了标签函数)我们可以使用 Python 自动化此类图像分类和对象检测任务,并将图像标记为骑自行车的男子或仅自行车。
查找前两个图像轮廓高度的全部代码在 GitHub 上。
通过使用一组多样化的 LFs 来捕捉图像内容的各个方面,我们可以增加至少一些函数将提供一种有用的方式来区分描绘自行车的图像、带有人的自行车的图像或两者都不是的图像的可能性。然后,由多数投票模型生成的概率标签将反映所有 LFs 提供的联合证据,并且可以用来做出更准确的分类决策。
示例 2 – 图像分类 – 狗和猫图像
让我们看看另一个基于属性相关规则的图像标记示例,用于分类狗或猫图像。
以下是一些规则,作为 LFs 来检测狗的图像,基于尖耳朵和鼻子的形状、眼睛的形状、毛发纹理和身体形状,以及检测其他特征的附加 LFs。这些函数的完整代码可在 GitHub 上找到。
标签函数 1:规则是,如果图像有尖耳朵和鼻子的形状,则将其标记为狗:
# Define a labeling function to detect dogs based on pointy ears and snouts
def dog_features(image):
....
# If the image has pointy ears and a snout, label it as a dog
if has_pointy_ears and has_snout:
return 1
else:
return 0
标签函数 2:规则是,如果图像有椭圆形的眼睛,则将其标记为猫:
# Define a labeling function to detect cats based on their eyes
def cat_features(image):
# Label images as positive if they contain cat features #such as oval-shaped eyes
# If the image has oval-shaped eyes, label it as a cat
if has_oval_eyes:
return 1
else:
return 0
标签函数 3:规则是,如果图像具有高方差的纹理,则将其标记为狗:
# Define a labeling function to detect dogs based on fur texture
def dog_fur_texture(image):
# If the image has high variance, label it as a dog
if variance > 100:
return 1
else:
return 0
标签函数 4:规则是,如果长宽比接近 1(表示更圆形的形状),则将其标记为猫:
# Define a labeling function to detect cats based on their body shape
def cat_body_shape(image):
.....
# If the aspect ratio is close to 1 (indicating a more circular shape), label it as a cat
if abs(aspect_ratio - 1) < 0.1:
return 1
else:
return 0
dog_features LF 通过检查蓝色通道的特定区域来寻找图像中尖耳朵和鼻子的存在。cat_features LF 在绿色通道中寻找椭圆形眼睛的存在。dog_fur_texture LF 在图像的灰度版本中寻找高方差,这通常与狗的毛发纹理相关。cat_body_shape LF 在图像中寻找圆形的身体形状,这通常与猫相关。
这些 LFs 可以与 Snorkel 结合起来创建模型并标记图像。在下一节中,我们将看看如何使用迁移学习应用标签。
使用迁移学习进行图像标记
迁移学习是一种机器学习技术,其中在一个任务上训练的模型被调整用于第二个相关任务。而不是从头开始学习过程,迁移学习利用解决一个问题的知识,并将其应用于不同但相关的问题。这种方法在深度学习中变得越来越流行,并且具有几个优点:
-
更快的学习:迁移学习可以显著减少训练模型所需的时间和计算资源。与其从随机初始化开始训练深度神经网络,你从已经学习到特征和表示的预训练模型开始。
-
更好的泛化:在大型数据集上预训练的模型,如用于图像识别的 ImageNet,已经学习到了对各种相关任务有用的通用特征。这些特征往往很好地泛化到新任务中,从而提高了性能。
-
降低数据需求:当您为您的目标任务有限的数据时,迁移学习特别有益。预训练模型可以提供一个起点,使使用较小的数据集进行有效学习成为可能。
-
领域自适应:迁移学习有助于将模型从一个领域(例如自然图像)迁移到另一个领域(例如医学图像)。当在目标领域收集数据具有挑战性时,这非常有价值。
让我们看看一个使用 Snorkel LFs 检测手写 MNIST 图像中数字的 Python 代码示例。
示例 – 使用预训练分类器进行数字分类
在这个例子中,我们首先使用 Keras 加载 MNIST 数据集,然后定义一个使用数字分类模型对每个图像中的数字进行分类的 LF。然后我们将 MNIST 图像加载到 Snorkel 数据集中,并应用 LF 为指定的数字生成标签。最后,我们使用 Snorkel 的查看器可视化标签。
注意,在这个例子中,我们假设您已经训练了一个数字分类模型并将其保存为名为 digit_classifier.h5 的文件。您可以将其替换为您选择的任何其他模型。同时,请确保提供模型文件的正确路径。最后,LF 生成的标签将是 1 如果图像具有指定的数字,否则是 -1:
#Importing Libraries
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import load_model
在此块中,导入了 TensorFlow 以及与 MNIST 数据集和预训练模型一起工作的特定模块。
MNIST 数据集被加载到两个集合中 - x_test 包含图像,而 y_test 包含相应的标签。训练集在此代码片段中未使用:
(_, _), (x_test, y_test) = mnist.load_data()
使用 load_model 函数加载预训练模型。确保将 mnist_model.h5 替换为您的预训练模型文件的正确路径:
model = load_model('mnist_model.h5')
图像的像素值通过将数据类型转换为 float32 并除以 255 来归一化,使其位于 [0, 1] 范围内:
x_test = x_test.astype('float32') / 255
图像被重塑以匹配模型期望的输入形状,即 (batch_size, height, width, 和 channels):
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
使用预训练模型在测试数据集上做出预测,并打印出第一张图像的预测结果:
predictions = model.predict(x_test)
print("predictions",predictions[0])
MNIST 数字(0-9)的类别标签被创建为字符串并打印:
class_labels = [str(i) for i in range(10)]
print("class_labels:", class_labels
脚本遍历测试数据集,打印出每个图像的最大预测值索引、预测数字和实际数字标签:
for i in range(len(x_test)):
print("maxpredict", predictions[i].argmax())
predicted_digit = class_labels[predictions[i].argmax()]
actual_digit = str(y_test[i])
print(f"Predicted: {predicted_digit}, Actual: {actual_digit}")
这是输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_05_3.jpg
图 5.3 – 数字分类的输出
让我们再看看另一个使用预训练分类器定义规则的示例。在下面的示例中,我们将使用预训练模型 YOLO V3 来检测图像中的人,然后我们将应用一个 LF 来标记大量图像数据。
示例 – 使用 YOLO V3 预训练分类器进行人员图像检测
让我们开始编写代码:
# Load an image for object detection using cv2
image = cv2.imread('path/to/image.jpg')
# Define rules based on image properties
# Returns True if image contains a person, otherwise returns False
# Use a pre-trained person detection model, e.g. YOLOv3 , to detect people in the image
预定义的 YOLO 模型和权重是开源的,可以在pjreddie.com/darknet/yolo下载:
def has_person(image):
# Load the YOLOv3 model with its weights and configuration files
net = cv2.dnn.readNetFromDarknet("path/to/yolov3.cfg", \
"path/to/yolov3.weights")
# Load the COCO class names (used for labeling detected objects)
classes = []
with open("path/to/coco.names", "r") as f:
classes = [line.strip() for line in f.readlines()]
# Create a blob from the image and set it as input to the network
blob = cv2.dnn.blobFromImage(image, 1/255.0, (416, 416), \
swapRB=True, crop=False) net.setInput(blob)
# Run forward pass to perform object detection
detections = net.forward()
# Process and interpret the detection results
for detection in detections:
# Process detection results and draw bounding boxes if needed
# You can use classes to map class IDs to class names
if confidence > confidence_threshold and classes[class_id] == "person":
if len(boxes) > 0:
return True
else:
return False
在此代码中,我们使用 OpenCV 加载 YOLO V3 模型、其权重和配置文件。然后,我们提供一个输入图像,通过网络进行前向传递,并处理检测结果。
你需要将 "path/to/yolov3.cfg"、"path/to/coco.names" 和 "path/to/image.jpg" 替换为你的 YOLOv3 配置文件、类别名称文件和你要进行对象检测的图像的实际路径。
记住,YOLO V3 是一个复杂的深度学习模型,旨在进行实时对象检测,有效地使用它通常需要一些计算机视觉和深度学习概念的知识。
示例 - 使用 YOLO V3 预训练分类器检测自行车图像
以下是这个示例的代码:
def has_bicycle(image):
# Returns True if image contains a bicycle, otherwise returns False
model = tf.saved_model.load(
"path/to/faster_rcnn_inception_v2_coco_2018_01_28/saved_model")
img_resized = cv2.resize(image, (600, 600))
input_tensor = tf.convert_to_tensor(img_resized)
input_tensor = input_tensor[tf.newaxis, ...]
detections = model(input_tensor)
num_detections = int(detections.pop('num_detections'))
detections = {key: value[0, :num_detections].numpy() \
for key, value in detections.items()}
总结来说,代码片段利用预训练的 Faster R-CNN 模型在输入图像上执行对象检测。它调整图像大小,将其转换为张量,然后提取并处理检测结果。要特别检测自行车,你需要根据模型提供的类别标签过滤结果,并检查检测到的对象中是否存在自行车。
现在,让我们探索如何将变换应用于给定的图像数据集以生成额外的合成数据。额外的合成数据有助于训练并实现更准确的结果,因为模型将学习图像的不同位置。
使用变换标记图像
在本节中,让我们看看可以应用于图像的不同类型的变换,以在数据有限的情况下生成合成数据。在机器学习中,剪切和翻转通常用作图像增强技术,以增加训练数据的多样性。它有助于提高模型识别不同角度或方向的物体的能力。
剪切可以在计算机视觉任务中用于纠正图像中的透视失真。例如,它可以应用于校正扫描文档中倾斜的文本。
图像剪切是一种通过将像素移动到特定方向来扭曲图像的变换。它涉及沿图像的一个轴移动图像的像素,同时保持另一个轴不变。主要有两种剪切类型:
-
水平剪切:在这种情况下,像素在水平方向上移动,通常以对角线方式移动,导致图像向左或向右倾斜
-
垂直剪切:在这里,像素在垂直方向上移动,导致图像向上或向下倾斜
要执行图像剪切,你通常指定剪切量(失真程度)和方向(水平或垂直)。剪切量通常定义为剪切角度或剪切因子。
图像剪切通常使用剪切矩阵来完成。例如,在 2D 计算机图形学中,一个水平剪切矩阵可能看起来像这样:
| 1 shear_x |
| 0 1 |
在这里,shear_x表示应用的横向剪切量。
通过对一个图像应用随机的剪切变换,我们可以生成具有略微不同像素值的多个图像版本。这些变化可以提供一种有用的方法来识别对象的特征性视觉模式或特征。
同样,图像翻转是另一种可以用于识别花朵的变换。通过水平或垂直翻转图像,我们可以生成包含不同视觉模式或特征的新图像版本。例如,我们可以使用一个检查图像是否沿某一轴翻转的 LF,将翻转的图像标注为正面描绘花朵。这个 LF 能够捕捉到许多花朵具有双边对称性的事实,这意味着它们沿特定轴翻转时看起来相似。
总体而言,通过应用剪切或翻转等图像变换,我们可以生成更多标记的示例,这些示例可以捕捉到图像内容的各个方面。这有助于通过提供更多样化和稳健的训练数据来提高分类模型的准确性。
我们将在下一章进一步探讨图像变换以及其他数据增强技术和示例。
摘要
在本章中,我们开始了对图像标注和分类世界的启发之旅。我们首先通过手动检查掌握创建标注规则的艺术,利用 Python 的广泛功能。这项新技能使我们能够将视觉直觉转化为有价值的数据,这在机器学习的领域中是一种关键资产。
随着我们进一步深入,我们探索了大小、宽高比、边界框和多边形及折线标注的复杂性。我们学习了如何根据这些定量图像特征制定标注规则,从而引入了一种系统化和可靠的标注方法。
我们的探索扩展到了图像处理的变革领域。我们利用了剪切和翻转等图像变换的潜力,通过动态灵活性增强了我们的标注过程。
此外,我们将我们的知识应用于现实世界的场景,通过基于规则的 LF 对植物病害图像进行分类。我们通过利用宽高比和轮廓高度来预测对象,提高了我们的技能,这在识别骑自行车的人等场景中是一种宝贵的资产。此外,我们还深入研究了预训练模型和迁移学习在图像分类中的强大领域。
但我们的旅程远未结束。在接下来的章节中,我们将更深入地探索图像数据增强的领域。我们将探讨高级技术,并学习如何使用增强数据通过支持向量机(SVMs)和卷积神经网络(CNNs)进行图像分类。准备好迎接下一章的精彩内容吧!
第六章:使用数据增强对图像数据进行标记
在本章中,我们将学习如何使用数据增强对图像数据进行标记,以进行半监督机器学习。我们将使用 CIFAR-10 数据集和 MNIST 手写数字数据集来生成标签,然后我们将构建一个图像分类机器学习模型。
数据增强在数据标记中起着至关重要的作用,通过增强数据集的多样性、大小和质量。数据增强技术通过对现有数据进行变换来生成额外的样本。这有效地增加了数据集的大小,为训练提供了更多示例,并提高了模型泛化的能力。
本章我们将涵盖以下内容:
-
如何使用图像数据增强准备训练数据并实现支持向量机
-
如何使用增强图像数据实现卷积神经网络
技术要求
对于本章,我们将使用 CIFAR-10 数据集,这是一个包含 10 个类别的 60,000 个 32x32 彩色图像的公开图像数据集(www.cs.toronto.edu/~kriz/cifar.html),以及著名的 MNIST 手写数字数据集。
使用增强图像数据训练支持向量机
支持向量机(SVMs)在机器学习中广泛用于解决分类问题。SVMs 以其高准确性和处理复杂数据集的能力而闻名。训练 SVMs 的一个挑战是大型和多样化的数据集的可用性。在本节中,我们将讨论数据增强在训练 SVMs 进行图像分类问题中的重要性。我们还将为每种技术提供 Python 代码示例。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_06_01.jpg
图 6.1 – SVM 使用最大间隔将类别 A 和类别 B 分开
SVMs 是一种用于分类和回归分析的监督学习算法。SVMs 可用于异常检测。SVMs 最初是为分类任务设计的,但也可以用于异常或异常检测。
SVMs 的目标是找到最大化两类数据之间间隔的超平面。超平面被定义为分隔两类数据点的决策边界。间隔是超平面与每个类最近的点之间的距离。
SVMs 使用一种称为核技巧的东西。让我们接下来了解这是什么。
核技巧
假设你在一张纸上有点,你想要将它们分成两组。想象你有一根魔法棒(即核技巧),它允许你将点从纸上抬起进入空中。在空中,你可以轻松地画一条线或曲线来分隔漂浮的点。
现在,当你对空气中的分离效果满意时,再次使用魔棒将所有内容拉回到纸上。奇迹般地,你在空中绘制的分离线在纸上转化为一个更复杂的决策边界,有效地分离了你的原始数据点。
在 SVM(支持向量机)的世界里,这个“魔棒”就是核技巧。它允许 SVM 在更高维的空间中隐式地工作,使得找到更复杂的决策边界成为可能,这些决策边界在原始空间中是无法实现的。关键是,你不必显式地计算更高维空间的坐标;核技巧会为你完成这项工作。
总结来说,核技巧将你的数据提升到更高维的空间,在那里 SVM 可以找到更复杂的方法来分离不同的类别。它是处理复杂数据场景的强大工具。
SVM 利用核技巧将输入数据转换到更高维的空间,在那里可以找到一个线性决策边界。核函数在这个过程中起着至关重要的作用,它将输入数据映射到一个特征空间,其中变量之间的关系可能更容易分离。
最常用的核函数包括线性核,它表示线性决策边界;多项式核,它通过引入高阶多项式特征引入非线性;以及径向基函数(RBF)核,它允许更灵活的非线性决策边界。核函数的选择及其参数显著影响 SVM 建模数据中复杂关系的能力。
既然我们已经对 SVM 有了基本的了解,接下来让我们了解数据增强、图像数据增强以及用于此的各种技术。
数据增强
数据增强是通过应用各种变换(如旋转、平移和缩放)从现有数据点创建新数据点的过程。数据增强通过帮助模型在数据中学习更多特征和模式,用于增加训练数据集的大小并提高模型的泛化能力和准确性。
图像数据增强
图像数据增强是一种增强图像数据集的技术,以提高模型的准确性。以下是一些可用于图像数据增强的技术选择。
图像旋转
图像旋转是一种技术,其中图像通过一定角度进行旋转。这项技术用于增加训练数据集的大小并提高模型从不同角度识别对象的能力。图像旋转的 Python 代码如下:
from PIL import Image
import numpy as np
def rotate_image(image_path, degrees):
img = Image.open(image_path)
rotated_image = img.rotate(degrees)
return rotated_image
image_path = "path/to/image.jpg"
rotated_image = rotate_image(image_path, 45)
rotated_image.show()
在前面的代码中,我们从图像路径加载图像,并以给定的度数旋转它。这为同一图像从不同角度创建了一个新的数据集,并提高了模型训练的效果。
图像平移
图像翻译是一种技术,其中图像通过一定的像素量水平或垂直移动。这种技术用于增加训练数据集的大小并提高模型识别不同位置对象的能力。图像翻译的 Python 代码如下:
from PIL import Image
import numpy as np
def translate_image(image_path, x_offset, y_offset):
img = Image.open(image_path)
translated_image = img.transform(img.size, \
Image.AFFINE, (1, 0, x_offset, 0, 1, y_offset))
return translated_image
image_path = "path/to/image.jpg"
translated_image = translate_image(image_path, 50, 50)
translated_image.show()
在前面的代码中,我们定义了一个 Python 函数,该函数通过一定的像素量移动图像。
图像缩放
图像缩放是一种增强技术,其中图像通过一定的因子放大或缩小。这种技术用于增加训练数据集的大小并提高模型识别不同尺度对象的能力。图像缩放的 Python 代码如下:
from PIL import Image
import numpy as np
def scale_image(image_path, scale_factor):
img = Image.open(image_path)
scaled_image = img.resize((int(img.size[0]*scale_factor),\
int(img.size[1]*scale_factor)))
return scaled_image
image_path = "path/to/image.jpg"
scaled_image = scale_image(image_path, 0.5)
scaled_image.show()
在前面的代码中,我们通过在 Python 函数中将图像乘以一个缩放因子来改变图像大小。接下来,让我们看看如何使用 CIFAR-10 数据集实现具有数据增强的 SVM。
在 Python 中实现具有数据增强的 SVM
在本节中,我们将提供使用 CIFAR-10 数据集在 Python 中实现具有数据增强的 SVM 的逐步指南。我们将首先介绍 CIFAR-10 数据集,然后转到在 Python 中加载数据集。然后,我们将对数据进行 SVM 训练的前处理,并实现具有默认超参数和数据集的 SVM。接下来,我们将使用增强数据集训练和评估 SVM 的性能,以表明 SVM 在增强数据集上的性能有所提高。
介绍 CIFAR-10 数据集
CIFAR-10 数据集是一个常用的图像分类数据集,包含 10 个类别的 60,000 个 32x32 彩色图像。这些类别包括:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。数据集分为 50,000 个训练图像和 10,000 个测试图像。数据集经过预处理,使得训练集和测试集中每个类别的图像数量相等。
在 Python 中加载 CIFAR-10 数据集
在 Python 中加载 CIFAR-10 数据集时,我们将使用 Keras 库中的cifar10模块。如果您还没有安装 Keras,可以使用以下命令进行安装:
pip install keras
安装 Keras 后,您可以使用以下代码加载 CIFAR-10 数据集:
from keras.datasets import cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
cifar10.load_data()函数返回两个元组:(x_train, y_train)和(x_test, y_test)。x_train和x_test元组包含输入图像,而y_train和y_test元组包含输入图像对应的类标签。
对 SVM 训练数据进行预处理
在本节中,我们首先将输入图像从 3D 矩阵转换为 2D 矩阵。我们还将输入图像的像素值归一化到 0 到 1 之间。最后,我们将输入图像重塑并转换类标签为 one-hot 编码向量。
使用reshape()函数将输入图像从 3D 矩阵重塑为 2D 矩阵。-1参数告诉函数根据行数和每行的大小推断列数:
# Reshape the input images
x_train = x_train.reshape(x_train.shape[0], -1)
x_test = x_test.reshape(x_test.shape[0], -1)
输入图像的像素值通过除以 255(这是最大像素值)进行归一化,使其介于 0 和 1 之间:
# Convert pixel values to between 0 and 1
x_train = x_train / 255
x_test = x_test / 255
使用to_categorical()函数将类别标签转换为独热编码向量。num_classes变量设置为10,这是 CIFAR-10 数据集中的类别数量:
# Convert class labels to one-hot encoded vectors
num_classes = 10
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
使用默认超参数实现 SVM
SVM 中的超参数是在训练过程之前设置的参数,而不是从数据中学习的参数。它们控制 SVM 模型的行为,并可能对其性能产生重大影响。以下是 SVM 中的一些重要超参数:
-
核函数:核函数决定了 SVM 使用的决策边界的类型。常见的核函数包括线性、多项式、径向基函数(RBF)和 sigmoid 函数。核函数的选择取决于数据和问题。
-
正则化参数(C):正则化是一种用于防止模型过拟合或欠拟合的技术。正则化方法有助于控制模型的复杂性并提高其在未见数据上的泛化能力。
对于二元分类问题,决策边界是一个将数据分为两个类别的超平面。边缘是此超平面与任一类别最近的数据点之间的距离。边缘的“宽度”是决策边界与最近数据点之间距离的实际数值或间隙。
较大的边缘意味着类别之间的分离更大,为潜在的误分类提供了更多空间,而不会影响决策边界。正则化参数,通常表示为 C,控制了实现低训练错误率与保持宽边缘之间的权衡。较小的 C 值允许更多的误分类,但会导致更大的边缘,而较大的 C 值试图以牺牲较窄的边缘为代价来最小化误分类。
-
伽马(对于 RBF 核):伽马参数影响具有 RBF 核的 SVM 决策边界的形状。它决定了每个训练样本的可达范围并影响决策边界的平滑度。较高的伽马值往往会导致更复杂的决策边界。
-
度(对于多项式核):度参数指定多项式核函数的度。它决定了决策边界的非线性。较高的度值允许更复杂的决策边界,但可能增加过拟合的风险。
这些超参数需要仔细调整以达到 SVM 模型的最佳性能。可以使用网格搜索、随机搜索或其他优化技术来探索不同超参数值的组合,并选择最佳集。
为了实现具有默认超参数的 SVM,我们将使用 scikit-learn 库中的svm.SVC类。我们首先创建一个SVC类的实例,然后将训练数据拟合到分类器。
使用svm.SVC()创建了一个SVC类的实例。通过不指定任何超参数,它使用默认的核函数、正则化参数(C)和其他相关参数的值:
from sklearn import svm
# Create an instance of the SVC class with default hyperparameters
clf = svm.SVC()
fit()函数用于将训练数据拟合到分类器:
# Fit the training data to the classifier
clf.fit(x_train, y_train)
评估原始数据集上的 SVM
我们评估原始数据集的性能,以比较与增强数据集的性能。
为了评估原始数据集上 SVM 的性能,我们将使用predict()函数预测测试数据的类别标签,然后使用 scikit-learn 库中的accuracy_score()函数计算分类器的准确率:
from sklearn.metrics import accuracy_score
# Predict the class labels of the test data
y_pred = clf.predict(x_test)
# Calculate the accuracy of the classifier
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
predict()函数用于预测测试数据的类别标签。accuracy_score()函数通过比较预测的类别标签和实际类别标签来计算分类器的准确率。
SVM 模型在测试数据集上的准确率约为47.97%,这并不很好。这表明 SVM 模型无法学习原始数据集中所有的重要特征和模式。
实现使用增强数据集的 SVM
为了实现具有数据增强的 SVM,我们将使用 Keras 库中的ImageDataGenerator类来生成新的训练数据。我们首先创建一个ImageDataGenerator类的实例,然后使用flow()函数生成新的训练数据批次:
from keras.preprocessing.image import ImageDataGenerator
# Create an instance of the ImageDataGenerator class
datagen = ImageDataGenerator(rotation_range=20, \
width_shift_range=0.1, height_shift_range=0.1, \
shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
# Generate new batches of training data
gen_train = datagen.flow(x_train, y_train, batch_size=64)
ImageDataGenerator()函数创建了一个ImageDataGenerator类的实例。rotation_range、width_shift_range、height_shift_range、shear_range、zoom_range和horizontal_flip参数用于指定要应用于训练数据的增强数据类型。
flow()函数用于从原始训练数据和ImageDataGenerator对象生成新的训练数据批次。
在增强数据上训练 SVM
要在增强数据上训练支持向量机(SVM),我们将使用SVC类的partial_fit()函数,在每个由ImageDataGenerator对象生成的训练数据批次上训练分类器:
# Train the classifier on each batch of training data
for i in range(100):
x_batch, y_batch = gen_train.next()
clf.partial_fit(x_batch, y_batch, classes=np.unique(y_train))
classes参数用于指定训练数据中的唯一类别。
评估增强数据集上 SVM 的性能
为了评估 SVM 在增强数据集上的性能,我们将再次使用predict()函数来预测测试数据的类别标签,然后使用accuracy_score()函数通过比较预测的类别标签和实际类别标签来计算分类器的准确度:
# Predict the class labels of the test data
y_pred_aug = clf.predict(x_test)
# Calculate the accuracy of the classifier
accuracy_aug = accuracy_score(y_test, y_pred_aug)
print("Accuracy with Data Augmentation: %.2f%%" % (accuracy_aug * 100.0))
在增强的测试数据集上,SVM 模型的准确率约为54.75%,这比之前的准确率要好。这表明 SVM 模型能够在增强数据集中学习到更多重要的特征和模式,并且能够更好地泛化到新数据。
总结来说,在本节中,我们讨论了数据增强在训练用于图像分类的 SVM 中的重要性。我们使用 CIFAR-10 数据集来说明数据增强对 SVM 模型性能的影响。我们还提供了加载 CIFAR-10 数据集、在原始数据集上训练 SVM 模型以及在增强数据集上训练 SVM 模型的 Python 代码示例。
结果表明,数据增强可以提高 SVM 模型在图像分类任务上的性能。通过应用随机旋转、平移和缩放,我们可以生成新的图像,SVM 模型可以使用这些图像来学习更多特征和模式。这使得 SVM 模型能够更好地泛化到新数据并实现更高的准确度。
在下一节中,我们将看到如何使用 MNIST 手写数字数据集实现具有数据增强的 SVM。
在 MNIST 数据集上使用具有数据增强的 SVM 进行图像分类
让我们看看如何使用 MNIST 数据集和 SVM 进行图像分类应用数据增强。所有步骤都与之前使用 CIFAR-10 数据集的示例类似,只是数据集本身不同:
import tensorflow as tf
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from keras.datasets import mnist
from keras.preprocessing.image import ImageDataGenerator
# load MNIST dataset
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# normalize pixel values between 0 and 1
x_train = x_train / 255.0
x_test = x_test / 255.0
# convert labels to one-hot encoded vectors
y_train = tf.keras.utils.to_categorical(y_train)
y_test = tf.keras.utils.to_categorical(y_test)
# create image data generator for data augmentation
datagen = ImageDataGenerator(rotation_range=20, \
width_shift_range=0.1, height_shift_range=0.1, zoom_range=0.2)
# fit image data generator on training dataset
datagen.fit(x_train.reshape(-1, 28, 28, 1))
# create SVM model
svm_model = SVC()
# define hyperparameters for grid search
param_grid = {'C': [0.1, 1, 10], 'kernel': ['linear', \
'poly', 'rbf'], 'degree': [2, 3, 4]}
# perform grid search for optimal hyperparameters
svm_grid_search = GridSearchCV(svm_model, param_grid, cv=3)
svm_grid_search.fit(datagen.flow(
x_train.reshape(-1, 28, 28, 1),y_train, batch_size=32), \
steps_per_epoch=len(x_train) / 32)
# evaluate SVM model on test dataset
accuracy = svm_grid_search.score(x_test.reshape(-1, 28*28), y_test)
print("Accuracy with data augmentation: {:.2f}%".format(accuracy*100))
如前所述,此代码与之前的示例类似,只是我们现在使用的是 MNIST 数据集,图像是灰度且大小为 28x28。我们还修改了 SVM 模型的输入形状和图像数据生成器,以适应新的图像大小和颜色通道。
结果表明,数据增强也可以提高 SVM 模型在 MNIST 数据集上的性能。通过应用随机旋转、平移和缩放,我们可以生成新的图像,SVM 模型可以使用这些图像来学习更多特征和模式。这使得 SVM 模型能够更好地泛化到新数据并实现更高的准确度。
此外,我们还使用网格搜索来找到 SVM 模型的最佳超参数。这很重要,因为 SVM 模型的表现高度依赖于超参数的选择。通过使用网格搜索调整超参数,我们可以进一步提高 SVM 模型的准确度。
总体而言,这个示例代码展示了数据增强在提高 SVM 模型在图像分类任务性能方面的有效性。它还强调了使用网格搜索进行超参数调整以实现最佳准确度的重要性。
总结来说,数据增强是一种强大的技术,可以提高机器学习模型在图像分类任务上的性能。通过生成模型可以用来学习更多特征和模式的新图像,我们可以提高模型的一般化能力,并实现更高的准确率。SVM 模型特别适合图像分类任务,并且可以从数据增强中受益良多。借助 Python 库如 scikit-learn 和 TensorFlow,我们可以轻松实现带有数据增强的 SVM 模型,并在图像分类任务上实现最先进的性能。
接下来,让我们看看如何使用增强训练数据实现卷积神经网络。
使用增强图像数据的卷积神经网络
卷积神经网络(CNNs)通过在诸如目标检测、图像分类和分割等图像相关任务中展现出卓越的性能,彻底改变了计算机视觉领域。然而,为 CNNs 训练提供大量、标注的数据集通常是一个挑战。幸运的是,一种有效克服这一局限性的方法是通过使用图像数据****增强技术。
让我们从零开始,解释 CNNs 是什么以及它们是如何工作的。想象你有一张图片,比如说一张猫的照片,你想要教计算机如何识别它是一张猫。CNNs 就像一种特殊的计算机程序,帮助计算机理解和识别图像中的事物,就像你识别照片中的物体一样。
图像由称为像素的小点组成。每个像素都有颜色,当你把它们全部放在一起时,你就得到了一张图像。像素越多,图像越详细。当你看一张图片时,你的大脑不会试图一次性理解它。相反,它会专注于小部分,比如耳朵的形状或眼睛的颜色。这就是我们识别事物的方式。我们把大图像分解成小块,并逐一理解它们。
卷积神经网络(CNNs)的工作原理有点像人脑,将图像分解成小块。这些小块被称为“特征”或“过滤器”。想象这些过滤器就像在图片上移动的小窗户。这些窗户一次查看图像的一小部分,并学习其中的重要信息。
CNNs 的工作原理
让我们了解 CNNs 是如何为期望的输出工作的:
-
卷积:这是第一步。它就像在图片上移动一个小窗口(过滤器)。过滤器检查它所查看区域中的颜色和形状,并学习其中的重要信息。
-
池化:在查看图像的不同部分之后,CNN 不需要所有细节。池化就像是对它所看到的内容做一个总结。它简化了事物,但我们没有丢失重要的部分。
-
全连接层:在观察了许多小部分并总结它们之后,接下来将所有部分连接在一起。这就像把拼图碎片拼在一起,以看到整个画面。这有助于卷积神经网络理解整个图像,并对其中的内容做出最终判断。
在卷积层通过提取各种特征和模式处理图像之后,全连接层在将所有信息汇总以对图像内容做出全面决策方面发挥着关键作用。这个过程类似于组装拼图碎片,其中每个碎片对应于卷积层检测到的特定特征。通过连接这些碎片,网络获得了对图像的整体理解。
然而,尽管全连接层非常强大,但它们也存在过拟合的风险,即模型在训练数据上变得过于专业化,在新数据上表现不佳。为了减轻这种风险,通常会采用正则化技术。
-
全连接层中的正则化:正则化是一组用于防止过拟合并增强模型泛化能力的技巧。在全连接层的上下文中,正则化方法被应用于控制模型的复杂性,并避免过度依赖训练数据中存在的特定特征。
-
训练卷积神经网络:为了教会卷积神经网络识别猫,你需要向它展示大量的猫图片。它观察它们,学习重要的特征,并随着时间的推移在识别它们方面变得更好。它还需要看到不是猫的图片,这样它才能区分它们。
-
做出预测:一旦卷积神经网络被训练,你可以向它展示一张新图片,它将尝试找到它学习到的重要特征。如果它找到了足够的猫类特征,它会说:“嘿,那是一只猫!”
因此,简单来说,卷积神经网络就像一个计算机程序,通过观察图像的小部分、寻找重要特征并基于这些特征做出决策来学习识别图像中的事物。
正如我们所见,卷积神经网络的架构由卷积、池化和全连接层组成。架构指定了模型的构建方式,包括层数、滤波器的大小以及神经元之间的连接。架构指导了如何使用学习到的权重和特征来处理图像和做出预测。
因此,最终的模型本质上是由架构、学习到的权重和学习到的特征组合而成的。让我们分解其中的一些元素:
-
学习到的权重:这些是卷积神经网络在训练过程中学习到的参数。模型调整这些权重以做出准确的预测。这些权重基本上是模型在训练过程中获得的“知识”。它们代表了某些特征对于做出决策的重要性。
-
学习到的特征:在 CNN 的上下文中,特征是图像的视觉模式和特征。它们是图像中重要信息的表示。这些特征对我们来说不是直接可见的,而是通过网络层的卷积和池化学习得到的。特征是图像的抽象表示,有助于模型识别模式和对象。
在实践中,这些学习到的权重和特征存储在模型的参数中。当你保存一个训练好的 CNN 模型时,你正在保存这些参数,这些参数可以用于对新、未见过的图像进行预测。模型接收一个图像作为输入,通过其层进行处理,并使用学习到的权重和特征进行预测,例如对图像中的对象进行分类或检测特定模式。
现在,我们将深入探讨 CNN 和图像数据增强的强大组合。通过人工增强数据,CNN 可以在训练过程中接触到更广泛的变化范围,从而帮助它们更好地泛化到未见过的图像。
使用图像数据增强的一些好处和考虑因素包括减少过拟合、增强模型鲁棒性和提高泛化性能。无论你是初学者还是有经验的从业者,本节都作为理解并实现 CNN 上下文中的图像数据增强的全面指南,帮助你将计算机视觉项目提升到新的高度。
CNN 使用数据增强的实用示例
让我们看看如何在 CNN 上实现图像数据增强。为此,你可以遵循以下步骤:
步骤 1:首先导入必要的库,包括 Keras 和 NumPy:
import keras
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from keras.preprocessing.image import ImageDataGenerator
import numpy as np
ImageDataGenerator 对象并指定所需的数据增强技术:
datagen = ImageDataGenerator(
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True,
validation_split=0.2
)
ImageDataGenerator 对象将使用指定的数据增强技术生成增强数据的批次。在本例中,我们使用了旋转、宽度和高度偏移以及水平翻转。
步骤 3:加载原始数据集并将其分为训练集和验证集:
train_generator = datagen.flow_from_directory(
'/path/to/dataset',
target_size=(224, 224),
batch_size=32,
class_mode='categorical',
subset='training'
)
val_generator = datagen.flow_from_directory(
'/path/to/dataset',
target_size=(224, 224),
batch_size=32,
class_mode='categorical',
subset='validation'
)
在这里,我们使用 flow_from_directory() 函数从指定的目录加载原始数据集。我们还指定了图像的目标大小、批处理大小和类别模式(在本例中为分类)。我们使用 subset 参数将数据分为训练集和验证集。
在提供的代码片段中,使用了 flow_from_directory 函数来生成数据生成器,用于从目录中加载图像。让我们分解一下参数:
-
'/path/to/dataset':这是包含数据集的目录的路径。函数将在该目录内查找子目录,其中每个子目录代表不同的类别或类别。 -
target_size=(224, 224):target_size是在加载过程中所有图像将被调整的大小。在这种情况下,每张图像将被调整为 224x224 像素的正方形。标准化图像大小对于一致性和与神经网络模型的兼容性很重要,尤其是在使用期望特定输入大小的预训练模型时。 -
batch_size=32:batch_size决定了在训练或验证过程中每次迭代中加载和处理的图像数量。较大的批处理大小可以加快训练速度,但可能需要更多的内存。当内存有限或用于微调模型时,通常使用较小的批处理大小。它还会影响训练过程中的梯度更新,从而影响训练过程的稳定性和收敛性。 -
class_mode='categorical':class_mode指定了目标类别的表示方式。在这种情况下,它被设置为categorical,表示标签是一维编码(类成员关系的二进制矩阵表示)。其他可能的值包括binary用于二分类,sparse用于整数编码的类别标签,以及None用于没有标签(用于测试数据集)。 -
subset='validation': 子集用于指定生成器是为训练集还是验证集。在这种情况下,它被设置为validation,表示生成器是为验证集。当使用子集时,请确保数据集目录包含train和validation等子目录,以方便分割。
总结来说,这些参数有助于配置数据生成器以从目录中加载和预处理图像。针对目标大小、批处理大小和类模式的选项通常由所使用的机器学习模型的要求、可用的计算资源以及数据集的特征决定。
步骤 4:创建一个 CNN 模型:
model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(256, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(2, activation='softmax'))
model.compile(loss='categorical_crossentropy', \
optimizer='adam', metrics=['accuracy'])
在这里,我们正在创建一个简单的 CNN 模型,具有四个卷积层和一个全连接层。我们使用 ReLU 激活函数用于卷积层,softmax 激活函数用于输出层。我们还使用分类交叉熵损失函数、Adam 优化器和准确度指标编译模型。
在前面的代码片段中,正在使用 Keras 库创建一个 CNN 模型。让我们分解一下这些组件:
-
activation='relu'用于卷积层和密集层。ReLU 是一个激活函数,它向模型引入非线性。如果输入为正,则直接输出输入;否则,输出零。ReLU 由于有助于模型学习数据中的复杂模式和关系而受到 CNN 的青睐。它计算效率高,并减轻了梯度消失问题。ReLU 的影响:ReLU 引入了非线性,使模型能够学习数据中的复杂特征和关系。它有助于解决梯度消失问题,通过允许模型在反向传播过程中传播梯度,从而促进更有效的训练。
-
activation='softmax'用于输出层。Softmax 是一个将原始分数(logits)转换为概率的函数。它常用于多类分类模型的输出层。在这个二元分类案例(两类)中,softmax 激活函数将每个类别的输出分数进行归一化,为每个类别分配一个概率。概率最高的类别被认为是模型的预测。Softmax 对于产生多个类别的概率分布很有用,使其适合分类问题。Softmax 的影响:Softmax 将原始模型输出转换为类别的概率分布。它确保预测概率之和为 1,便于对模型对每个类别的信心进行有意义的解释。在二元分类中,它通常与交叉熵损失一起使用。
为什么我们应该使用它们?ReLU 被选择是因为其简单性、计算效率和在训练深度神经网络中的有效性。Softmax 被选为输出层以获得类别概率,这对于解释和评估模型的预测非常有价值。
总结来说,ReLU 和 softmax 激活通过引入非线性、促进高效训练和产生有意义的分类概率分布,有助于 CNN 模型的有效性。它们在图像分类任务中广泛应用于 CNN。
在提供的代码片段中,模型通过三个重要组件进行编译——交叉熵损失、Adam 优化器和准确度指标。让我们深入了解每个组件:
-
loss='categorical_crossentropy'):-
交叉熵损失函数是常用于多类分类问题的损失函数。
-
在这个背景下,模型是为二元分类(两类)设计的,但它使用交叉熵来处理有超过两类的情况。目标标签应为一热编码。
-
损失函数衡量预测概率(从输出层的 softmax 激活中获得)与真实类别标签之间的差异。
-
在训练过程中,目标是最小化这个损失,从而有效提高模型进行准确类别预测的能力。
-
-
optimizer='adam'):-
自适应动量估计(Adam)是一种广泛用于训练神经网络的优化算法。
-
它结合了两种其他优化算法的思想——均方根传播(RMSprop)和动量。
-
Adam 适应每个参数的个别学习率,使其非常适合各种优化问题。
-
它以其在训练深度神经网络中的效率和有效性而闻名,并且通常是许多应用的默认选择。
-
-
metrics=['accuracy']):-
准确率是用于评估分类模型性能的指标。
-
在二元分类的背景下,准确率衡量的是所有实例中正确分类的实例比例(包括真正的正例和真正的负例)。
-
准确率指标对于评估模型在训练和验证数据集上的表现至关重要。
-
虽然准确率是一个常用的指标,但它可能不足以用于不平衡的数据集,其中一类比另一类更为普遍。在这种情况下,可能需要考虑额外的指标,如精确率、召回率或 F1 分数。
-
总结来说,在编译过程中选择分类交叉熵损失、Adam 优化器和准确率指标反映了训练二元分类模型的最佳实践。这些选择基于它们在优化模型参数、处理多类场景和提供分类准确度直接评估方面的有效性。
步骤 5: 使用增强数据集训练模型:
model.fit(
train_generator,
steps_per_epoch=train_generator.samples // 32,
validation_data=val_generator,
validation_steps=val_generator.samples // 32,
epochs=10
)
我们使用fit()函数在增强数据集上训练模型。我们指定了训练和验证生成器、每个周期的步骤数、验证步骤数和周期数。
在这个代码片段中,使用fit()函数在增强数据集上训练模型。让我们分解一下关键组件:
-
train_generator):训练生成器是一个数据生成器的实例,它在步骤 3中实时对训练数据进行增强。数据生成器是一种在训练过程中以块的形式高效加载和预处理数据的方法,而不是将整个数据集加载到内存中。train_generator负责为模型提供增强后的训练数据批次。 -
val_generator):与训练生成器类似,验证生成器是一个数据生成器的实例,它生成验证数据批次。验证生成器提供了一组模型在训练期间未见过的数据。它有助于评估模型对未见示例的泛化能力,并防止过拟合。 -
steps_per_epoch=train_generator.samples // 32):steps_per_epoch指定每个训练周期中要处理的数据批次数量。它计算为训练数据集中样本总数除以批次大小(在本例中为32)。每个步骤涉及对数据批次的前向传递(预测)和反向传递(梯度计算和参数更新)。较小的steps_per_epoch值意味着模型在每个周期中看到的批次更少,这可能导致训练速度更快,但整个数据集的曝光度较低。 -
validation_steps=val_generator.samples // 32):validation_steps与steps_per_epoch类似,但用于验证数据集。它决定了每个验证周期中处理的批次数。与steps_per_epoch一样,它是基于验证数据集中样本总数除以批大小来计算的。 -
epochs=10):周期数指定了在训练期间整个数据集被处理的次数。进行更多周期的训练允许模型在多次遍历数据中学习,从而可能提高性能。然而,过多的周期训练可能会导致过拟合,此时模型会记住训练数据,但无法泛化到新数据。
调整批大小、每个周期的步数和验证步数会影响训练速度和内存需求。较大的批大小和更多的每个周期步数可能会导致训练速度变慢,但可能更节省内存。应该仔细选择周期数,以平衡模型训练并防止过拟合。
总结来说,提供给fit()的设置控制了模型的训练方式、每个周期中模型看到的数据以及验证集的评估。正确调整这些设置对于实现良好的模型性能和防止过拟合等问题至关重要。
通过遵循这些步骤,您可以使用 Keras 中的图像数据增强实现监督 CNN。这可以帮助提高模型性能,并使其对输入数据的变更加鲁棒。
使用 CIFAR-10 数据集进行图像数据增强的 CNN
让我们看看一些使用 CIFAR-10 数据集进行图像数据增强的监督 CNN 的 Python 代码示例:
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# Load the CIFAR-10 dataset
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
# Normalize the input data
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
# Convert the labels to one-hot encoding
y_train = tf.keras.utils.to_categorical(y_train)
y_test = tf.keras.utils.to_categorical(y_test)
# Define the CNN architecture
以下代码定义了使用 Keras 库的 CNN 架构。让我们逐行分析,以了解每个组件的目的和功能。
以下行创建了一个顺序模型,这允许我们按顺序堆叠层:
model = Sequential()
以下代码片段向模型添加了一个 2D 卷积层。它有 32 个滤波器,滤波器大小为(3, 3),ReLU 激活函数,以及'same'填充。input_shape参数设置为输入数据(x_train)的形状,但不包括批维度:
让我们深入分析以下 CNN 代码片段:
model.add(Conv2D(32, (3, 3), activation='relu', \
padding='same', input_shape=x_train.shape[1:]))
2D 卷积层添加:在图像处理的深度学习中,卷积层对于从输入图像中学习层次特征至关重要。卷积层用于检测输入数据中的局部模式。卷积层中的每个滤波器都学习识别不同的特征或模式。代码向神经网络模型添加了一层,具体来说,是一个 2D 卷积层。
卷积层有以下配置:
-
滤波器:有 32 个滤波器。滤波器是滑动在输入数据上以检测模式或特征的小网格。
-
滤波器大小:每个滤波器的大小为(3, 3)。这意味着在卷积操作过程中,它考虑了某个点的 3x3 像素网格,以捕获局部信息。
-
激活函数:ReLU 激活函数逐元素应用于每个卷积操作的输出。ReLU 引入了非线性,使模型能够学习复杂的模式。
-
使用
Same填充。填充是一种在卷积后保持空间维度的技术,防止在图像边缘丢失信息。Same填充填充输入,使得输出具有与输入相同的空间维度。 -
input_shape参数设置为输入数据的形状(x_train),不包括批量维度。输入形状决定了层将处理的数据输入大小。在这种情况下,它设置为训练数据x_train的形状,不考虑批量维度。
总结来说,此代码片段向神经网络模型添加了一个卷积层,并使用特定的参数配置了滤波器大小、滤波器数量、激活函数和填充。卷积层在从输入图像学习层次特征中起着至关重要的作用。
以下行添加了一个与之前相同的 2D 卷积层,但没有指定输入形状。模型将根据前一层推断输入形状:
model.add(Conv2D(32, (3, 3), activation='relu'))
以下行添加了一个池大小为(2, 2)的最大池化层,通过在每个池内取最大值来减少输入的空间维度:
model.add(MaxPooling2D(pool_size=(2, 2)))
以下行添加了一个丢弃率为 0.25 的 dropout 层,在训练期间随机将 25%的输入单元设置为 0。Dropout 通过引入随机性和减少对特定特征的依赖来帮助防止过拟合:
model.add(Dropout(0.25))
代码继续添加更多的卷积层、最大池化层和 dropout 层,最后以全连接(密集)层结束:
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
以下行将前一层输出展平为 1D 张量,为将其连接到密集层做准备:
model.add(Flatten())
以下行添加了一个具有 512 个单元和 ReLU 激活的密集层:
model.add(Dense(512, activation='relu'))
以下行添加了一个丢弃率为 0.5 的 dropout 层:
model.add(Dropout(0.5))
以下行添加了一个具有 10 个单元和 softmax 激活的最终密集层,它为分类生成 10 个类别的概率分布:
model.add(Dense(10, activation='softmax'))
以下代码初始化了 Keras 中的ImageDataGenerator类的一个实例,该类用于图像数据集的数据增强:
# Define the data augmentation parameters
datagen = ImageDataGenerator(
rotation_range=15,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True
)
# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy',\
metrics=['accuracy'])
# Train the model with data augmentation
history = model.fit(datagen.flow(x_train, y_train, \
batch_size=64), epochs=100, \
validation_data=(x_test, y_test))
# Evaluate the model on the test set
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
此代码定义了一个具有两个卷积层、两个最大池化层和三个全连接层的 CNN。使用ImageDataGenerator类执行数据增强,该类随机应用于训练图像以生成更多训练数据。使用fit方法以数据生成器作为输入训练模型 100 个 epoch。最后,使用evaluate方法在测试集上评估模型。
摘要
在本章中,我们介绍了各种图像数据增强技术。我们学习了如何在 Python 中使用 scikit-learn 和 Keras 库实现带有数据增强的支持向量机(SVM)。我们首先使用默认的超参数实现了 SVM,并在原始数据集上评估了分类器的性能。然后,我们实现了带有数据增强的 SVM,并在由ImageDataGenerator对象生成的每个训练数据批次上训练了分类器。最后,我们在增强数据集上评估了分类器的性能。
我们还看到了如何使用 CIFAR-10 数据集实现 CNN,并使用数据增强。通过数据增强,我们能够提高分类器在增强数据集上的准确性。这证明了数据增强在提高机器学习模型性能方面的有效性,尤其是在可用数据集有限的情况下。
数据增强可以通过创建现有标记数据的变体来减少对人工标注的需求。而不是单独对每个转换后的图像进行标注,增强技术允许在不需额外人工标注努力的情况下生成额外的标记样本。
在下一章中,我们将探讨如何使用生成模型标注文本数据。
第三部分:标注文本、音频和视频数据
在本书的这一部分,您将探索如何使用 Python 读取文本、音频和视频数据,分析数据并提取特征。内容深入探讨了在 Python 中通过编程对文本、视频和音频数据进行标记的各种方法,利用 OpenAI 的大型语言模型,以及半监督和无监督技术,如 K-means 聚类。此外,本节还帮助理解不同的开源数据标注工具,如 Label Studio、CVAT、pyOpenAnnotate 和 Azure Machine Learning,用于图像、视频、音频和文本数据,并提供它们之间的全面比较。
本部分包括以下章节:
-
第七章,标注文本数据
-
第八章,探索视频数据
-
第九章,标注视频数据
-
第十章,探索音频数据
-
第十一章,标注音频数据
-
第十二章,动手探索数据标注工具
第七章:标注文本数据
在本章中,我们将探讨在标注数据不足的情况下对文本数据进行分类的技术。我们将使用生成式 AI 来标注文本数据,除了 Snorkel 和 k-means 聚类。本章重点介绍了为 NLP 和文本分析标注文本数据的必要过程。它旨在为读者提供关于各种标注技术的实用知识和见解。本章将具体涵盖使用 OpenAI 的自动标注、基于 Snorkel 标注函数的规则标注以及使用 k-means 聚类的无监督学习。通过理解这些技术,读者将能够有效地标注文本数据并从非结构化文本信息中提取有意义的见解。
在本章中,我们将涵盖以下部分:
-
文本数据标注的实战应用
-
文本数据标注的工具和框架
-
文本数据的探索性数据分析
-
用于标注文本数据的生成式 AI 和 OpenAI
-
使用 Snorkel 标注文本数据
-
使用逻辑回归标注文本数据
-
使用 K-means 聚类标注文本数据
-
使用神经网络标注客户评论(情感分析)
技术要求
本章中使用的代码文件位于github.com/PacktPublishing/Data-Labeling-in-Machine-Learning-with-Python/tree/main/code/Ch07。
Gutenberg 语料库和电影评论数据集可在此找到:
您还需要创建一个 Azure 账户,并添加用于与生成式 AI 工作的 OpenAI 资源。要注册免费的 Azure 订阅,请访问 https://azure.microsoft.com/free。要申请访问 Azure OpenAI 服务,请访问aka.ms/oaiapply。
一旦您配置了 Azure OpenAI 服务,请设置以下环境变量:
os.environ['AZURE_OPENAI_KEY'] = 'your_api_key'
os.environ['AZURE_OPENAI_ENDPOINT") ='your_azure_openai_endpoint'
您的端点应类似于YOUR_RESOURCE_NAME.openai.azure.com/。
文本数据标注的实战应用
文本数据标注或分类在各个行业和应用中得到了广泛应用,用于提取有价值的信息、自动化流程和改善决策。以下是不同用例中的真实世界示例:
-
客户支持工单分类:
-
用例:公司收到大量客户支持工单。
-
应用:将支持工单自动分类到账单、技术支持和产品咨询等类别。这有助于优先排序并将工单路由到正确的团队。
-
-
垃圾邮件过滤:
-
用例:将电子邮件分类为垃圾邮件和非垃圾邮件。
-
应用:电子邮件服务提供商使用文本分类来识别和过滤掉不想要的电子邮件,为用户提供更干净的收件箱,并降低钓鱼攻击的风险。
-
-
社交媒体情感分析:
-
用例:分析社交媒体评论和帖子。
-
应用:品牌使用情感分析来衡量公众舆论、跟踪品牌情绪并回应客户反馈。这有助于声誉管理和理解客户偏好。
-
-
新闻分类:
-
用例:将新闻文章分类。
-
应用:新闻网站使用文本分类自动将文章分类到政治、科技和娱乐等版块,使读者更容易找到相关内容。
-
-
简历筛选:
-
用例:对求职申请进行分类。
-
应用:人力资源部门使用文本分类快速识别符合特定工作要求的简历。这加速了招聘流程并确保了更高效的候选人筛选。
-
-
医疗文档分类:
-
用例:对医疗记录和文件进行分类。
-
应用:医疗保健组织使用文本分类对医疗记录、实验室报告和患者笔记进行分类和组织。这有助于高效的数据检索和分析。
-
-
法律文档分类:
-
用例:对法律文件进行分类。
-
应用:律师事务所使用文本分类对法律文件、合同和与案件相关的信息进行分类和管理,简化法律研究和案件管理。
-
-
金融交易欺诈检测:
-
用例:识别欺诈活动。
-
应用:金融机构使用文本分类分析交易描述并识别潜在的欺诈或可疑活动,增强安全措施。
-
-
产品评论分析:
-
用例:分析客户评论。
-
应用:电子商务平台使用情感分析对产品评论进行分类和理解。这有助于改进产品、解决客户关注的问题并提高整体客户满意度。
-
-
语言识别:
-
用例:确定给定文本的语言。
-
应用:社交媒体平台和翻译服务使用文本分类自动识别用户的帖子或内容所使用的语言,实现准确的语言特定交互。
-
这些例子突出了文本分类在不同领域的多功能性,展示了它在自动化任务、提高效率和从文本数据中获得有价值见解中的重要性。
文本数据标注的工具和框架
有几个开源工具和框架可用于文本数据分析与标注。以下是一些流行的工具,以及它们的优缺点:
| 工具 和框架 | 优点 | 缺点 |
|---|---|---|
| 自然语言 工具包 (NLTK) | 用于 NLP 任务的综合性库。提供丰富的分词、词干提取、标注、解析等工具。拥有活跃的社区支持。适合教育目的和科研项目。 | 对于大规模工业应用,某些组件可能效率不高。对于初学者,学习曲线可能较陡。 |
| spaCy | 快速高效,专为生产使用设计。提供多种语言的预训练模型。提供强大的分词、命名实体识别和依存句法分析支持。易于使用的 API。 | 相比 NLTK,对教育资源重视度较低。对某些语言的支持有限。 |
| scikit-learn | 具有出色文本处理能力的通用机器学习库。易于与其他 scikit-learn 模块集成进行特征提取和模型训练。文档完善,在机器学习社区中广泛使用。 | 对于某些 NLP 任务可能没有专门的工具。对基于深度学习的模型支持有限。 |
| TextBlob | 提供常见 NLP 任务的简单 API,如词性标注、名词短语提取和情感分析。基于 NLTK 构建,为初学者提供便捷的入门途径。适用于快速原型设计和小型项目。 | 相比底层库,定制选项有限。对于大规模应用,性能可能不如。 |
| Gensim | 专注于主题建模、文档相似性和向量空间建模。Word2Vec 等算法的高效实现。适合大型文本语料库和文档相似性任务。 | 对于通用 NLP 任务来说,功能可能不够全面。对某些高级 NLP 功能支持有限。 |
| Transformers (Hugging Face) | 提供广泛 NLP 任务的预训练模型(BERT、GPT 等)。提供易于使用的接口以集成最先进的模型。拥有卓越的社区支持。 | 调整大型模型时计算需求量大。对于初学者来说可能不够直观。 |
| 斯坦福 NLP | 综合的 NLP 工具套件,包括分词、词性标注和命名实体识别。基于 Java,适合 Java 项目使用。 | 相比基于 Python 的库,资源使用量更大。对于某些任务,学习曲线可能更陡峭。 |
| Flair | 专注于最先进的 NLP 模型和嵌入。提供多种语言的嵌入。易于使用的 API。 | 相比其他库,预建模型可能较少。可能不如一些较老框架那样成熟。 |
表 7.1 – 流行工具及其优缺点
除了这个列表之外,还有 OpenAI 的生成预训练转换器(GPT),这是一个最先进的语言模型,它利用了转换器架构。它在大量多样化的数据上进行预训练,并且可以针对特定任务进行微调。GPT 以其生成连贯且上下文相关的文本的能力而闻名,使其成为各种自然语言处理(NLP)应用的强大工具。
Vaswani 等人提出的论文《Attention is All You Need》中引入的转换器架构,彻底改变了 NLP。它依赖于自注意力机制来捕捉序列中单词之间的上下文关系,从而实现并行化和可扩展性。由于它们能够有效地捕捉序列数据中的长距离依赖关系,转换器已成为包括 GPT 和 BERT 在内的许多高级语言模型的基础。其优点包括多功能性和理解文本上下文的能力,这就是为什么它被用于各种自然语言理解任务。其缺点是资源密集,需要大量的计算能力,并且微调需要访问大量的计算资源。
这些工具各有优缺点,选择取决于项目需求、可用资源和所需的定制程度。在更复杂的 NLP 管道中,常见的是将这些工具组合使用。在选择工具时,重要的是要考虑使用简便性、社区支持和与特定任务的兼容性等因素。
文本探索性数据分析
探索性数据分析(EDA)是任何数据科学项目中的关键步骤。当涉及到文本数据时,EDA 可以帮助我们了解数据的结构和特征,识别潜在的问题或不一致性,并指导我们选择数据预处理和建模技术。在本节中,我们将介绍在文本数据上执行 EDA 的步骤。
加载数据
EDA(探索性数据分析)的第一步是将文本数据加载到我们的环境中。文本数据可以以多种格式存在,包括纯文本文件、CSV 文件或数据库表。一旦数据被加载,我们就可以开始探索其结构和内容。
理解数据
EDA 的下一步是了解数据。对于文本数据,这可能包括检查数据集的大小、文档或样本的数量,以及文本的整体结构(例如,是否为结构化或非结构化)。我们可以使用描述性统计来深入了解数据,例如文本长度的分布或某些单词或短语的频率。
数据清洗和预处理
在理解数据之后,探索性数据分析的下一步是对文本数据进行清理和预处理。这可能涉及多个步骤,例如删除标点符号和停用词,对单词进行词干提取或词形还原,以及将文本转换为小写。清理和预处理数据对于为建模准备数据以及确保我们使用高质量数据至关重要。
探索文本的内容
在清理和预处理数据之后,我们可以开始探索文本本身的内容。这可能包括检查最频繁出现的单词或短语,识别文本中的模式或主题,并使用如词云或频率直方图等技术来可视化数据。我们还可以使用自然语言处理技术从文本中提取特征,例如命名实体、词性标签或情感分数。
分析文本与其他变量之间的关系
在某些情况下,我们可能想要探索文本数据与其他变量之间的关系,例如人口统计或行为数据。例如,我们可能想要检查电影评论的情感是否因类型而异,或者社交媒体帖子中讨论的主题是否因用户年龄或地理位置而异。这种分析可以帮助我们更深入地了解文本数据,并指导我们的建模方法。
可视化结果
最后,我们可以使用各种技术来可视化我们的探索性数据分析结果,例如词云、条形图、散点图或热图。可视化是向利益相关者传达见解和发现的重要工具,可以帮助我们识别数据中的模式和关系,这些模式和关系可能从原始文本中并不立即明显。
总之,探索性数据分析是任何文本数据项目中的关键步骤。通过理解数据的结构和内容,对其进行清理和预处理,探索文本的内容,分析文本与其他变量之间的关系,以及可视化结果,我们可以深入了解文本数据,并指导我们的建模方法。有了合适的工具和技术,探索性数据分析可以帮助我们发现文本数据中的隐藏模式和见解,这些模式和见解可以用于驱动业务决策并改善结果。
样本文本数据集的探索性数据分析
下面是一个用于在文本数据集上执行探索性数据分析的 Python 代码示例。我们将使用古腾堡语料库(pypi.org/project/Gutenberg/),这是一个包含 60,000 多本电子书的公开可用集合。
NLTK 语料库是用于 NLP 研究和开发的公开可用数据集的集合。Gutenberg 语料库(www.nltk.org/book/ch02.html),NLTK 包含的数据集之一,特别包含来自 Project Gutenberg 的公共领域文本的选择。Project Gutenberg 是一个提供免费访问不再受版权保护的书本和其他文本的数字图书馆。
因此,NLTK 中的 Gutenberg 语料库基于公共领域文本,使其成为一个公开可用的数据集。它可以用于各种 NLP 任务,如文本分类、语言建模和信息检索,没有任何商业限制或许可要求:
import nltk
from nltk.corpus import gutenberg
import string
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
让我们使用 NLTK 库下载 Gutenberg 语料库:
# Download the Gutenberg corpus
nltk.download('gutenberg')
让我们通过迭代 Gutenberg 的字段并将文档添加到列表数据中来将文本数据加载到 Pandas DataFrame 中。然后我们将列表数据转换为包含单个列text的 DataFrame,用于存储文档:
# Load the data
data = []
for file_id in gutenberg.fileids():
document = ' '.join(gutenberg.words(file_id))
data.append(document)
df = pd.DataFrame(data, columns=['text'])
# View the first few rows of the data
print(df.head())
让我们通过调用shape函数来检查 DataFrame 的大小:
# Check the size of the dataset
print("Dataset size:", df.shape)
这里是输出结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_01.jpg
图 7.1 – 数据的前几行
让我们通过调用apply函数来检查每个文档的长度:
# Check the length of each document
df['text_length'] = df['text'].apply(len)
Let us plot the histogram plot of the 'text_length' column using seaborn library sns.
# Visualize the distribution of document lengths
plt.figure(figsize=(8, 6))
sns.distplot(df['text_length'], bins=50, kde=False, color='blue')
plt.title('Distribution of Text Lengths')
plt.xlabel('Text Length')
plt.ylabel('Count')
plt.show()
这里是输出结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_02.jpg
图 7.2 – 文档长度的分布
在文本分析中,移除停用词和标点是其中最常见的任务之一,因为停用词不会告诉我们关于文本的任何信息:
# Remove punctuation and stop words
def remove_punctuation(text):
return text.translate(str.maketrans('', '', string.punctuation))
我们将使用 NLTK 语料库中的停用词列表:
def remove_stopwords(text):
stopwords_list = nltk.corpus.stopwords.words('english')
return " ".join([word for word in text.split() if \
word.lower() not in stopwords_list])
df['text_clean'] = df['text'].apply(remove_punctuation)
df['text_clean'] = df['text_clean'].apply(remove_stopwords)
现在我们使用value_counts函数来计算清洗文本中单词的频率:
# Count the frequency of each word
word_freq = pd.Series(np.concatenate([x.split() for x in \
df['text_clean']])).value_counts()
最后,绘制一个条形图来可视化最频繁的单词:
# Visualize the most frequent words
plt.figure(figsize=(12, 8))
word_freq[:20].plot(kind='bar', color='blue')
plt.title('Most Frequent Words')
plt.xlabel('Word')
plt.ylabel('Frequency')
plt.show()
这里是输出结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_03.jpg
图 7.3 – 最频繁的单词
在此代码中,我们首先使用 NLTK 库下载了 Gutenberg 语料库。然后我们将文本数据加载到 Pandas DataFrame 中,并对数据集的大小和结构进行了初步检查。
接下来,我们计算了每个文档的长度,并使用直方图可视化文档长度的分布。然后我们从文本数据中移除了标点符号和停用词,并计算了每个单词的频率。我们使用条形图可视化了最频繁的单词。
注意,这段代码只是文本数据探索性数据分析(EDA)的一个基本示例,你可能需要根据你的特定数据集和研究问题对其进行修改。现在我们有了清洗后的文本数据。
让我们看看如何在下一节中使用生成式 AI 对文本数据进行标注。
探索使用生成式 AI 和 OpenAI 进行文本数据标注
生成式 AI 是指一类人工智能,它涉及根据训练数据中的模式和信息训练模型以生成新的内容或数据。OpenAI 是一个杰出的组织,它为各种 NLP 任务开发和发布了强大的生成模型。其中一些引人注目的模型是 GPT,例如 GPT-3、GPT-3.5 和 GPT-4。这些模型在文本数据标注和分类领域产生了重大影响。
生成式 AI 专注于训练模型生成与现有示例相似的新数据实例。它通常用于文本生成、图像合成等任务。生成模型在大型数据集上训练,以学习潜在的模式,从而生成连贯且与上下文相关的内 容。在文本相关任务中,生成式 AI 可以应用于文本补全、摘要、问答甚至创意写作。让我们看看一些关键概念,这些概念将帮助我们进行文本数据标注。
OpenAI 的 GPT 模型
OpenAI 开发了一系列复杂的语言模型,其中 GPT-4 是最先进的之一。这些模型在多样化的数据集上进行预训练,使它们在自然语言理解和生成任务上表现出色。
零样本学习能力
GPT 模型以其零样本学习能力而闻名,这使得它们能够在没有明确训练的情况下对任务进行预测或生成内容。这种多功能性增强了它们在各个领域的适用性。
使用 OpenAI 模型进行文本分类
利用 OpenAI 模型的自然语言理解和生成能力,它们可以有效地用于文本分类任务。这包括情感分析、主题分类以及其他基于分类的应用。
数据标注辅助
尽管 GPT 模型并非专门为传统的数据标注任务设计,但它们可以在生成标注数据方面提供帮助。这可以通过自然语言指令或提供有助于做出标注决策的上下文来实现。
OpenAI API 概述
OpenAI API 是 OpenAI 提供的一项服务,允许用户通过 API 访问其高级语言模型。它作为将 OpenAI 的语言能力集成到各种应用中的门户。
让我们看看 OpenAI 的 GPT 模型的优缺点:
-
优点:
-
多功能性:OpenAI 的 GPT 模型具有多功能性,可以适应各种与文本相关的任务,包括数据标注和分类
-
大规模:这些模型在大量数据上训练,使它们能够捕捉自然语言中存在的复杂模式和细微差别
-
-
缺点:
-
可解释性:生成的内 容可能缺乏可解释性,这使得理解模型的决策过程变得具有挑战性
-
资源密集型:训练和使用像 GPT-4 这样的大型生成模型在计算上可能非常昂贵
-
总结来说,OpenAI 的生成模型,特别是 GPT-3、GPT-3.5 和 GPT-4,在文本数据处理领域做出了重大贡献,并且可以利用它们的语言理解能力创造性地用于数据标注和分类等任务。然而,在考虑道德问题和生成内容中可能存在的偏见时,需要谨慎考虑和评估。
在语言处理领域,文本分类用于根据内容对文档进行分类。传统上,这项任务依赖于标注的训练数据;然而,像 OpenAI 的 GPT 这样的先进模型通过在明确指令或提示的帮助下自主生成标签,彻底改变了这一过程。
探索使用 Azure OpenAI 进行文本数据标注,这是微软 Azure 云中的协作倡议,释放了强大语言模型的能力。本节作为指南,通过利用生成 AI 和 OpenAI 模型的能力,以及为用户提供文本数据分析中典型任务的定制工具,促进高效文本数据标注。
让我们看看一些使用 Python 和 Azure OpenAI 进行文本数据标注的用例。
用例 1 – 文本摘要
摘要是涉及在保留文本的必要信息和主要思想的同时压缩文本的关键 NLP 任务。在 Azure OpenAI 的背景下,以下代码示例展示了在 Azure 平台上部署的 GPT-3.5-turbo 模型应用摘要的示例。
以下代码示例首先设置了 Azure OpenAI API 所需的环境变量,包括 API 密钥和端点。然后,使用模型的部署名称配置 OpenAI API,使代码能够与特定的 GPT-3.5-turbo 实例交互。
提供的输入文本是对印度安得拉邦达切帕利镇的详细描述,用于摘要。代码利用 Azure OpenAI Completion API 生成摘要,使用温度、最大标记数以及频率和存在性惩罚等参数。
代码的输出包括生成的摘要,展示了从输入文本中提取的主要思想。摘要内容强调了作者与达切帕利的联系、城镇的特点以及显著的历史事件。这个例子展示了 Azure OpenAI 如何有效地总结信息,提供简洁且信息丰富的输出。
让我们从导入所需的库和获取配置值(Azure OpenAI 密钥和端点、API 版本以及已设置的 GPT 模型部署名称)开始:
import os
openai.api.key=os.getenv("AZURE_OPENAI_KEY")
Openai.api_base=os.getenv("AZURE_OPENAI_ENDPOINT")
Openai.api_type='azure'
Openai.api_version='2023-5-15' # this might change in the future
#this will correspond to the custom name you choose for your deployment when you deployed a model.
model_deployment_name = 'your_azure_openai_model_name'
# Set the input text
text = "create a summary of below text and provide main idea.\n\n Dachepalli is popular town in palnadu district in Andhra pradesh, India.I love dachepalli because i born and brought up at Dachepalli. I studied at Dachepalli zph school and got school first and my name was written on school toppers board at high school.My father worked in the same high school as hindi pandit for 20 years.The famous palnadu battle has took place near Naguleru river of Karempudi which flows across Dachepalli.It has lime mines and number of cement factories around Dachepalli.The Nadikudi railway junction connect Dachepalli to Hyderbad and Guntur. being born in Dachepalli and studied at Dachepalli high school, I love Dachepalli."
response = openai.Completion.create(
engine=model_deployment_name,
prompt=text,
temperature=0,
max_tokens=118,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=None)
让我们了解这个 OpenAI 完成 API 中使用的参数。
OpenAI 的参数控制语言模型在文本生成过程中的行为。以下是提供的参数的简要描述:
-
温度 (
temperature=0): 它决定了模型输出的随机性。高值(例如,0.8)会使输出更加多样化,而低值(例如,0.2)会使输出更加确定。 -
最大标记数 (
max_tokens=118): 这指定了在输出中生成最大标记数(单词或字符)。它对于限制响应长度很有用。 -
Top P (
top_p=1): 也称为核采样,它控制着生成输出的多样性。将其设置为1确保在采样过程中只考虑概率最高的标记。 -
频率惩罚 (
frequency_penalty=0): 这会阻止在输出中重复特定的标记。非零值会惩罚模型选择频繁出现的标记。 -
存在惩罚 (
presence_penalty=0): 与频率惩罚类似,存在惩罚会阻止整个短语或概念的重复,从而促进更多样化的响应。 -
停止 (
stop=None): 这允许用户指定生成过程的自定义停止标准。当模型遇到指定的标记时,它将停止生成进一步的内容。
这些参数为用户提供了对生成过程的精细控制,允许根据随机性、长度、多样性和重复等因素自定义模型的输出。调整这些参数使用户能够根据各种应用的具体要求定制语言模型的行为,例如聊天机器人、内容生成等:
# Print the generated summary
print("Generated summary:", summary.choices[0].text.strip())
运行此代码将输出以下摘要:
Generated summary: Main Idea: The author loves Dachepalli because he was born and brought up there and studied at Dachepalli high school. The town is located in Palnadu district in Andhra Pradesh, India and is known for its lime mines and cement factories. The Nadikudi railway junction connects Dachepalli to Hyderabad and Guntur. The famous Palnadu battle took place near Naguleru river of Karempudi which flows across Dachepalli. The author's father worked in the same high school as a Hindi pandit for 20 years.
我们已经看到了如何使用 OpenAI GPT-3.5 模型生成摘要。现在让我们看看如何使用 OpenAI 的 GPT 模型生成新闻文章的主题。
用例 2 – 新闻文章的主题生成
让我们探索使用生成模型生成新闻文章的主题名称,具体来说,是使用 Azure OpenAI。
主题生成是 NLP 的强大应用,它涉及根据给定的提示创建相关且连贯的内容。在 Azure OpenAI 提示的背景下,使用新闻标题分类示例展示了生成主题的能力。
在此代码片段中,任务是将新闻标题分类到预定义的类别之一,这些类别是商业、科技、政治、体育和娱乐。提供的输入新闻标题是 “特朗普准备在 2024 年 11 月选举中竞选。” 代码使用 Azure OpenAI API 生成一个响应,预测给定标题最合适的类别。
完成引擎配置了特定的参数,如温度、最大标记数以及频率和存在惩罚。在生成响应后,代码从输出中提取并打印预测的类别。
此示例展示了如何利用 Azure OpenAI 提示自动分类新闻标题,展示了 NLP 在主题生成任务中的灵活性和有效性:
news_headline="Label the following news headline into 1 of the following categories: Business, Tech, Politics, Sport, Entertainment\n\n Headline 1: Trump is ready to contest in nov 2024 elections\nCategory:",
response = openai.Completion.create(
engine=model_deployment_name,
prompt= news_headline,
temperature=0,
max_tokens=118,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=None)
index_of_newline=response.choice[0].text.find('\n')
print('category:',response.choices[0].text[:index_of_newline])
这里是输出:
category: Politics
用例 3 – 使用用户定义的类别和子类别对客户查询进行分类
让我们看看如何使用Azure OpenAI将客户查询分类到用户定义的类别和子类别。
文本分类是自然语言处理的一个基本任务,涉及将预定义的类别分配给文本输入。在提供的代码中,客户支持系统利用文本分类对与订单相关的客户查询进行分类。系统使用用户定义的主要和次要类别,每个类别都有特定的子类别。
系统消息作为分类任务的指南,概述了主要类别(订单状态、产品咨询、运输和配送以及支付帮助)及其对应的次要类别。主要和次要类别被组织起来以捕捉客户查询的各个方面,例如跟踪信息、产品可用性和支付确认。
例如,当用户提交取消订单的查询时,代码使用 OpenAI ChatCompletion API 生成响应。输出包括一个 JSON 格式的响应,指示分配给用户查询的主要和次要类别。在这种情况下,主要类别是订单状态,次要类别是订单修改或取消。
此示例演示了如何在客户支持环境中应用文本分类,允许根据预定义的类别高效地处理和分类客户查询。系统提供了一种结构化的方法来处理与订单相关的各种查询,从而提高整体客户支持体验:
system_message = f"""
Welcome to Customer Order Support!
You will receive customer queries related to their orders, each delimited by {delimiter} characters.
Your task is to classify each query into a primary and secondary category.
Provide your response in JSON format with the keys: "primary" and "secondary."
Primary Categories:
1\. Order Status
2\. Product Inquiries
3\. Shipping and Delivery
4\. Payment Assistance
Order Status Secondary Categories:
- Tracking Information
- Order Confirmation
- Order Modification or Cancellation
- Refund Status
Product Inquiries Secondary Categories:
- Product Availability
- Size and Color Options
- Product Specifications
- Return and Exchange Policies
Shipping and Delivery Secondary Categories:
- Delivery Timeframe
- Shipping Methods
- Address Changes
- Lost or Delayed Shipments
Payment Assistance Secondary Categories:
- Payment Confirmation
- Refund Process
- Payment Errors
- Billing Inquiries
Please review each query and provide the appropriate primary and secondary category in your response.
Thank you for assisting our customers with their orders!"""
user_message=f"""\
I want to cancel my order """
response = openai.ChatCompletion.create(
engine=deployment_name, # engine = "deployment_name".
messages=[
{"role": "system", "content": system_message},
{"role": "user", "content": f"{delimiter}{user_message}
{delimiter}"},],
temperature=0,
max_tokens=60,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=None
)
print(response)
print(response['choices'][0]['message']['content'])
下面是输出结果:
{ "id": "chatcmpl-8eEc86GxAO4BePuRepvve9XhTQZfa", "object": "chat.completion", "created": 1704599988, "model": "gpt-35-turbo", "choices": [ { "finish_reason": "stop", "index": 0, "message": { "role": "assistant", "content": "{\n \"primary\": \"Order Status\",\n \"secondary\": \"Order Modification or Cancellation\"\n}" } } ], "usage": { "prompt_tokens": 232, "completion_tokens": 21, "total_tokens": 253 } } { "primary": "Order Status", "secondary": "Order Modification or Cancellation" }
用例 4 – 使用实体提取进行信息检索
让我们看看如何使用 Azure OpenAI 从文本数据中提取实体名称。
实体提取是自然语言处理的一个重要方面,涉及从给定文本中识别和提取特定实体,如姓名、组织、地点和联系电话。在提供的代码片段中,任务是识别和提取来自各种文本段落的人名、组织名称、地理位置和联系电话。
提示为实体提取任务提供了清晰的指令,指明了感兴趣的实体及其对应的类别。它包括示例,说明了如何从不同的文本中提取信息,展示了实体提取过程的灵活性。
代码使用 OpenAI API 生成响应,包括从给定文本段落中提取的实体,如人名、组织名称、地点和联系电话。输出以 JSON 格式结构化,便于解析和将提取的实体集成到进一步的处理或分析中。
这个例子展示了实体提取在从多样化的文本数据中提取相关信息方面的实际应用,展示了其在客户关系管理、信息检索和数据分析等各个领域的潜力:
response = openai.Completion.create(
engine="gpt3.5 deployment name",
prompt = "Identify the individual's name, organization, geographical location, and contact number in the following text.\n\nHello. I'm Sarah Johnson, and I'm reaching out on behalf of XYZ Tech Solutions based in Austin, Texas. Our team believes that our innovative products could greatly benefit your business. Please feel free to contact me at (555) 123-4567 at your convenience, and we can discuss how our solutions align with your needs.",
temperature=0.2,
max_tokens=150,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=None)
print(response['choices'])
这里是输出结果:
[<OpenAIObject at 0x215d2c40770> JSON: {
"text": " Thank you for your time, and I look forward to hearing from you soon. \n\nName: Sarah Johnson\nOrganization: XYZ Tech Solutions\nGeographical location: Austin, Texas\nContact number: (555) 123-4567",
"index": 0,
"finish_reason": "stop",
"logprobs": null,
"content_filter_results": {
"hate": {
"filtered": false,
"severity": "safe"
},
"self_harm": {
"filtered": false,
"severity": "safe"
},
"sexual": {
"filtered": false,
"severity": "safe"
},
"violence": {
"filtered": false,
"severity": "safe"
}
}
}]
现在让我们从输出 JSON 中提取所需的信息:名称、组织、地点和联系方式,如下所示:
import json
# Parse JSON
json_data = response['choices']
# Extract information
# Extracting information from the JSON object
for entry in json_data:
text = entry.get("text", "")
# Extracting information using string manipulation or regular expressions
name = text.split("Name:")[1].split("\n")[0].strip()
organization = text.split("Organization:")[1].split("\n")[0].strip()
location = text.split("Geographical location:")[1].split("\n")[0].strip()
contact_number = text.split("Contact number:")[1].split("\n")[0].strip()
# Print the extracted information
print("Name:", name)
print("Organization:", organization)
print("Location:", location)
print("Contact Number:", contact_number)
这里是输出结果:
Name: Sarah Johnson Organization: XYZ Tech Solutions Location: Austin, Texas Contact Number: (555) 123-4567
用例 5 – 基于方面的情感分析
情感方面分析是一个复杂的自然语言处理任务,涉及评估给定文本中特定方面或特征的所表达的情感。在提供的代码片段中,对产品评论进行了基于方面的情感分析,旨在评估评论的整体情感以及与提到的各个方面的情感极性。
提示概述了情感分析任务的目标,包括为每个评论提供一个从 0 到 5 的整体情感分数,为每个方面分配 0 到 5 之间的情感极性分数,并识别最正面和最负面的方面。
代码处理了多个产品评论,提取了与相机质量、电池寿命、设计、扬声器质量、性能、键盘、显示、触摸板响应速度、音质、触控、图形、加载时间、在线社区、订阅费和控制器等方面相关的情感。
输出包括全面的情感分数、极性分数,以及识别每个评论中最正面和最负面的方面。这个例子说明了基于方面的情感分析如何提供对多样化评论中细微观点的详细见解,帮助企业在理解客户对特定产品功能的情感态度。
让我们看看基于方面的情感分析的代码示例:
response = openai.Completion.create(
engine="gpt3.5 deployment name",
prompt = "Conduct aspect-based sentiment analysis on the following product reviews:\n Provide an overall sentiment score between 0 and 5 for each review.\n Assign a sentiment polarity score between 0 and 5 for each aspect mentioned. \n Identify the top positive and negative aspects, if any. \n Review 1: \n I recently purchased this smartphone, and it has exceeded my expectations! The camera quality is superb, capturing vivid and detailed photos. The battery life is impressive, easily lasting a full day with regular use. The sleek design adds a premium feel to the device. However, the speaker quality could be improved. Overall sentiment score: 4.8 \nAspects with sentiment polarity score: \n - Camera: 5 \n - Battery Life: 5 \n - Design: 5 \n - Speaker: 3 \n \n Top positive aspect: Camera \n Top negative aspect: Speaker \n \n Review 2: \n This laptop offers powerful performance and a sleek design. The keyboard is comfortable for extended typing sessions, and the display is vibrant with accurate colors. However, the trackpad responsiveness can be inconsistent at times.",
temperature=0,
max_tokens=100,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=None)
print(response.choices[0].text.strip())
这里是输出结果:
Overall sentiment score: 4.5
Aspects with sentiment polarity score:
- Performance: 5
- Design: 5
- Keyboard: 5
- Display: 5
- Trackpad: 3
Top positive aspects: Performance, Design, Keyboard, Display
Top negative aspect: Trackpad
接下来,让我们使用 Snorkel API 来对这段文本数据进行分类,并通过创建基于规则的标注函数来生成标签。
使用 Snorkel API 进行文本数据的实际标注
在本节中,我们将学习如何使用 Snorkel API 对文本数据进行标注。
Snorkel 提供了一个 API,用于使用一组由领域专家创建的少量真实标签来编程式地标注文本数据。Snorkel 是一个开源的数据标注和训练平台,被不同行业的各种公司和组织使用,例如 Google、Apple、Facebook、IBM 和 SAP。
它具有独特的功能,使其与其他竞争对手区分开来,尤其是在弱监督和编程式生成标注数据的情况下。以下是与一些其他工具的比较:
-
弱监督:Snorkel 在标注数据稀缺且人工标注成本高昂的场景中表现出色。它允许用户通过启发式方法、模式和外部资源编程式地标注大量数据。
-
灵活的标签函数:Snorkel 允许创建标签函数,这些函数本质上是一种启发式函数,用于为数据分配标签。这提供了一种灵活且可扩展的方式来生成标记数据。
-
概率标签:Snorkel 生成概率标签,承认标签函数可能具有不同级别的准确性。这种概率框架在下游任务中非常有用。
使用 Snorkel 可能会存在学习曲线,尤其是对于新接触弱监督概念的初学者。其他工具,如 Prodigy 和 Labelbox,是商业工具,可能涉及许可费用。
在选择这些工具时,项目的具体要求、可用的预算和用户的专长起着至关重要的作用。当弱监督和程序化生成的标签对于手头的任务至关重要时,Snorkel 脱颖而出。它特别适合于手动标记不切实际或成本高昂的场景。其他工具可能更适合不同的用例、界面偏好和集成要求。
我们将使用 Snorkel 创建基于规则的标签函数,然后将这些标签函数应用于文本的分类和标签。
我们已经看到了标签函数是什么以及如何创建标签函数,请参阅第二章。让我们回顾一下。在 Snorkel 中,标签函数是一个 Python 函数,它启发式地为数据集生成标签。这些函数用于弱监督的过程,在这个过程中,不是完全依赖于手动标记的数据,而是使用噪声的、不完美的或弱标记的数据来训练机器学习模型。
这里是一个使用 Snorkel API 通过基于规则的标签函数标记文本数据的 Python 代码示例。
让我们使用 pip 安装 Snorkel,并导入用于标签的必需 Python 库,如下所示:
!pip install snorkel
让我们将代码分解为四个步骤,并解释每个步骤。
步骤 1:数据准备和标签函数定义。此步骤准备数据并定义标签函数。首先导入 Pandas 库并定义一些标签的常量。然后创建一个包含电影评论的 DataFrame,并将其分为训练集和测试集。测试集的真实标签被定义并转换为 NumPy 数组。最后,定义了三个标签函数,根据某些词的存在将评论标记为正面、负面或弃权:
import pandas as pd
# Define the constants
ABSTAIN = -1
POS = 0
NEG = 1
# Create a DataFrame with more data
df = pd.DataFrame({
'id': [1, 2, 3, 4, 5, 6, 7, 8],
'review': [
"This movie was absolutely wonderful!",
"The film was terrible and boring.",
"I have mixed feelings about the movie.",
"I have no opinion about the movie.",
"The movie was fantastic and exciting!",
"I didn't like the movie, it was too slow.",
"The movie was okay, not great but not bad either.",
"The movie was confusing and dull."
]
})
# Split the DataFrame into a training set and a test set
df_train = df.iloc[:6] # First 6 records for training
df_test = df.iloc[6:] # Remaining records for testing
# Define the true labels for the test set
Y_test = [ABSTAIN, NEG] # Replace this with the actual labels
# Convert Y_test to a NumPy array
Y_test = np.array(Y_test)
现在,让我们定义标签函数,一个用于正面评论,一个用于负面评论,一个用于中性评论,如下使用正则表达式:
# Define rule-based labeling functions using regular expressions
@labeling_function()
def lf_positive_review(x):
return POS if 'wonderful' in x.review or 'fantastic' in x.review else ABSTAIN
@labeling_function()
def lf_negative_review(x):
return NEG if 'terrible' in x.review or 'boring' in \
x.review or 'slow' in x.review or 'dull' in \
x.review else ABSTAIN
@labeling_function()
def lf_neutral_review(x):
return ABSTAIN if 'mixed feelings' in x.review or \
'no opinion' in x.review or 'okay' in x.review \
else ABSTAIN
步骤 2:应用标签函数和多数投票。这段代码将标签函数应用于训练集和测试集,然后使用多数投票模型来预测标签。它首先创建一个标签函数列表,并使用PandasLFApplier将它们应用于训练集和测试集。然后,它打印出结果标签矩阵及其形状。它从 Snorkel 导入MajorityLabelVoter和LabelModel类,创建一个多数投票模型,并使用它来预测训练集的标签:
# Apply the labeling functions to the training set and the test set
lfs = [lf_positive_review, lf_negative_review, lf_neutral_review]
applier = PandasLFApplier(lfs=lfs)
L_train = applier.apply(df=df_train)
L_test = applier.apply(df=df_test)
print(L_train)
print(L_test)
print(L_test.shape)
print(Y_test.shape)
这里是输出结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_04.jpg
图 7.4 – 标签矩阵
让我们使用MajorityLabelVoter模型在测试集上计算模型的准确率并打印出来:
from snorkel.labeling.model import MajorityLabelVoter, LabelModel
majority_model = MajorityLabelVoter()
majority_model.predict(L=L_train)
majority_acc = majority_model.score(L=L_test, Y=Y_test, \
tie_break_policy="random")["accuracy"]
print( majority_acc)
这里是输出结果:
1.0
最后,它为训练集预测标签并打印出来:
preds_train = majority_model.predict(L=L_train)
print(preds_train)
这里是输出结果:
[ 0 1 -1 -1 0 1]
步骤 3:训练标签模型并预测标签。这段代码训练一个标签模型并使用它来预测标签。它创建一个LabelModel,其cardinality为2(对于两个标签,正面和负面),将其拟合到训练集,并在测试集上计算其准确率:
label_model = LabelModel(cardinality=2, verbose=True)
label_model.fit(L_train=L_train, n_epochs=500, \
log_freq=100, seed=123)
label_model_acc = label_model.score(L=L_test, Y=Y_test, \
tie_break_policy="random")[
"accuracy"
]
print(label_model_acc)
这里是输出结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_05.jpg
图 7.5 – 训练标签模型
然后,它为训练集预测标签并打印出来:
# Predict the labels for the training data
Y_train_pred = label_model.predict(L=L_train)
# Print the predicted labels
print(Y_train_pred)
这里是输出结果:
[ 0 1 -1 -1 0 1]
步骤 4:分析标签函数并创建包含预测标签的 DataFrame。我们可以使用LFAnalysis类通过传递标签(L)和标签函数列表(lfs)来分析标签函数。lf_summary()方法提供了标签函数及其覆盖范围的概述:
# Analyze the labeled data
LFAnalysis(L=L_train, lfs=lfs).lf_summary()
这里是输出结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_06.jpg
图 7.6 – LFAnalysis 摘要
该表是 LFAnalysis 的结果摘要,具体针对三个标签函数:lf_positive_review、lf_negative_review和if_neutral_review。
让我们分解列:
-
j:标签函数在标签函数列表中的索引。在这里,j=0对应于lf_positive_review,而j=1对应于lf_negative_review。 -
极性:分配给标签函数的极性,表示函数分配的标签值。在这种情况下,lf_positive_review的极性为[0, 1],意味着它分配了标签0和标签1。另一方面,lf_negative_review的极性为[0],表示它只分配标签0。 -
覆盖范围:标签函数预测的标签集合。对于lf_positive_review,它预测了标签0和标签1([0, 1]),表示它为所有示例提供了非弃权输出。然而,lf_negative_review只预测标签0([0]),意味着它只为 55.25%的示例提供了非弃权输出。 -
Overlaps:对于提供非弃权输出的标签函数的示例百分比。它表示标签函数适用的程度。在这种情况下,lf_positive_review和lf_negative_review的覆盖率为 0.5525,表明它们为 55.25% 的示例提供了非弃权标签。 -
Conflicts:对于至少与其他一个标签函数存在分歧的示例的百分比。它衡量标签函数与其他函数之间的冲突水平。lf_positive_review和lf_negative_review的冲突值为 0.2105,表明它们在大约 21.05% 的示例中与其他标签函数存在冲突。
这个摘要提供了对标签函数的性能、覆盖率和冲突的见解,使你能够评估它们的有效性,并在你的标签过程中识别改进的领域。
最后,以下代码块分析标签函数并创建一个包含预测标签的 DataFrame。它使用 Snorkel 的 LFAnalysis 类来分析标签函数并打印摘要。然后,它创建一个包含预测标签的 DataFrame:
# Create a DataFrame with the predicted labels
df_train_pred = df_train.copy()
df_train_pred['predicted_label'] = Y_train_pred
# Display the DataFrame
print(df_train_pred)
这里是输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_07.jpg
图 7.7 – 预测标签
在这个例子中,我们首先创建了 Movie Reviews DataFrame。然后,我们定义了三个基于规则的标签函数,使用正则表达式根据某些关键词的存在将评论标注为正面、负面或中性。我们使用 Snorkel API 提供的 PandasLFApplier 将这些标签函数应用于文本数据。最后,我们使用 LFAnalysis 分析了标注数据,并打印了结果摘要。
注意,这是一个简单的示例,你可能需要根据你用例的具体要求调整代码。此外,你可以根据你的任务添加更多的标签函数,并且这些函数应该被精心设计和测试,以确保高质量的标签。
现在,让我们看看如何使用逻辑回归进行数据标注。
使用逻辑回归进行实战文本标注
文本标注是自然语言处理中的一个关键任务,它使文本数据能够被分类到预定义的类别或情感中。逻辑回归,一种流行的机器学习算法,在文本分类场景中证明是有效的。在下面的代码中,我们将通过使用逻辑回归将电影评论分类为正面或负面情感的过程进行说明。以下是代码的分解。
步骤 1. 导入必要的库和模块。
代码首先导入必要的库和模块。这些包括用于自然语言处理的 NLTK、用于机器学习的 scikit-learn,以及用于情感分析、文本预处理和分类的特定模块:
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import nltk
from nltk.corpus import movie_reviews
from nltk.sentiment import SentimentAnalyzer
from nltk.classify import NaiveBayesClassifier
步骤 2。下载必要的 NLTK 数据。代码下载电影评论数据集和其他必要的 NLTK 数据,如 WordNet 词元化和 Punkt 分词器:
nltk.download('movie_reviews')
nltk.download('wordnet')
nltk.download('omw-1.4')
nltk.download('punkt')
步骤 3。初始化情感分析器和获取电影评论 ID。代码初始化一个情感分析器并获取电影评论的 ID:
sentiment_analyzer = SentimentAnalyzer()
ids = movie_reviews.fileids()
步骤 4。预处理设置。代码设置了预处理工具,包括词元化和英语停用词列表。它还定义了一个预处理函数,该函数对文本进行分词、去除停用词并进行词元化:
lemmatizer = WordNetLemmatizer()
stop_words = set(stopwords.words('english'))
def preprocess(document):
words = word_tokenize(document)
words = [lemmatizer.lemmatize(word) for word in \
words if word not in stop_words]
return ' '.join(words)
步骤 5。特征提取。代码设置了一个带有预处理函数的 TF-IDF 向量器,并使用它将电影评论转换为特征矩阵:
vectorizer = TfidfVectorizer(preprocessor=preprocess, ngram_range=(1, 2))
X = vectorizer.fit_transform( \
[movie_reviews.raw(fileid) for fileid in ids])
步骤 6。创建目标向量。代码创建了一个包含电影评论类别的目标向量:
y = [movie_reviews.categories([f])[0] for f in ids]
步骤 7。分割数据。代码将数据分割为训练集和测试集:
X_train, X_test, y_train, y_test = train_test_split( \
X, y, test_size=0.2, random_state=42)
步骤 8。模型训练。代码初始化一个逻辑回归分类器,并在训练数据上对其进行训练:
model = LogisticRegression()
model.fit(X_train, y_train)
步骤 9。模型评估。代码在测试数据上评估模型并打印准确率:
accuracy = model.score(X_test, y_test)
print(f"Accuracy: {accuracy:.2%}")
这里是输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_08.jpg
图 7.8 – 逻辑回归的准确率
步骤 10。使用自定义句子进行测试。代码使用自定义句子测试模型。它预处理句子,将它们转换为特征,预测它们的情感,并打印结果:
custom_sentences = [
"I loved the movie and it was amazing. Best movie I have seen this year.",
"The movie was terrible. The plot was non-existent and the acting was subpar.",
"I have mixed feelings about the movie. Some parts were good, but some were not.",
]
for sentence in custom_sentences:
preprocessed_sentence = preprocess(sentence)
features = vectorizer.transform([preprocessed_sentence])
sentiment = model.predict(features)
print(f"Sentence: {sentence}\nSentiment: {sentiment[0]}\n")
这里是输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_09.jpg
图 7.9 – 预测标签
这段代码作为使用逻辑回归进行文本标记的全面指南,涵盖了数据预处理、模型训练、评估以及应用于自定义句子。
现在,让我们来看看第二种方法,K-means 聚类,通过将相似文本分组并为此组或簇创建标签来对文本数据进行标记。
使用 K-means 聚类进行手动的标签预测
K-means 聚类是一种强大的无监督机器学习技术,用于将相似的数据点分组到簇中。在文本数据的上下文中,K-means 聚类可以用来根据文本的相似性预测给定的文本的标签或类别。提供的代码展示了如何利用 K-Means 聚类来预测电影评论的标签,将整个过程分解为几个关键步骤。
步骤 1:导入库和下载数据。
以下代码首先导入必要的库,如 scikit-learn 和 NLTK。然后下载必要的 NLTK 数据,包括电影评论数据集:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from nltk.corpus import movie_reviews
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
import nltk
import re
# Download the necessary NLTK data
nltk.download('movie_reviews')
nltk.download('stopwords')
nltk.download('wordnet')
步骤 2:检索和预处理电影评论。
从 NLTK 数据集中检索电影评论并进行预处理。这包括词元化、去除停用词并将文本转换为小写:
# Get the reviews
reviews = [movie_reviews.raw(fileid) for fileid in movie_reviews.fileids()]
# Preprocess the text
stop_words = set(stopwords.words('english'))
lemmatizer = WordNetLemmatizer()
reviews = [' '.join(lemmatizer.lemmatize(word) for word in re.sub('[^a-zA-Z]', ' ', review).lower().split() if word not in stop_words) for review in reviews]
步骤 3:创建 TF-IDF 向量器和转换数据。
创建一个 TF-IDF 向量化器,将预处理后的评论转换为数值特征。这一步对于为聚类准备数据至关重要:
# Create a TF-IDF vectorizer
vectorizer = TfidfVectorizer()
# Transform the reviews into TF-IDF features
X_tfidf = vectorizer.fit_transform(reviews)
步骤 4:应用 K-means 聚类。
将 TF-IDF 特征应用于 K-means 聚类,指定聚类数量。在本例中,代码设置 n_clusters=3:
# Cluster the reviews using K-means
kmeans = KMeans(n_clusters=3).fit(X_tfidf)
步骤 5:使用自定义句子进行标签化和测试。
定义聚类标签并使用自定义句子测试 K-means 分类器。代码对句子进行预处理,将它们转换为 TF-IDF 特征,预测聚类,并根据预定义的聚类标签分配标签:
# Define the labels for the clusters
cluster_labels = {0: "positive", 1: "negative", 2: "neutral"}
# Test the classifier with custom sentences
custom_sentences = ["I loved the movie and Best movie I have seen this year.",
"The movie was terrible. The plot was non-existent and the acting was subpar.",
"I have mixed feelings about the movie.it is partly good and partly not good."]
for sentence in custom_sentences:
# Preprocess the sentence
sentence = ' '.join(lemmatizer.lemmatize(word) for word in re.sub('[^a-zA-Z]', ' ', sentence).lower().split() if word not in stop_words)
# Transform the sentence into TF-IDF features
features = vectorizer.transform([sentence])
# Predict the cluster of the sentence
cluster = kmeans.predict(features)
# Get the label for the cluster
label = cluster_labels[cluster[0]]
print(f"Sentence: {sentence}\nLabel: {label}\n")
下面是输出结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_10.jpg
图 7.10 – 文本 K-means 聚类
这段代码演示了使用 K-means 聚类进行文本标签预测的全面过程,包括数据预处理、特征提取、聚类以及使用自定义句子进行测试。
生成客户评论标签(情感分析)
客户评论是企业信息宝库。分析客户评论中的情感有助于了解客户满意度,确定改进领域,并做出数据驱动的商业决策。
在以下示例中,我们深入探讨使用神经网络模型进行情感分析。代码利用 TensorFlow 和 Keras 创建了一个简单的神经网络架构,包括嵌入层、展平层和密集层。该模型在用于情感分类的小型标记数据集上训练,区分积极和消极情绪。训练后,该模型用于分类新句子。提供的 Python 代码演示了从分词和填充序列到编译、训练和预测的每个步骤。
以下数据集用于情感分析训练:
sentences = ["I love this movie", "This movie is terrible", "The acting was amazing", "The plot was confusing"]
labels = [1, 0, 1, 0] # 1 for positive, 0 for negative
然后,我们使用分词器将文本转换为数字序列,然后填充序列以确保它们具有相同的长度。然后我们定义一个具有嵌入层、展平层和密集层的生成式 AI 模型。然后,我们在训练数据上编译和训练模型。最后,我们使用训练好的模型将新句子分类为积极或消极。
下面是一个包含四个句子数据集的完整 Python 代码示例,这些句子被标记为积极或消极。我们首先导入库:
import numpy as np
from tensorflow import keras
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
将 NumPy 库导入为 np 以进行数值计算。从 TensorFlow 库中导入必要的模块用于文本预处理和模型创建。然后我们定义标记的数据集:
sentences = ["I love this movie", "This movie is terrible", "The acting was amazing", "The plot was confusing"]
labels = [1, 0, 1, 0]
sentences 列表包含文本句子。labels 列表包含相应的标签,其中 1 代表积极情绪,0 代表消极情绪。接下来,我们对文本进行分词并将其转换为序列:
tokenizer = Tokenizer()
tokenizer.fit_on_texts(sentences)
sequences = tokenizer.texts_to_sequences(sentences)
tokenizer = Tokenizer()
tokenizer.fit_on_texts(sentences)
sequences = tokenizer.texts_to_sequences(sentences)
创建了一个Tokenizer对象来分词文本。使用fit_on_texts方法将分词器拟合到提供的句子上。使用texts_to_sequences方法将句子转换为标记序列。现在我们需要填充序列,使它们的长度相同:
max_sequence_length = max([len(seq) for seq in sequences])
padded_sequences = pad_sequences(sequences, maxlen=max_sequence_length)
最大序列长度是通过找到最长序列的长度来确定的。使用pad_sequences函数将序列填充到最大长度。接下来,我们定义模型架构:
model = keras.Sequential([
keras.layers.Embedding(len(tokenizer.word_index) + 1, \
16, input_length=max_sequence_length),
keras.layers.Flatten(),
keras.layers.Dense(1, activation='sigmoid')
])
使用 Keras 的Sequential类创建了一个顺序模型。该模型由一个嵌入层、一个展平层和一个密集层组成。嵌入层将标记转换为密集向量。展平层将输入展平以供后续的密集层使用。密集层用于具有 sigmoid 激活的二元分类。现在,我们需要编译模型:
model.compile(optimizer='adam', loss='binary_crossentropy', \
metrics=['accuracy'])
该模型使用 Adam 优化器、二元交叉熵损失和准确率作为指标进行编译。现在,我们开始训练模型:
model.fit(padded_sequences, np.array(labels), epochs=10)
模型在填充的序列和相应的标签上训练了指定数量的轮次。接下来,我们分类一个新句子:
new_sentence = ["This movie is good"]
new_sequence = tokenizer.texts_to_sequences(new_sentence)
padded_new_sequence = pad_sequences(new_sequence, \
maxlen=max_sequence_length)
raw_prediction = model.predict(padded_new_sequence)
print("raw_prediction:",raw_prediction)
prediction = (raw_prediction > 0.5).astype('int32')
print("prediction:",prediction)
提供了一个新的句子用于分类。该句子通过分词器转换为一系列标记。该序列被填充以匹配训练期间使用的最大序列长度。模型预测新句子的情感类别。最后,我们打印出预测的标签:
if prediction[0][0] == 1:
print("Positive")
else:
print("Negative")
这是输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_07_11.jpg
图 7.11 – 使用神经网络模型的预测
根据预测输出打印出预测的标签。如果预测标签是1,则被认为是积极情绪,如果是0,则被认为是消极情绪。总之,提供的代码演示了使用神经网络模型进行情感分析的任务。
摘要
在本章中,我们深入探讨了使用 Python 进行文本数据探索的领域,全面了解了利用生成式 AI 和 OpenAI 模型进行有效的文本数据标记。通过代码示例,我们探讨了包括分类、摘要和情感分析在内的各种文本数据标记任务。
我们通过探索 Snorkel 标记函数扩展了我们的知识,这使得我们能够以增强的灵活性标记文本数据。此外,我们深入研究了 K-means 聚类在标记文本数据中的应用,并通过发现如何使用神经网络标记客户评论来结束研究。
通过获得这些技能,你现在拥有了解锁文本数据全部潜力的工具,为各种应用提取有价值的见解。下一章等待着,我们将把重点转向视频数据探索,探索从这种动态数据类型中获取洞察力的不同方法。
第八章:探索视频数据
在今天以数据为驱动力的世界中,视频已成为信息洞察的重要来源。分析视频数据可以提供关于人类行为、场景理解和各种现实世界现象的宝贵知识。在本章中,我们将踏上使用 Python、Matplotlib 和 cv2 的强大组合来探索和理解视频数据的激动人心的旅程。
我们将首先学习如何使用 cv2 库,这是 Python 中流行的计算机视觉库,来读取视频数据。使用 cv2,我们可以轻松地加载视频文件、访问单个帧并对它们执行各种操作。这些基本技能为我们的探索和分析奠定了基础。
接下来,我们将深入了解从视频数据中提取帧的过程。视频帧是构成视频序列的单独图像。提取帧使我们能够处理单个快照,从而分析、操作并从视频数据中提取有用的见解。我们将讨论不同的策略来高效地提取帧,并探索在特定时间间隔或帧率下工作的可能性。
一旦我们提取了帧,我们将探索视频帧的属性。这包括分析诸如颜色分布、纹理模式、物体运动和空间关系等特征。通过利用 Python 的 Matplotlib 库的强大功能,我们可以创建引人入胜的视觉图表,从而更深入地理解视频数据。
在本章中,我们将学习如何在 Python 中使用 Matplotlib 和 OpenCV (cv2)来探索视频数据。具体来说,我们将深入研究人体动作动力学数据集。在下一章中,我们将专注于标记这个视频数据集。本章为视频数据提供了一个基础性的介绍,提供了后续标记过程中必需的知识。
我们将学习以下内容:
-
使用 cv2 加载视频数据
-
从视频数据中提取帧以进行分析
-
从视频帧中提取特征
-
使用 Matplotlib 可视化视频数据
-
使用 k-means 聚类标记视频数据
-
视频数据分析的高级概念
到本章结束时,你将获得探索和分析视频数据的有价技能。你将具备知识和工具来解锁视频的潜在价值,使你能够提取有意义的见解并做出明智的决策。因此,让我们开始这段激动人心的探索视频数据之旅,揭开它所蕴含的迷人故事。
技术要求
在本节中,我们将使用以下 GitHub 链接中的数据集:github.com/PacktPublishing/Data-Labeling-in-Machine-Learning-with-Python./datasets/Ch08。
让我们从如何使用 Python 将视频数据读入应用程序开始。
使用 cv2 加载视频数据
探索性数据分析(EDA)是任何数据分析过程中的一个重要步骤。它帮助您了解您的数据,识别模式和关系,并为进一步的分析准备您的数据。视频数据是一种复杂的数据类型,需要特定的工具和技术来分析。在本节中,我们将探讨如何使用 Python 对视频数据进行 EDA。
任何 EDA(电子设计自动化)流程的第一步是加载和检查数据。在视频数据的情况下,我们将使用 OpenCV 库来加载视频文件。OpenCV 是一个流行的计算机视觉和图像处理库,它包含许多使处理视频数据变得容易的功能。
OpenCV 和 cv2 通常指的是同一个计算机视觉库——它们可以互换使用,只是在命名约定上略有不同:
-
OpenCV(代表开源计算机视觉库):这是库的官方名称。它是一个开源的计算机视觉和机器学习软件库,包含用于图像和视频处理的多种功能。OpenCV 是用 C++编写的,并为 Python、Java 和其他语言提供了绑定。
-
在 Python 代码中
import cv2,意味着代码正在使用 OpenCV 库。
要使用 OpenCV 加载视频文件,我们可以使用cv2.VideoCapture函数。这个函数接受视频文件的路径作为输入,并返回一个VideoCapture对象,我们可以使用它来访问视频的帧。以下是一个加载视频文件并打印一些关于它的信息的示例代码:
import cv2
video_path = "path/to/video.mp4"
cap = cv2.VideoCapture(video_path)
fps = cap.get(cv2.CAP_PROP_FPS)
num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
frame_size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), \
int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
print("FPS: ", fps)
print("Number of frames: ", num_frames)
print("Frame size: ", frame_size)
这是输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_01.jpg
图 8.1 – 视频文件信息
此代码从指定的路径加载视频文件,并打印其帧率(FPS)、帧数和帧大小。这些信息对于理解视频数据的属性可能很有用。
从视频数据中提取帧以进行分析
一旦我们加载了视频数据,我们就可以开始探索它。视频数据 EDA(探索性数据分析)的一个常见技术是可视化视频的一些帧。这可以帮助我们识别数据中的模式和异常。以下是一个显示视频前 10 帧的示例代码:
import cv2
video_path = "path/to/video.mp4"
cap = cv2.VideoCapture(video_path)
for i in range(10):
ret, frame = cap.read()
if not ret:
break
cv2.imshow("Frame", frame)
cv2.waitKey(0)
cap.release()
cv2.destroyAllWindows()
此代码从给定路径读取视频的前 10 帧,并使用cv2.imshow函数显示它们。cv2.waitKey(0)函数在显示下一帧之前等待按键。这允许我们在移动到下一帧之前检查每一帧。
从视频帧中提取特征
另一种用于视频数据 EDA 的有用技术是从每个帧中提取特征并分析它们。特征是测量或描述符,它们捕捉图像的某些方面,例如颜色、纹理或形状。通过分析这些特征,我们可以识别数据中的模式和关系。
要从每个帧中提取特征,我们可以使用 OpenCV 函数来计算各种类型的特征,例如颜色直方图、纹理描述符和形状测量。选择最佳特征提取方法取决于您的数据特征和聚类任务的性质。
让我们看看颜色直方图特征提取方法。
颜色直方图
颜色直方图是图像中颜色分布的表示。它显示了颜色空间中每个范围内具有不同颜色的像素数量。例如,颜色直方图可以显示图像中有多少像素是红色、绿色或蓝色。以下是一个示例代码,用于从每个帧中提取颜色直方图并绘制它:
import cv2
import matplotlib.pyplot as plt
video_path = "path/to/video.mp4"
cap = cv2.VideoCapture(video_path)
histograms = []
下面是对代码中每行的详细解释:
-
第一行导入
cv2库,我们将使用它来读取和处理视频数据。 -
第二行导入
matplotlib库,我们将使用它来绘制直方图。 -
第三行设置视频文件的路径。将
"path/to/video.mp4"替换为您的视频文件的实际路径。 -
第四行使用
cv2.VideoCapture函数创建一个VideoCapture对象。这个对象允许我们读取视频中的帧。 -
第五行创建一个名为
histograms的空列表。我们将在此列表中存储每个帧的直方图。
然后,我们添加一个 while 循环。这个循环逐个读取视频中的帧,直到没有更多的帧:
while True:
ret, frame = cap.read()
if not ret:
break
histogram = cv2.calcHist([frame], [0, 1, 2], \
None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
histogram = cv2.normalize(histogram, None).flatten()
histograms.append(histogram)
cap.release()
下面是循环内部每行所做的事情:
-
ret, frame = cap.read(): 这一行使用cap.read()函数从视频中读取下一帧。ret变量是一个布尔值,表示帧是否成功读取,frame变量是一个包含帧像素值的 NumPy 数组。 -
if not ret: break: 如果ret是False,则表示视频中没有更多的帧,因此我们退出循环。 -
histogram = cv2.calcHist([frame], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256]): 这一行使用cv2.calcHist函数计算帧的颜色直方图。第一个参数是帧,第二个参数指定要包含在直方图中的通道(在这种情况下,所有三个 RGB 通道),第三个参数是一个掩码(我们将其设置为None),第四个参数是直方图的大小(每个通道 8 个桶),第五个参数是要包含在直方图中的值范围(每个通道为 0 到 256)。 -
histogram = cv2.normalize(histogram, None).flatten(): 这一行使用cv2.normalize函数对直方图进行归一化,并使用 NumPy 数组的flatten方法将其展平为 1D 数组。归一化直方图确保它是尺度不变的,可以与其他帧或视频的直方图进行比较。 -
histograms.append(histogram): 这一行将直方图追加到histograms列表中。
最后一行使用cap.release()函数释放VideoCapture对象。这释放了对象使用的资源,并允许我们在需要时打开另一个视频文件。
光流特征
我们将基于连续帧之间的光流来提取特征。光流捕捉视频中的物体运动。例如,OpenCV 库提供了计算光流的函数。
让我们看看计算光流特征的示例代码:
# Example of optical flow calculation
prev_frame = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
next_frame = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prev_frame, \
next_frame, None, 0.5, 3, 15, 3, 5, 1.2, 0)
运动向量
运动向量在理解视频数据的动态方面起着至关重要的作用。它们代表了关键点或区域在帧间的轨迹,为视频序列内的运动模式提供了洞察。计算这些运动向量的常见技术涉及使用 Shi-Tomasi 角点检测与 Lucas-Kanade 光流相结合:
-
prev_frame) 这些特征点作为后续帧跟踪的锚点。 -
cv2.calcOpticalFlowPyrLK。此算法通过计算这些特征点从前一帧(prev_frame)到当前帧(next_frame)的流动来估计运动向量。
我们通过跟踪帧间的关键点或区域来计算运动向量。这些向量代表了视频中的运动模式。让我们看看计算运动向量的示例代码:
# Example of feature tracking using Shi-Tomasi corner detection and Lucas-Kanade optical flow
corners = cv2.goodFeaturesToTrack(prev_frame, \
maxCorners=100, qualityLevel=0.01, minDistance=10)
next_corners, status, err = cv2.calcOpticalFlowPyrLK(\
prev_frame, next_frame, corners, None)
这个代码片段展示了使用 Shi-Tomasi 角点检测初始化特征点,并随后计算光流以获得运动向量。理解这些概念对于计算机视觉中的目标跟踪和运动分析等任务至关重要。
深度学习特征
使用除 VGG16 之外的其他预训练模型的特征,如 ResNet、Inception 或 MobileNet。尝试适合图像和视频分析的良好模型。这些方法的实现超出了本书的范围。你可以在各种深度学习文档中找到详细信息。
当使用预训练模型如 ResNet、Inception 或 MobileNet 时,你将找到相应的深度学习框架提供的全面文档和示例。以下是一些基于流行框架的建议:
-
TensorFlow 文档:TensorFlow 提供了使用预训练模型的详细文档和示例。你可以探索 TensorFlow Hub,它提供了一个预训练模型的存储库,包括各种架构,如 ResNet、Inception 和 MobileNet。
-
Keras 文档:如果你在 TensorFlow 中使用 Keras,你可以参考 Keras Applications 模块。它包括 ResNet50、InceptionV3 和 MobileNet 等预训练模型。
-
PyTorch 文档:PyTorch 通过 torchvision 库提供使用预训练模型的文档。你可以找到 ResNet、Inception 和 MobileNet 等模型。
-
Hugging Face Transformers 库:对于更广泛的预训练模型,包括自然语言处理和计算机视觉领域的模型,您可以探索 Hugging Face Transformers 库。它涵盖了各种架构,并允许轻松集成到您的项目中。
-
OpenCV 深度神经网络(DNN)模块:如果您正在使用 OpenCV,DNN 模块支持从 TensorFlow、Caffe 等框架加载预训练模型。您可以在示例和文档中找到如何使用这些模型的信息。
通过查阅这些资源,您将找到大量关于如何将预训练模型集成到您的图像和视频分析任务中的文档、代码示例和指南。请记住检查您项目中使用的框架的文档。
外观和形状描述符
基于物体外观和形状特征提取特征。例如包括 Hu 矩、Zernike 矩和 Haralick 纹理特征。
外观和形状描述符是计算机视觉和图像处理中用于量化物体视觉特征的方法。以下是三种常用描述符的详细信息:
-
Hu 矩:Hu 矩是一组对平移、旋转和尺度变化不变的七个矩。它们是从图像的中心矩导出的,用于描述物体的形状。
应用:Hu 矩在形状识别和物体匹配中特别有用,在这些应用中,对变换的鲁棒性至关重要。
-
Zernike 矩:Zernike 矩是一组定义在圆形域上的正交矩。它们用于表示物体的形状,并且对旋转不变。
应用:Zernike 矩在模式识别、图像分析和光学字符识别(OCR)中找到应用。
-
Haralick 纹理特征:Haralick 纹理特征是一组用于描述图像中纹理模式的统计度量。它们基于共现矩阵,该矩阵表示像素强度的空间关系。
应用:Haralick 纹理特征在纹理分析任务中得到了应用,例如在医学图像或材料检查中识别具有不同纹理的区域。
特征提取方法涉及从图像中提取特定的数值或向量,以表示其外观或形状特征。对变换如平移、旋转和尺度的不变性使这些描述符在物体识别任务中具有鲁棒性。
它们提供了对象视觉特征的量化表示,使高效的比较和分析成为可能。许多这些描述符可以使用 OpenCV 库实现,该库提供计算矩、纹理特征和其他描述符的函数。这些描述符在理解对象形状和纹理至关重要的应用中非常有价值,例如在图像识别、基于内容的图像检索和医学图像分析中。通过利用这些外观和形状描述符,计算机视觉系统可以深入了解对象的独特特征,从而在各个领域实现有效的分析和识别。
尝试不同的特征提取方法并观察其对聚类性能的影响通常是必要的。您还可以考虑结合多种类型的特征来捕捉数据的各个方面。
请记住,在应用聚类算法之前,适当预处理特征(缩放、归一化)。此外,K-means 中聚类数量的选择也可能影响结果,可能需要调整此参数。
使用 Matplotlib 可视化视频数据
让我们看看探索和分析视频数据的可视化示例。我们将生成一些样本数据,并使用 Python 中的 Matplotlib 库演示不同的可视化。首先,我们将导入库。然后,我们将生成一些样本数据。frame_indices代表帧索引,frame_intensities代表每个帧的强度值:
import matplotlib.pyplot as plt
import numpy as np
# Generate sample data
frame_indices = np.arange(0, 100)
frame_intensities = np.random.randint(0, 255, size=100)
帧可视化
我们创建一个线形图来可视化帧索引上的帧强度。这有助于我们理解帧之间强度的变化:
# Frame Visualization
plt.figure(figsize=(10, 6))
plt.title("Frame Visualization")
plt.xlabel("Frame Index")
plt.ylabel("Intensity")
plt.plot(frame_indices, frame_intensities)
plt.show()
我们得到以下结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_02.jpg
图 8.2 – 帧可视化图表
时间可视化
在这里,我们将帧强度与时间戳进行绘图。这使我们能够观察强度随时间的变化,从而深入了解时间模式:
# Temporal Visualization
timestamps = np.linspace(0, 10, 100)
plt.figure(figsize=(10, 6))
plt.title("Temporal Visualization")
plt.xlabel("Time (s)")
plt.ylabel("Intensity")
plt.plot(timestamps, frame_intensities)
plt.show()
我们得到以下图表:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_03.jpg
图 8.3 – 时间可视化图表
运动可视化
为了可视化运动,我们生成表示x和y方向运动的随机位移值dx和dy。使用quiver函数,我们在每个帧索引处绘制箭头,指示运动方向和大小:
# Motion Visualization
dx = np.random.randn(100)
dy = np.random.randn(100)
plt.figure(figsize=(6, 6))
plt.title("Motion Visualization")
plt.quiver(frame_indices, frame_indices, dx, dy)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
我们得到以下结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_04.jpg
图 8.4 – 运动可视化图表
通过利用这些可视化,我们可以更好地理解视频数据,探索时间模式,并分析运动特征。
重要的是要注意,这些只是探索视频数据时可以创建的可视化的一些示例。根据数据集的具体特性和目标,您可以使用广泛的可视化技术来深入了解数据。
使用 k-means 聚类对视频数据进行标注
数据标注是机器学习中的一个重要步骤,它涉及将数据集中的数据点分配到类别或标签。对于视频数据,标注可能是一个具有挑战性的任务,因为它需要分析大量帧并识别每帧中描绘的对象或事件。
自动化标注过程的一种方法是通过使用无监督学习技术,如聚类。k-means 聚类是一种基于数据相似性进行聚类的流行方法。在视频数据的情况下,我们可以使用 k-means 聚类将包含相似对象或事件的帧分组在一起,并为每个簇分配一个标签。
使用 k-means 聚类进行数据标注概述
这里是如何使用 k-means 聚类对视频数据进行数据标注的逐步指南:
-
加载视频数据并从每个帧中提取特征。这些特征可以是颜色直方图、边缘直方图或光流特征,具体取决于视频数据的类型。
-
将特征应用于 k-means 聚类以将相似的帧分组在一起。聚类数k可以根据领域知识设置,或者通过使用肘部方法来确定最佳聚类数。
-
根据帧中描绘的对象或事件为每个簇分配标签。这可以通过手动分析每个簇中的帧或使用对象检测或场景识别等自动化方法来完成。
-
将分配的标签应用于每个簇中的帧。这可以通过在数据集中添加包含簇标签的新列或创建簇标签与帧索引之间的映射来完成。
-
在标注数据上训练机器学习模型。标注的视频数据可用于训练执行各种任务(如动作识别、事件检测或视频摘要)的模型。
使用颜色直方图进行 k-means 聚类标注视频数据的示例
让我们看看使用开源 scikit-learn Python 包和Kinetics human action数据集进行视频数据 k-means 聚类的示例代码。该数据集可在技术要求部分的 GitHub 路径中找到。
此代码使用颜色直方图特征对视频数据进行 K-means 聚类。步骤包括从目录中加载视频帧、提取颜色直方图特征、标准化特征以及使用 K-means 将它们聚类成两组。
让我们通过相应的代码片段来查看这些步骤的实现:
-
加载视频并预处理帧:从指定的目录加载视频帧。将帧大小调整为(64,64),归一化像素值,并创建结构化的视频数据集:
input_video_dir = "<your_path>/PacktPublishing/DataLabeling/ch08/kmeans/kmeans_input" input_video, _ = load_videos_from_directory(input_video_dir) -
提取颜色直方图特征:将每个帧转换为 HSV 颜色空间。计算每个通道(色调、饱和度、亮度)的直方图。将直方图连接成一个单独的特征向量:
hist_features = extract_histogram_features( \ input_video.reshape(-1, 64, 64, 3)) -
使用
StandardScaler使数据具有零均值和单位方差:scaler = StandardScaler() scaled_features = scaler.fit_transform(hist_features) -
应用 K-means 聚类:在标准化特征上使用 K-means 聚类,分为两个簇。打印分配给每个视频帧的预测标签:
kmeans = KMeans(n_clusters=2, random_state=42) predicted_labels = kmeans.fit_predict(scaled_features) print("Predicted Labels:", predicted_labels)
此代码根据颜色直方图特征执行视频帧聚类,类似于上一个版本。聚类是在指定的输入视频目录上完成的,并在最后打印出预测的簇标签。
我们得到以下输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_05.jpg
图 8.5 – k-means 预测标记的输出
现在,将这些预测标签帧写入相应的输出簇目录。
以下代码将视频数据数组展平以遍历单个帧。然后它为簇创建两个输出目录(Cluster_0和Cluster_1)。每个帧根据从 k-means 聚类获得的预测标签保存在相应的簇文件夹中。这些帧以 PNG 图像的形式写入指定的输出目录:
# Flatten the video_data array to iterate through frames
flattened_video_data = input_video.reshape(-1, \
input_video.shape[-3], input_video.shape[-2], \
input_video.shape[-1])
# Create two separate output directories for clusters
output_directory_0 = "/<your_path>/kmeans_output/Cluster_0"
output_directory_1 = "/<your_path>/kmeans_output/Cluster_1"
os.makedirs(output_directory_0, exist_ok=True)
os.makedirs(output_directory_1, exist_ok=True)
# Iterate through each frame, save frames in the corresponding cluster folder
for idx, (frame, predicted_label) in enumerate( \
zip(flattened_video_data, predicted_labels)):
cluster_folder = output_directory_0 if predicted_label == 0 else output_directory_1
frame_filename = f"video_frame_{idx}.png"
frame_path = os.path.join(cluster_folder, frame_filename)
cv2.imwrite(frame_path, (frame * 255).astype(np.uint8))
现在,让我们绘制图表以可视化每个簇中的帧。以下代码可视化 K-means 聚类创建的每个簇的几个帧。它遍历Cluster_0和Cluster_1文件夹,从每个簇中选择指定数量的帧,并使用 Matplotlib 显示它们。生成的图像显示了每个簇的帧及其对应的簇标签:
# Visualize a few frames from each cluster
num_frames_to_visualize = 2
for cluster_label in range(2):
cluster_folder = os.path.join("./kmeans/kmeans_output", \
f"Cluster_{cluster_label}")
frame_files = os.listdir(cluster_folder)[:num_frames_to_visualize]
for frame_file in frame_files:
frame_path = os.path.join(cluster_folder, frame_file)
frame = cv2.imread(frame_path)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
plt.imshow(frame)
plt.title(f"Cluster {cluster_label}")
plt.axis("off")
plt.show()
我们得到簇 0 的输出如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_06.jpg
图 8.6 – 雪地滑冰(簇 0)
对于簇 1,我们得到以下输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_07.jpg
图 8.7 – 儿童玩耍(簇 1)
在本节中,我们看到了如何使用 k-means 聚类对视频数据进行标记,并将视频数据聚类成两类。一个簇(标签:簇 0)包含滑冰视频的帧,第二个簇(标签:簇 1)包含儿童玩耍的视频。
现在,让我们看看在现实世界项目中使用的视频数据分析的一些高级概念。
视频数据分析的高级概念
以下概念在视频数据分析中是基本的,并且在现实世界的机器学习应用中通常被应用。让我们简要地看看这些概念。请注意,这些概念中的一些实现超出了本书的范围。
视频中的运动分析
概念:运动分析涉及提取和理解视频中物体运动的信息。这可能包括检测和跟踪移动对象、估计它们的轨迹以及分析运动模式。
工具:OpenCV(用于计算机视觉任务)和光流算法(例如,Lucas-Kanade 方法)。
让我们看看视频数据中运动分析代码的概述。
初始化:打开视频文件并设置 Lucas-Kanade 光流参数:
import cv2
import numpy as np
# Read a video file
cap = cv2.VideoCapture('/<your_path>/CricketBowling.mp4')
# Initialize Lucas-Kanade optical flow
lk_params = dict(winSize=(15, 15), maxLevel=2, \
criteria=(cv2.TERM_CRITERIA_EPS |
cv2.TERM_CRITERIA_COUNT, 10, 0.03))
特征检测:使用 Shi-Tomasi 角点检测算法在第一帧中检测良好的特征点:
ret, frame1 = cap.read()
prvs = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
prvs_points = cv2.goodFeaturesToTrack(prvs, maxCorners=100, \
qualityLevel=0.3, minDistance=7)
运动分析循环:遍历视频帧,计算光流并在每个帧上绘制运动矢量:
while True:
ret, frame2 = cap.read()
if not ret:
break
next_frame = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# Calculate optical flow
next_points, status, err = cv2.calcOpticalFlowPyrLK( \
prvs, next_frame, prvs_points, None, **lk_params)
可视化:实时显示叠加了运动矢量的原始帧:
# Draw motion vectors on the frame
mask = np.zeros_like(frame2)
for i, (new, old) in enumerate(zip(next_points, prvs_points)):
a, b = new.ravel().astype(int)
c, d = old.ravel().astype(int)
mask = cv2.line(mask, (a, b), (c, d), (0, 255, 0), 2)
frame2 = cv2.circle(frame2, (a, b), 5, (0, 0, 255), -1)
result = cv2.add(frame2, mask)
cv2.imshow('Motion Analysis', result)
退出条件:按下 Esc 键时退出循环:
# Break the loop on 'Esc' key
if cv2.waitKey(30) & 0xFF == 27:
break
清理:释放视频捕获对象并关闭所有 OpenCV 窗口:
cap.release()
cv2.destroyAllWindows()
此代码提供了一个简单而有效的使用光流进行运动分析的演示,可视化视频中的特征点运动。
我们得到以下输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_08.jpg
图 8.8 – 视频中的运动分析
视频中的对象跟踪
概念:对象跟踪涉及在连续的视频帧中定位和跟踪对象。这对于监控、人机交互和自动驾驶汽车等应用至关重要。
工具:OpenCV(用于跟踪算法,如 KLT 和 MedianFlow)。
下面是对象跟踪代码中的步骤概述:
cv2.TrackerKCF_create():
import cv2
# Create a KCF tracker
tracker = cv2.TrackerKCF_create()
使用 cv2.VideoCapture 从 sample_video.mp4):
# Read a video file
cap = cv2.VideoCapture('./PacktPublishing/DataLabeling/ch08/video_dataset/CricketBowling.mp4')
使用 cv2.selectROI 交互式选择要跟踪的对象:
# Read the first frame
ret, frame = cap.read()
bbox = cv2.selectROI('Select Object to Track', frame, False)
我们得到以下结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_09.jpg
图 8.9 – 选择要跟踪的对象
在第一帧中,bbox):
tracker.init(frame, bbox)
对象跟踪循环:遍历视频中的后续帧:
while True:
ret, frame = cap.read()
if not ret:
break
更新跟踪器:使用当前帧更新跟踪器以获得跟踪对象的新的边界框:
# Update the tracker
success, bbox = tracker.update(frame)
绘制边界框:如果跟踪成功,则在帧中绘制一个绿色的边界框来包围跟踪到的对象。
if success:
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, (0, 255, 0), 2)
使用 cv2.imshow 的 'Object Tracking':
cv2.imshow('Object Tracking', frame)
我们看到以下结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/dt-lbl-ml-py/img/B18944_08_10.jpg
图 8.10 – 对象跟踪
cv2.waitKey):
# Break the loop on 'Esc' key
if cv2.waitKey(30) & 0xFF == 27:
break
清理:释放视频捕获对象并关闭所有 OpenCV 窗口:
cap.release()
cv2.destroyAllWindows()
此代码演示了一个基本的对象跟踪场景,其中用户在第一帧中选择一个对象,并使用 KCF 跟踪器在视频的后续帧中跟踪并绘制该对象的边界框。
视频中的人脸识别
概念:人脸识别涉及在视频中识别和验证人脸。它用于安全系统、用户身份验证和各种人机交互应用。
face_recognition)
下面是面部识别代码中的步骤概述:
-
使用
dlib.get_frontal_face_detector()和人脸关键点预测器 (dlib.shape_predictor('shape_predictor_68_face_landmarks.dat'))。 -
使用
cv2.VideoCapture从sample_video.mp4): -
人脸检测循环:遍历视频中的帧。
-
检测人脸:使用人脸检测器识别每帧中的面孔。
-
人脸关键点检测:对于每个检测到的人脸,使用人脸关键点预测器定位人脸关键点。
-
绘制人脸关键点:在帧中检测到的人脸关键点位置绘制圆圈。
-
绘制边界框:在帧中每个检测到的人脸周围绘制一个绿色的边界框。
-
cv2.imshow. -
cv2.waitKey). -
清理:释放视频捕获对象并关闭所有 OpenCV 窗口。
此代码展示了基本的人脸识别应用程序,其中每一帧都会检测到人脸,并为每个检测到的人脸绘制面部特征点。边界框勾勒出人脸,圆圈突出显示特定的面部特征:
from deepface import DeepFace
import cv2
# Load a sample image
img_path1 = './PacktPublishing/DataLabeling/ch08/data/pic1.jpeg'
img_path2 = './PacktPublishing/DataLabeling/ch08/data/pic2.jpeg'
img = cv2.imread(img_path)
# Perform facial recognition
result = DeepFace.verify(img1_path=img_path1, img2_path=img_path2)
# Display the result
print("Are these faces the same person? ", result["verified"])
# Additional information
print("Facial recognition result:", result)
我们得到以下输出:
Are these faces the same person? True
Facial recognition result: {'verified': True, 'distance': 0.20667349278322178, 'threshold': 0.4, 'model': 'VGG-Face', 'detector_backend': 'opencv', 'similarity_metric': 'cosine', 'facial_areas': {'img1': {'x': 74, 'y': 50, 'w': 713, 'h': 713}, 'img2': {'x': 63, 'y': 8, 'w': 386, 'h': 386}}, 'time': 0.48}
视频压缩技术
视频压缩减少了视频文件的大小,使其在存储、传输和处理方面更加易于管理。
一些常见的技术如下:
-
有损压缩:为了减小文件大小而牺牲一些质量(例如,H.264,H.265)
视频流平台如 YouTube 使用有损压缩(H.264)来高效地在互联网上传输视频。质量上的牺牲确保了更平滑的流媒体体验、更快的加载时间和减少用户的数据使用。
-
无损压缩:保持原始质量但压缩程度较低(例如,Apple ProRes,FFV1)
在专业视频编辑工作流程中,保持最高可能的质量至关重要,因此使用无损压缩。Apple ProRes 或 FFV1 等格式用于存储和处理视频文件,而不影响质量。这在电影制作、视频编辑工作室和存档目的中很常见。
实时视频处理
实时视频处理涉及以最小延迟分析和操作视频数据,这对于监控、机器人和现场直播等应用至关重要。
其挑战如下:
-
计算效率:算法需要优化以实现快速执行
-
硬件加速:使用 GPU 或专用硬件进行并行处理
-
流媒体基础设施:在实时场景中进行 k-means 聚类数据传输和处理
这里有一些常见的实时视频数据捕获和处理技术:
-
视频流:
-
技术:实时视频流涉及在网络上的连续传输视频数据
-
应用:现场直播、监控系统、视频会议
-
工具:
-
RTMP(代表实时消息协议):用于在互联网上传输视频
-
WebRTC(代表Web 实时通信):使网页浏览器能够实现实时通信
-
-
-
IP 摄像头 和 CCTV:
-
技术:IP 摄像头和闭路电视(CCTV)系统捕获和传输视频数据
-
应用:监控和安全监控
-
工具:
-
Axis Communications:提供 IP 摄像头和监控解决方案
-
Hikvision:提供一系列 CCTV 和 IP 摄像头产品
-
-
-
深度感知 相机:
-
技术:具有深度感知能力的摄像头除了捕获 2D 图像外,还捕获 3D 信息
-
应用:手势识别、物体跟踪、增强现实
-
工具:
-
Intel RealSense:适用于各种应用的深度感知相机
-
Microsoft Azure Kinect: 拥有用于计算机视觉任务的深度相机
-
-
-
帧 抓取器:
-
技术:帧抓取器从模拟或数字源捕获视频帧
-
应用:工业自动化和医学成像
-
工具:
-
Matrox Imaging:为机器视觉应用提供帧抓取器
-
Euresys:提供视频获取和图像处理解决方案
-
-
-
时间卷积网络 (TCNs):
-
概述:TCNs 扩展 CNNs 以处理时间序列,对视频数据有益
-
应用:
-
在视频中识别随时间变化的模式和事件
-
动作识别的时间特征提取
-
-
-
动作 识别
-
概述:在视频序列中识别和分类动作或活动
-
技术:
-
3D CNNs:捕捉动作识别的空间和时间特征
-
双流网络:分离空间和运动信息流
-
-
-
深度伪造 检测:
-
概述:检测和减轻使用深度学习技术创建逼真但虚假视频的使用
-
技术:
-
法医分析:分析深度伪造视频中的一致性、伪迹或异常
-
深度伪造数据集:在多样化的数据集上训练模型以提高检测准确性。
-
-
让我们讨论一些重要的道德考量:
-
知情同意:确保个人了解视频录制及其潜在分析。
动作:明确传达视频数据收集的目的。为敏感应用获得明确同意。
-
透明度:促进视频数据收集、处理和使用方面的透明度。
动作:向利益相关者明确传达数据处理实践。提供关于所使用算法的易获取信息。
-
偏见缓解:解决和缓解可能存在于视频数据分析中的偏见。
动作:定期评估和审计模型以消除偏见。实施公平感知算法和策略。
-
数据安全:保护视频数据免受未经授权的访问和使用。
动作:对存储和传输的视频数据进行强加密。建立严格的访问控制和权限。
-
问责制:确保对视频数据分析后果的问责制。
动作:明确数据处理的职责界限。建立处理和纠正错误的机制。
随着视频数据分析和处理技术的进步,道德考量变得越来越重要,以确保视频数据的负责任和公平使用。遵守道德原则有助于与利益相关者建立信任,并有助于视频基础 AI 应用的积极影响。
机器学习中的视频数据格式和质量
-
视频格式:
常见格式:视频可以存储在各种格式中,如 MP4、AVI、MKV、MOV 等。
容器与编解码器:容器(格式)包含视频和音频流,而编解码器(压缩)确定数据如何编码。
-
视频质量:
分辨率:从标准定义(SD)到高清(HD)以及更高
帧率:每秒帧数可能不同,影响运动的平滑度
比特率:更高的比特率通常意味着更好的质量但更大的文件大小
处理机器学习模型视频数据时常见的常见问题
-
不稳定的帧率
-
问题:不同帧率的视频可能会干扰模型训练
解决方案:在预处理期间标准化帧率或使用插值等技术
-
可变分辨率
-
问题:不同的分辨率可能会使模型输入要求复杂化
解决方案:调整或裁剪帧到一致的分辨率,平衡质量和计算
-
大文件大小
-
问题:高质量的视频可能导致大型数据集,影响存储和处理
解决方案:如果可能,压缩视频,并在开发期间考虑使用子集
-
缺乏标准化
-
问题:非统一的编码和压缩可能导致兼容性问题
解决方案:将视频转换为标准格式,确保数据集的一致性
-
有限的元数据
-
问题:元数据不足(例如,时间戳、标签)可能会阻碍模型理解
解决方案:通过添加相关元数据来增强视频,以帮助模型学习和评估
故障排除步骤
-
预处理和标准化:
行动:在预处理期间标准化视频属性(例如,帧率、分辨率)
好处:确保数据集的统一性和兼容性
-
数据增强:
行动:应用数据增强技术以人工增加数据集大小
好处:有助于解决数据有限的问题并提高模型泛化能力
-
质量与计算权衡:
行动:根据项目需求平衡视频质量和计算资源
好处:优化特定用例的模型训练和部署
-
元数据增强:
行动:包括相关元数据(例如,时间戳、标签)以获得更好的模型上下文
好处:提高模型理解并促进准确预测
-
协作调试:
行动:与领域专家和同行研究人员合作,解决具体挑战
好处:获得多样化的见解并加速问题解决
-
模型性能监控:
行动:定期监控不同视频样本上的模型性能
好处:识别漂移或性能下降,及时进行调整
在机器学习中处理视频数据需要结合技术专长、深思熟虑的预处理和持续监控来应对挑战并优化模型性能。根据项目特定要求定期评估和改进方法,确保视频数据有效集成到 AI 模型中。
摘要
在本章中,我们开始了探索视频数据并揭示其洞察力的旅程。通过利用 cv2 库,我们学习了如何读取视频数据,提取用于分析的帧,分析帧的特征,并使用强大的 Matplotlib 库进行可视化。掌握了这些技能,你将能够充分应对视频数据集,深入研究它们的独特特性,并更深入地理解其中包含的数据。探索视频数据为从识别人类动作到理解场景动态等一系列可能性打开了大门,本章为在视频数据标注领域进一步探索和分析奠定了基础。
最后,你学习了如何使用无监督机器学习 k-means 聚类来标注视频数据。在下一章中,我们将看到如何使用卷积神经网络(CNNs)、自动编码器和分水岭算法来标注视频数据。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)