【开源】基于飞桨PaddleClas构建个人PC智慧相册

开源

一、项目简介

使用PaddleClas和WatchDog实现PC端个人相册分类智慧管理。基于图像识别结果中的多个标签,智能相册可以自定义图像分类,比如“植物”、“美食”、“工作”等类别。方便用户管理相册,带来良好体验。

42Dain.png

演示:

二、数据集

  • 风景数据集:https://github.com/yuweiming70/Landscape-Dataset

  • 食物数据集:https://www.datafountain.cn/datasets/5423

apple_pie,bibimbap,cannoli,edamame,falafel,french_toast,ice_cream,ramen,sushi,tiramisu

  • 人物数据集:http://www.seeprettyface.com/mydataset_page2.html

  • 文本数据集:https://challenge.xfyun.cn/topic/info?type=ad-2021&ch=dc-wbzmt-05

  • 动物数据集:https://blog.csdn.net/sunshine__sun/article/details/115558151

狗,猫,马,大象,鸡,牛,羊

三、模型训练

!pip install paddlepaddle-gpu # --upgrade -i https://mirror.baidu.com/pypi/simple -q
!pip install paddlex -q
!pip install paddlelite -q
# 克隆paddleclas组件代码
!git clone https://gitee.com/paddlepaddle/PaddleClas.git -b develop
# 安装环境
%cd PaddleClas
#!pip install --upgrade -r requirements.txt -i https://mirror.baidu.com/pypi/simple
!rm -rf dataset/flowers102
!unzip /home/aistudio/data/data110303/dataset.zip -d /home/aistudio/PaddleClas/dataset/
# 数据集切分: 训练:测试:验证=8:1:2
!paddlex --split_dataset --format ImageNet --dataset_dir './dataset/' --val_value 0.2 --test_value 0.1

配置文件修改

训练文件配置,修改PaddleClas/ppcls/configs/quick_start/ResNet50_vd.yaml为(所有要修改的行我都用【】标注了,使用的是时候删除【】就可以):

# global configs
Global:
  checkpoints: null
  pretrained_model: null
  output_dir: ./output/
  device: gpu
  【save_interval: 5】
  eval_during_train: True
  【eval_interval: 5】
  【epochs: 50】
  print_batch_step: 10
  use_visualdl: False
  # used for static mode and model export
  image_shape: [3, 224, 224]
  save_inference_dir: ./inference

# model architecture
Arch:
  name: MobileNetV3_large_x1_0
  【class_num: 99】
 
# loss function config for traing/eval process
Loss:
  Train:
    - CELoss:
        weight: 1.0
  Eval:
    - CELoss:
        weight: 1.0


Optimizer:
  name: Momentum
  momentum: 0.9
  lr:
    name: Cosine
    learning_rate: 0.00375
    warmup_epoch: 5
    last_epoch: -1
  regularizer:
    name: 'L2'
    coeff: 0.000001


# data loader for train and eval
DataLoader:
  Train:
    dataset:
      name: ImageNetDataset
      【image_root: ./dataset/】
      【cls_label_path: ./dataset/train_list.txt】
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - RandCropImage:
            size: 224
        - RandFlipImage:
            flip_code: 1
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''

    sampler:
      name: DistributedBatchSampler
      batch_size: 32
      drop_last: False
      shuffle: True
    loader:
      【num_workers: 0】
      use_shared_memory: True

  Eval:
    dataset: 
      name: ImageNetDataset
      【image_root: ./dataset/】
      【cls_label_path: ./dataset/val_list.txt】
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            resize_short: 256
        - CropImage:
            size: 224
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''
    sampler:
      name: DistributedBatchSampler
      batch_size: 64
      drop_last: False
      shuffle: False
    loader:
      【num_workers: 0】
      use_shared_memory: True

Infer:
  【infer_imgs: ./dataset/AmsactaLactinea/28.jpg】
  batch_size: 10
  transforms:
    - DecodeImage:
        to_rgb: True
        channel_first: False
    - ResizeImage:
        resize_short: 256
    - CropImage:
        size: 224
    - NormalizeImage:
        scale: 1.0/255.0
        mean: [0.485, 0.456, 0.406]
        std: [0.229, 0.224, 0.225]
        order: ''
    - ToCHWImage:
  PostProcess:
    name: Topk
    topk: 5
    【class_id_map_file: ./dataset/labels.txt】

Metric:
  Train:
    - TopkAcc:
        topk: [1, 5]
  Eval:
    - TopkAcc:
        topk: [1, 5]

类别映射文件修改

dataset下的label.txt修改为:

