主頁 >  其他 > 詳解視頻中動作識別模型與代碼實踐

詳解視頻中動作識別模型與代碼實踐

2022-12-15 07:45:46 其他

摘要:本案例將為大家介紹視頻動作識別領域的經典模型并進行代碼實踐,

本文分享自華為云社區《視頻動作識別》,作者:HWCloudAI,實驗目標

通過本案例的學習:

  • 掌握 C3D 模型訓練和模型推理、I3D 模型推理的方法;

注意事項

  1. 本案例推薦使用TensorFlow-1.13.1,需使用 GPU 運行,請查看《ModelArts JupyterLab 硬體規格使用指南》了解切換硬體規格的方法;

  2. 如果您是第一次使用 JupyterLab,請查看《ModelArts JupyterLab使用指導》了解使用方法;

  3. 如果您在使用 JupyterLab 程序中碰到報錯,請參考《ModelArts JupyterLab常見問題解決辦法》嘗試解決問題,

實驗步驟

案例內容介紹

視頻動作識別是指對一小段視頻中的內容進行分析,判斷視頻中的人物做了哪種動作,視頻動作識別與影像領域的影像識別,既有聯系又有區別,影像識別是對一張靜態圖片進行識別,而視頻動作識別不僅要考察每張圖片的靜態內容,還要考察不同圖片靜態內容之間的時空關系,比如一個人扶著一扇半開的門,僅憑這一張圖片無法判斷該動作是開門動作還是關門動作,

視頻分析領域的研究相比較影像分析領域的研究,發展時間更短,也更有難度,視頻分析模型完成的難點首先在于,需要強大的計算資源來完成視頻的分析,視頻要拆解成為影像進行分析,導致模型的資料量十分龐大,視頻內容有很重要的考慮因素是動作的時間順序,需要將視頻轉換成的影像通過時間關系聯系起來,做出判斷,所以模型需要考慮時序因素,加入時間維度之后引數也會大量增加,

得益于 PASCAL VOC、ImageNet、MS COCO 等資料集的公開,影像領域產生了很多的經典模型,那么在視頻分析領域有沒有什么經典的模型呢?答案是有的,本案例將為大家介紹視頻動作識別領域的經典模型并進行代碼實踐,

1. 準備源代碼和資料

這一步準備案例所需的源代碼和資料,相關資源已經保存在 OBS 中,我們通過ModelArts SDK將資源下載到本地,并解壓到當前目錄下,解壓后,當前目錄包含 data、dataset_subset 和其他目錄檔案,分別是預訓練引數檔案、資料集和代碼檔案等,

import os
import moxing as mox
if not os.path.exists('videos'):
 mox.file.copy("obs://ai-course-common-26-bj4-v2/video/video.tar.gz", "./video.tar.gz")
 # 使用tar命令解壓資源包
 os.system("tar xf ./video.tar.gz")
 # 使用rm命令洗掉壓縮包
 os.system("rm ./video.tar.gz")
INFO:root:Using MoXing-v1.17.3-
INFO:root:Using OBS-Python-SDK-3.20.7

上一節課我們已經介紹了視頻動作識別有 HMDB51、UCF-101 和 Kinetics 三個常用的資料集,本案例選用了 UCF-101 資料集的部分子集作為演示用資料集,接下來,我們播放一段 UCF-101 中的視頻:

video_name = "./data/v_TaiChi_g01_c01.avi"

 

