深度学习进阶,Keras视频分类

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
全局流量管理 GTM,标准版 1个月
简介: 深度学习进阶,Keras视频分类

Keras视频分类

在此教程中,您将学习如何使用Keras、Python 和深度学习执行视频分类。


具体来说,您将学习:


视频分类与标准图像分类的区别

如何使用 Keras 进行图像分类来训练一个旋转神经网络

如何采取CNN,然后使用它的视频分类

如何使用滚动预测平均值来减少结果中的"闪烁"

本教程将作为对时间性深度学习概念的介绍,为我们讨论长期短期记忆网络(LSTM)并最终获得人类活动识别铺平道路。


要学习如何执行视频分类与Keras和深度学习,只是继续阅读!


视频可以理解为一系列单独的图像;因此,许多深度学习从业者会很快将视频分类视为执行图像分类的总次数为 N次,其中N是视频中帧的总数。


不过, 这种方法有问题。


视频分类不仅仅是简单的图像分类 -*视频,我们通常可以假设视频中的后续帧与其*语义内容*相关*。


如果我们能够利用视频的时效性,我们就能改进我们的实际视频分类结果。


神经网络架构,如长期短期记忆 (LSTM) 和经常性神经网络 (RNN) 适合时间系列数据 - 我们将在以后的教程中涵盖两个主题 - 但在某些情况下,它们可能过于杀戮。当涉及到对数千个视频文件进行培训时,它们也非常耗时,你可以想象。


相反,对于某些应用程序,您只需要*滚动平均*超过预测。


在本教程的其余部分,您将学习如何训练 CNN进行图像分类(特别是体育分类),然后通过采用滚动平均值将其转化为更准确的视频分类器。


在执行图像分类时,我们:


向我们的 CNN 输入图像

从 CNN 获取预测

选择具有最大相应概率的标签

由于视频只是一系列帧,一个天真的视频分类方法将是:


在视频文件中的所有帧上循环

对于每个帧,通过 CNN 传递帧

单独和独立**地对每个帧进行分类

选择具有最大相应概率的标签

标记帧并将输出帧写入磁盘

不过,这种方法存在问题 - 如果您曾经尝试将简单的图像分类应用于视频分类,您可能会遇到某种**“预测闪烁”,**如本节顶部视频中所示。请注意,在这个可视化中,我们看到我们的 CNN 在两个预测之间移动:"足球"和正确的标签"weight_lifting"。


视频显然是举重,我们希望我们的整个视频被贴上这样的标签 - 但我们怎样才能防止CNN在这两个标签之间"闪烁"?


一个简单而优雅的解决方案是利用滚动预测平均值。


我们的算法现在变成:


在视频文件中的所有帧上循环

对于每个帧,通过 CNN 传递帧

从 CNN 获取预测

保留最后K预测的列表

计算最后K预测的平均值,并选择具有最大相应概率的标签

标记帧并将输出帧写入磁盘

此算法的结果可以在这篇文章的顶部的视频中看到 - 注意预测闪烁是如何消失,整个视频剪辑被正确标记!


在本教程的其余部分,您将学习如何实现此算法的视频分类与 Keras。


体育分类数据集


oo.png

**图1:**由GitHub 用户使用Google 图片搜索策划的体育数据集"无足小视"。我们将使用此图像数据集与 Keras 进行视频分类。(图片来源)


我们今天在这里使用的数据集用于体育/活动分类。数据集由阿努巴夫·迈蒂策划,从谷歌图片下载照片(您也可以使用必应)为以下类别:


游泳


羽毛球


摔跤


奥运射击


蟋蟀


足球


网球


曲棍球


冰球


卡巴迪


WWE


体育馆


举重


排球


乒乓球


棒球


一级方程式


摩托 GP



拳击


击剑


篮球


为了节省时间、计算资源,并演示实际视频分类算法(本教程的实际点),我们将对运动类型数据集的子集进行培训:


足球(即足球):799张图片

网球: 718 图片

举重: 577 图像

让我们继续下载我们的数据集!


项目结构

项目结构如下:

$ tree --dirsfirst --filelimit 50
.
├── Sports-Type-Classifier
│   ├── data
│   │   ├── football [799 entries]
│   │   ├── tennis [718 entries]
│   │   └── weight_lifting [577 entries]
├── example_clips
│   ├── lifting.mp4
│   ├── soccer.mp4
│   └── tennis.mp4
├── model
│   ├── activity.model
│   └── lb.pickle
├── output
├── plot.png
├── predict_video.py
└── train.py