0 animals
1 food
2 people
3 scenery
4 text
!python3 tools/train.py \
    -c ./ppcls/configs/quick_start/ResNet50_vd.yaml \
    -o Arch.pretrained=True

最终的一个训练结果:

[2021/09/26 17:02:11] root INFO: [Train][Epoch 6/100][Iter: 0/204]lr: 0.01250, CELoss: 0.21896, loss: 0.21896, top1: 0.93750, top5: 1.00000, batch_cost: 0.28717s, reader_cost: 0.23059, ips: 111.43318 images/sec, eta: 1:32:45
[2021/09/26 17:02:14] root INFO: [Train][Epoch 6/100][Iter: 10/204]lr: 0.01250, CELoss: 0.16529, loss: 0.16529, top1: 0.95455, top5: 1.00000, batch_cost: 0.26309s, reader_cost: 0.20698, ips: 121.63060 images/sec, eta: 1:24:56
[2021/09/26 17:02:16] root INFO: [Train][Epoch 6/100][Iter: 20/204]lr: 0.01250, CELoss: 0.14305, loss: 0.14305, top1: 0.95536, top5: 1.00000, batch_cost: 0.25574s, reader_cost: 0.19961, ips: 125.12556 images/sec, eta: 1:22:31
[2021/09/26 17:02:19] root INFO: [Train][Epoch 6/100][Iter: 30/204]lr: 0.01250, CELoss: 0.14826, loss: 0.14826, top1: 0.95565, top5: 1.00000, batch_cost: 0.27352s, reader_cost: 0.21715, ips: 116.99388 images/sec, eta: 1:28:12
[2021/09/26 17:02:22] root INFO: [Train][Epoch 6/100][Iter: 40/204]lr: 0.01250, CELoss: 0.14288, loss: 0.14288, top1: 0.95579, top5: 1.00000, batch_cost: 0.28418s, reader_cost: 0.22783, ips: 112.60358 images/sec, eta: 1:31:36
[2021/09/26 17:02:25] root INFO: [Train][Epoch 6/100][Iter: 50/204]lr: 0.01250, CELoss: 0.14453, loss: 0.14453, top1: 0.95466, top5: 1.00000, batch_cost: 0.28580s, reader_cost: 0.22947, ips: 111.96648 images/sec, eta: 1:32:04
[2021/09/26 17:02:28] root INFO: [Train][Epoch 6/100][Iter: 60/204]lr: 0.01250, CELoss: 0.14173, loss: 0.14173, top1: 0.95543, top5: 1.00000, batch_cost: 0.28339s, reader_cost: 0.22700, ips: 112.91845 images/sec, eta: 1:31:15
[2021/09/26 17:02:31] root INFO: [Train][Epoch 6/100][Iter: 70/204]lr: 0.01250, CELoss: 0.14219, loss: 0.14219, top1: 0.95555, top5: 1.00000, batch_cost: 0.28145s, reader_cost: 0.22503, ips: 113.69719 images/sec, eta: 1:30:34
[2021/09/26 17:02:33] root INFO: [Train][Epoch 6/100][Iter: 80/204]lr: 0.01250, CELoss: 0.13479, loss: 0.13479, top1: 0.95833, top5: 1.00000, batch_cost: 0.28028s, reader_cost: 0.22383, ips: 114.16997 images/sec, eta: 1:30:09
[2021/09/26 17:02:36] root INFO: [Train][Epoch 6/100][Iter: 90/204]lr: 0.01250, CELoss: 0.13717, loss: 0.13717, top1: 0.95776, top5: 1.00000, batch_cost: 0.27936s, reader_cost: 0.22292, ips: 114.54742 images/sec, eta: 1:29:48
[2021/09/26 17:02:39] root INFO: [Train][Epoch 6/100][Iter: 100/204]lr: 0.01250, CELoss: 0.13193, loss: 0.13193, top1: 0.95916, top5: 1.00000, batch_cost: 0.27771s, reader_cost: 0.22126, ips: 115.22808 images/sec, eta: 1:29:14
[2021/09/26 17:02:42] root INFO: [Train][Epoch 6/100][Iter: 110/204]lr: 0.01250, CELoss: 0.12981, loss: 0.12981, top1: 0.95974, top5: 1.00000, batch_cost: 0.27882s, reader_cost: 0.22233, ips: 114.76755 images/sec, eta: 1:29:32
[2021/09/26 17:02:45] root INFO: [Train][Epoch 6/100][Iter: 120/204]lr: 0.01250, CELoss: 0.12835, loss: 0.12835, top1: 0.95997, top5: 1.00000, batch_cost: 0.28274s, reader_cost: 0.22619, ips: 113.17778 images/sec, eta: 1:30:45
[2021/09/26 17:02:47] root INFO: [Train][Epoch 6/100][Iter: 130/204]lr: 0.01250, CELoss: 0.13026, loss: 0.13026, top1: 0.95754, top5: 1.00000, batch_cost: 0.28116s, reader_cost: 0.22461, ips: 113.81383 images/sec, eta: 1:30:12
[2021/09/26 17:02:50] root INFO: [Train][Epoch 6/100][Iter: 140/204]lr: 0.01250, CELoss: 0.12561, loss: 0.12561, top1: 0.95922, top5: 1.00000, batch_cost: 0.28104s, reader_cost: 0.22446, ips: 113.86471 images/sec, eta: 1:30:07
[2021/09/26 17:02:53] root INFO: [Train][Epoch 6/100][Iter: 150/204]lr: 0.01250, CELoss: 0.12391, loss: 0.12391, top1: 0.95944, top5: 1.00000, batch_cost: 0.28117s, reader_cost: 0.22454, ips: 113.80841 images/sec, eta: 1:30:06
[2021/09/26 17:02:56] root INFO: [Train][Epoch 6/100][Iter: 160/204]lr: 0.01250, CELoss: 0.12471, loss: 0.12471, top1: 0.95885, top5: 1.00000, batch_cost: 0.28056s, reader_cost: 0.22392, ips: 114.05585 images/sec, eta: 1:29:52
[2021/09/26 17:02:59] root INFO: [Train][Epoch 6/100][Iter: 170/204]lr: 0.01250, CELoss: 0.12546, loss: 0.12546, top1: 0.95888, top5: 1.00000, batch_cost: 0.28183s, reader_cost: 0.22515, ips: 113.54456 images/sec, eta: 1:30:13
[2021/09/26 17:03:02] root INFO: [Train][Epoch 6/100][Iter: 180/204]lr: 0.01250, CELoss: 0.12573, loss: 0.12573, top1: 0.95943, top5: 1.00000, batch_cost: 0.28235s, reader_cost: 0.22570, ips: 113.33392 images/sec, eta: 1:30:21
[2021/09/26 17:03:05] root INFO: [Train][Epoch 6/100][Iter: 190/204]lr: 0.01250, CELoss: 0.12404, loss: 0.12404, top1: 0.96024, top5: 1.00000, batch_cost: 0.28296s, reader_cost: 0.22634, ips: 113.08878 images/sec, eta: 1:30:30
[2021/09/26 17:03:07] root INFO: [Train][Epoch 6/100][Iter: 200/204]lr: 0.01250, CELoss: 0.12203, loss: 0.12203, top1: 0.96113, top5: 1.00000, batch_cost: 0.28260s, reader_cost: 0.22599, ips: 113.23431 images/sec, eta: 1:30:20
[2021/09/26 17:03:08] root INFO: [Train][Epoch 6/100][Avg]CELoss: 0.12242, loss: 0.12242, top1: 0.96114, top5: 1.00000
[2021/09/26 17:03:08] root INFO: Already save model in ./output/ResNet50_vd/epoch_6
[2021/09/26 17:03:09] root INFO: Already save model in ./output/ResNet50_vd/latest
!mkdir ./output/ResNet50_vd/latest
!mv ./output/ResNet50_vd/latest.pdparams ./output/ResNet50_vd/latest/
!mv ./output/ResNet50_vd/latest.pdopt ./output/ResNet50_vd/latest/
!mv ./output/ResNet50_vd/latest.pdstates ./output/ResNet50_vd/latest/