from IPython.display import clear_output, Image, display, HTML
import time
import cv2
import base64
import numpy as np
def arrayShow(img):
 _,ret = cv2.imencode('.jpg', img) 
 return Image(data=https://www.cnblogs.com/huaweiyun/p/ret) 
cap = cv2.VideoCapture(video_name)
while True:
 try:
 clear_output(wait=True)
        ret, frame = cap.read()
 if ret:
 tmp = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
 img = arrayShow(frame)
            display(img)
 time.sleep(0.05)
 else:
 break
 except KeyboardInterrupt:
 cap.release()
cap.release()

2. 視頻動作識別模型介紹

在影像領域中,ImageNet 作為一個大型影像識別資料集,自 2010 年開始,使用此資料集訓練出的影像演算法層出不窮,深度學習模型經歷了從 AlexNet 到 VGG-16 再到更加復雜的結構,模型的表現也越來越好,在識別千種類別的圖片時,錯誤率表現如下:

在影像識別中表現很好的模型,可以在影像領域的其他任務中繼續使用,通過復用模型中部分層的引數,就可以提升模型的訓練效果,有了基于 ImageNet 模型的影像模型,很多模型和任務都有了更好的訓練基礎,比如說物體檢測、實體分割、人臉檢測、人臉識別等,

那么訓練效果顯著的影像模型是否可以用于視頻模型的訓練呢?答案是 yes,有研究證明,在視頻領域,如果能夠復用影像模型結構,甚至引數,將對視頻模型的訓練有很大幫助,但是怎樣才能復用上影像模型的結構呢?首先需要知道視頻分類與影像分類的不同,如果將視頻視作是影像的集合,每一個幀將作為一個影像,視頻分類任務除了要考慮到影像中的表現,也要考慮影像間的時空關系,才可以對視頻動作進行分類,

為了捕獲影像間的時空關系,論文 I3D 介紹了三種舊的視頻分類模型,并提出了一種更有效的 Two-Stream Inflated 3D ConvNets(簡稱 I3D)的模型,下面將逐一簡介這四種模型,更多細節資訊請查看原論文,

舊模型一:卷積網路 + LSTM

模型使用了訓練成熟的影像模型,通過卷積網路,對每一幀影像進行特征提取、池化和預測,最后在模型的末端加一個 LSTM 層(長短期記憶網路),如下圖所示,這樣就可以使模型能夠考慮時間性結構,將背景關系特征聯系起來,做出動作判斷,這種模型的缺點是只能捕獲較大的作業,對小動作的識別效果較差,而且由于視頻中的每一幀影像都要經過網路的計算,所以訓練時間很長,

舊模型二:3D 卷積網路

3D 卷積類似于 2D 卷積,將時序資訊加入卷積操作,雖然這是一種看起來更加自然的視頻處理方式,但是由于卷積核維度增加,引數的數量也增加了,模型的訓練變得更加困難,這種模型沒有對影像模型進行復用,而是直接將視頻資料傳入 3D 卷積網路進行訓練,

舊模型三:Two-Stream 網路

Two-Stream 網路的兩個流分別為 1 張 RGB 快照和 10 張計算之后的光流幀畫面組成的堆疊,兩個流都通過 ImageNet 預訓練好的影像卷積網路,光流部分可以分為豎直和水平兩個通道,所以是普通圖片輸入的 2 倍,模型在訓練和測驗中表現都十分出色,

光流視頻 optical flow video

上面講到了光流,在此對光流做一下介紹,光流是什么呢?名字很專業,感覺很陌生,但實際上這種視覺現象我們每天都在經歷,我們坐高鐵的時候,可以看到窗外的景物都在快速往后退,開得越快,就感受到外面的景物就是 “刷” 地一個殘影,這種視覺上目標的運動方向和速度就是光流,光流從概念上講,是對物體運動的觀察,通過找到相鄰幀之間的相關性來判斷幀之間的對應關系,計算出相鄰幀畫面中物體的運動資訊,獲取像素運動的瞬時速度,在原始視頻中,有運動部分和靜止的背景部分,我們通常需要判斷的只是視頻中運動部分的狀態,而光流就是通過計算得到了視頻中運動部分的運動資訊,

下面是一個經過計算后的原視頻及光流視頻,

原視頻

See videos/v_CricketShot_g04_c01_rgb.gif

光流視頻

See videos/v_CricketShot_g04_c01_flow.gif

新模型:Two-Stream Inflated 3D ConvNets

新模型采取了以下幾點結構改進:

  • 拓展 2D 卷積為 3D,直接利用成熟的影像分類模型,只不過將網路中二維 $ N × N 的 filters 和 pooling kernels 直接變成的 filters 和 poolingkernels 直接變成 N × N × N $;
  • 用 2D filter 的預訓練引數來初始化 3D filter 的引數,上一步已經利用了影像分類模型的網路,這一步的目的是能利用上網路的預訓練引數,直接將 2D filter 的引數直接沿著第三個時間維度進行復制 N 次,最后將所有引數值再除以 N;
  • 調整感受野的形狀和大小,新模型改造了影像分類模型 Inception-v1 的結構,前兩個 max-pooling 層改成使用 $ 1 × 3 × 3 kernels and stride 1 in time,其他所有 max-pooling 層都仍然使用對此的 kernel 和 stride,最后一個 average pooling 層使用 kernelsandstride1intime,其他所有 max?pooling 層都仍然使用對此的 kernel 和 stride,最后一個 averagepooling 層使用 2 × 7 × 7 $ 的 kernel,
  • 延續了 Two-Stream 的基本方法,用雙流結構來捕獲圖片之間的時空關系仍然是有效的,

最后新模型的整體結構如下圖所示:

好,到目前為止,我們已經講解了視頻動作識別的經典資料集和經典模型,下面我們通過代碼來實踐地跑一跑其中的兩個模型:C3D 模型( 3D 卷積網路)以及 I3D 模型(Two-Stream Inflated 3D ConvNets),

C3D 模型結構

我們已經在前面的 “舊模型二:3D 卷積網路” 中講解到 3D 卷積網路是一種看起來比較自然的處理視頻的網路,雖然它有效果不夠好,計算量也大的特點,但它的結構很簡單,可以構造一個很簡單的網路就可以實作視頻動作識別,如下圖所示是 3D 卷積的示意圖:

a) 中,一張圖片進行了 2D 卷積, b) 中,對視頻進行 2D 卷積,將多個幀視作多個通道, c) 中,對視頻進行 3D 卷積,將時序資訊加入輸入信號中,

