【C4-2022】奶牛异常行为监测系统

★★★ 本文源自AI Studio社区精品项目,【点击此处】查看更多精品内容 >>>


前言

1 项目概述

本项目采用轻量级的目标检测算法、关键点检测算法以及基于骨骼点的动作识别算法搭建奶牛异常行为监测系统。基于PaddleDetection和PaddleVideo完成算法开发,使用AI Studio开放平台进行模型训练以及借助PyQt5完成系统界面设计。
模型开发与训练所使用的数据集来源于开源数据集与自制数据集。其中奶牛目标检测的数据集来源于COCO数据集、奶牛关键点检测的数据集来源于Animal-Pose数据集以及基于奶牛骨骼点的动作识别的数据集来源于各大视频网站,经标注后用于模型开发。
奶牛异常行为监测系统下图所示,将视频数据输入至该系统,该系统首先通过目标检测得到目标框,然后将目标框输入至关键点检测模型得到奶牛骨骼点数据。通过关联的奶牛,获得奶牛连续时间骨骼点数据作为奶牛动作识别的输入,通过奶牛动作识别模型获得奶牛的行为识别结果,最终判断奶牛是否具有异常行为,是否需要进行专家诊断,最终通过桌面端以及移动端软件进行展示。

2 项目视频展示

一、训练环境准备

!git clone https://gitee.com/paddlepaddle/PaddleDetection.git
%cd /home/aistudio/PaddleDetection/
!pip install --upgrade -r requirements.txt -i https://mirror.baidu.com/pypi/simple

二、数据集准备

%cd /home/aistudio/data/
!unzip -oq /home/aistudio/data/data151339/Animal_Pose.zip
/home/aistudio/data

二、奶牛骨骼点检测模型训练

2.1 奶牛骨骼点数据准备

%cd /home/aistudio/data/Keypoints/
import json

json_data = open('keypoints.json')
keypoints = json.load(json_data)
print(len(keypoints['images']))
print(len(keypoints['categories']))
print(len(keypoints['annotations']))
names = []
for item in keypoints['categories']:
    names.append([item['name'], item['id']])
for ann_item in keypoints['annotations']:
    if ann_item['category_id'] == 5:
        print(ann_item)
        break
/home/aistudio/data/Keypoints
4608
5
6117
{'image_id': 5, 'bbox': [71, 252, 216, 314], 'keypoints': [[103, 269, 1], [86, 269, 1], [92, 284, 1], [108, 260, 1], [83, 261, 1], [110, 303, 1], [0, 0, 0], [0, 0, 0], [0, 0, 0], [108, 307, 1], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [105, 289, 1], [121, 263, 1], [211, 272, 1]], 'num_keypoints': 20, 'category_id': 5}
%cd /home/aistudio/data/
!unzip -oq /home/aistudio/data/annot.zip
/home/aistudio/data
import json

json_data = open('annot/train.json')
keypoints = json.load(json_data)

print(len(keypoints))
for item in keypoints:
    print(item)
    break
22246
{'joints_vis': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'joints': [[620.0, 394.0], [616.0, 269.0], [573.0, 185.0], [647.0, 188.0], [661.0, 221.0], [656.0, 231.0], [610.0, 187.0], [647.0, 176.0], [637.0201, 189.8183], [695.9799, 108.1817], [606.0, 217.0], [553.0, 161.0], [601.0, 167.0], [692.0, 185.0], [693.0, 240.0], [688.0, 313.0]], 'image': '015601864.jpg', 'scale': 3.021046, 'center': [594.0, 257.0]}
#将Animal-Pose数据集中的标注格式转换成MPII格式标注
%cd /home/aistudio/data/Keypoints/
import json

animal_pose = open('keypoints.json', 'r')
keypoints = json.load(animal_pose)
MPII_type = {'root':[]}
pose_new_item = {'image_id':0, 'joints_vis':[], 'joints':[], 'image':0, 'scale':0, 'center':0}

