実践型AIプログラミング特講 karasによる動画認識について その1 #34

実践型AIプログラミング特講 karasによる動画認識について その1 #34

今回はpythonを用いて動画認識を行なっていきたいと考えています。動画にかかるチュートリアルは少し前に触れたかとは思いますがより発展的な内容に落とし込んだ上で皆様に共有しようかと思います。特に中級上級者向けなので初学者には幾分か手厳しいコンテンツになっていますが、特に学習者のレベル問わず理解できるようまとめているつもりなので気負う必要はありません。あらましとして、フレームワークはkeras、機械学習方法としてCNN(畳み込みニューラルネットワーク)を採択しております。

概要

コンピュータビジョンとディープラーニングの技術を使って、動画データを扱う方法を学びましょう。Pythonで独自の映像分析モデルを構築していきます。このチュートリアルは、映像分析のための実践的なチュートリアルになります。

はじめに

これまで、画像データを使ったコンピュータ・ビジョン・モデルの構築方法について、さまざまな記事やマニュアルを書いてきました。画像内のオブジェクトの検出、それらのオブジェクトの分類、コンピュータビジョンとディープラーニングを使ってできることはたくさんあります。

今回は、コンピュータビジョンの中でも、あまり注目されていない「動画」に注目してみました。私たちは、かつてないスピードで動画コンテンツを生成しそれを数多の人々が閲覧しています。コンピュータビジョンのこの分野は、データサイエンティストにとって大きな可能性を秘めていると感じています。

同じコンピュータビジョンのアルゴリズムを動画データに適用してみたいと思いました。画像分類モデルを構築する際に使用したアプローチは、汎用できるものだったのでしょうか?

映像分析

動画は、機械が扱うには難しいものです。画像が静的なものであるのに対し、動画は動的な性質を持っているため、データサイエンティストがモデルを構築するのは複雑です。

しかし、画像データを扱うのとそれほど変わらないので、ご安心ください。今回の記事では、Pythonで独自の映像分析モデルを構築します。

ディープラーニングやコンピュータビジョンの初めて触れる方には、最適なコース前回の記事以前で何本も上げているのでそちらをご確認ください。

ディープラーニングを使ったコンピュータビジョン

この映像分析チュートリアルで扱う内容

・動画分類の概要
・独自の動画分類モデルを構築する手順
・動画分類データセットの探索
・動画分類モデルの学習
・作成した動画分類モデルを評価する

動画分類の概要

動画はどのように定義されるのでしょうか。動画とは、特定の順序で配置された一連の画像の集合体であると言えます。これらの画像のセットは、フレームとも呼ばれます。

そのため、動画の分類問題は、画像の分類問題とそれほど変わらないのです。画像分類問題では、画像を撮影し、(畳み込みニューラルネットワークやCNNのような)特徴抽出器を使って画像から特徴を抽出し、その抽出された特徴に基づいて画像を分類します。動画の分類には、1つだけ余分なステップがあります。

まず、与えられたビデオからフレームを抽出します。あとは、画像の分類タスクと同じ手順を踏めばよい。これは、動画データを扱う最も簡単な方法です。
※動画は写真のコマ送りに近いものなので今回の記事でフレームとはその一枚一枚の写真のことを意味します。

実際には、動画を扱う方法は他にもたくさんあり、動画分析というニッチな分野もあります。

また、今回はCNNを使って動画のフレームから特徴を抽出します。CNNとは何か、どのように動作するのかを簡単に確認したい場合は、前回以前の記事をご確認ください。

動画分類モデル構築の手順

動画をそれぞれのカテゴリに分類するモデルを作りましょう。ここでは、101個の異なるカテゴリに属する13,320個のビデオクリップで構成されたUCF101 – Action Recognition Data Setを使用します。
動画分類モデルを構築するための手順をまとめてみましょう。

1.データセットを調査し、トレーニングセットと検証セットを作成する。学習セットはモデルの学習に、検証セットは学習したモデルの評価に使用します。
2.トレーニングセットとバリデーションセットのすべてのビデオからフレームを抽出する。
3.これらのフレームを前処理し、トレーニングセットのフレームを使ってモデルをトレーニングします。検証セットに含まれるフレームを使って、モデルを評価します。
4.検証セットでのパフォーマンスに満足したら、学習したモデルを使って新しいビデオを分類する。

