2024年10月

今天是2024年10月24日,是第15个程序员节,祝大家节日快乐!

将每年的10月24日作为程序员节,是2010年在园子里发起的(详见
博文
),然后逐步被越来越多人认同,于是就有了这样一个属于开发者的节日。

从2010年到2024年的这十五年,移动互联网与云计算的两波浪潮让开发者队伍飞速壮大,在开发人才紧缺的年代,对开发者来说,只要代码功夫深,遍地是黄金,于是很多开发者如饥似渴地学习,尽情地在网上分享与交流,园子的发展过程就见证了开发者成长的燃情岁月。

但最近几年,随着昔日的浪潮退去,新的浪潮还没落地之际,兵强码壮、浩浩荡荡的开发者队伍却出现了焦虑,一边开发人才开始出现过剩,一边越来越多的日常开发工作将会被AI取代,很多开发者在担心,开发者的机会在哪里?开发者的未来在哪里?

为开发者服务、被开发者救活的园子已经和开发者的命运深深地绑定在一起,开发者的焦虑成为园子不得不且必须要面对的问题。在今天序员节,我们想对程序员们说,不必焦虑,未来依然可期。当你静下心来反思每天的开发工作,反思外人以为的高大上的软件开发行业的分工与协作方式,你也许会和我们有一样的想法——未来的软件开发肯定不会怎么繁琐、这么累、这么压抑开发者的创造力,只有解决了这些问题,开发者的黄金时代才真正到来。

在今年的程序员节,这个破园子,只能发篇简短的博文,在
闪存
上线几颗节日星,寒碜地庆祝一下。但我们希望大家不嫌弃现在这个百废待兴的破园子,希望大家和我们一起努力创造开发者的未来。

需求调研:发现身边的同事追踪业务代码的时候,如果遇见feign接口,大家都是通过全局搜url进一步找到远程服务的实现。一旦项目大起来,路径变得复杂甚至重名之后,这将会是灾难。