四、模型测试

!python tools/infer.py -c ./ppcls/configs/quick_start/ResNet50_vd.yaml \
                       -o Infer.infer_imgs=./dataset/food/1043283.jpg \
                       -o Global.pretrained_model=./output/ResNet50_vd/latest/latest

输出为:

[{'class_ids': [1, 0, 4, 2, 3], 'scores': [0.99962, 0.00026, 7e-05, 2e-05, 0.0], 'file_name': './dataset/food/1043283.jpg', 'label_names': ['food', 'animals', 'text', 'people', 'scenery']}]

分类正确~

五、本地部署

本地部署需要用到一个很关键的东西-watchdog,那么watchdog是什么呢?

watchdog用来监控指定目录/文件的变化,如添加删除文件或目录、修改文件内容、重命名文件或目录等,每种变化都会产生一个事件,且有一个特定的事件类与之对应,然后再通过事件处理类来处理对应的事件,怎么样处理事件完全可以自定义,只需继承事件处理类的基类并重写对应实例方法。

426mOf.png

通俗解释来说,就是一个listener和handler:

  • listener:用来监听一个文件夹或者是事件;
  • handler:用来触发内部相关条件判断后执行的操作;

由两部分完成一个智慧相册的管理操作。

下载到本地后,需要修改config的use_gpu为cpu!!!