for ann_item in keypoints['annotations']:
    if ann_item['category_id'] == 5:
        for points in ann_item['keypoints']:
            pose_new_item['joints_vis'].append(points[2])
            pose_new_item['joints'].append([points[0], points[1]])
        pose_new_item['image'] = keypoints['images'][str(ann_item['image_id'])]
        x1, y1, x2, y2 = ann_item['bbox']
        pose_new_item['scale'] = (y2-y1)/200
        pose_new_item['center'] = [(x1+x2)/2, (y1+y2)/2]
        pose_new_item['image_id'] = int(ann_item['image_id'])
        MPII_type['root'].append(pose_new_item)
        pose_new_item = {'image_id':0, 'joints_vis':[], 'joints':[], 'image':0, 'scale':0, 'center':0}
print(len(MPII_type['root']))
f = open('mpii_type.json', 'w')
json.dump(MPII_type, f)

/home/aistudio/data/Keypoints
842

2.2 骨骼点检测模型训练

2.2.1 修改训练配置文件

2.2.2 Training

%cd /home/aistudio/PaddleDetection/
!python3 tools/train.py -c configs/keypoint/hrnet/animal_pose.yml

2.3 骨骼点检测模型导出

!python tools/export_model.py -c configs/keypoint/hrnet/animal_pose.yml -o weights=output/animal_pose/model_final.pdparams
Warning: import ppdet from source directory without installing, run 'python setup.py install' to install ppdet firstly
[06/12 19:41:51] ppdet.utils.checkpoint INFO: Finish loading model weights: output/animal_pose/model_final.pdparams
[06/12 19:41:51] ppdet.engine INFO: Export inference config file to output_inference/animal_pose/infer_cfg.yml
W0612 19:42:02.842363 22728 gpu_context.cc:278] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1
W0612 19:42:02.842419 22728 gpu_context.cc:306] device: 0, cuDNN Version: 7.6.
# 保留final_model
%cd /home/aistudio/PaddleDetection/output/
!mkdir animal_key_point
%cd /home/aistudio/PaddleDetection/output/animal_pose/
!mv model_final.pdparams /home/aistudio/PaddleDetection/output/animal_key_point/
!mv model_final.pdopt /home/aistudio/PaddleDetection/output/animal_key_point/
%cd /home/aistudio/PaddleDetection/output/
!rm -rf animal_pose
/home/aistudio/PaddleDetection/output/animal_pose

三、奶牛检测模型训练

3.1 奶牛数据集准备

#从coco数据集中提取奶牛数据
%cd /home/aistudio/data/data105593/
!unzip -oq /home/aistudio/data/data105593/train2017.zip
!unzip -oq /home/aistudio/data/data105593/annotations_trainval2017.zip
!unzip -oq /home/aistudio/data/data105593/val2017.zip
/home/aistudio/data/data105593
%cd /home/aistudio/data/data105593/annotations/
import json

################################################################
########################写train coco json#######################
################################################################
isinstance_train = open("instances_train2017.json", "r")
data = json.load(isinstance_train)

cow_coco_dict = {"info":[], "licenses":0, "images":[], "annotations":[], "categories":[]}
cow_coco_dict["info"].append(data["info"])
cow_coco_dict["licenses"] = data["licenses"]

for item_cate in data["categories"]:
    if item_cate["name"] == "cow":
        item_cate["id"] == 0
        cow_coco_dict["categories"] = item_cate
image_id_list = []
for item_ann in data["annotations"]:
    if item_ann["category_id"] == 21:
        item_ann["category_id"] == 0
        cow_coco_dict["annotations"].append(item_ann)
        if item_ann["image_id"] not in image_id_list:
            image_id_list.append(item_ann["image_id"])
for item_image in data["images"]:
    if item_image["id"] in image_id_list:
        cow_coco_dict["images"].append(item_image)
print("train images:{}".format(len(cow_coco_dict["images"])))
f = open("cow_coco_train.json", "w")
json.dump(cow_coco_dict, f)
print("-------------train json file have been writen------------")
################################################################
#####################验证 json格式是否能解析正确##################
################################################################
isinstance_train = open("cow_coco_train.json", "r")
data = json.load(isinstance_train)
/home/aistudio/data/data105593/annotations
train images:1968
-------------train json file have been writen------------
%cd /home/aistudio/data/data105593/annotations/
import json

################################################################
########################写val coco json#######################
################################################################
isinstance_val = open("instances_val2017.json", "r")
data_val = json.load(isinstance_val)