我们的训练图像数据位于 Sports-Type-Classifier/data/ 目录中,按类别组织。


我从 YouTube 中为我们提取了三个 example_clips/ 来测试我们的模型。三个剪辑的积分位于“Keras 视频分类结果”部分的底部。


我们的分类器文件位于 model/ 目录中。包括 activity.model(经过训练的 Keras 模型)和 lb.pickle(我们的标签二值化器)。


一个空的 output/ 文件夹是我们将存储视频分类结果的位置。


我们将在今天的教程中介绍两个 Python 脚本:


train.py :一个 Keras 训练脚本,它抓取我们关心的数据集类图像,加载 ResNet50 CNN,并应用 ImageNet 权重的转移学习/微调来训练我们的模型。训练脚本生成/输出三个文件:

model/activity.model :基于 ResNet50 的微调分类器,用于识别运动。

model/lb.pickle :包含我们独特的类标签的序列化标签二值化器。

plot.png :准确率/损失训练历史图。

predict_video.py :从 example_clips/ 加载输入视频,然后使用今天的滚动平均方法对视频进行理想的分类。

实施我们的 Keras 培训脚本

让我们继续实施我们的训练脚本,用于训练Keras CNN来识别每一项体育活动。


打开train.py文件并插入以下代码:

# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")
# import the necessary packages
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import SGD
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import pickle
import cv2
import os

导入必要的包来训练我们的分类器:


matplotlib :用于绘图。第 3 行设置后端,以便我们可以将训练图输出到 .png 图像文件。


tensorflow.keras:用于深度学习。也就是说,我们将使用 ResNet50 CNN。我们还将使用您可以在上周的教程中阅读的 ImageDataGenerator。


sklearn :从 scikit-learn,我们将使用他们的 LabelBinarizer 实现来对我们的类标签进行单热编码。


train_test_split 函数将我们的数据集分割成训练和测试分割。我们还将以传统格式打印分类报告。


path :包含用于列出给定路径中的所有图像文件的便利函数。从那里我们将能够将我们的图像加载到内存中。


numpy :Python 的事实上的数值处理库。


argparse :用于解析命令行参数。


pickle :用于将我们的标签二值化器序列化到磁盘。


cv2:OpenCV。


os :操作系统模块将用于确保我们获取与操作系统相关的正确文件/路径分隔符。


现在让我们继续解析我们的命令行参数:

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
  help="path to input dataset")
ap.add_argument("-m", "--model", required=True,
  help="path to output serialized model")
ap.add_argument("-l", "--label-bin", required=True,
  help="path to output label binarizer")
ap.add_argument("-e", "--epochs", type=int, default=25,
  help="# of epochs to train our network for")
ap.add_argument("-p", "--plot", type=str, default="plot.png",
  help="path to output loss/accuracy plot")
args = vars(ap.parse_args())

我们的脚本接受五个命令行参数,其中前三个是必需的:


–dataset :输入数据集的路径。


–model :我们输出 Keras 模型文件的路径。


–label-bin :我们的输出标签二值化器pickle文件的路径。


–epochs :我们的网络要训练多少个时期——默认情况下,我们将训练 25 个时期,但正如我将在本教程后面展示的,50 个时期可以带来更好的结果。


–plot :我们的输出绘图图像文件的路径——默认情况下,它将被命名为 plot.png 并放置在与此训练脚本相同的目录中。


解析并掌握我们的命令行参数后,让我们继续初始化我们的 LABELS 并加载我们的数据:

# initialize the set of labels from the spots activity dataset we are
# going to train our network on
LABELS = set(["weight_lifting", "tennis", "football"])
# grab the list of images in our dataset directory, then initialize
# the list of data (i.e., images) and class images
print("[INFO] loading images...")
imagePaths = list(paths.list_images(args["dataset"]))
data = []
labels = []
# loop over the image paths
for imagePath in imagePaths:
  # extract the class label from the filename
  label = imagePath.split(os.path.sep)[-2]
  # if the label of the current image is not part of of the labels
  # are interested in, then ignore the image
  if label not in LABELS:
    continue
  # load the image, convert it to RGB channel ordering, and resize
  # it to be a fixed 224x224 pixels, ignoring aspect ratio
  image = cv2.imread(imagePath)
  image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
  image = cv2.resize(image, (224, 224))
  # update the data and labels lists, respectively
  data.append(image)
  labels.append(label)

