亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

硬貨 | 手把手帶你構建視頻分類模型(附Python演練))

系統 1818 0
硬貨 | 手把手帶你構建視頻分類模型(附Python演練))_第1張圖片
譯者 |?VK
來源 |?Analytics?Vidhya

概述

  • 了解如何使用計算機視覺和深度學習技術處理視頻數據

  • 我們將在Python中構建自己的視頻分類模型

  • 這是一個非常實用的視頻分類教程,所以準備好Jupyter Notebook

介紹

我們可以使用計算機視覺和深度學習做很多事情,例如檢測圖像中的對象,對這些對象進行分類,從電影海報中生成標簽。

這一次,我決定將注意力轉向計算機視覺中不太引人注目的方面-視頻!我們正以前所未有的速度消費視頻內容。我覺得對數據科學家來說這個計算機視覺的領域具有很大的潛力。

我很好奇將相同的計算機視覺算法應用于視頻數據。我用于構建圖像分類模型的方法是否可以推廣?

對于機器來說,視頻可能很棘手。它們的動態特性與圖像的靜態特性相反,這可能使數據科學家構建這些模型變得復雜。

但不要擔心,它與處理圖像數據沒有什么不同。在本文中,我們將使用Python構建我們自己的視頻分類模型。這是一個非常實用的教程,所以準備好Jupyter Notebook,這將是一個非常有趣的過程。

我們將在本視頻分類教程中介紹的內容

  • 視頻分類概述

  • 構建視頻分類模型的步驟

  • 探索視頻分類數據集

  • 訓練視頻分類模型

  • 評估視頻分類模型

視頻分類概述

你會如何定義視頻?

我們可以說視頻是按特定順序排列的一組圖像的集合。這些圖像也稱為幀。

這就是為什么視頻分類問題與圖像分類問題沒有什么不同 。對于圖像分類任務,我們采用圖像,使用特征提取器(如卷積神經網絡或CNN)從圖像中提取特征,然后基于這些提取的特征對該圖像進行分類。視頻分類僅涉及一個額外步驟。

我們首先從給定視頻中提取幀。然后,我們可以按照與圖像分類任務相同的步驟進行操作。這是處理視頻數據的最簡單方法。

實際上有多種其他方式來處理視頻,甚至還有視頻分析領域。我們將使用CNN從視頻幀中提取特征。

構建視頻分類模型的步驟

建立一個能夠將視頻分類到各自類別的模型很興奮吧!我們將研究UCF101 – Action Recognition Data Set(動作識別數據集),它包含13,320種不同的視頻片段,屬于101個不同的類別。

讓我總結一下我們將構建視頻分類模型的步驟:

  1. 瀏覽數據集并創建訓練和驗證集。我們將使用訓練集來訓練模型和驗證集來評估模型

  2. 從訓練集以及驗證集中的所有視頻提取幀

  3. 預處理這些幀,然后使用訓練集中的幀來訓練模型。使用驗證集中的幀來評估模型

  4. 一旦我們對驗證集上的性能感到滿意,就可以使用訓練好的模型對新視頻進行分類

我們現在開始探索數據吧!

探索視頻分類數據集

你可以從官方UCF101站點(https://www.crcv.ucf.edu/data/UCF101.php)下載數據集。數據集采用.rar格式,因此我們首先必須從中提取視頻。創建一個新文件夾,假設為"視頻"(你也可以選擇任何其他名稱),然后使用以下命令提取所有下載的視頻:

                
                  unrar?e?UCF101.rar?Videos/

                
              

UCF101的官方文件指出:

"在訓練和測試中,將屬于同一組的視頻分開是非常重要的。由于組內的視頻都是來自一個較長的視頻,所以在訓練集和測試集上共享來自同一組的視頻可以獲得較高的性能。"

因此,我們將按照官方文檔中的建議將數據集拆分為訓練和測試集。你可以從這里下載訓練/測試集(https://www.crcv.ucf.edu/data/UCF101/UCF101TrainTestSplits-RecognitionTask.zip)。請記住,由于我們處理的是大型數據集,因此你可能需要較高的計算能力。

我們現在將視頻放在一個文件夾中,將訓練/測試拆分文件放在另一個文件夾中。接下來,我們將創建數據集。打開你的Jupyter Notebook,然后按照下面的代碼塊。我們將首先導入所需的庫:

                
                  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

                
              

我們現在將視頻的名稱存儲在dataframe中:

                
                  #?導入訓練集txt文件,里面有視頻名字列表
f?=?open("trainlist01.txt",?"r")
temp?=?f.read()
videos?=?temp.split('\n')

#?創建含有視頻名字列表的dataframe
train?=?pd.DataFrame()
train['video_name']?=?videos
train?=?train[:-1]
train.head()

                
              

這就是.txt文件中視頻名稱的方式。它沒有正確對齊,我們需要預處理它。在此之前,讓我們為測試視頻創建一個類似的dataframe:

                
                  #?導入測試集txt文件,里面有視頻名字列表
f?=?open("testlist01.txt",?"r")
temp?=?f.read()
videos?=?temp.split('\n')

#?創建含有視頻名字列表的dataframe
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])