cow_coco_dict_val = {"info":[], "licenses":0, "images":[], "annotations":[], "categories":[]}
cow_coco_dict_val["info"].append(data_val["info"])
cow_coco_dict_val["licenses"] = data_val["licenses"]
for item_cate in data_val["categories"]:
    if item_cate["name"] == "cow":
        item_cate["id"] == 0
        cow_coco_dict_val["categories"].append(item_cate)
image_id_list = []
for item_ann in data_val["annotations"]:
    if item_ann["category_id"] == 21:
        item_ann["category_id"] == 0
        cow_coco_dict_val["annotations"].append(item_ann)
        if item_ann["image_id"] not in image_id_list:
            image_id_list.append(item_ann["image_id"])
for item_image in data_val["images"]:
    if item_image["id"] in image_id_list:
        cow_coco_dict_val["images"].append(item_image)
print("val images:{}".format(len(cow_coco_dict_val["images"])))
#print(cow_coco_dict_val)
f = open("cow_coco_val.json", "w")
json.dump(cow_coco_dict_val, f)
print("-------------val json file have been writen------------")
################################################################
#####################验证 json格式是否能解析正确##################
################################################################
isinstance_val = open("cow_coco_val.json", "r")
data_val = json.load(isinstance_val)
/home/aistudio/data/data105593/annotations
val images:87
-------------val json file have been writen------------

分割线

###########################################
###########################################
%cd /home/aistudio/data
!mkdir cow

from pycocotools.coco import COCO
import os
import shutil
from tqdm import tqdm
import matplotlib.pyplot as plt
import cv2
from PIL import Image, ImageDraw
 
# 需要设置的路径

savepath = "/home/aistudio/data/cow/"  
img_dir = savepath + 'images/'
anno_dir = savepath + 'annotations/'
datasets_list = ['train2017', 'val2017']
 
# coco有80类,这里写要提取类的名字,以person为例
classes_names = ['cow']
 
# 包含所有类别的原coco数据集路径
'''
目录格式如下:
$COCO_PATH
----|annotations
----|train2017
----|val2017
----|test2017
'''
dataDir = '/home/aistudio/data/data105593/'
 
headstr = """\
<annotation>
    <folder>VOC</folder>
    <filename>%s</filename>
    <source>
        <database>My Database</database>
        <annotation>COCO</annotation>
        <image>flickr</image>
        <flickrid>NULL</flickrid>
    </source>
    <owner>
        <flickrid>NULL</flickrid>
        <name>company</name>
    </owner>
    <size>
        <width>%d</width>
        <height>%d</height>
        <depth>%d</depth>
    </size>
    
"""
objstr = """\
    <object>
        <name>%s</name>
        <bndbox>
            <cx>%s</cx>
            <cy>%s</cy>
            <w>%s</w>
            <h>%s</h>
        </bndbox>
    </object>
"""
tailstr = '''\
</annotation>
'''
 
 
# 检查目录是否存在,如果存在,先删除再创建,否则,直接创建
def mkr(path):
    if not os.path.exists(path):
        os.makedirs(path)  # 可以创建多级目录
 
 
def id2name(coco):
    classes = dict()
    for cls in coco.dataset['categories']:
        classes[cls['id']] = cls['name']
    return classes
 
 
def write_xml(anno_path, head, objs, tail):
    f = open(anno_path, "w")
    f.write(head)
    for obj in objs:
        f.write(objstr % (obj[0], obj[1], obj[2], obj[3], obj[4]))
    f.write(tail)
 
 
def save_annotations_and_imgs(coco, dataset, filename, objs):
    # 将图片转为xml,例:COCO_train2017_000000196610.jpg-->COCO_train2017_000000196610.xml
    dst_anno_dir = os.path.join(anno_dir, dataset)
    mkr(dst_anno_dir)
    anno_path = dst_anno_dir + '/' + filename[:-3] + 'xml'
    img_path = dataDir + dataset + '/' + filename
    print("img_path: ", img_path)
    dst_img_dir = os.path.join(img_dir, dataset)
    mkr(dst_img_dir)
    dst_imgpath = dst_img_dir + '/' + filename
    print("dst_imgpath: ", dst_imgpath)
    img = cv2.imread(img_path)
    # if (img.shape[2] == 1):
    #    print(filename + " not a RGB image")
    #   return
    shutil.copy(img_path, dst_imgpath)
 
    head = headstr % (filename, img.shape[1], img.shape[0], img.shape[2])
    tail = tailstr
    write_xml(anno_path, head, objs, tail)
 
 