定义类 LABELS 的集合。该集合中不存在的所有标签都将被排除在我们的数据集之外。为了节省训练时间,我们的数据集将只包含举重、网球和足球/足球。通过对 LABELS 集进行更改,您可以随意使用其他类。


初始化我们的数据和标签列表。


遍历所有 imagePath。


在循环中,首先我们从 imagePath 中提取类标签


忽略不在 LABELS 集合中的任何标签。


加载并预处理图像。预处理包括将 OpenCV 的颜色通道交换到 Keras 兼容性并将大小调整为 224×224px。在此处阅读有关调整 CNN 图像大小的更多信息。要了解有关预处理重要性的更多信息,请务必参阅使用 Python 进行计算机视觉深度学习。


然后分别将图像和标签添加到数据和标签列表中。


继续,我们将对我们的标签进行单热编码并分区我们的数据:


# convert the data and labels to NumPy arrays
data = np.array(data)
labels = np.array(labels)
# perform one-hot encoding on the labels
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(data, labels,
  test_size=0.25, stratify=labels, random_state=42)

将我们的数据和标签列表转换为 NumPy 数组。


执行one-hot编码。one-hot编码是一种通过二进制数组元素标记活动类标签的方法。 例如,“足球”可能是 array([1, 0, 0]) 而“举重”可能是 array([0, 0, 1]) 。 请注意在任何给定时间只有一个类是“热的”。


按照4:1的比例,将我们的数据分成训练和测试部分。


初始化我们的数据增强对象:


# initialize the training data augmentation object
trainAug = ImageDataGenerator(
  rotation_range=30,
  zoom_range=0.15,
  width_shift_range=0.2,
  height_shift_range=0.2,
  shear_range=0.15,
  horizontal_flip=True,
  fill_mode="nearest")
# initialize the validation/testing data augmentation object (which
# we'll be adding mean subtraction to)
valAug = ImageDataGenerator()
# define the ImageNet mean subtraction (in RGB order) and set the
# the mean subtraction value for each of the data augmentation
# objects
mean = np.array([123.68, 116.779, 103.939], dtype="float32")
trainAug.mean = mean
valAug.mean = mean

初始化了两个数据增强对象——一个用于训练,一个用于验证。 在计算机视觉的深度学习中,几乎总是建议使用数据增强来提高模型泛化能力。


trainAug 对象对我们的数据执行随机旋转、缩放、移位、剪切和翻转。 您可以在此处阅读有关 ImageDataGenerator 和 fit 的更多信息。 正如我们上周强调的那样,请记住,使用 Keras,图像将即时生成(这不是附加操作)。


不会对验证数据 (valAug) 进行扩充,但我们将执行均值减法。


平均像素值,设置 trainAug 和 valAug 的均值属性,以便在训练/评估期间生成图像时进行均值减法。 现在,我们将执行我喜欢称之为“网络手术”的操作,作为微调的一部分:

# load the ResNet-50 network, ensuring the head FC layer sets are left
# off
baseModel = ResNet50(weights="imagenet", include_top=False,
  input_tensor=Input(shape=(224, 224, 3)))
# construct the head of the model that will be placed on top of the
# the base model
headModel = baseModel.output
headModel = AveragePooling2D(pool_size=(7, 7))(headModel)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(512, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(len(lb.classes_), activation="softmax")(headModel)
# place the head FC model on top of the base model (this will become
# the actual model we will train)
model = Model(inputs=baseModel.input, outputs=headModel)
# loop over all layers in the base model and freeze them so they will
# *not* be updated during the training process
for layer in baseModel.layers:
  layer.trainable = False

加载用 ImageNet 权重预训练的 ResNet50,同时切掉网络的头部。

组装了一个新的 headModel 并将其缝合到 baseModel 上。

我们现在将冻结 baseModel,以便它不会通过反向传播进行训练。

让我们继续编译+训练我们的模型:

# compile our model (this needs to be done after our setting our
# layers to being non-trainable)
print("[INFO] compiling model...")
opt = SGD(lr=1e-4, momentum=0.9, decay=1e-4 / args["epochs"])
model.compile(loss="categorical_crossentropy", optimizer=opt,
  metrics=["accuracy"])
# train the head of the network for a few epochs (all other layers
# are frozen) -- this will allow the new FC layers to start to become
# initialized with actual "learned" values versus pure random
print("[INFO] training head...")
H = model.fit(
  x=trainAug.flow(trainX, trainY, batch_size=32),
  steps_per_epoch=len(trainX) // 32,
  validation_data=valAug.flow(testX, testY),
  validation_steps=len(testX) // 32,
  epochs=args["epochs"])

为了使此绘图片段与 TensorFlow 2+ 兼容,更新了 H.history 字典键以完全拼出“accuracy”无“acc”(H.history[“val_accuracy”] 和 H.历史[“准确性”])。 “val”没有拼写为“validation”,这有点令人困惑; 我们必须学会热爱 API 并与之共存,并始终记住这是一项正在进行的工作,世界各地的许多开发人员都在为之做出贡献。


在我们在测试集上评估我们的网络并打印分类报告


之后,我们继续使用 matplotlib


绘制准确率/损失曲线。 该图通过第 164 行保存到磁盘。


最后将我们的模型和标签二值化器 (lb) 序列化到磁盘:

# serialize the model to disk
print("[INFO] serializing network...")
model.save(args["model"], save_format="h5")
# serialize the label binarizer to disk
f = open(args["label_bin"], "wb")
f.write(pickle.dumps(lb))
f.close()

训练结果

在我们 使用我们的 CNN 对视频中的帧进行分类,然后) 利用我们的 CNN 进行视频分类之前,我们首先需要训练模型。