市面上并没有很好的IDEA插件支持feign接口的解析以及相对应的远程服务之间的跳转,因此本人([lyflexi](https://github.com/lyflexi))亲自做了一款插件FeignX,并开源出来给大家免费使用。

已上架idea插件市场:[https://plugins.jetbrains.com](https://plugins.jetbrains.com/) , 搜索FeignX下载安装:

FeignX的灵感来自IDEA的明星插件MybatisX。

FeignX插件基于实时扫描机制监控项目中的所有FeignClient和ApiController,并提供方法级导航跳转功能。

简而言之,您可以通过方法级导航按钮灵活地在FeignClient和远程服务ApiController之间来回切换。


FeignX is inspired by IDEA's star plugin MybatisX.

The FeignX plugin monitors all FeignClient and ApiController in the project based on real-time scanning mechanism, and provides method-level navigation jump capability.

In short, You can flexibly jump back and forth between FeignClient and remote service ApiController through method-level navigation buttons.

eg. feignClient -> ApiController

eg. ApiController -> feignClient

So, install the FeignX plugin as soon as possible!.

开放源代码:[lyflexi/feignx-plugin: 插件开发:IDEA搜索FeignX](https://github.com/lyflexi/feignx-plugin) 觉得好用多多给⭐支持!

在企业级 Web 开发中,
MySQL 优化
是至关重要的,它直接影响系统的响应速度、可扩展性和整体性能。下面从不同角度,列出详细的 MySQL 优化技巧,涵盖查询优化、索引设计、表结构设计、配置调整等方面。

一、查询优化

1.
合理使用索引

  • 单列索引
    :为查询频繁的字段(如
    WHERE

    ORDER BY

    GROUP BY
    中的字段)创建单列索引。
  • 组合索引
    :对于涉及多列条件的查询,建议使用组合索引。注意组合索引的顺序(最左前缀匹配原则)。
  • 覆盖索引
    :确保查询的字段全部被索引覆盖,这样 MySQL 可以直接从索引中获取数据,而无需访问表数据。
  • 避免过度索引
    :过多的索引会增加写操作的开销,如
    INSERT

    UPDATE

    DELETE
    操作,因为每次都要维护索引。

2.
优化查询语句

  • 避免使用
    SELECT \*

    :明确选择需要的字段,避免多余的字段查询,减小数据传输量。
  • 避免在
    WHERE
    条件中对字段进行函数操作

    :如
    WHERE YEAR(date_column) = 2023
    ,这种操作会使索引失效,改为
    WHERE date_column >= '2023-01-01' AND date_column < '2024-01-01'
  • 避免在
    WHERE
    条件中使用
    OR


    OR
    会导致全表扫描,尽量使用
    IN
    或分解查询。
  • 尽量减少子查询
    :使用
    JOIN
    替代子查询。子查询会在嵌套时频繁执行,每次可能都会导致重新扫描表。
  • 合理使用
    JOIN

    :如果有多表关联查询,确保关联的字段有索引,且表连接顺序要优化(小表驱动大表)。

3.
分页查询优化

  • 大数据分页
    :对于数据量非常大的分页查询,可以避免
    LIMIT offset
    方式,而是通过索引定位起始位置,例如
    WHERE id > last_seen_id LIMIT 10
  • 减少数据扫描量
    :分页时不要
    SELECT *
    ,只选择主键字段返回结果后再根据主键查询详细信息。

4.
合理使用临时表和缓存

  • 复杂查询
    :对于复杂查询,可以先查询并存储到临时表中,再进行进一步查询操作,减少重复计算。
  • 缓存机制
    :在应用层或数据库层(如使用 Redis、Memcached)对频繁访问的数据做缓存,避免每次都查询数据库。

5.
避免死锁和锁等待

  • 减少锁范围
    :尽量让锁的范围小(如只锁定必要的行),避免表锁的使用。
  • 减少事务执行时间
    :事务越长,锁定的资源时间越长,容易导致锁等待甚至死锁。尽量减少事务中的查询或更新操作时间。


二、索引优化

1.
主键和唯一索引的合理使用

  • 主键索引
    :选择唯一且不变的字段作为主键,尽量使用自增整数主键,避免使用长字符串主键。
  • 唯一索引
    :在不允许重复值的字段上(如用户名、邮箱等)创建唯一索引,避免重复数据的插入。

2.
覆盖索引

  • 减少回表操作
    :对于查询涉及的字段全部在索引中时,MySQL 可以直接通过索引返回结果,避免回表查询。

3.
前缀索引

  • 长字符串字段的索引
    :对 VARCHAR 等长字符串类型字段建立索引时,可以使用前缀索引(如
    CREATE INDEX idx_name ON users(name(10))
    ),通过截取前几位字符来节省索引空间。

4.
避免冗余索引

  • 避免重复索引
    :例如已经有
    (a, b)
    组合索引时,不需要再单独给
    a
    建索引。
  • 索引维护
    :定期检查无用的索引(使用
    SHOW INDEX FROM table_name
    )并删除,减少索引维护的开销。


三、表结构设计优化

1.
合理的表字段设计

  • 数据类型选择
    :选择最小且足够的字段类型。比如
    INT(11)
    占用 4 字节,如果值范围较小,可以使用
    TINYINT
    (1 字节)、
    SMALLINT
    (2 字节)来节省空间。
  • 使用
    VARCHAR
    而非
    CHAR


    CHAR
    为定长,存储固定长度字符会造成空间浪费,而
    VARCHAR
    为变长,适合存储不确定长度的字符串。
  • 避免使用 BLOB 和 TEXT 类型
    :大字段会造成性能问题,尽量将大文件或大数据放在文件系统中,数据库中仅存储文件路径。

2.
表分区

  • 水平分表
    :当表数据量过大(如上亿条记录)时,可以将表进行水平拆分,比如按照时间、用户ID等进行分表,减小单个表的大小。
  • 分区表
    :MySQL 提供表分区功能,可以根据数据范围将数据划分到不同的物理分区,优化大表查询性能。

3.
表规范化和反规范化

  • 表规范化
    :将数据分离到多个表中,避免数据冗余。数据量少时,范式化设计更易于维护。
  • 反规范化
    :当查询性能成为瓶颈时,可以考虑反规范化,增加冗余字段减少表的关联查询。


四、事务和锁机制优化

1.
减少锁竞争

  • 行锁优先
    :尽量避免使用锁范围更大的表锁,MySQL 的 InnoDB 引擎支持行锁,保证并发性。
  • 分批提交
    :批量操作数据时,可以将操作拆分成多个小批次提交,减少长时间锁持有。

2.
合理使用事务

  • 尽量减少事务时间
    :事务应尽可能短,避免长时间持有锁,导致资源被其他事务等待。
  • 事务隔离级别选择
    :根据业务需求选择合适的隔离级别,较高的隔离级别如
    SERIALIZABLE
    会有更多的锁定开销,常用的是
    REPEATABLE READ

3.
使用乐观锁

  • 应用层乐观锁
    :对于并发更新的业务场景,可以在应用层使用版本号控制(乐观锁)来避免锁冲突。


五、配置优化

1.
调整 InnoDB Buffer Pool

  • Buffer Pool 的大小
    :InnoDB 的 Buffer Pool 用于缓存数据和索引,配置合理的缓存大小是优化 MySQL 性能的关键之一。建议 Buffer Pool 设置为物理内存的 70-80%。

    innodb_buffer_pool_size = 4G  # 根据内存大小调整
    

2.
查询缓存(Query Cache)

  • 关闭查询缓存
    :在 MySQL 5.7 及以后的版本,查询缓存功能逐渐被弃用,因为它在高并发场景下容易成为瓶颈。因此,建议将其关闭。

    query_cache_type = 0
    

3.
线程池优化

  • 调整连接线程
    :对于高并发的业务场景,可以调整 MySQL 的最大连接数(
    max_connections
    )和每个连接线程的最大数量。

    max_connections = 500
    

4.
磁盘 I/O 优化

  • 调整 innodb_flush_log_at_trx_commit

    innodb_flush_log_at_trx_commit
    控制日志何时写入磁盘。设置为
    2
    时,可以降低磁盘 I/O,提升性能,但会稍微增加数据丢失的风险。

    innodb_flush_log_at_trx_commit = 2
    

5.
调整日志文件大小

  • 设置合适的 redo log 大小

    innodb_log_file_size
    配置 redo log 文件大小,建议根据写操作的频率和磁盘情况设置适合的大小,过小的 redo log 会频繁触发检查点,影响性能。

    innodb_log_file_size = 512M
    

6.
调整连接超时

  • 避免无效连接长时间占用
    :可以设置 MySQL 的连接超时参数,避免连接长时间闲置,造成资源浪费。

    wait_timeout = 600
    interactive_timeout = 600
    


六、监控与调优

1.
使用
EXPLAIN
分析查询

  • EXPLAIN
    分析执行计划

    :通过
    EXPLAIN
    命令分析查询的执行计划,检查是否使用索引、扫描的行数等,优化 SQL 查询。

    EXPLAIN SELECT * FROM users WHERE name = 'Alice';
    

2.
慢查询日志

  • 开启慢查询日志
    :通过慢查询日志可以监控哪些查询执行时间过长,帮助定位性能瓶颈。

    slow_query_log = 1
    long_query_time = 2  # 设置为超过2秒的查询记录到日志
    

3.
数据库性能监控

  • MySQL Enterprise Monitor 或其他监控工具
    :使用监控工具跟踪数据库的整体性能指标,如 CPU、I/O、内存使用情况、查询响应时间、锁等待等,便于及时发现问题。


七、总结

MySQL 的性能优化需要从多个层面进行综合考虑:
查询优化

索引设计

表结构设计

事务控制

配置调优
等。在企业级 Web 开发中,不同业务场景下的优化需求有所差异,通常需要结合业务的实际需求做出合适的权衡。通过持续监控与调优,可以让 MySQL 数据库在高并发、大数据量的场景中保持高效稳定的性能。

来不及拥抱清晨,就已经手握黄昏。曾经的我苦苦找寻这份答案,如今已工作8年,已经是30岁的程序员了。时光流逝,白驹过隙,留给八年前的自己的答案。

说明

该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。

该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。

说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。

友情提醒:本篇文章是属于系列文章,看该文章前,建议先看之前文章,可以更好理解项目结构。

有兴趣的朋友,请关注我吧(*^▽^*)。

关注我,学不会你来打我

废话文学

震惊!什么?你还不会使用Vue3+Element Plus搭建前端框架?

什么?你还在为找Vue3+Element Plus的前端框架模板而烦恼?

简单的不符合心意,成熟的又复杂看不懂?怎么办?

那还等什么,关注我,手把手教你搭建自己的前端模板。

创建项目,前置条件

安装VsCode

安装脚手架:npm install -g @vue/cli  我的版本v5.0.8

安装node.js(下载地址):
点击下载
我用的版本v21.7.3

创建Vue3项目

打开vsCode,在终端中切换创建项目路径(如果不切换,默认安装在C:\Users\admin):如:cd  E:\Vue项目

使用vue create xxx命令创建项目,
这里需要注意的是,项目名称中,不能包含大写字母

如下图所示

这里我们直接选择:使用Vue3安装,当然你也可以选择手动选择功能。

安装成功后,我们打开项目。

可以看到,新建项目的目录结构,非常简单明了。我们使用命令,运行看下效果

运行命令:npm run serve

默认项目样式

出现如下界面,证明我们创建项目成功。

安装Element Plus

--使用npm

npm install element-plus --save

--使用

yarn add element-plus

--使用

pnpm install element-plus

安装成功后,我们在main中配置全局变量

import { createApp } from 'vue'import Appfrom './App.vue'import ElementPlusfrom 'element-plus'import'element-plus/dist/index.css'

const app =createApp(App)
app.use(ElementPlus)
app.mount(
'#app')

安装小图标:npm install @element-plus/icons-vue

全局配置:

import { createApp } from 'vue'import Appfrom './App.vue'import ElementPlusfrom 'element-plus'import'element-plus/dist/index.css'import* as Icons from '@element-plus/icons-vue'

const app =createApp(App)
app.use(ElementPlus)
for (const[key, component] of Object.entries(Icons)) {
app.component(key, component)
}
app.mount(
'#app')

安装Typescript :npm install  --save-dev typescript ts-loader

把js文件转成ts: vue add typescript

说明下:因为element plus 官方用例也是使用ts,所以我们需要把js转换成ts

添加tsconfig.json配置文件,示例如下(不然使用ts会报错)

{"compilerOptions": {"target": "esnext","module": "esnext","strict": true,"jsx": "preserve","moduleResolution": "node","experimentalDecorators": true,"allowJs": true,"skipLibCheck": true,"esModuleInterop": true,"allowSyntheticDefaultImports": true,"forceConsistentCasingInFileNames": true,"useDefineForClassFields": true,"sourceMap": true,"baseUrl": ".","types": ["webpack-env"],"paths": {"@/*": ["src/*"]
},
"lib": ["esnext","dom","dom.iterable","scripthost"]
},
"include": ["src/**/*.ts","src/**/*.tsx","src/**/*.vue","tests/**/*.ts","tests/**/*.tsx"],"exclude": ["node_modules"]
}

做完以上操作后,我们vue项目的基本结构如下图

测试Element Plus

做好以上步骤,我们vue3+Element Plus搭建项目的基本模板已经创建好,接下来测试Element Plus是否可以使用

这里我选择使用Element Plus 中的Menu组件,因为接下来我们会使用Menu做系统菜单

找到系统默认生成的HelloWorld.vue文件,用如下代码替换里面的代码

<template>
      <el-menu
active
-text-color="#ffd04b"background-color="#545c64" class="el-menu-vertical-demo" default-active="2"text-color="#fff" > <el-sub-menu index="1"> <template #title> <el-icon><location /></el-icon> <span>Navigator One</span> </template> <el-menu-item-group title="Group One"> <el-menu-item index="1-1">item one</el-menu-item> <el-menu-item index="1-2">item two</el-menu-item> </el-menu-item-group> <el-menu-item-group title="Group Two"> <el-menu-item index="1-3">item three</el-menu-item> </el-menu-item-group> <el-sub-menu index="1-4"> <template #title>item four</template> <el-menu-item index="1-4-1">item one</el-menu-item> </el-sub-menu> </el-sub-menu> <el-menu-item index="2"> <el-icon><icon-menu /></el-icon> <span>Navigator Two</span> </el-menu-item> <el-menu-item index="3" disabled> <el-icon><document /></el-icon> <span>Navigator Three</span> </el-menu-item> <el-menu-item index="4"> <el-icon><setting /></el-icon> <span>Navigator Four</span> </el-menu-item> </el-menu> </template> <script lang="ts">import { defineComponent }from "vue";

export
defaultdefineComponent({
setup() {
},
components: {},
});
</script>

该代码,基本和官网的示例一致。是构建一个Menu导航菜单

然后再找到App.vue文件,用如下代码替换里面代码

<template>
  <HelloWorld />
</template>

<script lang="ts">import { defineComponent }from "vue";
import HelloWorld
from "./components/HelloWorld.vue"exportdefaultdefineComponent({
setup() {
},
components: {HelloWorld},
});
</script> <style>#app {
font
-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
text
-align: center;
color: #2c3e50;
margin
-top: 60px;
}
</style>

做好以上步骤后,我们使用npm run serve命令,启动项目

出下如下界面,证明项目创建成功

搭建框架

安装好Element Plus后,我们就要使用它来搭建框架

使用Element Plus的布局组件container+菜单组件Menu,来搭建框架。

这里是写样式布局,没有啥好说的,直接上代码

HelloWorld.vue 代码如下

<template>
  <div style="height: calc(100vh); overflow: hidden">
    <el-container style="height: 100%; overflow: hidden">
      <el-aside width="auto">
        <el-menuclass="el-menu-vertical-demo"background-color="#545c64"text-color="#fff"active-text-color="#ffd04b"style="height: 100%"
        >
        <div class="el-menu-box">
            <divclass="logo-image"style="width: 18px; height: 18px; background-size: 18px 18px"
            ></div>
            <div style="padding-left: 5px; padding-top: 7px">OverallAuth2.0
            </div>
          </div>
          <el-sub-menu index="1">
            <template #title>
              <el-icon><location /></el-icon>
              <span>Navigator One</span>
            </template>
            <el-menu-item-group title="Group One">
              <el-menu-item index="1-1">item one</el-menu-item>
              <el-menu-item index="1-2">item two</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="Group Two">
              <el-menu-item index="1-3">item three</el-menu-item>
            </el-menu-item-group>
            <el-sub-menu index="1-4">
              <template #title>item four</template>
              <el-menu-item index="1-4-1">item one</el-menu-item>
            </el-sub-menu>
          </el-sub-menu>
          <el-menu-item index="2">
            <el-icon><icon-menu /></el-icon>
            <span>Navigator Two</span>
          </el-menu-item>
          <el-menu-item index="3" disabled>
            <el-icon><document /></el-icon>
            <span>Navigator Three</span>
          </el-menu-item>
          <el-menu-item index="4">
            <el-icon><setting /></el-icon>
            <span>Navigator Four</span>
          </el-menu-item>
        </el-menu>
      </el-aside>

      <el-container>
        <el-header class="headerCss">
          <div style="display: flex; height: 100%; align-items: center">
            <div
style
=" text-align: left;
width:
50%;
font
-size: 18px;
display: flex;
" > <div class="logo-image" style="width: 32px; height: 32px"></div> <div style="padding-left: 10px; padding-top: 7px">OverallAuth2.0权限管理系统</div> </div> <div
style
=" text-align: right;
width:
50%;
display: flex;
justify
-content: right;
cursor: pointer;
" > <divclass="user-image"style="width: 22px; height: 22px; background-size: 22px 22px" ></div> <div style="padding-left: 5px; padding-top: 3px">王小虎</div> </div> </div> </el-header> <el-main class="el-main">欢迎</el-main> </el-container> </el-container> </div> </template> <script lang="ts">import { defineComponent }from "vue";

export
defaultdefineComponent({
setup() {},
components: {},
});
</script> <style scoped>.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min
-height: 400px;
}
.el
-menu-box {
display: flex;
padding
-left: 25px;
align
-items: center;
height: 57px;
box
-shadow: 0 1px 4px #00152914;
border: 1px solid #
00152914;
color: white;
}
.el
-main {
padding
-top: 0px;
padding
-left: 1px;
padding
-right: 1px;
margin:
0;
}
.headerCss {
font
-size: 12px;
border: 1px solid #
00152914;
box
-shadow: 0 1px 4px #00152914;
justify
-content: right;
align
-items: center;/*display: flex;*/}
.logo
-image {
background
-image: url("../components/权限分配.png");
}
.user
-image {
background
-image: url("../components/用户.png");
}
.demo
-tabs /deep/ .el-tabs__header {
color: #
333; /*标签页头部字体颜色*/margin:0 0 5px !important;
}
.demo
-tabs /deep/ .el-tabs__nav-wrap {
padding
-left: 10px;
}
</style>

App.vue 代码如下

<template>
  <HelloWorld />
</template>

<script lang="ts">import { defineComponent }from "vue";
import HelloWorld
from "./components/HelloWorld.vue"exportdefaultdefineComponent({
setup() {
},
components: {HelloWorld},
});
</script> <style>#app {
font
-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
text
-align: center;
color: #2c3e50;
/*margin-top: 60px;*/}
html,
body,
#app {
height:
100%;
margin:
0;
padding:
0;
}
</style>