def showimg(coco, dataset, img, classes, cls_id, show=True):
    global dataDir
    I = Image.open('%s/%s/%s' % (dataDir, dataset, img['file_name']))
    # 通过id,得到注释的信息
    annIds = coco.getAnnIds(imgIds=img['id'], catIds=cls_id, iscrowd=None)
    # print(annIds)
    anns = coco.loadAnns(annIds)
    # print(anns)
    # coco.showAnns(anns)
    objs = []
    for ann in anns:
        class_name = classes[ann['category_id']]
        if class_name in classes_names:
            print(class_name)
            if 'bbox' in ann:
                bbox = ann['bbox']
                xmin = float(bbox[0])
                ymin = float(bbox[1])
                xmax = float(bbox[2])  #bbox[2] + bbox[0]
                ymax = float(bbox[3])  #bbox[3] + bbox[1]
                obj = [class_name, xmin, ymin, xmax, ymax]
                objs.append(obj)
                draw = ImageDraw.Draw(I)
                draw.rectangle([xmin, ymin, xmax, ymax])
    if show:
        plt.figure()
        plt.axis('off')
        plt.imshow(I)
        plt.show()
 
    return objs
 
 
for dataset in datasets_list:
    # ./COCO/annotations/instances_train2017.json
    annFile = '{}/annotations/instances_{}.json'.format(dataDir, dataset)
 
    # 使用COCO API用来初始化注释数据
    coco = COCO(annFile)
 
    # 获取COCO数据集中的所有类别
    classes = id2name(coco)
    print(classes)
    # [1, 2, 3, 4, 6, 8]
    classes_ids = coco.getCatIds(catNms=classes_names)
    print(classes_ids)
    for cls in classes_names:
        # 获取该类的id
        cls_id = coco.getCatIds(catNms=[cls])
        img_ids = coco.getImgIds(catIds=cls_id)
        print(cls, len(img_ids))
        # imgIds=img_ids[0:10]
        for imgId in tqdm(img_ids):
            img = coco.loadImgs(imgId)[0]
            filename = img['file_name']
            # print(filename)
            objs = showimg(coco, dataset, img, classes, classes_ids, show=False)
            print(objs)
            save_annotations_and_imgs(coco, dataset, filename, objs)
 
import xml.etree.ElementTree as ET
import os
import json
 
coco = dict()
coco['images'] = []
coco['type'] = 'instances'
coco['annotations'] = []
coco['categories'] = []
 
category_set = dict()
image_set = set()
 
category_item_id = 0
image_id = 20210000000
annotation_id = 0
 
 
def addCatItem(name):
    global category_item_id
    category_item = dict()
    category_item['supercategory'] = 'none'
    category_item_id += 1
    category_item['id'] = category_item_id
    category_item['name'] = name
    coco['categories'].append(category_item)
    category_set[name] = category_item_id
    return category_item_id
 
 
def addImgItem(file_name, size):
    global image_id
    if file_name is None:
        raise Exception('Could not find filename tag in xml file.')
    if size['width'] is None:
        raise Exception('Could not find width tag in xml file.')
    if size['height'] is None:
        raise Exception('Could not find height tag in xml file.')
    image_id += 1
    image_item = dict()
    image_item['id'] = image_id
    image_item['file_name'] = file_name
    image_item['width'] = size['width']
    image_item['height'] = size['height']
    coco['images'].append(image_item)
    image_set.add(file_name)
    return image_id
 
 