#?存儲在dataframe里
train_data?=?pd.DataFrame()
train_data['image']?=?train_image
train_data['class']?=?train_class

#?轉換dataframe為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.layers?import?Dense,?InputLayer,?Dropout,?Flatten
from?keras.layers?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()

                
              

這是前五行的樣子。我們為每個幀都有相應的標簽。現在,使用此.csv文件,我們將讀取先前提取的幀,然后將這些幀存儲為NumPy數組:

                
                  #?創建空列表
train_image?=?[]

#?循環讀取和保存幀
for?i?in?tqdm(range(train.shape[0])):
????#?載入圖片
????img?=?image.load_img('train_1/'+train['image'][i],?target_size=(224,224,3))
????#?轉換為array
????img?=?image.img_to_array(img)
????#?標準化像素值
????img?=?img/255
????#?保存到train_image列表
????train_image.append(img)

#?轉換為numpy數組
X?=?np.array(train_image)

#?輸出形狀
X.shape

                
              

輸出:(73844,224,224,3)

我們有73,844張形狀為(224,224,3)的圖片。接下來,我們將創建驗證集。

創建驗證集

要創建驗證集,我們需要確保每個類的分布在訓練集和驗證集中都相似。我們可以使用stratify參數來做到這一點:

                
                  #?分離數據集
y?=?train['class']

#?創建訓練與測試集
X_train,?X_test,?y_train,?y_test?=?train_test_split(X,?y,?random_state=42,?test_size=0.2,?stratify?=?y)

                
              

這里,stratify = y(每個幀的標簽)在訓練和驗證集中保持一個類似分布。

視頻可以被分為101類。因此,我們必須在目標中創建101個不同的列,每個列對應一個類別。我們將使用get_dummies()函數:

                
                  y_train?=?pd.get_dummies(y_train)
y_test?=?pd.get_dummies(y_test)

                
              

下一步,定義視頻分類模型的結構。

定義視頻分類模型的結構

由于我們沒有非常大的數據集,因此從頭開始創建模型可能效果不佳。因此,我們將使用預先訓練的模型并利用其學習來解決我們的問題。

對于這個特定的數據集,我們將使用VGG-16預訓練模型。讓我們創建預訓練模型的基本模型:

                
                  #?創建預訓練的VGG16基本模型
base_model?=?VGG16(weights='imagenet',?include_top=False)

                
              

該模型在具有1,000個類的數據集上進行訓練。我們將根據我們的要求對此模型進行微調。 include_top = False 將刪除此模型的最后一層,以便我們可以根據需要對其進行調整。

現在,我們將從這個預先訓練的模型中提取我們的訓練和驗證圖像的功能:

                
                  #?從訓練集的幀中提取特征
X_train?=?base_model.predict(X_train)
X_train.shape

                
              

輸出:(59075,7,7,512)

我們在訓練集中有59,075個圖像,并且由于我們已經通過VGG16架構傳遞了這些圖像,因此形狀已更改為(7,7,512)。同樣,我們將提取驗證集的特征:

                
                  #?從驗證集的幀中提取特征
X_test?=?base_model.predict(X_test)
X_test.shape

                
              

輸出:(14769,7,7,512)

驗證集中有14,769個圖像,這些圖像的形狀也變為(7,7,512)。我們現在將使用完全連接的網絡來微調模型。這個完全連接的網絡以單一維度輸入。因此,我們將圖像重塑為一個維度:

                
                  X_train?=?X_train.reshape(59075,?7*7*512)
X_test?=?X_test.reshape(14769,?7*7*512)

                
              

始終建議對像素值進行歸一化,即將像素值保持在0和1之間。這有助于模型更快地收斂。

                
                  #?標準化像素值
max?=?X_train.max()
X_train?=?X_train/max
X_test?=?X_test/max

                
              

接下來,我們將創建模型的體系結構。我們必須為此定義輸入形狀。那么,讓我們檢查一下圖像的形狀:

                
                  #?圖像形狀
X_train.shape

                
              

輸出:(59075,25088)

輸入形狀為25,088。我們現在定義結構:

                
                  #定義結構
