标签搜索

目 录CONTENT

文章目录

户型分类模型V2.0 迭代

陈铭
2024-05-26 / 0 评论 / 0 点赞 / 60 阅读 / 2,490 字 / 正在检测是否收录...

ea843de325630a5d13da948663005a59_2Q==

🔎V1.0 户型分类

  • 多分类模型,耦合强,复杂-户外-非户型图不一定完全分开
  • 多二分类模型,整体数据处理流程为漏斗型,精度最强的二分类模型前置,尽量去提升整体分类的精度
    54a3b0203a4f23203618142fa0a7e541_9k=

📑开发RoadMap

新类别 旧类别 样本下载 样本清洗 样本去重 样本上载 初次训练 增量训练1 增量训练2 增量训练3 概率分布 误差样本 验收(使用6-9月生产数据进行验证)
线框 线框 f85395a313a8444fdacbafb3d0ee365f__preview_type=16
卫星 卫星 643ada71342735e9306b4f9fc97aefb9__preview_type=16
拍照 拍照 e6bb3900e37c90f6eecfabd2351fe000__preview_type=16
简单 全彩 eccf4673c4a348459e32083c6828582f__preview_type=16
非全彩
复杂 干扰遮挡
干扰不遮挡
墙体小于30
墙体大于30
户外园林 不存在 89793e3698f07a6ccd3da240e24f9a2c__preview_type=16
不可解户型 不存在 先暂停

🔥模型性能验证

使用6-9月生产上户型图进行验证
一文记住什么是TP/TN/FP/FN?_tp fp tn fn分别代表什么-CSDN博客

类别 总样本量 TP+FP+TN+FN 样本量 TP+FP 错误样本 FP 遗漏样本 FN Accuracy Precison Recall
线框 7333 270 17 6 0.996863 0.93 0.98
卫星 7333 122 3 1 0.999455 0.97541 0.991667
拍照 7333 216 0 7 0.999045 1 0.96861
简单 7333 5229 29 0 0.99 1
复杂 7333 1479 2 1 0.999591 0.998648 0.999323
户外园林 7333 17 1 1 0.999727 0.941176 0.941176

🛠模型静态量化(Beta)

注意!!!!量化模型仅支持推理且不支持GPU加速,但经过量化的模型,CPU推理耗时可以大幅降低,但仍不至于达到GPU推理的效率

Quantization — PyTorch 2.3 documentation

(beta) Static Quantization with Eager Mode in PyTorch — PyTorch Tutorials 2.3.0+cu121 documentation

a85a40f595f010ea2ab96ee7c4d665fa_73f3473e-8991-41b3-8d1f-b4a3c479afbc

任务 模型 模型大小 耗时 >=50 >=80 >=90 >=95 总结
线框图 全精度 Resnet50 94.35 MB CPU: 1.13 s

GPU: 0.15 s
97% 93% 88% 84% ed4b62cfeb0c275731831817cfe7893b_529a69d1-ede5-4c58-9d8c-3f97cfdef5a7 >=50精度下降 9%

>=80精度下降 15%

>=90精度下降 18%

>=95精度下降 23%
线框图 INT8 Resnet50 23.69 MB CPU: 0.51 s 88% 78% 70% 61% 1c098cd4311ff9688231e9e868cec45f__preview_type=16
卫星图 全精度 Resnet50 94.35 MB CPU: 1.21 s

GPU: 0.09 s
97% 91% 85% 77% 4b4510dd7ca548c49c9bad0a22d1432c__preview_type=16 文件大小减少 74%

耗时降低 56%

>=50精度下降 2%

>=80精度下降 9%

>=90精度下降 16%

>=95精度下降 17%
卫星图 INT8 Resnet50 24.14 MB CPU: 0.53 s 95% 82% 69% 60% 72d09b60350b37bfb0b7f4dda743e22c__preview_type=16
拍照图 全精度 Resnet50 94.35 MB CPU: 1.12 s

GPU: 0.11 s
99% 96% 93% 86% 6d92c3c65eca747875abe8b0aaca989a__preview_type=16 >=50精度下降 1%

>=80精度下降 2%

>=90精度下降 7%

>=95精度下降 9%
拍照图 INT8 Resnet50 24.14 MB CPU: 0.49 s 98% 94% 86% 76% 09fadfcca924a93e1c7c83aa51b39bd5__preview_type=16
简单/复杂 全精度 Resnet50 94.35 MB CPU: 1.11 s

GPU: 0.15 s
98% 96% 94% 90% 1b4e1d9bf12c585b0bba938791ed893d__preview_type=16 >=50精度下降 2%

>=80精度下降 7%

>=90精度下降 11%

>=95精度下降 16%
简单/复杂 INT8 Resnet50 23.69 MB CPU: 0.56 s 96% 89% 83% 74% 51ee2086cb9eac516d175912ce55a1bc__preview_type=16