それでは、早速データを見てみましょう。

動画分類のデータセットを見る

UCF101の公式サイトからデータセットをダウンロードできます。データセットは.rar形式なので、まずそこから動画を抽出する必要があります。新しいフォルダを作り、’Videos’とします(他の名前でも構いません)。そして、次のコマンドを使って、ダウンロードしたビデオをすべて取り出します。

unrar e UCF101.rar Videos/

UCF101の公式ドキュメントには次のように書かれています。

“トレーニングとテストでは、同じグループに属するビデオを分けておくことが非常に重要です。グループ内のビデオは1本の長いビデオから得られているので、トレーニングセットとテストセットで同じグループのビデオを共有することで、高いパフォーマンスが得られる。” とあります。

そこで、公式ドキュメントで提案されているように、データセットを訓練セットとテストセットに分割します。訓練/テストの分割データはこちらからダウンロードできます。大規模なデータセットを扱っているので、pcのそこそこのスペックが必要になるかもしれないことに注意して下さい。最適環境で行うためにはラップトップよりもデスクトップでSSD、GPU、i5以降のCPUが搭載されていることを推奨します。

これで、ビデオが1つのフォルダに、訓練/テスト分割ファイルが別のフォルダに入ったことになります。次に、データセットを作成します。Jupyterノートブックを開き、以下のコードブロックに従ってください。まず、必要なライブラリをインポートします。

import cv2 # 動画をキャプチャするためのライブラリ

import math # 数式処理用

import matplotlib.pyplot as plt # 画像をプロットする。

%matplotlib inline

import pandas as pd

from keras.preprocessing import image # 画像の前処理用

import numpy as np # 数学的操作のため

from keras.utils import np_utils

from skimage.transform import resize # 画像のリサイズ用

from sklearn.model_selection import train_test_split

from glob import glob

from tqdm import tqdm

 

これから動画の名前をデータフレームに格納していきます。

# トレーニングビデオの名前が書かれた.txtファイルを開く

f = open(“trainlist01.txt”, “r”)

temp = f.read()

videos = temp.split(‘n’)

# ビデオの名前を持つデータフレームを作成

train = pd.DataFrame()

train[‘video_name’] = videos

train = train[:-1].

train.head()

このように、動画の名前が.txtファイルで与えられています。きちんと整列していないので、前処理が必要になります。その前に、テスト動画についても同様のデータフレームを作ってみましょう。

# テスト動画の名前が書かれた.txtファイルを開く

f = open(“testlist01.txt”, “r”)

temp = f.read()

videos = temp.split(‘n’)

# ビデオの名前を持つデータフレームの作成

test = pd.DataFrame()

test[‘video_name’] = videos

test = test[:-1] とします。

test.head()

次に、各ビデオのタグを追加します(トレーニングセットとテストセットの両方)。動画名の「/」の前の部分全体が動画のタグを表していることに気付きましたか?そこで、’/’で文字列全体を分割して、すべての動画のタグを選択します。

# トレーニングビデオ用のタグの作成

train_video_tag = []

for i in range(train.shape[0]):

train_video_tag.append(train[‘video_name’][i].split(‘/’)[0])

train[‘tag’] = train_video_tag

# テストビデオ用のタグを作成

test_video_tag = []

for i in range(test.shape[0]):

test_video_tag.append(test[‘video_name’][i].split(‘/’)[0])

test[‘tag’] = test_video_tag

次はモデルの学習に使用するトレーニングビデオからフレームを抽出します。すべてのフレームは、train_1というフォルダに保存します。

まず、新しいフォルダを作成し、名前を「train_1」に変更してから、以下のコードに従ってフレームを抽出します。

# トレーニングビデオからフレームを保存する

for i in tqdm(range(train.shape[0])):

count = 0

videoFile = train[‘video_name’][i].

cap = cv2.VideoCapture(‘UCF/’+videoFile.split(‘ ‘)[0].split(‘/’)[1])   # 与えられたパスからビデオをキャプチャする