# 一个watchdog的小demo
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
import os

folder_to_track = "D:\\workspace\\python\\movingFiles\\src"
folder_destination_pic = "D:\\workspace\\python\\movingFiles\\des\\pic"
folder_destination_music = "D:\\workspace\\python\\movingFiles\\des\\music"
folder_destination_kaoyan = "D:\\workspace\\python\\movingFiles\\des\\kaoyan"


class MyHandler(FileSystemEventHandler):
    def on_any_event(self, event):
        for filename in os.listdir(folder_to_track) :
            src = folder_to_track +"\\"+ filename
            if filename.endswith("jpg") or filename.endswith("png"):
                new_destination=folder_destination_pic + "\\"+filename
            elif filename.endswith("mp3") :
                new_destination=folder_destination_music + "\\" + filename
            elif filename.__contains__("肖秀荣") :
                new_destination = folder_destination_kaoyan + "\\"+filename
            os.rename(src, new_destination)


event_handler = MyHandler()
observer = Observer()
observer.schedule(event_handler, folder_to_track, recursive=True)
observer.start()
try:
    while True:
        time.sleep(10)
except KeyboardInterrupt:
    observer.stop()

observer.join()
# 智慧相册的核心watchdog
# coding:utf-8
import os
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time

# 保持监听的文件
folder_to_track = "./src"
# 图片文件
#folder_destination_picture = "./source/picture"
animals = "./source/picture/animals"
food = "./source/picture/food"
people = "./source/picture/people"
scenery = "./source/picture/scenery"
text = "./source/picture/text"
# 音乐文件
folder_destination_music = "./source/music"
# 视频文件
folder_destination_video = "./source/video"


class MyHandler(FileSystemEventHandler):
    def on_any_event(self, event):
        for filename in os.listdir(folder_to_track) :
            src = folder_to_track +"/"+ filename
            if filename.endswith("jpg") or filename.endswith("png"):
                #new_destination=folder_destination_picture + "/"+filename
                print(filename)
                os.system(r"python PaddleClas/tools/infer.py -c ./PaddleClas/ppcls/configs/quick_start/ResNet50_vd.yaml -o Infer.infer_imgs=./src/"+str(filename)+" -o Global.pretrained_model=./PaddleClas/output/ResNet50_vd/latest/latest > ./result.txt")
                with open('result.txt', 'r', encoding='utf-8') as f:  # 打开文件
                    lines = f.readlines()  # 读取所有行
                    last_line = lines[-1]  # 取最后一行
                    #print(eval(last_line))
                    result = eval(last_line)[0]['label_names'][0]
                    #print(type(eval(last_line)))
                if result=='animals':
                    new_destination=animals + "/" +filename
                if result=='people':
                    new_destination=people + "/" +filename
                if result=='food':
                    new_destination=food + "/" +filename
                if result=='scenery':
                    new_destination=scenery + "/" +filename
                if result=='text':
                    new_destination=text + "/" +filename
            elif filename.endswith("mp3") :
                new_destination=folder_destination_music + "/" + filename
            elif filename.endswith("avi") or filename.endswith("mp4"):
                #filename.__contains__("肖秀荣") :
                new_destination = folder_destination_video + "/"+filename
            os.rename(src, new_destination)


event_handler = MyHandler()
observer = Observer()
observer.schedule(event_handler, folder_to_track, recursive=True)
observer.start()
try:
    while True:
        time.sleep(10)
        print('正在监听...')
except KeyboardInterrupt:
    observer.stop()

   while True:
        time.sleep(10)
        print('正在监听...')
except KeyboardInterrupt:
    observer.stop()

observer.join()

六、继续开发

这个【智慧相册】还是很简单的一个基于PaddleClas的demo项目,大家如果想要丰富还是可以的,比如将相册种类继续细化划分,加入视频分类等,或者大家有基于此项目的其他想法丰富可以联系我

七、部署使用

  1. 下载源码

git clone https://github.com/WangRongsheng/smart-photo

  1. 下载权重

提取码:wrsn

下载lastest文件夹,放到PaddleClas/output/ResNet50_vd

  1. 启动
    命令行启动main.py

  2. 使用

将任意文件放入src文件夹完成自动管理分类

项目完整代码+权重(提取码:wrsn)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落难Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值