def addAnnoItem(object_name, image_id, category_id, bbox):
    global annotation_id
    annotation_item = dict()
    annotation_item['segmentation'] = []
    seg = []
    # bbox[] is x,y,w,h
    # left_top
    seg.append(bbox[0])
    seg.append(bbox[1])
    # left_bottom
    seg.append(bbox[0])
    seg.append(bbox[1] + bbox[3])
    # right_bottom
    seg.append(bbox[0] + bbox[2])
    seg.append(bbox[1] + bbox[3])
    # right_top
    seg.append(bbox[0] + bbox[2])
    seg.append(bbox[1])
 
    annotation_item['segmentation'].append(seg)
 
    annotation_item['area'] = bbox[2] * bbox[3]
    annotation_item['iscrowd'] = 0
    annotation_item['ignore'] = 0
    annotation_item['image_id'] = image_id
    annotation_item['bbox'] = bbox
    annotation_item['category_id'] = 1  #category_id
    annotation_id += 1
    annotation_item['id'] = annotation_id
    coco['annotations'].append(annotation_item)
 
 
def parseXmlFiles(xml_path):
    for f in os.listdir(xml_path):
        if not f.endswith('.xml'):
            continue
 
        bndbox = dict()
        size = dict()
        current_image_id = None
        current_category_id = None
        file_name = None
        size['width'] = None
        size['height'] = None
        size['depth'] = None
 
        xml_file = os.path.join(xml_path, f)
        print(xml_file)
 
        tree = ET.parse(xml_file)
        root = tree.getroot()
        if root.tag != 'annotation':
            raise Exception('pascal voc xml root element should be annotation, rather than {}'.format(root.tag))
 
        # elem is <folder>, <filename>, <size>, <object>
        for elem in root:
            current_parent = elem.tag
            current_sub = None
            object_name = None
 
            if elem.tag == 'folder':
                continue
 
            if elem.tag == 'filename':
                file_name = elem.text
                if file_name in category_set:
                    raise Exception('file_name duplicated')
 
            # add img item only after parse <size> tag
            elif current_image_id is None and file_name is not None and size['width'] is not None:
                if file_name not in image_set:
                    current_image_id = addImgItem(file_name, size)
                    print('add image with {} and {}'.format(file_name, size))
                else:
                    raise Exception('duplicated image: {}'.format(file_name))
                    # subelem is <width>, <height>, <depth>, <name>, <bndbox>
            for subelem in elem:
                bndbox['cx'] = None
                bndbox['cy'] = None
                bndbox['w'] = None
                bndbox['h'] = None
 
                current_sub = subelem.tag
                if current_parent == 'object' and subelem.tag == 'name':
                    object_name = subelem.text
                    if object_name not in category_set:
                        current_category_id = addCatItem(object_name)
                    else:
                        current_category_id = category_set[object_name]
 
                elif current_parent == 'size':
                    if size[subelem.tag] is not None:
                        raise Exception('xml structure broken at size tag.')
                    size[subelem.tag] = int(subelem.text)
 
                # option is <xmin>, <ymin>, <xmax>, <ymax>, when subelem is <bndbox>
                for option in subelem:
                    if current_sub == 'bndbox':
                        if bndbox[option.tag] is not None:
                            raise Exception('xml structure corrupted at bndbox tag.')
                        bndbox[option.tag] = float(option.text)
 
                # only after parse the <object> tag
                if bndbox['cx'] is not None:#'xmin'
                    if object_name is None:
                        raise Exception('xml structure broken at bndbox tag')
                    if current_image_id is None:
                        raise Exception('xml structure broken at bndbox tag')
                    if current_category_id is None:
                        raise Exception('xml structure broken at bndbox tag')
                    bbox = []
                    # x
                    bbox.append(bndbox['cx'])
                    # y
                    bbox.append(bndbox['cy'])
                    # w
                    bbox.append(bndbox['w'])
                    # h
                    bbox.append(bndbox['h'])
                    print('add annotation with {},{},{},{}'.format(object_name, current_image_id, current_category_id,
                                                                   bbox))
                    addAnnoItem(object_name, current_image_id, current_category_id, bbox)
 
 