ab 中,output 都是一張二維特征圖,所以無論是輸入是否有時間資訊,輸出都是一張二維的特征圖,2D 卷積失去了時序資訊,只有 3D 卷積在輸出時,保留了時序資訊,2D 和 3D 池化操作同樣有這樣的問題,

如下圖所示是一種 C3D 網路的變種:(如需閱讀原文描述,請查看 I3D 論文 2.2 節)

C3D 結構,包括 8 個卷積層,5 個最大池化層以及 2 個全連接層,最后是 softmax 輸出層,

所有的 3D 卷積核為 $ 3 × 3 × 3$ 步長為 1,使用 SGD,初始學習率為 0.003,每 150k 個迭代,除以 2,優化在 1.9M 個迭代的時候結束,大約 13epoch,

資料處理時,視頻抽幀定義大小為:$ c × l × h × w,,c 為通道數量,為通道數量,l 為幀的數量,為幀的數量,h 為幀畫面的高度,為幀畫面的高度,w 為幀畫面的寬度,3D 卷積核和池化核的大小為為幀畫面的寬度,3D 卷積核和池化核的大小為 d × k × k,,d 是核的時間深度,是核的時間深度,k 是核的空間大小,網路的輸入為視頻的抽幀,預測出的是類別標簽,所有的視頻幀畫面都調整大小為是核的空間大小,網路的輸入為視頻的抽幀,預測出的是類別標簽,所有的視頻幀畫面都調整大小為 128 × 171 $,幾乎將 UCF-101 資料集中的幀調整為一半大小,視頻被分為不重復的 16 幀畫面,這些畫面將作為模型網路的輸入,最后對幀畫面的大小進行裁剪,輸入的資料為 $16 × 112 × 112 $

3.C3D 模型訓練

接下來,我們將對 C3D 模型進行訓練,訓練程序分為:資料預處理以及模型訓練,在此次訓練中,我們使用的資料集為 UCF-101,由于 C3D 模型的輸入是視頻的每幀圖片,因此我們需要對資料集的視頻進行抽幀,也就是將視頻轉換為圖片,然后將圖片資料傳入模型之中,進行訓練,

在本案例中,我們隨機抽取了 UCF-101 資料集的一部分進行訓練的演示,感興趣的同學可以下載完整的 UCF-101 資料集進行訓練,

UCF-101 下載

資料集存盤在目錄 dataset_subset 下

如下代碼是使用 cv2 庫進行視頻檔案到圖片檔案的轉換

import cv2
import os
# 視頻資料集存盤位置
video_path = './dataset_subset/'
# 生成的影像資料集存盤位置
save_path = './dataset/'
# 如果檔案路徑不存在則創建路徑
if not os.path.exists(save_path):
 os.mkdir(save_path)
