https://amirabbas.me
تنسورفلو ۱۳: دسته بندی ویدئو
سلام
بعد از چند ماه یه آموزش جدید به سری تنسورفلو اضافه می کنم :-)
در این آموزش می خواهیم ویدئو های دیتاست IXMAS Actions رو دسته بندی کنیم.
این دیتاست یکی از دیتاست های مورد استفاده در زمینه HAR یا تشخیص فعالیت های انسانی هست
در این دیتاست تعدادی ویدئو از چند فرد با چند دوربین در جهت های مختلف ضبط شده که افراد ۱۱ تا فعالیت مختلف رو انجام می دن.
قدم اول
دیتاست رو از اینجا دانلود کنید و محیط توسعه رو فراهم کنید :)
قدم دوم
در این قدم قصد داریم ویدئو رو به یک سری فریم تبدیل کنیم برای اینکار از openCV استفاده می کنیم
برای نصب openCV از خط زیر استفاده کنید:
pip install opencv-python
یک فایل پایتون به اسم vid-img-convertor.py بسازید و تکه کد زیر رو داخلش قرار بدید این کد کمک میکنه تا چند فریم از هر کدوم از clip ها استخراج کنیم:
import cv2
from os import listdir
folder_name = "nixmas"
def getFrame(sec, vid_name):
vidcap.set(cv2.CAP_PROP_POS_MSEC, sec*1000)
hasFrames, image = vidcap.read()
if hasFrames:
# save frame as JPG file
cv2.imwrite(folder_name+"-img/"+vid_name+"_"+str(count)+".jpg", image)
return hasFrames
for item in listdir(folder_name):
print(item)
if item.endswith('.avi'):
vidcap = cv2.VideoCapture(folder_name+'/' + item)
vid_name = item.replace('.avi', '')
sec = 0
frameRate = 0.5 # //it will capture image in each 0.5 second
count = 1
success = getFrame(sec, vid_name)
while success:
count = count + 1
sec = sec + frameRate
sec = round(sec, 2)
success = getFrame(sec, vid_name)
vidcap.release()
قدم سوم
از الان میتونیم شروع کنیم که با تنسورفلو کار کنیم. ابتدا کتابخانه های لازم رو وارد می کنیم
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.models import Model
from sklearn.preprocessing import LabelEncoder
import matplotlib.pyplot as plt
from PIL import Image
import os
import numpy as np
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
یک تابع تعریف می کنیم که تغییرات loss function رو چاپ کنیم
def plot_loss(history, label, n):
# Use a log scale to show the wide range of values.
plt.semilogy(history.epoch, history.history['loss'], color=colors[n], label='Train '+label)
plt.semilogy(history.epoch, history.history['val_loss'], color=colors[n], label='Val '+label,
linestyle="--")
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
بعد دیتا ها رو load می کنیم
data_x = []
data_y = []
for path in os.listdir('./nixmas-img'):
img = Image.open('nixmas-img/'+path)
data_x.append(np.array(img))
data_y.append(path.split('_')[3])
print({i:data_y.count(i) for i in data_y})
le = LabelEncoder()
a = le.fit_transform(data_y)
b = np.zeros((a.size, a.max()+1))
b[np.arange(a.size),a] = 1
data_y = a
فرمت دیتا ها رو اطلاح می کنیم و همچنین دیتا ها رو تقسیم بر 255 می کنیم چون هر پیکسل مقداری بین 0 تا 255 داره و می خواهیم مقادیر بین 0 تا 1 قرار بگیره
data_x = np.array(data_x)
data_x = data_x.astype(np.float32)
data_x /= 255.0
دیتا ها رو به فرمت دیتاست تنسورفلو تبدیل می کنیم
dataset = tf.data.Dataset.from_tensor_slices((data_x, data_y))
dataset = dataset.cache().shuffle(10000)
دیتاستمون رو به چند قسمت برای test, validate و train تقسیم میکنیم
test_dataset = dataset.take(30).batch(10)
val_dataset = dataset.skip(30).take(100).batch(10)
train_dataset = dataset.skip(130).batch(100)
حالا که دیتا آماده است سعی می کنیم مدل رو بسازیم. برای این تسک از الگوریتم CNN استفاده میکنیم توی این پست در مورد CNN صحبت کردم
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(64, 48, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(11))
الان دیگه میتونیم مدل رو compile کنیم و نتیجه ساختار مدل رو مشاهده کنیم
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 62, 46, 32) 896
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 31, 23, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 29, 21, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 10, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 12, 8, 64) 36928
_________________________________________________________________
flatten (Flatten) (None, 6144) 0
_________________________________________________________________
dense (Dense) (None, 64) 393280
_________________________________________________________________
dense_1 (Dense) (None, 11) 715
=================================================================
Total params: 450,315
Trainable params: 450,315
Non-trainable params: 0
خب بالاخره میتونیم مدل رو train کنیم
history = model.fit(train_dataset, validation_data=val_dataset, epochs=60)
بیایید نمودار بکشیم :-)
plot_loss(history, "history", 1)
ببینید نمودار نزولی هست و همزمان loss دیتاست validate و train در حال کاهش هست. نکته مهم اینه که نمودار val تقریبا همزمان با train در حال کاهش هست و معنی این رو میده که مدل overfit نشده اما نوسانات آخر میتونه معنی بده شاید چون دیتا کمه. شاید اگه از الگوریتم دیگه مثل RNN استفاده کنیم چونکه ورودی ما ویدئو هست نتیجه بهتر هم بشه
در آخر هم بر روی دیتاست تست خروجی رو تست می کنیم
model.evaluate(test_dataset)
خروجی که من از این مدل گرفتم به صورت زیر است:
train_loss: 0.0541 - train_accuracy: 0.9819
val_loss: 0.0097 - val_accuracy: 1.0000
test_loss: 0.0829 - test_accuracy: 0.9667
مطلبی دیگر از این انتشارات
بررسی الگوریتم های PageRank و HITS برای استخراج صفحات وب
مطلبی دیگر از این انتشارات
آمار vs. احتمال
مطلبی دیگر از این انتشارات
هوش مصنوعی در مخابرات