模型结构化剪支(Beta)

整个大活,以卫星图为例,直接裁剪掉全精度模型的90%权重,性能如下,剪完性能直接拉了,完全没有表达了:
0e9e6ee8067466f3189862a71647151f_fd867383-f540-4371-bf52-03637008cb29
在剪支模型基础上进一步微调,性能恢复如下:
07779a06812d61aa64b0115d2b8a77aa_dc8b3f2d-76f8-48df-80cc-4a80ee6008e1

任务 模型 模型大小 显存占用 耗时 >=50 >=80 >=90 >=95 总结
卫星图 全精度 94.35 MB 450.4 MB(推理+模型)

256.4 MB(模型)
CPU: 1.21 s

GPU: 0.14 s
97% 91% 85% 77% 08ba99b48175ad8f91c6e48cfbb5947c_92ea1427-24ce-4c9c-87ad-5a9cf360be4a >=50精度下降 7%

>=80精度下降 17%

>=90精度下降 24%

>=95精度下降 27%
卫星图 结构化剪支 1.10 MB 366.4 MB(推理+模型)

96.4 MB(模型)
CPU: 0.22 s

GPU: 0.13 s
90% 74% 61% 50% d71a66e7c000fee15cea3c8e3864946c__preview_type=16
拍照 全精度 94.35 MB 450.4 MB(推理+模型)

256.4 MB(模型)
CPU: 1.31 s

GPU: 0.13 s
99% 96% 93% 86% fe1e1bd7aacd45034003623354f7d72a__preview_type=16 >=50精度下降 2%

>=80精度下降 3%

>=90精度下降 4%

>=95精度下降 5%
拍照 结构化剪支 1.10 MB 366.4 MB(推理+模型)

96.4 MB(模型)
CPU: 0.18 s

GPU: 0.13 s
97% 93% 89% 81% d9e37febceff71cff88bc1ea0d1f0aa2__preview_type=16
简单/复杂 全精度 94.35 MB 450.4 MB(推理+模型)

256.4 MB(模型)
CPU: 1.11 s

GPU: 0.15 s
98% 96% 94% 90% c6675ec8c4cad579e4e100b85be167f9__preview_type=16 >=50精度下降 2%

>=80精度下降 6%

>=90精度下降 10%

>=95精度下降 14%
简单/复杂 结构化剪支 1.10 MB 366.4 MB(推理+模型)

96.4 MB(模型)
CPU: 0.19 s

GPU: 0.12 s
96% 90% 84% 76% 529f9f9f19df05e826ad952b96bb975a__preview_type=16
线框 全精度 94.35 MB 450.4 MB(推理+模型)

256.4 MB(模型)
CPU: 1.14 s

GPU: 0.12 s
97% 93% 88% 84% b06191d4c3ef704537c8e299b4666031__preview_type=16 >=50精度下降 9%

>=80精度下降 22%

>=90精度下降 33%

>=95精度下降 43%
线框 结构化剪支 1.10 MB 366.4 MB(推理+模型)

96.4 MB(模型)
CPU: 0.18 s

GPU: 0.14 s
88% 71% 55% 41% 7a55acb3dae59a98c1d0b3e5151614e6__preview_type=16
  • CUDA推理已经很快了,剪支加速不明显,但是CPU推理加速显著
  • 剪支后的模型,CPU和GPU推理耗时差距不大
  • 剪支后的模型,纯CPU推理已经可以支持移动端的基线了

🐶流水线

GPU流水线,下游计算依赖上游计算 ==> 多二分类模型串行执行
02ceff0715512ebac5e90c69c5580868_4b866d67-238a-4cc7-80bb-9479c431aa6d

为了提升效率 ==> 并发执行多二分类模型,这导致了:

  • 卫星图户型已经命中,后续其他二分类户型模型仍继续推理
  • 并发模型队列为同一个队列,各个模型任务互相堵塞

优化项:

  • 队列隔离,每个队列对应一个二分类模型
  • 模型退场,比如卫星图户型已经命中,后续其他二分类户型模型不继续推理

原理:
并发安全的TTL缓存,模拟threadlocal,打标当前请求的模型推理结果,支撑模型退场

压测:
30并发,1w张样本进行测试

方案 显存 内存 准确率 耗时
单队列 45% 20.3% 6010/6413 14.27s
队列隔离+退场 50% 23.0% 6010/6413 11.34s

🐷缓存层

import hashlib
import io

from cachetools import TTLCache

# ttl: 过期时间,秒
model_cache = TTLCache(maxsize=10000, ttl=1 * 60 * 60)

def img_md5(pil_img):
    with io.BytesIO() as f:
        pil_img.save(f, format='PNG')  # 保存 PIL 图片对象为 PNG 格式的二进制数据
        image_data = f.getvalue()
        md5_hash = hashlib.md5(image_data).hexdigest()
        return md5_hash