ps:页面中的图标,可以用任何小图标替换(也可以删除)。

运行项目

下一篇:Vue3菜单和路由的结合使用

后端WebApi
预览地址:http://139.155.137.144:8880/swagger/index.html

前端vue 预览地址:http://139.155.137.144:8881

关注公众号:发送【权限】,获取前后端代码

有兴趣的朋友,请关注我微信公众号吧(*^▽^*)。

关注我:一个全栈多端的宝藏博主,定时分享技术文章,不定时分享开源项目。关注我,带你认识不一样的程序世界

CleanVision是一个开源的Python库,旨在帮助用户自动检测图像数据集中可能影响机器学习项目的常见问题。该库被设计为计算机视觉项目的初步工具,以便在应用机器学习之前发现并解决数据集中的问题。CleanVision的核心功能包括检测完全重复、近似重复、模糊、低信息量、过暗、过亮、灰度、不规则长宽比和尺寸异常等问题图片。CleanVision开源仓库地址为:
CleanVision
,官方文档地址为:
CleanVision-docs

CleanVision基础版安装命令如下:

pip install cleanvision

完整版安装命令如下:

pip install "cleanvision[all]"

查看CleanVision版本:

# 查看版本
import cleanvision
cleanvision.__version__
'0.3.6'

本文代码必要库版本:

# 用于表格显示
import tabulate
# tabulate版本需要0.8.10以上
tabulate.__version__
'0.9.0'

1 使用说明

1.1 CleanVision功能介绍

CleanVision支持多种
格式
的图像文件,并能检测以下类型的数据问题:

示例图片 问题类型 描述 关键字
完全重复 完全相同的图像 exact_duplicates
近似重复 视觉上几乎相同的图像 near_duplicates
模糊 图像细节模糊(焦点不实) blurry
信息量低 缺乏内容的图像(像素值的熵很小) low_information
过暗 不规则的暗图像(曝光不足) dark
过亮 不规则的亮图像(曝光过度) light
灰度 缺乏颜色的图像 grayscale
异常宽高比 宽高比异常的图像 odd_aspect_ratio
异常大小 相比数据集中其他图像,尺寸异常的图像 odd_size

上表中,CleanVision针对这些问题的检测主要依赖于多种统计方法,其中关键字列表用于指定CleanVision代码中每种问题类型的名称。CleanVision兼容Linux、macOS和Windows系统,可在Python 3.7及以上版本的环境中运行。

1.2 基础使用

本节介绍如何读取文件夹中的图片以进行问题检测。以下示例展示了对一个包含607张图片的文件夹进行质量检测的过程。在检测过程中,CleanVision将自动加载多进程以加快处理速度:

基础使用

from cleanvision import Imagelab

# 示例数据:https://cleanlab-public.s3.amazonaws.com/CleanVision/image_files.zip
# 读取示例图片
dataset_path = "./image_files/"

# 实例化Imagelab类,以用于后续处理
imagelab = Imagelab(data_path=dataset_path)

# 使用multiprocessing进行多进程处理,n_jobs设置进程数
# n_jobs默认为None,表示自动确定进程数
# 处理时会先检测每张图片的image_property(图像质量)
# 等所有图片处理完后,再检测duplicate(重复)
imagelab.find_issues(verbose=False, n_jobs=2)
Reading images from D:/cleanvision/image_files

如果在Windows系统上运行CleanVision代码,需要将相关代码放入main函数中,以便正确加载multiprocessing模块。当然,也可以将n_jobs设置为1,以使用单进程:

from cleanvision import Imagelab

if '__main__' == __name__:
    # 示例数据:https://cleanlab-public.s3.amazonaws.com/CleanVision/image_files.zip
    # 读取示例图片
    dataset_path = "./image_files/"
    imagelab = Imagelab(data_path=dataset_path)
    imagelab.find_issues(verbose=False)
Reading images from D:/cleanvision/image_files

基于report函数,能够报告数据集中每种问题类型的图像数量,并展示每种问题类型中最严重实例的图像:

imagelab.report()
Issues found in images in order of severity in the dataset

|    | issue_type       |   num_images |
|---:|:-----------------|-------------:|
|  0 | odd_size         |          109 |
|  1 | grayscale        |           20 |
|  2 | near_duplicates  |           20 |
|  3 | exact_duplicates |           19 |
|  4 | odd_aspect_ratio |           11 |
|  5 | dark             |           10 |
|  6 | blurry           |            6 |
|  7 | light            |            5 |
|  8 | low_information  |            5 | 

--------------------- odd_size images ----------------------

Number of examples with this issue: 109
Examples representing most severe instances of this issue:

png

--------------------- grayscale images ---------------------

Number of examples with this issue: 20
Examples representing most severe instances of this issue:

png

------------------ near_duplicates images ------------------

Number of examples with this issue: 20
Examples representing most severe instances of this issue:

Set: 0

png

Set: 1

png

Set: 2

png

Set: 3

png

----------------- exact_duplicates images ------------------

Number of examples with this issue: 19
Examples representing most severe instances of this issue:

Set: 0

png

Set: 1

png

Set: 2

png

Set: 3

png

----------------- odd_aspect_ratio images ------------------

Number of examples with this issue: 11
Examples representing most severe instances of this issue:

png

----------------------- dark images ------------------------

Number of examples with this issue: 10
Examples representing most severe instances of this issue:

png

---------------------- blurry images -----------------------

Number of examples with this issue: 6
Examples representing most severe instances of this issue:

png

----------------------- light images -----------------------

Number of examples with this issue: 5
Examples representing most severe instances of this issue:

png

------------------ low_information images ------------------

Number of examples with this issue: 5
Examples representing most severe instances of this issue:

png

如果想创建自定义的问题识别类型,可以参考:
custom_issue_manager

与数据结果交互的主要方式是通过Imagelab类。此类可用于在宏观层面(全局概览)和微观层面(每张图片的问题和质量评分)了解数据集中的问题。它包含三个主要属性:

  • Imagelab.issue_summary:问题摘要
  • Imagelab.issues:问题列表
  • Imagelab.info:数据集信息,包括相似图片信息

问题结果分析

通过issue_summary属性可以展示数据集中不同问题类别的图像数量:

# 返回结果为pandas的dataframe
res = imagelab.issue_summary
type(res)
pandas.core.frame.DataFrame

查看汇总结果:

res
issue_type num_images
0 odd_size 109
1 grayscale 20
2 near_duplicates 20
3 exact_duplicates 19
4 odd_aspect_ratio 11
5 dark 10
6 blurry 6
7 light 5
8 low_information 5

通过issues属性,可以展示每张图片中各种问题的质量分数及其存在情况。这些质量分数的范围从0到1,较低的分数表示问题的严重性更高:

imagelab.issues.head()
odd_size_score is_odd_size_issue odd_aspect_ratio_score is_odd_aspect_ratio_issue low_information_score is_low_information_issue light_score is_light_issue grayscale_score is_grayscale_issue dark_score is_dark_issue blurry_score is_blurry_issue exact_duplicates_score is_exact_duplicates_issue near_duplicates_score is_near_duplicates_issue
D:/cleanvision/image_files/image_0.png 1.0 False 1.0 False 0.806332 False 0.925490 False 1 False 1.000000 False 0.980373 False 1.0 False 1.0 False
D:/cleanvision/image_files/image_1.png 1.0 False 1.0 False 0.923116 False 0.906609 False 1 False 0.990676 False 0.472314 False 1.0 False 1.0 False
D:/cleanvision/image_files/image_10.png 1.0 False 1.0 False 0.875129 False 0.995127 False 1 False 0.795937 False 0.470706 False 1.0 False 1.0 False
D:/cleanvision/image_files/image_100.png 1.0 False 1.0 False 0.916140 False 0.889762 False 1 False 0.827587 False 0.441195 False 1.0 False 1.0 False
D:/cleanvision/image_files/image_101.png 1.0 False 1.0 False 0.779338 False 0.960784 False 0 True 0.992157 False 0.507767 False 1.0 False 1.0 False

由于imagelab.issues返回的是Pandas的数据表格,因此可以对特定类型的数据进行筛选:

# 得分越小,越严重
dark_images = imagelab.issues[imagelab.issues["is_dark_issue"] == True].sort_values(
    by=["dark_score"]
)
dark_images_files = dark_images.index.tolist()
dark_images_files
['D:/cleanvision/image_files/image_417.png',
 'D:/cleanvision/image_files/image_350.png',
 'D:/cleanvision/image_files/image_605.png',
 'D:/cleanvision/image_files/image_177.png',
 'D:/cleanvision/image_files/image_346.png',
 'D:/cleanvision/image_files/image_198.png',
 'D:/cleanvision/image_files/image_204.png',
 'D:/cleanvision/image_files/image_485.png',
 'D:/cleanvision/image_files/image_457.png',
 'D:/cleanvision/image_files/image_576.png']