frameRate = cap.get(5) #フレームレート

x=1

while(cap.isOpened()):

frameId = cap.get(1) #現在のフレーム番号

ret, frame = cap.read()

if (ret != True):

break

if (frameId % math.floor(frameRate) == 0):

# フレームを train_1 という名前の新しいフォルダに保存する。

filename =’train_1/’ + videoFile.split(‘/’)[1].split(‘ ‘)[0] +”_frame%d.jpg” % count;count+=1

cv2.imwrite(filename, frame)

cap.release()

 

トレーニングセットには9,500本以上のビデオが含まれているため、この作業には時間がかかります。フレームが抽出されたら、これらのフレームの名前と対応するタグを.csvファイルに保存します。このファイルを作成することで、次のセクションで紹介するフレームを読み取ることができます。

# 全画像の名前の取得

images = glob(“train_1/*.jpg”)

train_image = []

train_class = []

for i in tqdm(range(len(images))):

# 画像名の作成

train_image.append(images[i].split(‘/’)[1])

# 画像のクラスを作成

train_class.append(images[i].split(‘/’)[1].split(‘_’)[1])

# 画像とそのクラスをデータフレームに格納する

train_data = pd.DataFrame()

train_data[‘image’] = train_image

train_data[‘class’] = train_class

# データフレームをcsvファイルに変換

train_data.to_csv(‘UCF/train_new.csv’,header=True, index=False)

 

ここまでで、すべてのトレーニングビデオからフレームを抽出し、対応するタグと一緒に.csvファイルに保存しました。いよいよ、テストセットのビデオのタグを予測するためのモデルを学習します。

映像分析モデルのトレーニング

いよいよ動画分類モデルを学習していきましょう。これは、このチュートリアルの中で醍醐味と言われるセクションです。わかりやすいように、このステップをサブステップに分けました。

1.学習用画像として抽出したフレームをすべて読み込む
2.見たことのないデータに対して、我々のモデルがどの程度の性能を発揮するかを調べるための検証セットを作成します。
3.モデルのアーキテクチャを定義する
4.最後に、モデルを学習し、その重みを保存する

すべてのビデオフレームの読み込み

それでは、まず最初のステップとして、フレームを抽出してみましょう。まず、ライブラリのインポートを行います。

import keras

from keras.models import Sequential

from keras.applications.vgg16 import VGG16

from keras.layer import Dense, InputLayer, Dropout, Flatten

from keras.layer import Conv2D, MaxPooling2D, GlobalMaxPooling2D

from keras.preprocessing import image

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from tqdm import tqdm

from sklearn.model_selection import train_test_split

各フレームの名前とそれに対応するタグを含む.csvファイルを作成しましたね。それも読んでみましょう。

train = pd.read_csv(‘UCF/train_new.csv’)

train.head()

最初の5行はこのようになっています。各フレームに対応するクラスやタグが表示されています。この.csvファイルを使って、先ほど抽出したフレームを読み込み、そのフレームをNumPyの配列として格納します。

# 空のリストの作成

train_image = []

#フレームを読み込んで保存する

for i in tqdm(range(train.shape[0])):

# 画像を読み込み、ターゲットサイズを(224,224,3)とする

img = image.load_img(‘train_1/’+train[‘image’][i], target_size=(224,224,3))

# #配列に変換

img = image.img_to_array(img)

# 画素値の正規化

img = img/255

# train_image リストに画像を追加する

train_image.append(img)

# リストを numpy 配列に変換

X = np.array(train_image)

# 配列の形状

X.shape

 

Output: (73844, 224, 224, 3)

サイズが(224, 224, 3)の画像がそれぞれ73,844枚あります。次に、検証セットの作成を行います。

いかがでしたでしょうか、少々小難しい話になってきましたね。ただ、これを全て理解する必要はありません。少しずつ、各コードが何の意味をなしているのか感覚的に理解できることが大切なので誰もコーディングしたものをその場ですんなり理解できる人は、たとえ現場のSEでも難しいでしょう。なので着実に少しづつ進歩していることを信じ学習を継続していただけたら幸いです。

次回の記事はこちら

プログラミングカテゴリの最新記事