이 기사는 Huawei 클라우드 커뮤니티 " CNN-VIT 비디오 동적 제스처 인식 [Huawei 클라우드로 재생] "에서 공유되었습니다. 저자: HouYanSong.
CNN-VIT 비디오 동적 제스처 인식
인공지능의 발전은 날이 갈수록 변화하고 있으며, 인간과 컴퓨터의 상호작용 분야의 발전에도 지대한 영향을 미치고 있습니다. 자연스럽고 빠른 상호작용 방식인 제스처는 지능형 운전, 가상현실 등의 분야에서 널리 활용되고 있다. 제스처 인식의 임무는 작업자가 특정 제스처를 취하면 컴퓨터가 제스처 유형을 빠르고 정확하게 판단할 수 있다는 것입니다. 이 기사에서는 ModelArts를 사용 하여 위로 스와이프, 아래로 스와이프, 왼쪽 스와이프, 오른쪽 스와이프, 열기, 닫기 등과 같은 동적 제스처 범주를 감지하여 공중과 유사한 기능을 달성하는 비디오 동적 제스처 인식 알고리즘 모델을 개발하고 훈련합니다. 화웨이 휴대폰의 제스처.
알고리즘 소개
CNN-VIT 비디오 동적 제스처 인식 알고리즘은 먼저 사전 훈련된 네트워크 InceptionResNetV2를 사용하여 비디오 액션 클립 특징을 프레임별로 추출한 다음 분류를 위해 Transformer Encoder를 입력합니다. 우리는 동적 제스처 인식 샘플 데이터 세트를 사용 하여 총 108개의 비디오가 포함된 알고리즘을 테스트합니다. 데이터 세트에는 잘못된 제스처, 위로 스와이프, 아래로 슬라이드, 왼쪽 스와이프, 오른쪽 스와이프, 열기, 닫기, 등. 구체적인 작업 프로세스는 다음과 같습니다.
먼저 캡처된 비디오 파일을 디코딩하여 키 프레임을 추출하고 4프레임마다 저장한 후 이미지의 중앙 자르기 및 전처리를 수행합니다.
def 로드_비디오(파일_이름): cap = cv2.VideoCapture(파일_이름) # 몇 프레임마다 추출 프레임_간격 = 4 프레임 = [] 개수 = 0 True인 동안: 오른쪽, 프레임 = cap.read() 리트윗하지 않으면: 부서지다 # 모든 Frame_interval 프레임을 저장합니다. 개수 %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( 가중치 = '이미지넷', include_top = 거짓, 풀링 = '평균', 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으로 구성된 배열을 만듭니다.
def load_data(동영상, 라벨): video_features = [] tqdm(videos)의 비디오: 프레임 = 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(labels) 반환
마지막으로 다음 코드를 사용하여 VIT 모델을 생성합니다.
#위치 인코딩 클래스 PositionalEmbedding(layers.Layer): def __init__(self, seq_length, 출력_dim): 슈퍼().__init__() #0~MAX_SEQUENCE_LENGTH의 목록을 구성합니다. self.positions = tf.range(0, 제한=MAX_SEQUENCE_LENGTH) self.positional_embedding = 레이어.임베딩(input_dim=seq_length, output_dim=output_dim) def 호출(자체,x): #위치 인코딩 position_embedding = self.positional_embedding(self.positions) # 입력 추가 x + position_embedding 반환 # 인코더 클래스 TransformerEncoder(layers.Layer): def __init__(self, num_heads, embed_dim): 슈퍼().__init__() self.p_embedding = 위치 삽입(MAX_SEQUENCE_LENGTH, NUM_FEATURES) self.attention = 레이어.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, dropout=0.1) self.layernorm = 레이어.LayerNormalization() def 호출(자체,x): # 위치 임베딩 positional_embedding = self.p_embedding(x) # 자기 관심 attention_out = self.attention( 쿼리 = positional_embedding, 값 = positional_embedding, 키 = positional_embedding, attention_mask = 없음 ) # 잔여 연결이 있는 레이어 표준 출력 = self.layernorm(positional_embedding + attention_out) 출력 반환 데프 video_cls_model(class_vocab): #카테고리 수 class_num = len(class_vocab) # 모델 정의 모델 =keras.Sequential([ 레이어.InputLayer(input_shape=(MAX_SEQUENCE_LENGTH, NUM_FEATURES)), TransformerEncoder(2, NUM_FEATURES), 레이어.GlobalMaxPooling1D(), 레이어.드롭아웃(0.1), 레이어.밀도(classes_num, 활성화="소프트맥스") ]) # 모델 컴파일 model.compile(최적화 프로그램 = keras.optimizers.Adam(1e-5), 손실 = 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(프레임): 프레임_카운트 = 길이(프레임) # 프레임 수가 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(프레임) 반환 video_feat
마지막으로 예측을 위해 비디오 시퀀스의 특징 벡터가 Transformer Encoder에 입력됩니다.
#영상예측 데프 테스트비디오(): test_file = 무작위.샘플(동영상, 1)[0] 라벨 = test_file.split('_')[-2] print('파일 이름: {}'.format(test_file) ) print('실제 카테고리:{}'.format(label_to_name.get(int(label))) ) # 비디오의 각 프레임을 읽습니다. 프레임 = load_video(test_file) #표시할 이전 프레임 MAX_SEQUENCE_LENGTH를 선택합니다. 프레임 = 프레임[:MAX_SEQUENCE_LENGTH].astype(np.uint8) # GIF로 저장 imageio.mimsave('animation.gif', 프레임, 기간=10) # 기능 가져오기 feat = getVideoFeat(프레임) # 모델 추론 prob = model.predict(tf.expand_dims(feat, 축=0))[0] print('예상 카테고리: ') np.argsort(prob)[::-1][:5]의 경우: print('{}: {}%'.format(label_to_name[i], round(prob[i]*100, 2))) return display(Image(open('animation.gif', 'rb').read()))
모델 예측 결과:
파일명 :hand_gesture/woman_014_0_7.mp4 실제 클래스: 잘못된 동작 예측 카테고리: 잘못된 제스처: 99.82% 하락: 0.12% 종가: 0.04% 왼쪽으로 스와이프: 0.01% 오픈: 0.01%
오픈 소스 산업용 소프트웨어를 포기하기로 결정했습니다 . 주요 이벤트 - OGG 1.0 출시, Huawei가 모든 소스 코드를 제공했습니다. Google Python Foundation 팀이 "코드 똥산"에 의해 해고되었습니다 . ". Fedora Linux 40이 정식 출시되었습니다. 유명 게임 회사가 출시했습니다. 새로운 규정: 직원의 결혼 선물은 100,000위안을 초과할 수 없습니다. China Unicom은 세계 최초로 오픈 소스 모델의 Llama3 8B 중국어 버전을 출시했습니다. Pinduoduo는 보상금을 선고 받았습니다 . 불공정 경쟁에 500만 위안 국내 클라우드 입력 방식 - 화웨이만 클라우드 데이터 업로드 보안 문제 없음