# 獲取動作串列
action_list = os.listdir(video_path)
# 遍歷所有動作
for action in action_list:
 if action.startswith(".")==False:
 if not os.path.exists(save_path+action):
 os.mkdir(save_path+action)
 video_list = os.listdir(video_path+action)
 # 遍歷所有視頻
 for video in video_list:
            prefix = video.split('.')[0]
 if not os.path.exists(os.path.join(save_path, action, prefix)):
 os.mkdir(os.path.join(save_path, action, prefix))
 save_name = os.path.join(save_path, action, prefix) + '/'
 video_name = video_path+action+'/'+video
 # 讀取視頻檔案
 # cap為視頻的幀
            cap = cv2.VideoCapture(video_name)
 # fps為幀率
            fps = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
 fps_count = 0
 for i in range(fps):
                ret, frame = cap.read()
 if ret:
 # 將幀畫面寫入圖片檔案中
                    cv2.imwrite(save_name+str(10000+fps_count)+'.jpg',frame)
 fps_count += 1

此時,視頻逐幀轉換成的圖片資料已經存盤起來,為模型訓練做準備,

4. 模型訓練

首先,我們構建模型結構,

C3D 模型結構我們之前已經介紹過,這里我們通過 keras 提供的 Conv3D,MaxPool3D,ZeroPadding3D 等函式進行模型的搭建,

from keras.layers import Dense,Dropout,Conv3D,Input,MaxPool3D,Flatten,Activation, ZeroPadding3D
from keras.regularizers import l2
from keras.models import Model, Sequential
# 輸入資料為 112×112 的圖片,16幀, 3通道
input_shape = (112,112,16,3)
# 權重衰減率
weight_decay = 0.005
# 型別數量,我們使用UCF-101 為資料集,所以為101
nb_classes = 101
# 構建模型結構
inputs = Input(input_shape)
x = Conv3D(64,(3,3,3),strides=(1,1,1),padding='same',
           activation='relu',kernel_regularizer=l2(weight_decay))(inputs)
x = MaxPool3D((2,2,1),strides=(2,2,1),padding='same')(x)
x = Conv3D(128,(3,3,3),strides=(1,1,1),padding='same',
           activation='relu',kernel_regularizer=l2(weight_decay))(x)
x = MaxPool3D((2,2,2),strides=(2,2,2),padding='same')(x)
x = Conv3D(128,(3,3,3),strides=(1,1,1),padding='same',
           activation='relu',kernel_regularizer=l2(weight_decay))(x)
x = MaxPool3D((2,2,2),strides=(2,2,2),padding='same')(x)
x = Conv3D(256,(3,3,3),strides=(1,1,1),padding='same',
           activation='relu',kernel_regularizer=l2(weight_decay))(x)
x = MaxPool3D((2,2,2),strides=(2,2,2),padding='same')(x)
x = Conv3D(256, (3, 3, 3), strides=(1, 1, 1), padding='same',
           activation='relu',kernel_regularizer=l2(weight_decay))(x)
x = MaxPool3D((2, 2, 2), strides=(2, 2, 2), padding='same')(x)
x = Flatten()(x)
x = Dense(2048,activation='relu',kernel_regularizer=l2(weight_decay))(x)
x = Dropout(0.5)(x)
x = Dense(2048,activation='relu',kernel_regularizer=l2(weight_decay))(x)
x = Dropout(0.5)(x)
x = Dense(nb_classes,kernel_regularizer=l2(weight_decay))(x)
x = Activation('softmax')(x)
model = Model(inputs, x)
Using TensorFlow backend.
/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:526: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint8 = np.dtype([("qint8", np.int8, 1)])
/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:527: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_quint8 = np.dtype([("quint8", np.uint8, 1)])
/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:528: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint16 = np.dtype([("qint16", np.int16, 1)])
/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:529: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_quint16 = np.dtype([("quint16", np.uint16, 1)])
/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:530: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint32 = np.dtype([("qint32", np.int32, 1)])
/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:535: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
 np_resource = np.dtype([("resource", np.ubyte, 1)])
WARNING:tensorflow:From /home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
WARNING:tensorflow:From /home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3445: calling dropout (from tensorflow.python.ops.nn_ops) with keep_prob is deprecated and will be removed in a future version.
Instructions for updating:
Please use `rate` instead of `keep_prob`. Rate should be set to `rate = 1 - keep_prob`.

通過 keras 提供的 summary () 方法,列印模型結構,可以看到模型的層構建以及各層的輸入輸出情況,

model.summary()

此處輸出較長,省略

通過 keras 的 input 方法可以查看模型的輸入形狀,shape 分別為 (batch size, width, height, frames, channels) ,