可视化其中的问题图片:

imagelab.visualize(image_files=dark_images_files[:4])

png

完成上述任务的更简洁方法是直接在imagelab.visualize函数中指定issue_types参数,这样可以直接显示某个问题下的图片,并按严重程度对其进行排序展示:

# issue_types:问题类型,num_images:显示图片数,cell_size:每个网格中图片尺寸
imagelab.visualize(issue_types=["low_information"], num_images=3, cell_size=(3, 3))

png

查看图片信息和相似图片

通过info属性可以查看数据集的信息:

# 查看存在的项目
imagelab.info.keys()
dict_keys(['statistics', 'dark', 'light', 'odd_aspect_ratio', 'low_information', 'blurry', 'grayscale', 'odd_size', 'exact_duplicates', 'near_duplicates'])
# 查看统计信息
imagelab.info["statistics"].keys()
dict_keys(['brightness', 'aspect_ratio', 'entropy', 'blurriness', 'color_space', 'size'])
# 查看数据集的统计信息
imagelab.info["statistics"]["size"]
count     607.000000
mean      280.830152
std       215.001908
min        32.000000
25%       256.000000
50%       256.000000
75%       256.000000
max      4666.050578
Name: size, dtype: float64

查看数据集中基本相似的图片个数:

imagelab.info["exact_duplicates"]["num_sets"]
9

查看数据集中近似的图片对:

imagelab.info["near_duplicates"]["sets"]
[['D:/cleanvision/image_files/image_103.png',
  'D:/cleanvision/image_files/image_408.png'],
 ['D:/cleanvision/image_files/image_109.png',
  'D:/cleanvision/image_files/image_329.png'],
 ['D:/cleanvision/image_files/image_119.png',
  'D:/cleanvision/image_files/image_250.png'],
 ['D:/cleanvision/image_files/image_140.png',
  'D:/cleanvision/image_files/image_538.png'],
 ['D:/cleanvision/image_files/image_25.png',
  'D:/cleanvision/image_files/image_357.png'],
 ['D:/cleanvision/image_files/image_255.png',
  'D:/cleanvision/image_files/image_43.png'],
 ['D:/cleanvision/image_files/image_263.png',
  'D:/cleanvision/image_files/image_486.png'],
 ['D:/cleanvision/image_files/image_3.png',
  'D:/cleanvision/image_files/image_64.png'],
 ['D:/cleanvision/image_files/image_389.png',
  'D:/cleanvision/image_files/image_426.png'],
 ['D:/cleanvision/image_files/image_52.png',
  'D:/cleanvision/image_files/image_66.png']]

1.3 自定义检测

指定检测类型

from cleanvision import Imagelab

# 示例数据:https://cleanlab-public.s3.amazonaws.com/CleanVision/image_files.zip
dataset_path = "./image_files/"

# 指定检测类型
issue_types = {"blurry":{}, "dark": {}}

imagelab = Imagelab(data_path=dataset_path)

imagelab.find_issues(issue_types=issue_types, verbose=False)
imagelab.report()
Reading images from D:/cleanvision/image_files


Issues found in images in order of severity in the dataset

|    | issue_type   |   num_images |
|---:|:-------------|-------------:|
|  0 | dark         |           10 |
|  1 | blurry       |            6 | 

----------------------- dark images ------------------------

Number of examples with this issue: 10
Examples representing most severe instances of this issue:

png

---------------------- blurry images -----------------------

Number of examples with this issue: 6
Examples representing most severe instances of this issue:

png

如果已经运行过find_issues函数,再次运行该函数时如果添加新的检测类型,当前结果将会与上一次的结果合并:

issue_types = {"light": {}}
imagelab.find_issues(issue_types)
# 报告三个类型的结果
imagelab.report()
Checking for light images ...
Issue checks completed. 21 issues found in the dataset. To see a detailed report of issues found, use imagelab.report().
Issues found in images in order of severity in the dataset

|    | issue_type   |   num_images |
|---:|:-------------|-------------:|
|  0 | dark         |           10 |
|  1 | blurry       |            6 |
|  2 | light        |            5 | 

----------------------- dark images ------------------------

Number of examples with this issue: 10
Examples representing most severe instances of this issue:

png

---------------------- blurry images -----------------------

Number of examples with this issue: 6
Examples representing most severe instances of this issue:

png

----------------------- light images -----------------------

Number of examples with this issue: 5
Examples representing most severe instances of this issue:

png

结果保存

以下代码展示了如何保存和加载结果,但加载结果时,数据路径和数据集必须与保存时保持一致:

save_path = "./results"
# 保存结果
# force表示是否覆盖原文件
imagelab.save(save_path, force=True)
# 加载结果
imagelab = Imagelab.load(save_path, dataset_path)
Successfully loaded Imagelab

阈值设置

CleanVision通过阈值控制来确定各种检测结果,其中exact_duplicates和near_duplicates是基于图像哈希(由
imagehash
库提供)进行检测的,而其他类型的检测则采用范围为0到1的阈值来控制结果。如果图片在某一问题类型上的得分低于设定的阈值,则认为该图片存在该问题;阈值越高,判定为存在该问题的可能性越大。如下所示:

关键字 超参数
1 light threshold
2 dark threshold
3 odd_aspect_ratio threshold
4 exact_duplicates N/A
5 near_duplicates hash_size(int),hash_types(whash,phash,ahash,dhash,chash)
6 blurry threshold
7 grayscale threshold
8 low_information threshold

对于单一检测类型,阈值设置代码如下:

imagelab = Imagelab(data_path=dataset_path)
issue_types = {"dark": {"threshold": 0.5}}
imagelab.find_issues(issue_types)

imagelab.report()
Reading images from D:/cleanvision/image_files
Checking for dark images ...

Issue checks completed. 20 issues found in the dataset. To see a detailed report of issues found, use imagelab.report().
Issues found in images in order of severity in the dataset

|    | issue_type   |   num_images |
|---:|:-------------|-------------:|
|  0 | dark         |           20 | 

----------------------- dark images ------------------------

Number of examples with this issue: 20
Examples representing most severe instances of this issue:

png

如果某类问题的存在是正常的,例如天文数据集中普遍图像过暗的情况,那么可以设置一个最大出现率(max_prevalence)。这意味着如果某一问题的图像所占比例超过了max_prevalence,则可以认为该问题是正常的。以上示例中,dark问题的图像数量为10,图像总数为607,因此dark问题的图像占比约为0.016。如果将max_prevalence设置为0.015,那么出现dark问题的图片将不会被报告为dark问题:

imagelab.report(max_prevalence=0.015)
Removing dark from potential issues in the dataset as it exceeds max_prevalence=0.015 
Please specify some issue_types to check for in imagelab.find_issues().

1.4 在Torchvision数据集上运行CleanVision

CleanVision支持使用Torchvision数据集进行问题检测,具体代码如下:

准备数据集

from torchvision.datasets import CIFAR10
from torch.utils.data import ConcatDataset
from cleanvision import Imagelab

# 准备torchvision中的CIFAR10数据集
train_set = CIFAR10(root="./", download=True)
test_set = CIFAR10(root="./", train=False, download=True)
Files already downloaded and verified
Files already downloaded and verified
# 查看训练集和测试集样本数
len(train_set), len(test_set)
(50000, 10000)

如果想对训练集和测试集进行合并处理,可以使用如下代码:

dataset = ConcatDataset([train_set, test_set])
len(dataset)
60000

查看图片:

dataset[0][0]

png

运行CleanVision

只需在创建Imagelab示例时指定torchvision_dataset参数,即可对Torchvision数据集进行操作,后续的处理步骤与读取文件夹中图片的处理方式相同:

imagelab = Imagelab(torchvision_dataset=dataset)
imagelab.find_issues()
# 查看结果
# imagelab.report()
Checking for dark, light, odd_aspect_ratio, low_information, exact_duplicates, near_duplicates, blurry, grayscale, odd_size images ...

Issue checks completed. 173 issues found in the dataset. To see a detailed report of issues found, use imagelab.report().
# 结果汇总
imagelab.issue_summary
issue_type num_images
0 blurry 118
1 near_duplicates 40
2 dark 11
3 light 3
4 low_information 1
5 grayscale 0
6 odd_aspect_ratio 0
7 odd_size 0
8 exact_duplicates 0

1.5 在Hugging Face数据集上运行CleanVision

CleanVision支持基于Hugging Face数据集(如果能用的话)进行问题检测,代码如下:

# datasets是专门用于下载huggingface数据集的工具
from datasets import load_dataset
from cleanvision import Imagelab
# 以https://huggingface.co/datasets/mah91/cat为例
# 下载某个hugging face数据集,只需要将参数path设置为待下载链接datasets后的文字
# split表示提取train或test的数据,如果没有提供分割后的数据集则返回完整的数据
dataset = load_dataset(path="mah91/cat", split="train")
Repo card metadata block was not found. Setting CardData to empty.
# 查看数据集,可以看到该数据集有800张图片,只提供了图片没有注释。
dataset
Dataset({
    features: ['image'],
    num_rows: 800
})
# dataset.features包含数据集中不同列的信息以及每列的类型,例如图像,音频
dataset.features
{'image': Image(mode=None, decode=True, id=None)}

指定hf_dataset参数加载hugging face数据集:

# 加载数据至CleanVision,image_key指定包含'image'的数据
imagelab = Imagelab(hf_dataset=dataset, image_key="image")

进行检测的代码如下:

imagelab.find_issues()
# 结果汇总
imagelab.issue_summary
Checking for dark, light, odd_aspect_ratio, low_information, exact_duplicates, near_duplicates, blurry, grayscale, odd_size images ...

Issue checks completed. 4 issues found in the dataset. To see a detailed report of issues found, use imagelab.report().
issue_type num_images
0 blurry 3
1 odd_size 1
2 dark 0
3 grayscale 0
4 light 0
5 low_information 0
6 odd_aspect_ratio 0
7 exact_duplicates 0
8 near_duplicates 0

2 参考