この記事は、Huawei Cloud コミュニティ「CNN-VIT ビデオ動的ジェスチャ認識 [Huawei Cloud で遊ぶ]」、著者: HouYanSong から共有されたものです。
CNN-VIT ビデオ動的ジェスチャ認識
人工知能の発展は日々変化しており、人間とコンピューターのインタラクション分野の発展にも大きな影響を与えています。ジェスチャーは、自然かつ迅速なインタラクション方法として、インテリジェント運転や仮想現実などの分野で広く使用されています。ジェスチャ認識のタスクは、オペレータが特定のジェスチャを行うと、コンピュータがそのジェスチャの種類を迅速かつ正確に判断できるようにすることです。この記事では、ModelArtsを使用してビデオ動的ジェスチャ認識アルゴリズム モデルを開発およびトレーニングし、上スワイプ、下スワイプ、左スワイプ、右スワイプ、開く、閉じるなどの動的なジェスチャ カテゴリを検出して、空気と同様の機能を実現します。ファーウェイ携帯電話のジェスチャー。
アルゴリズムの紹介
CNN-VIT ビデオ動的ジェスチャ認識アルゴリズムは、まず事前トレーニング済みネットワーク InceptionResNetV2 を使用してビデオ アクション クリップの特徴をフレームごとに抽出し、次に分類のために Transformer Encoder を入力します。動的ジェスチャ認識サンプル データ セットを使用してアルゴリズムをテストします。このデータ セットには、無効なジェスチャ、上にスワイプ、下にスライド、左スワイプ、右スワイプ、開く、閉じる、など 7 つのジェスチャのビデオが含まれています。具体的な操作プロセスは次のとおりです。
まず、キャプチャしたビデオ ファイルをデコードしてキー フレームを抽出し、4 フレームごとに保存してから、画像の中央トリミングと前処理を実行します。コードは次のとおりです。
def ロード_ビデオ(ファイル名): cap = cv2.VideoCapture(ファイル名) # 数フレームごとに抽出 フレーム間隔 = 4 フレーム = [] カウント = 0 True の場合: 右、フレーム = cap.read() ret でない場合: 壊す # Frame_interval フレームごとに保存 カウント % フレーム間隔 == 0 の場合: #センタークロップ フレーム = Crop_center_square(フレーム) # ズーム フレーム = cv2.resize(フレーム, (IMG_SIZE, IMG_SIZE)) # BGR -> RGB [0,1,2] -> [2,1,0] フレーム = フレーム[:, :, [2, 1, 0]] フレーム.追加(フレーム) カウント += 1 np.array(フレーム)を返す
次に、画像特徴抽出器を作成し、事前トレーニングされたモデル InceptionResNetV2 を使用して画像特徴を抽出します。コードは次のとおりです。
def get_feature_extractor(): feature_extractor = keras.applications.inception_resnet_v2.InceptionResNetV2( 重み = 'imagenet'、 include_top = False、 プーリング = '平均'、 input_shape = (IMG_SIZE, IMG_SIZE, 3) ) preprocess_input = keras.applications.inception_resnet_v2.preprocess_input 入力 = keras.Input((IMG_SIZE, IMG_SIZE, 3)) 前処理 = preprocess_input(入力) 出力 = feature_extractor(前処理済み) モデル = keras.Model(入力、出力、名前 = 'feature_extractor') リターンモデル
次に、ビデオの特徴ベクトルを抽出します。ビデオのフレーム数が 40 未満の場合は、パディング用にすべて 0 の配列を作成します。
defload_data(ビデオ、ラベル): ビデオの特徴 = [] tqdm のビデオ (ビデオ): フレーム =load_video(ビデオ) カウント = len(フレーム) # フレーム数が MAX_SEQUENCE_LENGTH 未満の場合 カウント < MAX_SEQUENCE_LENGTH の場合: #フィラー diff = MAX_SEQUENCE_LENGTH - カウント #すべて 0 の numpy 配列を作成する パディング = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3)) # 配列の連結 フレーム = np.concatenate((フレーム, パディング)) # 前の MAX_SEQUENCE_LENGTH フレームを取得する フレーム = フレーム[:MAX_SEQUENCE_LENGTH, :] # 特徴量をバッチで抽出する video_feature = feature_extractor.predict(フレーム) video_features.append(video_feature) np.array(video_features)、np.array(ラベル)を返す
最後に、次のコードを使用して VIT モデルを作成します。
#位置エンコーディング クラス PositionalEmbedding(layers.Layer): def __init__(self、seq_length、output_dim): super().__init__() #0~MAX_SEQUENCE_LENGTH のリストを作成します self.positions = tf.range(0,limit=MAX_SEQUENCE_LENGTH) self.positional_embedding =layers.Embedding(input_dim=seq_length、output_dim=output_dim) def call(self,x): #位置エンコーディング Positions_embedding = self.positional_embedding(self.positions) # 入力を追加する 戻り値 x + 位置埋め込み # エンコーダ クラス TransformerEncoder(layers.Layer): def __init__(self, num_heads, embed_dim): super().__init__() self.p_embedding = PositionalEmbedding(MAX_SEQUENCE_LENGTH, NUM_FEATURES) self.attention =layers.MultiHeadtention(num_heads=num_heads、key_dim=embed_dim、dropout=0.1) self.layernorm = レイヤー.LayerNormalization() def call(self,x): # 位置埋め込み 位置埋め込み = self.p_embedding(x) #自分自身への注意 アテンションアウト = self.attention( クエリ = 位置埋め込み、 値 = 位置埋め込み、 キー = 位置埋め込み、 アテンションマスク = なし ) # 残留接続のある層ノルム 出力 = self.layernorm(位置埋め込み + アテンションアウト) 出力を返す def video_cls_model(class_vocab): #カテゴリの数 クラス番号 = len(クラス語彙) # モデルを定義する モデル =keras.Sequential([ layers.InputLayer(input_shape=(MAX_SEQUENCE_LENGTH, NUM_FEATURES)), TransformerEncoder(2, NUM_FEATURES)、 レイヤー.GlobalMaxPooling1D()、 レイヤー.ドロップアウト(0.1)、 layers.Dense(classes_num, activity="softmax") ]) # モデルをコンパイルする model.compile(optimizer = keras.optimizers.Adam(1e-5), loss = keras.losses.SparseCategoricalCrossentropy(from_logits=False), メトリクス = ['精度'] ) リターンモデル
モデルのトレーニング
完全なエクスペリエンスを得るには、[ModelArts で実行] をクリックして、ワンクリックで公開したノートブックを実行できます。
データ セット全体に対するモデルの最終精度は 87% に達しました。これは、小規模なデータ セットでのトレーニングが比較的良好な結果を達成したことを意味します。
ビデオ推論
まず、VIT モデルをロードし、ビデオ カテゴリのインデックス タグを取得します。
ランダムにインポート #モデルのロード モデル = tf.keras.models.load_model('saved_model') # カテゴリタグ label_to_name = {0:'無効なジェスチャ'、1:'上にスワイプ'、2:'下にスライド'、3:'左にスライド'、4:'右にスライド'、5:'開く'、6:'閉じる'、 7 :「ズームイン」、8:「ズームアウト」}
次に、画像特徴抽出ツール InceptionResNetV2 を使用してビデオ特徴を抽出します。
# ビデオ機能を取得する def getVideoFeat(フレーム): フレーム数 = len(フレーム) # フレーム数が MAX_SEQUENCE_LENGTH 未満の場合 フレーム数 < MAX_SEQUENCE_LENGTH の場合: #フィラー diff = MAX_SEQUENCE_LENGTH - フレーム数 #すべて 0 の numpy 配列を作成する パディング = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3)) # 配列の連結 フレーム = np.concatenate((フレーム, パディング)) # 前の MAX_SEQ_LENGTH フレームを取得する フレーム = フレーム[:MAX_SEQUENCE_LENGTH,:] # ビデオ特徴を計算 N、1536 video_feat = feature_extractor.predict(フレーム) ビデオを返す_feat
最後に、ビデオ シーケンスの特徴ベクトルが予測のために Transformer Encoder に入力されます。
#ビデオ予測 def testVideo(): test_file = ランダム.サンプル(ビデオ, 1)[0] ラベル = test_file.split('_')[-2] print('ファイル名: {}'.format(test_file) ) print('実際のカテゴリ:{}'.format(label_to_name.get(int(label))) ) # ビデオの各フレームを読み取ります フレーム = ロード_ビデオ(テスト_ファイル) #表示する前のフレーム MAX_SEQUENCE_LENGTH を選択します フレーム = フレーム[:MAX_SEQUENCE_LENGTH].astype(np.uint8) # GIFとして保存 imageio.mimsave('animation.gif', フレーム, 継続時間=10) # 機能を取得する feat = getVideoFeat(フレーム) # モデル推論 prob = model.predict(tf.expand_dims(feat, axis=0))[0] print('予測されたカテゴリ: ') np.argsort(prob)[::-1][:5] の i の場合: print('{}: {}%'.format(label_to_name[i],round(prob[i]*100, 2))) return display(Image(open('animation.gif', 'rb').read()))
モデルの予測結果:
ファイル名:hand_gesture/women_014_0_7.mp4 実クラス: 無効なジェスチャ 予測カテゴリー: 無効なジェスチャー: 99.82% 下落: 0.12% 終値: 0.04% 左にスワイプ: 0.01% オープン: 0.01%
私はオープンソースの産業用ソフトウェアを諦めることにしました - OGG 1.0 がリリースされ、Huawei がすべてのソース コードを提供しました。Google Python Foundation チームは「コード クソ マウンテン」によって解雇されました 。 Fedora Linux 40が正式リリース。有名ゲーム会社がリリース 新規定:従業員の結婚祝儀は10万元を超えてはならない。チャイナユニコム、世界初のオープンソースモデルLlama3 8B中国語版をリリース。Pinduoduoに賠償判決国内のクラウド入力方式に500万元の罰金- クラウドデータアップロードのセキュリティ問題がないのはファーウェイだけ