model.input
<tf.Tensor 'input_1:0' shape=(?, 112, 112, 16, 3) dtype=float32>

可以看到模型的資料處理的維度與影像處理模型有一些差別,多了 frames 維度,體現出時序關系在視頻分析中的影響,

接下來,我們開始將圖片檔案轉為訓練需要的資料形式,

# 參考必要的庫
from keras.optimizers import SGD,Adam
from keras.utils import np_utils
import numpy as np
import random
import cv2
import matplotlib.pyplot as plt
# 自定義callbacks
from schedules import onetenth_4_8_12
INFO:matplotlib.font_manager:font search path ['/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf', '/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/afm', '/home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/pdfcorefonts']
INFO:matplotlib.font_manager:generated new fontManager

引數定義

img_path = save_path # 圖片檔案存盤位置
results_path = './results' # 訓練結果保存位置
if not os.path.exists(results_path):
 os.mkdir(results_path)

資料集劃分,隨機抽取 4/5 作為訓練集,其余為驗證集,將檔案資訊分別存盤在 train_list 和 test_list 中,為訓練做準備,

cates = os.listdir(img_path)
train_list = []
test_list = []
# 遍歷所有的動作型別
for cate in cates:
    videos = os.listdir(os.path.join(img_path, cate))
    length = len(videos)//5
 # 訓練集大小,隨機取視頻檔案加入訓練集
    train= random.sample(videos, length*4)
 train_list.extend(train)
 # 將余下的視頻加入測驗集
 for video in videos:
 if video not in train:
 test_list.append(video)
print("訓練集為:") 
print( train_list)
print("共%d 個視頻\n"%(len(train_list)))
print("驗證集為:") 
print(test_list)
print("共%d 個視頻"%(len(test_list)))

此處輸出較長,省略

接下來開始進行模型的訓練,

首先定義資料讀取方法,方法 process_data 中讀取一個 batch 的資料,包含 16 幀的圖片資訊的資料,以及資料的標注資訊,在讀取圖片資料時,對圖片進行隨機裁剪和翻轉操作以完成資料增廣,

def process_data(img_path, file_list,batch_size=16,train=True):
    batch = np.zeros((batch_size,16,112,112,3),dtype='float32')
    labels = np.zeros(batch_size,dtype='int')
 cate_list = os.listdir(img_path)
 def read_classes():
        path = "./classInd.txt"
 with open(path, "r+") as f:
            lines = f.readlines()
        classes = {}
 for line in lines:
 c_id = line.split()[0]
 c_name = line.split()[1]
            classes[c_name] =c_id 
 return classes
 classes_dict = read_classes()
 for file in file_list:
        cate = file.split("_")[1]
 img_list = os.listdir(os.path.join(img_path, cate, file))
 img_list.sort()
 batch_img = []
 for i in range(batch_size):
            path = os.path.join(img_path, cate, file)
            label = int(classes_dict[cate])-1
            symbol = len(img_list)//16
 if train:
 # 隨機進行裁剪
 crop_x = random.randint(0, 15)
 crop_y = random.randint(0, 58)
 # 隨機進行翻轉
 is_flip = random.randint(0, 1)
 # 以16 幀為單位
 for j in range(16):
 img = img_list[symbol + j]
                    image = cv2.imread( path + '/' + img)
                    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                    image = cv2.resize(image, (171, 128))
 if is_flip == 1:
                        image = cv2.flip(image, 1)
                    batch[i][j][:][:][:] = image[crop_x:crop_x + 112, crop_y:crop_y + 112, :]
                    symbol-=1
 if symbol<0:
 break
                labels[i] = label
 else:
 for j in range(16):
 img = img_list[symbol + j]
                    image = cv2.imread( path + '/' + img)
                    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                    image = cv2.resize(image, (171, 128))
                    batch[i][j][:][:][:] = image[8:120, 30:142, :]
                    symbol-=1
 if symbol<0:
 break
                labels[i] = label
 return batch, labels
batch, labels = process_data(img_path, train_list)
print("每個batch的形狀為:%s"%(str(batch.shape)))
print("每個label的形狀為:%s"%(str(labels.shape)))
每個batch的形狀為:(16, 16, 112, 112, 3)
每個label的形狀為:(16,)

定義 data generator, 將資料批次傳入訓練函式中,