if __name__ == '__main__':
    # 需要自己设定的地址,一个是已生成的是xml文件的父目录;一个是要生成的json文件的目录
    xml_dir = r'/home/aistudio/data/cow/annotations'
    json_dir = r'/home/aistudio/data/cow/annotations'
    dataset_lists = ['val2017']
    for dataset in dataset_lists:
        xml_path = os.path.join(xml_dir, dataset)
        json_file = json_dir + '/{}.json'.format(dataset)
        parseXmlFiles(xml_path)
        json.dump(coco, open(json_file, 'w'))
    
    xml_dir = r'/home/aistudio/data/cow/annotations'
    json_dir = r'/home/aistudio/data/cow/annotations'
    dataset_lists = ['train2017']
    for dataset in dataset_lists:
        xml_path = os.path.join(xml_dir, dataset)
        json_file = json_dir + '/{}.json'.format(dataset)
        parseXmlFiles(xml_path)
        json.dump(coco, open(json_file, 'w'))

3.2 检测模型训练

3.2.1 修改配置文件


%cd /home/aistudio/PaddleDetection/
!python tools/train.py -c configs/ppyoloe/ppyoloe_cow.yml --eval

3.3 模型导出

%cd /home/aistudio/PaddleDetection/
!python tools/export_model.py -c configs/ppyoloe/ppyoloe_cow.yml -o weights=output/ppyoloe_cow/model_final.pdparams
%cd /home/aistudio/PaddleDetection/output/
!mkdir cow_detection
%cd /home/aistudio/PaddleDetection/output/ppyoloe_cow/
!mv best_model.pdparams /home/aistudio/PaddleDetection/output/cow_detection
!mv best_model.pdopt /home/aistudio/PaddleDetection/output/cow_detection
%cd /home/aistudio/PaddleDetection/output/
!rm -rf ppyoloe_cow

四、动作异常识别模型训练

4.1 骨骼点数据准备

%cd /home/aistudio
!unzip -oq /home/aistudio/data/data151339/Final_data.zip
/home/aistudio
%cd /home/aistudio/
import numpy as np
import os

training = []
label_list = []

for item in os.listdir("/home/aistudio/Final_data"):
    training.append(np.load("/home/aistudio/Final_data/{}".format(item)))
np.save("training.npy", training)
for i in range(len(os.listdir("/home/aistudio/Final_data"))):
    label_list.append(0)

np.save("labels.npy", label_list)
/home/aistudio
%cd /home/aistudio/
print(len(os.listdir("Final_data")))
print(np.load("labels.npy").shape)
/home/aistudio
135
(135,)

4.2 定义数据集Reader

%cd /home/aistudio/
from paddle.io import Dataset
import numpy as np


class Reader(Dataset):
    def __init__(self, data_path, label_path):
        super().__init__()
        self.data_list = np.load(data_path)
        self.label_list = np.load(label_path)
        self.index_list = list()
        for index in range(len(self.label_list)):
            self.index_list.append(index)

    def __getitem__(self, idx):
        idx = self.index_list[idx]
        x = self.data_list[idx]
        x = x.astype("float32")
        return x, self.label_list[idx]

    def __len__(self):
        return len(self.index_list)
/home/aistudio

4.3 AGCN Model搭建

import paddle as pp
import paddle.nn as nn
import paddle.nn.functional as F
import paddle