def set_model_cache(md5,api_res):
    model_cache[md5]=api_res

def get_model_cache(md5):
    return model_cache.get(md5, None)

📹服务监控

02ceff0715512ebac5e90c69c5580868_4b866d67-238a-4cc7-80bb-9479c431aa6d-1716707782704

f8464d9db83b718c5756f3e9555b5b15_1b340972-b732-41a5-b3ff-fde8335c3cc8

📸OpenAPI

import json

import cv2
import numpy as np
from PIL import Image
import requests


API_BASE_URL = 'xxxxx'


def pred(pil_img, img_size=1024):
    cv_img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
    cv_img = cv2.resize(cv_img, (img_size, img_size))
    _, img_encoded = cv2.imencode('.jpg', cv_img)

    files = {'file': ('image.jpg', img_encoded.tobytes(), 'image/jpeg')}
    body = {'task_types': 'satellite,photo,wireframe,white',}

    response = requests.post(API_BASE_URL,data=body, files=files)
    res = json.loads(response.content)
    return res


if __name__ == '__main__':
    # 替换本地的img_path
    print(f'户型分类预测结果: {pred(Image.open(f"img/1.jpg"))["apartment_class"]}')
    print(f'户型分类预测结果: {pred(Image.open(f"img/2.png"))["apartment_class"]}')

😡并发模型压测

日访问量太低,完全不需要太担心并发压力

  • 并发度6,对应6个小二分类模型
  • warm_up.lua
wrk.method = "POST"
wrk.body = ""
wrk.headers["Content-Type"] = "application/json"
thread_num=10
connection_num=10
duration='60s'
timeout='10s'
wrk -t${thread_num} -c${connection_num} -d${duration} --latency --timeout ${timeout} --script=warm_up.lua http://127.0.0.1:3872/warm_up

全精度压测结果

Running 1m test @ http://127.0.0.1:3872/warm_up
  10 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.69s   837.16ms   6.35s    94.00%
    Req/Sec     0.00      0.00     0.00    100.00%
  Latency Distribution
     50%    5.90s
     75%    5.95s
     90%    6.02s
     99%    6.35s
  100 requests in 1.00m, 63.77KB read
Requests/sec:      1.66
Transfer/sec:      1.06KB

INT8量化压测结果

Running 1m test @ http://127.0.0.1:3872/warm_up
  10 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    13.40s     3.02s   15.77s    87.18%
    Req/Sec     0.00      0.00     0.00    100.00%
  Latency Distribution
     50%   14.59s
     75%   15.07s
     90%   15.16s
     99%   15.77s
  39 requests in 1.00m, 22.27KB read
Requests/sec:      0.65
Transfer/sec:     379.38B

WSGI全精度压测结果

不用wrk是因为接口请求要塞图片,比较麻烦,我自己起了脚本去调30并发的接口请求
30并发

  • 不建议一个进程内太多线程,争抢,本质上这个接口是计算密集服务,不是IO密集服务
  • 太多线程,会导致大量Tensor放置在显存中!且内存也会大量占用
base='/macc/apartment_class'
cd $base
rm -rf $base/log.txt
rm -rf $base/error_log.txt
ps -aux | grep apartment_class_main:app | awk '{print $2}' | xargs kill -9


# 由于GIL锁存在,本质上模型服务的最大并发 = 进程数
# 单个进程中,一个时间片下,预测代码(model(input))的运行当且仅当只有一个线程可执行
# 即显存占用 = (torch占用 + [model占用 + Tensor占用]) * 进程数
# 其中,model占用、Tensor占用可以显式进行卸载
worker_num=4
thread_num=1
port=3872
echo '=============== 进程数 $worker_num ==============='
echo '=============== 线程数 $thread_num ==============='
echo '=============== 监听端口     $port ==============='
$base/env/bin/gunicorn --workers=${worker_num} --threads=${thread_num} --daemon --access-logfile=$base/log.txt --error-logfile=$base/error_log.txt -b=0.0.0.0:$port apartment_class_main:app

3进程1线程

8772dcdbce2e2ba4e020f57b47d2efb2_380aac95-63ee-4793-8f11-ca3976a7c0f4
cc40c98208e7dc5104f0b32bcf7f5705_28f251ad-e4df-4051-a054-c4c094ce9cf0

4进程1线程

67e1de6efd16414b3a394f3d169eaf03_050c2a1d-050e-4de2-9461-ff6299f67e2e
51add1590684d5e41d3de1b01fa686f6_03fdf9b3-4343-4b7c-b3ca-f0d3a2f27032

5进程1线程

c267ce1dbc869b02804c4a4fc14617ff_5de5a50a-623e-4d9a-8ed5-026c48d39b85
c490242e2db2485a7b03aea98dee5a35_e68fd78e-26ef-4bd2-adc0-2f9a30fbfb02

0

评论区