前沿拓展:
avi解碼
預(yù)覽時候卡,是機器配置問題,你的機器配置相對于家用機來說,可以算的上相當(dāng)不錯的了,但是用于pe(premiere)來說,就不算高了,尤其是顯卡,視頻編輯用的顯卡,要更好,另外你還應(yīng)該有一塊卡,視頻編輯卡,便宜點的叫視頻壓縮卡,一般叫全長卡。你的顯卡也就是一般家用的好顯卡,所以卡。
視頻解之序衛(wèi)絕碼器,一般式視頻編輯卡里面帶的解碼器
PREMIERE必安插件
包括PREMIERE模版的一些常用插件,強烈建議使用模版之前先安裝它們。
1、JPG公司的AVI文件解碼器MJPEG VIDEO CODEC
2、PREMIERE
3.2.1 算法原理
C3D的算法來源于論文《Learning spatiotemporal features with 3d convolutional networks.》,關(guān)于算法介紹可以參見論文筆記——基于的視頻行為識別/動作識別算法筆記(三)。
3.2.2 算法網(wǎng)絡(luò)結(jié)構(gòu)
圖3 C3D網(wǎng)絡(luò)
3.2.3 編譯方法
C3D的caffe實現(xiàn)版本較舊(caffe git commit b80fc86),有一個fork出來的caffe版本較新,此外還有tensorflow的實現(xiàn)版本與keras的實現(xiàn)版本,本文將分析tensorflow的實現(xiàn)版本。
Git下載后文件內(nèi)容如下:
train_c3d_ucf101.py 以ucf101數(shù)據(jù)集作為訓(xùn)練集進(jìn)行訓(xùn)練
predict_c3d_ucf101.py以ucf101數(shù)據(jù)集作為測試集進(jìn)行預(yù)測
c3d_model.py c3d構(gòu)建的網(wǎng)絡(luò)模型
input_data.py 輸入數(shù)據(jù)預(yù)處理
list 文件夾內(nèi)train.list與test.list分別是待訓(xùn)練或預(yù)測的文件列表,腳本分別用來視頻解碼、列表生成,詳細(xì)內(nèi)容參加Readme.md。
直接運行 python train_c3d_ucf101.py或python predict_c3d_ucf101.py即可實現(xiàn)訓(xùn)練或預(yù)測。
tensorflow版本之所以能夠以較少的代碼實現(xiàn),是由于本身API包含了3d的卷積與池化,不用自己再單獨實現(xiàn)了。
tf.nn.conv3d(input, filter, strides, padding, name=None)
Computes a 3-D convolution given 5-D input and filter tensors. In signal processing, cross-correlation is a measure of similarity of two waveforms as a function of a time-lag applied to one of them. This is also known as a sliding dot product or sliding inner-product. Our Conv3D implements a form of cross-correlation.
tf.nn.avg_pool3d(input, ksize, strides, padding, name=None)
Performs 3D average pooling on the input.
tf.nn.max_pool3d(input, ksize, strides, padding, name=None)
Performs 3D max pooling on the input.
3.2.4 源碼分析
(1). 數(shù)據(jù)預(yù)處理
a. 數(shù)據(jù)載入
在get_frames_data函數(shù)中完成。通過讀取目錄filename下隨機且連續(xù)num_frames_per_clip個數(shù)的圖片(時域深度一般是16,即num_frames_per_clip=16),并轉(zhuǎn)換成np.array格式。例如v_ApplyEyeMakeup_g01_c01目錄下有描述該動作的連續(xù)165張圖片(1個avi視頻解碼成若干jpg圖片),隨機選擇編號從32到48(32+16)的圖片,其實這種方式有缺陷,應(yīng)該基于某種幀率進(jìn)行均勻采樣抽取更合理一些。
b. 數(shù)據(jù)劃分
在read_clip_and_label函數(shù)中完成。設(shè)置好index全局下的當(dāng)前序號,batch_index批量中的序號、batch_size批量大小和next_batch_start下一批次的起始序號這四者之間的關(guān)系即可。
for index in video_indices:
if(batch_index>=batch_size):
next_batch_start = index
break
c. 數(shù)據(jù)打亂
在read_clip_and_label函數(shù)中完成,video_indices為序號列表。
video_indices = range(len(lines))
random.seed(time.time())
random.shuffle(video_indices)
d. 并行計算設(shè)定
在run_training()函數(shù)中,根據(jù)gpu的數(shù)量確定與傳入batch_size的大小,來確定最終batch_size的大小,主要有如下幾處。
images_placeholder, labels_placeholder = placeholder_inputs(
FLAGS.batch_size * gpu_num
) #占位符
for gpu_index in range(0, gpu_num):
with tf.device(‘/gpu:%d’ % gpu_index):
…
logit = c3d_model.inference_c3d(
images_placeholder[gpu_index * FLAGS.batch_size:(gpu_index + 1) * FLAGS.batch_size,:,:,:,:],
0.5,
FLAGS.batch_size,
weights,
biases
)#并行數(shù)據(jù)樣本模型賦值
…
loss = tower_loss(
loss_name_scope,
logit,
labels_placeholder[gpu_index * FLAGS.batch_size:(gpu_index + 1) * FLAGS.batch_size]
)#并行數(shù)據(jù)標(biāo)簽?zāi)P唾x值
…
for step in xrange(FLAGS.max_steps):
…
train_images, train_labels, _, _, _ = input_data.read_clip_and_label(
filename=’list/train.list’,
batch_size=FLAGS.batch_size * gpu_num,
num_frames_per_clip=c3d_model.NUM_FRAMES_PER_CLIP,
crop_size=c3d_model.CROP_SIZE,
shuffle=True
) #訓(xùn)練集batch size設(shè)置
val_images, val_labels, _, _, _ = input_data.read_clip_and_label(
filename=’list/test.list’,
batch_size=FLAGS.batch_size * gpu_num,
num_frames_per_clip=c3d_model.NUM_FRAMES_PER_CLIP,
crop_size=c3d_model.CROP_SIZE,
shuffle=True
)#驗證集batch size設(shè)置
e. 數(shù)據(jù)中心化
均值已經(jīng)事先算好,并以numpy的壓縮格式存儲在crop_mean.py文件中。
read_clip_and_label函數(shù)中實現(xiàn):
np_mean = np.load(‘crop_mean.npy’).reshape([num_frames_per_clip, crop_size, crop_size, 3])
由于歸一化和白化對圖像數(shù)據(jù)來說不是必須的,故未進(jìn)行這兩項處理。
f. 視頻數(shù)據(jù)縮放、裁剪
從np.array數(shù)據(jù)格式還原回image格式,進(jìn)行縮放和裁剪。
img = Image.fromarray(tmp_data[j].astype(np.uint8))
if(img.width>img.height):
scale = float(crop_size)/float(img.height)
img = np.array(cv2.resize(np.array(img),(int(img.width * scale + 1), crop_size))).astype(np.float32)
else:
scale = float(crop_size)/float(img.width)
img = np.array(cv2.resize(np.array(img),(crop_size, int(img.height * scale + 1)))).astype(np.float32)
crop_x = int((img.shape[0] – crop_size)/2)
crop_y = int((img.shape[1] – crop_size)/2)
img = img[crop_x:crop_x+crop_size, crop_y:crop_y+crop_size,:] – np_mean[j]
img_datas.append(img)
(2). 網(wǎng)絡(luò)構(gòu)建
a. 網(wǎng)絡(luò)設(shè)計
with tf.variable_scope(‘var_name’) as var_scope:
weights = {
‘wc1’: _variable_with_weight_decay(‘wc1’, [3, 3, 3, 3, 64], 0.0005),
‘wc2’: _variable_with_weight_decay(‘wc2’, [3, 3, 3, 64, 128], 0.0005),
‘wc3a’: _variable_with_weight_decay(‘wc3a’, [3, 3, 3, 128, 256], 0.0005),
‘wc3b’: _variable_with_weight_decay(‘wc3b’, [3, 3, 3, 256, 256], 0.0005),
‘wc4a’: _variable_with_weight_decay(‘wc4a’, [3, 3, 3, 256, 512], 0.0005),
‘wc4b’: _variable_with_weight_decay(‘wc4b’, [3, 3, 3, 512, 512], 0.0005),
‘wc5a’: _variable_with_weight_decay(‘wc5a’, [3, 3, 3, 512, 512], 0.0005),
‘wc5b’: _variable_with_weight_decay(‘wc5b’, [3, 3, 3, 512, 512], 0.0005),
‘wd1’: _variable_with_weight_decay(‘wd1’, [8192, 4096], 0.0005),
‘wd2’: _variable_with_weight_decay(‘wd2’, [4096, 4096], 0.0005),
‘out’: _variable_with_weight_decay(‘wout’, [4096, c3d_model.NUM_CLASSES], 0.0005)
}
biases = {
‘bc1’: _variable_with_weight_decay(‘bc1’, [64], 0.000),
‘bc2’: _variable_with_weight_decay(‘bc2’, [128], 0.000),
‘bc3a’: _variable_with_weight_decay(‘bc3a’, [256], 0.000),
‘bc3b’: _variable_with_weight_decay(‘bc3b’, [256], 0.000),
‘bc4a’: _variable_with_weight_decay(‘bc4a’, [512], 0.000),
‘bc4b’: _variable_with_weight_decay(‘bc4b’, [512], 0.000),
‘bc5a’: _variable_with_weight_decay(‘bc5a’, [512], 0.000),
‘bc5b’: _variable_with_weight_decay(‘bc5b’, [512], 0.000),
‘bd1’: _variable_with_weight_decay(‘bd1’, [4096], 0.000),
‘bd2’: _variable_with_weight_decay(‘bd2’, [4096], 0.000),
‘out’: _variable_with_weight_decay(’bout’, [c3d_model.NUM_CLASSES], 0.000),
}
b. 網(wǎng)絡(luò)初始化
采用了xavier_initializer的方式進(jìn)行初始化,并使用l2懲罰進(jìn)行正則化
def _variable_with_weight_decay(name, shape, wd):
var = _variable_on_cpu(name, shape, tf.contrib.layers.xavier_initializer())
if wd is not None:
weight_decay = tf.nn.l2_loss(var)*wd
tf.add_to_collection(‘weightdecay_losses’, weight_decay)
return var
c. 模型載入
模型用的是sports1M
use_pretrained_model = True
model_filename = “./sports1m_finetuning_ucf101.model”
(3). 分類函數(shù)與loss定義
分類函數(shù)是Softmax,loss是交叉熵函數(shù)。
def tower_loss(name_scope, logit, labels):
cross_entropy_mean = tf.reduce_mean(
tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels,logits=logit)
)
tf.summary.scalar(
name_scope + ‘_cross_entropy’,
cross_entropy_mean
)
weight_decay_loss = tf.get_collection(‘weightdecay_losses’)
tf.summary.scalar(name_scope + ‘_weight_decay_loss’, tf.reduce_mean(weight_decay_loss) )
# Calculate the total loss for the current tower.
total_loss = cross_entropy_mean + weight_decay_loss
tf.summary.scalar(name_scope + ‘_total_loss’, tf.reduce_mean(total_loss) )
return total_loss
(4). 優(yōu)化器定義
采用了Adam,并設(shè)置了粗調(diào)和微調(diào)兩種學(xué)習(xí)率
opt_stable = tf.train.AdamOptimizer(1e-4)
opt_finetuning = tf.train.AdamOptimizer(1e-3)
(5). 訓(xùn)練與驗證過程
訓(xùn)練過程的每個Step都會記錄時間消耗。
for step in xrange(FLAGS.max_steps):
start_time = time.time()
train_images, train_labels, _, _, _ = input_data.read_clip_and_label(
filename=’list/train.list’,
batch_size=FLAGS.batch_size * gpu_num,
num_frames_per_clip=c3d_model.NUM_FRAMES_PER_CLIP,
crop_size=c3d_model.CROP_SIZE,
shuffle=True
)
sess.run(train_op, feed_dict={
images_placeholder: train_images,
labels_placeholder: train_labels
})
duration = time.time() – start_time
print(‘Step %d: %.3f sec’ % (step, duration))
每10次對訓(xùn)練準(zhǔn)確率進(jìn)行報告,并開啟驗證過程,并將驗證準(zhǔn)確率進(jìn)行報告。
if (step) % 10 == 0 or (step + 1) == FLAGS.max_steps:
saver.save(sess, os.path.join(model_save_dir, ‘c3d_ucf_model’), global_step=step)
print(‘Training Data Eval:’)
summary, acc = sess.run(
[merged, accuracy],
feed_dict={images_placeholder: train_images,
labels_placeholder: train_labels
})
print (“accuracy: ” + “{:.5f}”.format(acc))
train_writer.add_summary(summary, step)
print(‘Validation Data Eval:’)
val_images, val_labels, _, _, _ = input_data.read_clip_and_label(
filename=’list/test.list’,
batch_size=FLAGS.batch_size * gpu_num,
num_frames_per_clip=c3d_model.NUM_FRAMES_PER_CLIP,
crop_size=c3d_model.CROP_SIZE,
shuffle=True
)
summary, acc = sess.run(
[merged, accuracy],
feed_dict={
images_placeholder: val_images,
labels_placeholder: val_labels
})
print (“accuracy: ” + “{:.5f}”.format(acc))
test_writer.add_summary(summary, step)
(6). 測試過程
測試過程在predict_c3d_ucf101.py中,進(jìn)行最終的評分計算。
for step in xrange(all_steps):
# Fill a feed dictionary with the actual set of images and labels
# for this particular training step.
start_time = time.time()
test_images, test_labels, next_start_pos, _, valid_len =
input_data.read_clip_and_label(
test_list_file,
FLAGS.batch_size * gpu_num,
start_pos=next_start_pos
)
predict_score = norm_score.eval(
session=sess,
feed_dict={images_placeholder: test_images}
)
3.2.5 結(jié)果
(1). t-SNE特征抽取可視化
C3D論文中曾經(jīng)將訓(xùn)練好的模型在分類前的數(shù)據(jù)用t-SNE算法進(jìn)行聚集程度表示,該算法來源于論文《Visualizing data using t-SNE》。
圖4 t-SNE數(shù)據(jù)聚集度呈現(xiàn)
圖5 C3D論文中UCF101數(shù)據(jù)集特征呈現(xiàn)
數(shù)據(jù)可視化內(nèi)涵就是將高維數(shù)據(jù)在低維空間進(jìn)行合理呈現(xiàn),由于人眼最高只能看到3維,這里的低維特指二維和三維。數(shù)據(jù)降維的方法有很多,如下圖所示,而SNE使用的降維方法就是流行學(xué)習(xí)(Manifold Learning),從高維采集數(shù)據(jù)中恢復(fù)低維的流形結(jié)構(gòu),從而將高維空間中數(shù)據(jù)聚集程度映射到低維流形空間中。關(guān)于流行學(xué)習(xí)和t-SNE算法本身可參考如下三篇文章:1,2,3
圖6 數(shù)據(jù)降維算法分類
在實現(xiàn)上使用了scikit learn機器學(xué)習(xí)庫的t-SNE算法實現(xiàn),其中t-SNE算法輸入是將訓(xùn)練好的C3D網(wǎng)絡(luò)當(dāng)成特征提取子(feature extractor)的輸出,即模型的fc7的輸出(101維),t-SNE算法輸出是根據(jù)不同label標(biāo)記不同顏色的二維數(shù)據(jù)分布。本文是通過預(yù)測過程中,將fc7輸出和label存成csv文件,再將csv文件數(shù)據(jù)進(jìn)行可視化呈現(xiàn)。predict載入的模型是c3d_ucf101_finetune_whole_iter_20000_TF.model,注意由于ucf101和sports1M第一個全連接層(fc6)上有所差異,需要將pool5的重排列屏蔽掉(c3d_model.py中tf.transpose(pool5)行)。
tsne.py代碼實現(xiàn)如下:
import tensorflow as tf
import numpy as np
from sklearn.manifold import TSNE
import csv
import matplotlib.pyplot as plt
colors = [“#476A2A”, “#7851B8”, “#BD3430”, “#4A2D4E”, “#875525”,
“#A83683”, “#4E655E”, “#853541”, “#3A3120”, “#535D8E”]
tsne = TSNE(random_state=42)
data_file=open(“data_file_part.csv”,’r’)
label_file=open(“label_file_part.csv”,’r’)
csv_reader_1=csv.reader(data_file,dialect=’excel’)
csv_reader_2=csv.reader(label_file,dialect=’excel’)
data = []
label = []
for row_1 in csv_reader_1:
data.append(row_1)
for row_2 in csv_reader_2:
label.append(row_2)
data = np.array(data)
label = np.array(label)
print (data.shape)
print (label.shape)
data_tsne=tsne.fit_transform(data)
plt.figure(figsize=(10,10))
plt.xlim(data_tsne[:,0].min(),data_tsne[:,0].max()+1)
plt.ylim(data_tsne[:,1].min(),data_tsne[:,1].max()+1)
for i in range(len(data)):
plt.text(data_tsne[i,0], data_tsne[i,1],str(int(label[i])),color=colors[int(label[i])%10],fontdict={‘weight’:’bold’,’size’:9})
plt.xlabel(“t-sne feature 0”)
plt.ylabel(“t-sne feature 1”)
plt.show()
predict_c3d_ucf101.py代碼修改如下:
def run_test():
data_file=open(“data_file.csv”,’wb’)
label_file=open(“label_file.csv”,’wb’)
csv_write_1=csv.writer(data_file,dialect=’excel’)
csv_write_2=csv.writer(label_file,dialect=’excel’)
model_name = “c3d_ucf101_finetune_whole_iter_20000_TF.model”
… …
predict_score = norm_score.eval(
session=sess,
feed_dict={images_placeholder: test_images}
)
feature=sess.run(logits,feed_dict={images_placeholder: test_images})
test_labels_T = test_labels.reshape(test_labels.shape[0],1)
for i in range(0,len(feature)):
csv_write_1.writerow(feature[i])
csv_write_2.writerow(test_labels_T[i])
… …
前5個分類的結(jié)果(label 0:AppleEyeMakeUp 1:ApplyLipStick 2:Archery 3:BabyCrawling 4:BalanceBeam)如下圖,可見label 0和label 1還不太能分開(畫眼線和涂口紅動作太相似了),其他類別動作都已經(jīng)良好的分開。
圖7 UCF101前5個分類t-SNE聚集度呈現(xiàn)
前50個分類的結(jié)果如下圖
圖8 UCF101前50個分類t-SNE聚集度呈現(xiàn)
由上圖可見,C3D特征提取后總體上數(shù)據(jù)離散度較明顯,通過良好的分類算法(如神經(jīng)網(wǎng)絡(luò)本身的交叉熵softmax,或SVM)實現(xiàn)分類。
(2). 特征圖可視化
C3D論文中對一些視頻的幾幀圖像進(jìn)行了特征圖可視化,特征圖可視化來源于論文《Visualizing and Understanding Convolutional Networks》。
圖9 C3D論文中對特征圖進(jìn)行可視化
特征圖可視化的目標(biāo)是搞清楚CNN的每一層到底學(xué)到了什么特征,即通過調(diào)參得到精度性能提升后所對應(yīng)的特征圖是什么樣的?具體來說,只有通過特征圖才能了解CNN的工作機理,才能進(jìn)一步指導(dǎo)調(diào)參來提升性能,此外一幅圖像不同部分對于分類準(zhǔn)確率有何影響,CNN每一層泛化能力是否相同也是需要通過特征圖來尋找**。具體方法就是將網(wǎng)絡(luò)各層的輸出特征圖作為輸入進(jìn)行反卷積過程(反卷積、反激活、反池化)得回原始圖片的重建。比如模型B=f(A),A為圖像二維數(shù)組,f為CNN中的第一層,B為輸出特征圖,由A可計算出B,但可以將B這個二維數(shù)組保留一個位置的數(shù)B(i,j),其他位置都清0,再經(jīng)過反卷積計算出A’,則B(i,j)由A’來激活,A’反映了A中各像素對B(i,j)的貢獻(xiàn)。圖10中左側(cè)即是得到A’,右側(cè)是傳統(tǒng)CNN做了兩處改進(jìn):
1). maxpooling需要記錄最大值在矩陣中的位置,Unpooling的時候再將數(shù)值放回該位置,其他位置置為0;
2). 因為能夠得到卷積核的權(quán)值,故反卷積變換一下直接使用即可,不需要進(jìn)行訓(xùn)練。
圖10 特征圖對原始圖像進(jìn)行重建過程
關(guān)于反卷積,更準(zhǔn)確的說法是轉(zhuǎn)置卷積,下面列舉了幾種正向卷積和其對應(yīng)的轉(zhuǎn)置卷積的示意圖(圖片來源《A guide to convolution arithmetic for deep learning》)。
圖11 轉(zhuǎn)置卷積(transpose of convolving)與卷積對應(yīng)關(guān)系(一)
圖12 轉(zhuǎn)置卷積(transpose of convolving)與卷積對應(yīng)關(guān)系(二)
特征圖可視化通用結(jié)論有三點:
1). 從空間層次上看,layer1、layer2學(xué)習(xí)到的是顏色、邊緣特征,layer3學(xué)習(xí)的是紋理特征,layer4學(xué)習(xí)到具體區(qū)別性特征,layer5學(xué)習(xí)到具有辨別性的關(guān)鍵特征;
2). 從時間步驟上看,同一層epochs次數(shù)不同迭代變化不同,網(wǎng)絡(luò)中低層的特征圖更容易收斂,高層的特征圖不同回合變化較大;
3). 圖像發(fā)生縮放、裁剪、平移等**作后,僅對網(wǎng)絡(luò)的第一層影響較大,這也是我們對圖片、視頻進(jìn)行數(shù)據(jù)擴張預(yù)處理的理論依據(jù)
文章轉(zhuǎn)自:https://zhuanlan.zhihu.com/p/45574276
拓展知識:
原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請注明出處:http:///57784.html