class GCN(nn.Layer):
    def __init__(self, in_channels, out_channels, vertex_nums=20, stride=1):
        super(GCN, self).__init__()
        self.conv1 = nn.Conv2D(in_channels=in_channels,
                               out_channels=3 * out_channels,
                               kernel_size=1,
                               stride=1)
        self.conv2 = nn.Conv2D(in_channels=vertex_nums * 3,
                               out_channels=vertex_nums,
                               kernel_size=1)

    def forward(self, x):
        # x --- N,C,T,V
        x = self.conv1(x)  # N,3C,T,V
        N, C, T, V = x.shape
        x = paddle.reshape(x, [N, C // 3, 3, T, V])  # N,C,3,T,V
        x = paddle.transpose(x, perm=[0, 1, 2, 4, 3])  # N,C,3,V,T
        x = paddle.reshape(x, [N, C // 3, 3 * V, T])  # N,C,3V,T
        x = paddle.transpose(x, perm=[0, 2, 1, 3])  # N,3V,C,T
        x = self.conv2(x)  # N,V,C,T
        x = paddle.transpose(x, perm=[0, 2, 3, 1])  # N,C,T,V
        return x


class Block(paddle.nn.Layer):
    def __init__(self,
                 in_channels,
                 out_channels,
                 vertex_nums=20,
                 temporal_size=9,
                 stride=1,
                 residual=True):
        super(Block, self).__init__()
        self.residual = residual
        self.out_channels = out_channels

        self.bn_res = nn.BatchNorm2D(out_channels)
        self.conv_res = nn.Conv2D(in_channels=in_channels,
                                  out_channels=out_channels,
                                  kernel_size=1,
                                  stride=(stride, 1))
        self.gcn = GCN(in_channels=in_channels,
                       out_channels=out_channels,
                       vertex_nums=vertex_nums)
        self.tcn = nn.Sequential(
            nn.BatchNorm2D(out_channels),
            nn.ReLU(),
            nn.Conv2D(in_channels=out_channels,
                      out_channels=out_channels,
                      kernel_size=(temporal_size, 1),
                      padding=((temporal_size - 1) // 2, 0),
                      stride=(stride, 1)),
            nn.BatchNorm2D(out_channels),
        )

    def forward(self, x):
        if self.residual:
            y = self.conv_res(x)
            y = self.bn_res(y)
        x = self.gcn(x)
        x = self.tcn(x)
        out = x + y if self.residual else x
        out = F.relu(out)
        return out


class AGCN(nn.Layer):
    """
    AGCN model improves the performance of ST-GCN using
    Adaptive Graph Convolutional Networks.
    Args:
        in_channels: int, channels of vertex coordinate. 2 for (x,y), 3 for (x,y,z). Default 2.
    """
    def __init__(self, in_channels=2, **kwargs):
        super(AGCN, self).__init__()

        self.data_bn = nn.BatchNorm1D(20 * 2)
        self.agcn = nn.Sequential(
            Block(in_channels=in_channels,
                  out_channels=64,
                  residual=False,
                  **kwargs), Block(in_channels=64, out_channels=64, **kwargs),
            Block(in_channels=64, out_channels=64, **kwargs),
            Block(in_channels=64, out_channels=64, **kwargs),
            Block(in_channels=64, out_channels=128, stride=2, **kwargs),
            Block(in_channels=128, out_channels=128, **kwargs),
            Block(in_channels=128, out_channels=128, **kwargs),
            Block(in_channels=128, out_channels=256, stride=2, **kwargs),
            Block(in_channels=256, out_channels=256, **kwargs),
            Block(in_channels=256, out_channels=256, **kwargs))

        self.pool = nn.AdaptiveAvgPool2D(output_size=(1, 1))
        
        self.out = pp.nn.Linear(in_features=256, out_features=2)
        
    def forward(self, x):
        # data normalization
        print(x.shape)
        N, C, T, V, M = x.shape

        x = x.transpose((0, 4, 1, 2, 3))  # N, M, C, T, V
        x = x.reshape((N * M, C, T, V))

        x = self.agcn(x)

        x = self.pool(x)  # NM,C,T,V --> NM,C,1,1
        C = x.shape[1]
        x = paddle.reshape(x, (N, M, C)).mean(axis=1)  # N,C,1,1
        x = self.out(x)
        
        return x

4.4 AGCN模型训练

data_path = 'training.npy'
label_path = 'labels.npy'

input_define = pp.static.InputSpec(shape=[-1, 3, 30, 20, 1], dtype="float32", name='data')
# 定义label输入层,用于计算损失和准确率
label_define = pp.static.InputSpec(shape=[-1, 1], dtype="int64", name="label")
# 实例化网络对象并定义优化器等训练逻辑
model = pp.Model(AGCN(in_channels=3), inputs=input_define, labels=label_define)
# 此处lr使用CosineAnnealingDecay对学习率进行调整
lr = paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=0.00625 , T_max=100, last_epoch=-1, verbose=False)
# 此处使用Momentum优化器
optimizer = pp.optimizer.Momentum(learning_rate=lr, parameters=model.parameters())
# 损失函数使用交叉熵,评价指标使用准确率
# 其中Top-k表示推理得到的概率分布中,概率最高的前k个推理结果中是否包含正确标签,如果包含则视为正确,这里的1,2,3分别计算k为1~3的情况
model.prepare(optimizer=optimizer,
              loss=pp.nn.CrossEntropyLoss(),
              metrics=pp.metric.Accuracy(topk=(1, 5)))
train_set = Reader(data_path=data_path,
                            label_path=label_path)

# print(train_set[0][0].shape)

model.fit(train_data=train_set,
          batch_size=32,
          epochs=100,
          save_dir="output/",
          save_freq=5,
          eval_freq=5,
          log_freq=20)
print("训练完毕")

4.5 AGCN模型推理

import paddle as pp
import numpy as np

def softmax(x):
    
    f_x = np.exp(x) / np.sum(np.exp(x))
    return f_x

input_define = pp.static.InputSpec(shape=[-1, 3, 30, 20, 1], dtype="float32", name='data')

model_infer = pp.Model(AGCN(in_channels=3), inputs=input_define)
model_infer.load("output/final.pdparams")
model_infer.prepare()

data = np.load("training.npy")
data_ = np.reshape(data[0], (1, 1, 3, 30, 20, 1))
data_ = data_.astype("float32")
print(data_.shape)
result = model_infer.predict(data_, batch_size=1)
print(result)
print(softmax(result))
tput/",
          save_freq=5,
          eval_freq=5,
          log_freq=20)
print("训练完毕")

4.5 AGCN模型推理

import paddle as pp
import numpy as np

def softmax(x):
    
    f_x = np.exp(x) / np.sum(np.exp(x))
    return f_x

input_define = pp.static.InputSpec(shape=[-1, 3, 30, 20, 1], dtype="float32", name='data')

model_infer = pp.Model(AGCN(in_channels=3), inputs=input_define)
model_infer.load("output/final.pdparams")
model_infer.prepare()

data = np.load("training.npy")
data_ = np.reshape(data[0], (1, 1, 3, 30, 20, 1))
data_ = data_.astype("float32")
print(data_.shape)
result = model_infer.predict(data_, batch_size=1)
print(result)
print(softmax(result))

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基于YOLOv8的牛羊识别检测系统源码(部署教程+训练好的模型+各项评估指标曲线).zip 平均准确率:0.91 类别:“sheep”,“cow” 【资源介绍】 1、ultralytics-main ultralytics-main为YOLOv8源代码,里面涵盖基于yolov8分类、目标检测额、姿态估计、图像分割四部分代码,我们使用的是detect部分,也就是目标检测代码 2、搭建环境 安装anaconda 和 pycharm windows系统、mac系统、Linux系统都适配 在anaconda中新建一个新的envs虚拟空间(可以参考博客来),命令窗口执行:conda create -n YOLOv8 python==3.8 创建完YOLOv8-GUI虚拟空间后,命令窗口执行:source activate YOLOv8 激活虚拟空间 然后就在YOLOv8虚拟空间内安装requirements.txt中的所有安装包,命令窗口执行:pip install -r requirements.txt 使用清华源安装更快 3、训练模型过程 进入到\ultralytics-main\ultralytics\yolo\v8\detect\文件夹下,datasets即为我们需要准备好的数据集,训练其他模型同理。 data文件夹下的bicycle.yaml文件为数据集配置文件,该文件为本人训练自行车检测模型时创建,训练其他模型,可自行创建。博文有介绍https://blog.csdn.net/DeepLearning_?spm=1011.2415.3001.5343 train.py中238行,修改为data = cfg.data or './bicycle.yaml' # or yolo.ClassificationDataset("mnist") 237行修改自己使用的预训练模型 若自己有显卡,修改239行,如我有四张显卡,即改成args = dict(model=model, data=data, device=”0,1,2,3“) 以上配置完成后运行train.py开始训练模型,训练完毕后会在runs/detect/文件夹下生成train*文件夹,里面包含模型和评估指标等 4、推理测试 训练好模型,打开predict.py,修改87行,model = cfg.model or 'yolov8n.pt',把yolov8n.pt换成我们刚才训练完生成的模型路径(在\ultralytics-main\ultralytics\yolo\v8\detect\runs\detect文件夹下),待测试的图片或者视频存放于ultralytics\ultralytics\assets文件夹, 运行predict.py即可,检测结果会在runs/detect/train文件夹下生成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值