def generator_train_batch(train_list, batch_size, num_classes, img_path):
 while True:
 # 讀取一個batch的資料
 x_train, x_labels = process_data(img_path, train_list, batch_size=16,train=True)
        x = preprocess(x_train)
 # 形成input要求的資料格式
        y = np_utils.to_categorical(np.array(x_labels), num_classes)
        x = np.transpose(x, (0,2,3,1,4))
 yield x, y
def generator_val_batch(test_list, batch_size, num_classes, img_path):
 while True:
 # 讀取一個batch的資料
 y_test,y_labels = process_data(img_path, train_list, batch_size=16,train=False)
        x = preprocess(y_test)
 # 形成input要求的資料格式
        x = np.transpose(x,(0,2,3,1,4))
        y = np_utils.to_categorical(np.array(y_labels), num_classes)
 yield x, y

定義方法 preprocess, 對函式的輸入資料進行影像的標準化處理,

def preprocess(inputs):
 inputs[..., 0] -= 99.9
 inputs[..., 1] -= 92.1
 inputs[..., 2] -= 82.6
 inputs[..., 0] /= 65.8
 inputs[..., 1] /= 62.3
 inputs[..., 2] /= 60.3
 return inputs
# 訓練一個epoch大約需4分鐘
# 類別數量
num_classes = 101
# batch大小
batch_size = 4
# epoch數量
epochs = 1
# 學習率大小
lr = 0.005
# 優化器定義
sgd = SGD(lr=lr, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
# 開始訓練
history = model.fit_generator(generator_train_batch(train_list, batch_size, num_classes,img_path),
 steps_per_epoch= len(train_list) // batch_size,
                              epochs=epochs,
                              callbacks=[onetenth_4_8_12(lr)],
 validation_data=generator_val_batch(test_list, batch_size,num_classes,img_path),
 validation_steps= len(test_list) // batch_size,
                              verbose=1)
# 對訓練結果進行保存
model.save_weights(os.path.join(results_path, 'weights_c3d.h5'))
WARNING:tensorflow:From /home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/ops/math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.cast instead.
Epoch 1/1
20/20 [==============================] - 442s 22s/step - loss: 28.7099 - acc: 0.9344 - val_loss: 27.7600 - val_acc: 1.0000

5. 模型測驗

接下來我們將訓練之后得到的模型進行測驗,隨機在 UCF-101 中選擇一個視頻檔案作為測驗資料,然后對視頻進行取幀,每 16 幀畫面傳入模型進行一次動作預測,并且將動作預測以及預測百分比列印在畫面中并進行視頻播放,

首先,引入相關的庫,

from IPython.display import clear_output, Image, display, HTML
import time
import cv2
import base64
import numpy as np

構建模型結構并且加載權重,

from models import c3d_model
model = c3d_model()
model.load_weights(os.path.join(results_path, 'weights_c3d.h5'), by_name=True) # 加載剛訓練的模型

定義函式 arrayshow,進行圖片變數的編碼格式轉換,

def arrayShow(img):
 _,ret = cv2.imencode('.jpg', img) 
 return Image(data=https://www.cnblogs.com/huaweiyun/p/ret) 

進行視頻的預處理以及預測,將預測結果列印到畫面中,最后進行播放,

# 加載所有的類別和編號
with open('./ucfTrainTestlist/classInd.txt', 'r') as f:
 class_names = f.readlines()
 f.close()
# 讀取視頻檔案
video = './videos/v_Punch_g03_c01.avi'
cap = cv2.VideoCapture(video)
clip = []
# 將視頻畫面傳入模型
while True:
 try:
 clear_output(wait=True)
        ret, frame = cap.read()
 if ret:
 tmp = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
 clip.append(cv2.resize(tmp, (171, 128)))
 # 每16幀進行一次預測
 if len(clip) == 16:
                inputs = np.array(clip).astype(np.float32)
                inputs = np.expand_dims(inputs, axis=0)
 inputs[..., 0] -= 99.9
 inputs[..., 1] -= 92.1
 inputs[..., 2] -= 82.6
 inputs[..., 0] /= 65.8
 inputs[..., 1] /= 62.3
 inputs[..., 2] /= 60.3
                inputs = inputs[:,:,8:120,30:142,:]
                inputs = np.transpose(inputs, (0, 2, 3, 1, 4))
 # 獲得預測結果
 pred = model.predict(inputs)
                label = np.argmax(pred[0])
 # 將預測結果繪制到畫面中
                cv2.putText(frame, class_names[label].split(' ')[-1].strip(), (20, 20),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.6,
 (0, 0, 255), 1)
                cv2.putText(frame, "prob: %.4f" % pred[0][label], (20, 40),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.6,
 (0, 0, 255), 1)
 clip.pop(0)
 # 播放預測后的視頻 
            lines, columns, _ = frame.shape
            frame = cv2.resize(frame, (int(columns), int(lines)))
 img = arrayShow(frame)
            display(img)
 time.sleep(0.02)
 else:
 break
 except:
 print(0)
cap.release()

6.I3D 模型

在之前我們簡單介紹了 I3D 模型,I3D 官方 github 庫提供了在 Kinetics 上預訓練的模型和預測代碼,接下來我們將體驗 I3D 模型如何對視頻進行預測,

首先,引入相關的包

import numpy as np
import tensorflow as tf
import i3d
WARNING: The TensorFlow contrib module will not be included in TensorFlow 2.0.
For more information, please see:
 * https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md
 * https://github.com/tensorflow/addons
If you depend on functionality not listed there, please file an issue.

進行引數的定義

# 輸入圖片大小
_IMAGE_SIZE = 224
#  視頻的幀數
_SAMPLE_VIDEO_FRAMES = 79
# 輸入資料包括兩部分:RGB和光流
# RGB和光流資料已經經過提前計算
_SAMPLE_PATHS = {
 'rgb': 'data/v_CricketShot_g04_c01_rgb.npy',
 'flow': 'data/v_CricketShot_g04_c01_flow.npy',
}
# 提供了多種可以選擇的預訓練權重
# 其中,imagenet系列模型從ImageNet的2D權重中拓展而來,其余為視頻資料下的預訓練權重
_CHECKPOINT_PATHS = {
 'rgb': 'data/checkpoints/rgb_scratch/model.ckpt',
 'flow': 'data/checkpoints/flow_scratch/model.ckpt',
 'rgb_imagenet': 'data/checkpoints/rgb_imagenet/model.ckpt',
 'flow_imagenet': 'data/checkpoints/flow_imagenet/model.ckpt',
}
# 記錄類別檔案
_LABEL_MAP_PATH = 'data/label_map.txt'
# 類別數量為400
NUM_CLASSES = 400

定義引數:

  • imagenet_pretrained :如果為 True,則呼叫預訓練權重,如果為 False,則呼叫 ImageNet 轉成的權重
imagenet_pretrained = True
# 加載動作型別
kinetics_classes = [x.strip() for x in open(_LABEL_MAP_PATH)]
tf.logging.set_verbosity(tf.logging.INFO)

構建 RGB 部分模型

rgb_input = tf.placeholder(tf.float32, shape=(1, _SAMPLE_VIDEO_FRAMES, _IMAGE_SIZE, _IMAGE_SIZE, 3))
with tf.variable_scope('RGB', reuse=tf.AUTO_REUSE):
 rgb_model = i3d.InceptionI3d(NUM_CLASSES, spatial_squeeze=True, final_endpoint='Logits')
 rgb_logits, _ = rgb_model(rgb_input, is_training=False, dropout_keep_prob=1.0)
rgb_variable_map = {}
for variable in tf.global_variables():
 if variable.name.split('/')[0] == 'RGB':
 rgb_variable_map[variable.name.replace(':0', '')] = variable
rgb_saver = tf.train.Saver(var_list=rgb_variable_map, reshape=True)

構建光流部分模型

flow_input = tf.placeholder(tf.float32,shape=(1, _SAMPLE_VIDEO_FRAMES, _IMAGE_SIZE, _IMAGE_SIZE, 2))
with tf.variable_scope('Flow', reuse=tf.AUTO_REUSE):
 flow_model = i3d.InceptionI3d(NUM_CLASSES, spatial_squeeze=True, final_endpoint='Logits')
 flow_logits, _ = flow_model(flow_input, is_training=False, dropout_keep_prob=1.0)
flow_variable_map = {}
for variable in tf.global_variables():
 if variable.name.split('/')[0] == 'Flow':
 flow_variable_map[variable.name.replace(':0', '')] = variable
flow_saver = tf.train.Saver(var_list=flow_variable_map, reshape=True) 

將模型聯合,成為完整的 I3D 模型

model_logits = rgb_logits + flow_logits
model_predictions = tf.nn.softmax(model_logits)

開始模型預測,獲得視頻動作預測結果,

預測資料為開篇提供的 RGB 和光流資料:

See videos/v_CricketShot_g04_c01_rgb.gif

See videos/v_CricketShot_g04_c01_flow.gif

 
with tf.Session() as sess:
 feed_dict = {}
 if imagenet_pretrained:
 rgb_saver.restore(sess, _CHECKPOINT_PATHS['rgb_imagenet']) # 加載rgb流的模型
 else:
 rgb_saver.restore(sess, _CHECKPOINT_PATHS['rgb'])
 tf.logging.info('RGB checkpoint restored')
 if imagenet_pretrained:
 flow_saver.restore(sess, _CHECKPOINT_PATHS['flow_imagenet']) # 加載flow流的模型
 else:
 flow_saver.restore(sess, _CHECKPOINT_PATHS['flow'])
 tf.logging.info('Flow checkpoint restored') 
 start_time = time.time()
 rgb_sample = np.load(_SAMPLE_PATHS['rgb']) # 加載rgb流的輸入資料
 tf.logging.info('RGB data loaded, shape=%s', str(rgb_sample.shape))
 feed_dict[rgb_input] = rgb_sample
 flow_sample = np.load(_SAMPLE_PATHS['flow']) # 加載flow流的輸入資料
 tf.logging.info('Flow data loaded, shape=%s', str(flow_sample.shape))
 feed_dict[flow_input] = flow_sample
 out_logits, out_predictions = sess.run(
 [model_logits, model_predictions],
 feed_dict=feed_dict)
 out_logits = out_logits[0]
 out_predictions = out_predictions[0]
 sorted_indices = np.argsort(out_predictions)[::-1]
 print('Inference time in sec: %.3f' % float(time.time() - start_time))
 print('Norm of logits: %f' % np.linalg.norm(out_logits))
 print('\nTop classes and probabilities')
 for index in sorted_indices[:20]:
 print(out_predictions[index], out_logits[index], kinetics_classes[index])
WARNING:tensorflow:From /home/ma-user/anaconda3/envs/TensorFlow-1.13.1/lib/python3.6/site-packages/tensorflow/python/training/saver.py:1266: checkpoint_exists (from tensorflow.python.training.checkpoint_management) is deprecated and will be removed in a future version.
Instructions for updating:
Use standard file APIs to check for files with this prefix.
INFO:tensorflow:Restoring parameters from data/checkpoints/rgb_imagenet/model.ckpt
INFO:tensorflow:RGB checkpoint restored
INFO:tensorflow:Restoring parameters from data/checkpoints/flow_imagenet/model.ckpt
INFO:tensorflow:Flow checkpoint restored
INFO:tensorflow:RGB data loaded, shape=(1, 79, 224, 224, 3)
INFO:tensorflow:Flow data loaded, shape=(1, 79, 224, 224, 2)
Inference time in sec: 1.511
Norm of logits: 138.468643
Top classes and probabilities
1.0 41.813675 playing cricket
1.497162e-09 21.49398 hurling (sport)
3.8431236e-10 20.13411 catching or throwing baseball
1.549242e-10 19.22559 catching or throwing softball
1.1360187e-10 18.915354 hitting baseball
8.801105e-11 18.660116 playing tennis
2.4415466e-11 17.37787 playing kickball
1.153184e-11 16.627766 playing squash or racquetball
6.1318893e-12 15.996157 shooting goal (soccer)
4.391727e-12 15.662376 hammer throw
2.2134352e-12 14.9772005 golf putting
1.6307096e-12 14.67167 throwing discus
1.5456218e-12 14.618079 javelin throw
7.6690325e-13 13.917259 pumping fist
5.1929587e-13 13.527372 shot put
4.2681337e-13 13.331245 celebrating
2.7205462e-13 12.880901 applauding
1.8357015e-13 12.487494 throwing ball
1.6134511e-13 12.358444 dodgeball
1.1388395e-13 12.010078 tap dancing

 

點擊關注,第一時間了解華為云新鮮技術~

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/539933.html

標籤:其他

上一篇:Backbone 網路-DenseNet 論文解讀

下一篇:【機器學習】李宏毅——機器學習基本概念簡介

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more