确保您已使用本教程的“下载”部分将源代码下载到此图像(以及下载运动类型数据集)。

从那里,打开一个终端并执行以下命令:

$ python train.py --dataset Sports-Type-Classifier/data --model model/activity.model \
  --label-bin output/lb.pickle --epochs 50
[INFO] loading images...
[INFO] compiling model...
[INFO] training head...
Epoch 1/50
48/48 [==============================] - 10s 209ms/step - loss: 1.4184 - accuracy: 0.4421 - val_loss: 0.7866 - val_accuracy: 0.6719
Epoch 2/50
48/48 [==============================] - 10s 198ms/step - loss: 0.9002 - accuracy: 0.6086 - val_loss: 0.5476 - val_accuracy: 0.7832
Epoch 3/50
48/48 [==============================] - 9s 198ms/step - loss: 0.7188 - accuracy: 0.7020 - val_loss: 0.4690 - val_accuracy: 0.8105
Epoch 4/50
48/48 [==============================] - 10s 203ms/step - loss: 0.6421 - accuracy: 0.7375 - val_loss: 0.3986 - val_accuracy: 0.8516
Epoch 5/50
48/48 [==============================] - 10s 200ms/step - loss: 0.5496 - accuracy: 0.7770 - val_loss: 0.3599 - val_accuracy: 0.8652
...
Epoch 46/50
48/48 [==============================] - 9s 192ms/step - loss: 0.2066 - accuracy: 0.9217 - val_loss: 0.1618 - val_accuracy: 0.9336
Epoch 47/50
48/48 [==============================] - 9s 193ms/step - loss: 0.2064 - accuracy: 0.9204 - val_loss: 0.1622 - val_accuracy: 0.9355
Epoch 48/50
48/48 [==============================] - 9s 192ms/step - loss: 0.2092 - accuracy: 0.9217 - val_loss: 0.1604 - val_accuracy: 0.9375
Epoch 49/50
48/48 [==============================] - 9s 195ms/step - loss: 0.1935 - accuracy: 0.9290 - val_loss: 0.1620 - val_accuracy: 0.9375
Epoch 50/50
48/48 [==============================] - 9s 192ms/step - loss: 0.2109 - accuracy: 0.9164 - val_loss: 0.1561 - val_accuracy: 0.9395
[INFO] evaluating network...
                precision    recall  f1-score   support
      football       0.93      0.96      0.95       196
        tennis       0.92      0.92      0.92       179
weight_lifting       0.97      0.92      0.95       143
      accuracy                           0.94       518
     macro avg       0.94      0.94      0.94       518
  weighted avg       0.94      0.94      0.94       518
[INFO] serializing network...

oo.png

如您所见,在体育数据集上对 ResNet50 进行微调后,我们获得了约 94% 的准确率。 检查我们的模型目录,我们可以看到微调模型和标签二值化器已经序列化到磁盘:


使用 Keras 进行视频分类和滚动预测平均

我们现在准备通过滚动预测精度使用 Keras 实现视频分类! 为了创建这个脚本,我们将利用视频的时间特性,特别是假设视频中的后续帧将具有相似的语义内容。 通过执行滚动预测准确性,我们将能够“平滑”预测并避免“预测闪烁”。 让我们开始吧——打开 predict_video.py 文件并插入以下代码:

# import the necessary packages
from tensorflow.keras.models import load_model
from collections import deque
import numpy as np
import argparse
import pickle
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-m", "--model", required=True,
  help="path to trained serialized model")
ap.add_argument("-l", "--label-bin", required=True,
  help="path to  label binarizer")
ap.add_argument("-i", "--input", required=True,
  help="path to our input video")
ap.add_argument("-o", "--output", required=True,
  help="path to our output video")
ap.add_argument("-s", "--size", type=int, default=128,
  help="size of queue for averaging")
args = vars(ap.parse_args())

载必要的包和模块。 特别是,我们将使用 Python 集合模块中的 deque 来协助我们的滚动平均算法。


然后,解析五个命令行参数,其中四个是必需的:


–model :从我们之前的训练步骤生成的输入模型的路径。


–label-bin :前一个脚本生成的序列化 pickle 格式标签二值化器的路径。


–input :用于视频分类的输入视频的路径。


–output :我们将保存到磁盘的输出视频的路径。


–size :滚动平均队列的最大大小(默认为 128)。 对于稍后的一些示例结果,我们将大小设置为 1,以便不执行平均。


相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
1月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
将Keras训练好的.hdf5模型转换为TensorFlow的.pb模型,然后再转换为TensorRT支持的.uff格式,并提供了转换代码和测试步骤。
86 3
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
|
1月前
|
机器学习/深度学习 自然语言处理 监控
深度学习之视频摘要生成
基于深度学习的视频摘要生成是一种通过自动化方式从长视频中提取关键片段,生成简洁且有代表性的视频摘要的技术。其目的是在保留视频主要内容的基础上,大幅缩短视频的播放时长,方便用户快速理解视频的核心信息。
82 7
|
18天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的地面垃圾识别分类技术
AI垃圾分类系统结合深度学习和计算机视觉技术,实现高效、精准的垃圾识别与自动分类。系统集成高精度图像识别、多模态数据分析和实时处理技术,适用于市政环卫、垃圾处理厂和智能回收设备,显著提升管理效率,降低人工成本。
基于深度学习的地面垃圾识别分类技术
|
1月前
|
机器学习/深度学习 数据处理 数据库
基于Django的深度学习视频分类Web系统
基于Django的深度学习视频分类Web系统
55 4
基于Django的深度学习视频分类Web系统
|
2月前
|
机器学习/深度学习 人工智能 算法
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集("体育类", "财经类", "房产类", "家居类", "教育类", "科技类", "时尚类", "时政类", "游戏类", "娱乐类"),然后基于TensorFlow搭建CNN卷积神经网络算法模型。通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型,并保存为本地的h5格式。然后使用Django开发Web网页端操作界面,实现用户上传一段文本识别其所属的类别。
93 1
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
1月前
|
机器学习/深度学习 运维 监控
深度学习之视频内容理解
基于深度学习的视频内容理解(Video Content Understanding, VCU)是一项关键技术,旨在通过神经网络模型自动分析、解读和提取视频中的语义信息。
90 10
|
1月前
|
机器学习/深度学习 PyTorch 算法框架/工具
深度学习入门案例:运用神经网络实现价格分类
深度学习入门案例:运用神经网络实现价格分类
|
1月前
|
机器学习/深度学习 监控 人机交互
深度学习之视频中的姿态跟踪
基于深度学习的视频姿态跟踪是一项用于从视频序列中持续检测和跟踪人体姿态的技术。它能够识别人体的2D或3D关键点,并在时间维度上进行跟踪,主要应用于人机交互、体育分析、动作识别和虚拟现实等领域。
52 3
|
1月前
|
机器学习/深度学习 传感器 监控
深度学习之动作识别与分类
基于深度学习的动作识别与分类是指通过深度学习模型从视频或传感器数据中自动识别和分类人类动作的过程。这项技术广泛应用于视频监控、安全监控、体育分析、医疗康复、虚拟现实(VR)和增强现实(AR)等领域。
65 1
|
1月前
|
机器学习/深度学习 移动开发 TensorFlow
深度学习之格式转换笔记(四):Keras(.h5)模型转化为TensorFlow(.pb)模型
本文介绍了如何使用Python脚本将Keras模型转换为TensorFlow的.pb格式模型,包括加载模型、重命名输出节点和量化等步骤,以便在TensorFlow中进行部署和推理。
80 0
下一篇
无影云桌面