model?=?Sequential()
model.add(Dense(1024,?activation='relu',?input_shape=(25088,)))
model.add(Dropout(0.5))
model.add(Dense(512,?activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(256,?activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(128,?activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(101,?activation='softmax'))

                
              

我們有多個完全連接的全連接層。我也添加了Dropout層控制模型不會過擬合。最后一層中的神經元數量等于我們擁有的類別數量,因此這里的神經元數量為101。

訓練視頻分類模型

我們現在將使用訓練框架訓練我們的模型,并使用驗證框架驗證模型。我們將保存模型的權重,以便我們不必一次又一次地重新訓練模型。

所以,讓我們定義一個函數來保存模型的權重:

                
                  #?保存權重函數
from?keras.callbacks?import?ModelCheckpoint
mcp_save?=?ModelCheckpoint('weight.hdf5',?save_best_only=True,?monitor='val_loss',?mode='min')

                
              

我們將根據驗證損失確定最佳模型。請注意,權重將保存為weights.hdf5。如果你愿意,可以重命名該文件。在訓練模型之前,我們必須編譯它:

                
                  #?編譯模型
model.compile(loss='categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])

                
              

我們使用 categorical_crossentropy 作為損失函數,優化器是Adam。讓我們訓練模型:

                
                  #?訓練模型
model.fit(X_train,?y_train,?epochs=200,?validation_data=(X_test,?y_test),?callbacks=[mcp_save],?batch_size=128)

                
              

我們現在有權重,我們將用它來預測新視頻。因此,在下一節中,我們將看到此模型在視頻分類任務中的表現如何!

評估視頻分類模型

讓我們打開一個新的Jupyter Notebook來評估模型。評估部分也可以分成多個步驟,以更清楚地理解過程:

  1. 定義模型結構并加載權重

  2. 創建測試數據

  3. 對測試視頻進行預測

  4. 最后,評估模型

定義模型結構并加載權重

導入所需的庫:

                
                  from?keras.models?import?Sequential
from?keras.layers?import?Dense,?Dropout,?Flatten
from?keras.layers?import?Conv2D,?MaxPooling2D
from?keras.preprocessing?import?image
import?numpy?as?np
import?pandas?as?pd
from?tqdm?import?tqdm
from?keras.applications.vgg16?import?VGG16
import?cv2
import?math
import?os
from?glob?import?glob
from?scipy?import?stats?as?s

                
              

接下來,我們將定義模型結構,它與我們在訓練模型時的模型結構類似:

                
                  base_model?=?VGG16(weights='imagenet',?include_top=False)

                
              

這是預先訓練好的模型,接下來我們將對其進行微調:

                
                  model?=?Sequential()
model.add(Dense(1024,?activation='relu',?input_shape=(25088,)))
model.add(Dropout(0.5))
model.add(Dense(512,?activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(256,?activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(128,?activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(101,?activation='softmax'))

                
              

現在,正如我們已經定義了架構,我們現在將加載訓練的權重,我們將其存儲為weights.hdf5:

                
                  #載入權重
model.load_weights("weights.hdf5")

                
              

編譯模型:

                
                  #?編譯模型
model.compile(loss='categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])

                
              

確保損失函數,優化程序和指標與我們在訓練模型時使用的相同。

創建測試數據

你應該根據UCF101數據集的官方文檔下載訓練/測試集文件。在下載的文件夾中,有一個名為" testlist01.txt " 的文件,其中包含測試視頻列表。我們將利用它來創建測試數據:

                
                  #?獲取測試列表
f?=?open("testlist01.txt",?"r")
temp?=?f.read()
videos?=?temp.split('\n')

#?創建dataframe
test?=?pd.DataFrame()
test['video_name']?=?videos
test?=?test[:-1]
test_videos?=?test['video_name']
test.head()

                
              

我們現在擁有存儲在數據框中的所有視頻的列表。要將預測類別與實際類別進行映射,我們將使用 train_new.csv 文件:

                
                  #?創建標簽
train?=?pd.read_csv('UCF/train_new.csv')
y?=?train['class']
y?=?pd.get_dummies(y)

                
              

現在,我們將對測試集中的視頻進行預測。

測試視頻的預測

讓我總結一下在查看代碼之前我們將在此步驟中執行的操作。以下步驟將幫助你了解預測部分:

  1. 首先,我們將創建兩個空列表,一個用于存儲預測標簽,另一個用于存儲實際標簽

  2. 然后,我們將從測試集中獲取每個視頻,提取該視頻的幀并將其存儲在一個文件夾中(在當前目錄中創建一個名為temp的文件夾來存儲幀)。我們將在每次迭代時從此文件夾中刪除所有其他文件

  3. 接下來,我們將讀取temp文件夾中的所有幀,使用預先訓練的模型提取這些幀的特征,進行預測得到標簽后將其附加到第一個列表中

  4. 我們將在第二個列表中為每個視頻添加實際標簽

讓我們編寫這些步驟并生成預測:

                
                  #?創建兩個列表來存儲預測的和實際的標簽
predict?=?[]
actual?=?[]

#?for循環從每個測試視頻中提取幀
for?i?in?tqdm(range(test_videos.shape[0])):
????count?=?0
????videoFile?=?test_videos[i]
????cap?=?cv2.VideoCapture('UCF/'+videoFile.split('?')[0].split('/')[1])???#?從給定路徑獲取視頻
????frameRate?=?cap.get(5)?#幀率
????x=1
????#?從臨時文件夾中刪除所有其他文件
????files?=?glob('temp/*')
????for?f?in?files:
????????os.remove(f)
????while(cap.isOpened()):
????????frameId?=?cap.get(1)?#當前幀編號
????????ret,?frame?=?cap.read()
????????if?(ret?!=?True):
????????????break
????????if?(frameId?%?math.floor(frameRate)?==?0):
????????????#?將此特定視頻的幀存儲在temp文件夾中
????????????filename?='temp/'?+?"_frame%d.jpg"?%?count;count+=1
????????????cv2.imwrite(filename,?frame)
????cap.release()

????#?從臨時文件夾中讀取所有幀
????images?=?glob("temp/*.jpg")

????prediction_images?=?[]
????for?i?in?range(len(images)):
????????img?=?image.load_img(images[i],?target_size=(224,224,3))
????????img?=?image.img_to_array(img)
????????img?=?img/255
????????prediction_images.append(img)

????#?將測試視頻的所有幀轉換為numpy數組
????prediction_images?=?np.array(prediction_images)
????#?extracting?features?using?pre-trained?model
????prediction_images?=?base_model.predict(prediction_images)
????#?使用預訓練模型提取特征
????prediction_images?=?prediction_images.reshape(prediction_images.shape[0],?7*7*512)
????#?轉換一維數組中的特征
????prediction?=?model.predict_classes(prediction_images)
????#?在預測列表中添加預測模式,將標簽分配給視頻
????predict.append(y.columns.values[s.mode(prediction)[0][0]])
????#?添加上視頻的真實標簽
????actual.append(videoFile.split('/')[1].split('_')[1])

                
              

此步驟需要一些時間,因為測試集中有大約3,800個視頻 。一旦我們得到預測的結果,我們將用來計算模型的性能。

評估模型

是時候評估我們的模型了。

我們有實際的標簽以及我們的模型預測的標簽。我們將利用這些來獲得準確度分數。在UCF101的官方文檔頁面上,當前準確率為43.90%。我們的模型可以擊敗它嗎?讓我們檢查!

                
                  from?sklearn.metrics?import?accuracy_score
accuracy_score(predict,?actual)*100

                
              

輸出:44.80570975416337

大!我們的模型的準確率為44.8%,與官方文件中的相似(43.9%)。

你可能想知道為什么我們對50%以下的準確度感到滿意。那么,這種低精度背后的原因主要是由于缺乏數據。我們只有大約13,000個視頻,甚至持續時間很短。

結束

在本文中,我們介紹了計算機視覺最有趣的應用之一,視頻分類。我們首先了解如何處理視頻,然后我們提取幀,訓練視頻分類模型,最后在測試視頻上獲得44.8%的準確度。

我們現在可以嘗試不同的方法,旨在提高模型的性能。我能想到的一些方法是使用可以直接處理視頻的3D卷積。

由于視頻是一系列幀,我們也可以將其解決為序列問題。所以,可以有更多的解決方案,我建議你可以探索它們。

你也許還想

●??

?? ? ?

??●?【ECCV 2018】谷歌AI超大規模圖像競賽,中國團隊獲目標檢測冠軍

歡迎掃碼關注:

640?wx_fmt=gif ? 點擊下方 ?|? ?|? 了解更多


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲精品久久久久久久久久ty | 99热这里只有精品在线播放 | 香蕉人人超人人超免费看视频 | 午夜一级免费视频 | 香蕉视频一区二区 | 亚洲国产精久久久久久久 | 曰本性l交视频 | 欧美亚洲桃花综合 | 雅虎日本免费一区二区三区 | 久久精品播放 | 亚洲啪啪看看 | 成人在激情在线视频 | 天天干天天草天天 | 99精品久久| 男女91视频 | 天天操天天射天天舔 | 欧美成人免费观看国产 | 91私拍 | 国产精自产拍久久久久久 | 日韩免费不卡 | 色婷婷精品免费视频 | 日韩黄色网址 | 国产精品99久久免费观看 | 伊人中文字幕 | 亚洲成a人在线播放www | 97影院理论在线观看 | 久久香蕉影视 | www香蕉视频| 奇米888四色在线精品 | 成人激情小视频 | 好吊妞视频一区二区 | 久久久久嫩草影院精品 | 欧美亚洲国产精品久久 | 午夜精品久久久久久久99热 | 日本精品在线 | 久久综合亚洲伊人色 | 波多野结衣中文丝袜字幕 | 久久天堂成人影院 | 五月婷婷伊人网 | 91视频国产高清 | 久久99久久99精品免观看动漫 |