wenmo8 发布的文章

基于像素级分类器的单图像超分辨率方法(
PCSR
)是一种针对大图像高效超分辨率的新方法,在像素级别分配计算资源,处理不同的恢复难度,并通过更精细的粒度减少冗余计算。它还在推断过程中提供可调节性,平衡性能和计算成本而无需重新训练。此外,还提供了使用K均值聚类进行自动像素分配以及后处理技术来消除伪影。

来源:晓飞的算法工程笔记 公众号

论文: Accelerating Image Super-Resolution Networks with Pixel-Level Classification

Introduction


单图像超分辨率(
SISR
)是一项专注于从低分辨率(
LR
)图像恢复高分辨率(
HR
)图像的任务。这一任务在数字摄影、医学成像、监控和安全等多个领域有广泛的实际应用。随着这些重要需求的增长,特别是在深度神经网络(
DNNs
)的推动下,
SISR
在过去几十年中取得了显著进展。

然而,随着新的
SISR
模型的推出,模型的容量和计算成本往往增加,这使得在具有有限资源的实际应用或设备中应用这些模型变得困难。因此,这导致了朝向设计更简单、高效的轻量级模型的转变,这些模型考虑了性能和计算成本之间的平衡。此外,还进行了大量研究,旨在减少现有模型的参数大小和/或浮点运算(
FLOPs
)数量,同时不影响其性能。

与此同时,对于高效的超分辨率(
SR
)技术的需求正在增加,尤其是随着为用户提供大规模图像的平台的兴起,例如先进的智能手机、高清电视或支持从
2K

8K
分辨率的专业显示器。然而,对大图像进行超分辨率处理是具有挑战性的;由于计算资源的限制,无法在单次处理中处理大图像(即每图像处理)。因此,处理大图像的常见方法是将给定的低分辨率(
LR
)图像分割成重叠的块,将超分辨率模型分别应用于每个块,然后合并输出以获得超分辨率图像。多项研究探讨了这种按块处理的方法,旨在提高现有模型的效率同时保持其性能。这些研究观察到,每个块的恢复难度各不相同,因此需要为每个块分配不同的计算资源。

尽管在块级别上自适应分配计算资源可以显著提高效率,但它存在两个限制可能阻碍其充分发挥更高效率的潜力:

  1. 由于超分辨率是一个低级视觉任务,即使是单个块也可能包含恢复难度不同的像素。当为包含简单像素的块分配大量计算资源时,可能会导致计算资源的浪费。相反,如果一个分配较少计算资源的块包含难处理的像素,会对性能产生负面影响。
  2. 这些所谓的块分配方法在较大块大小时效率降低,因为这些块更可能包含易处理和难处理像素的平衡混合。这引入了一个两难情境:我们可能希望使用较大的块,因为这不仅可以减少重叠区域中的冗余操作,还可以通过利用更多的上下文信息来增强性能。

本文的主要目标是增强现有的单幅图像超分辨率(
SISR
)模型的效率,特别是针对较大的图像。为了克服前述的块分配方法所面临的限制,论文提出了一种名为像素级分类器单幅图像超分辨率(
PCSR
)的新方法,专门设计用于在像素级别自适应分配计算资源。模型包括三个主要部分:骨干网络、像素级分类器和一组容量不同的像素级上采样器。该模型的运作如下:1)骨干网络接受低分辨率输入并生成低分辨率特征图。2)对于
HR
空间中的每个像素,像素级分类器使用低分辨率特征图和像素的相对位置预测将其分配给特定的上采样器的概率。3)每个像素都根据需要自适应地分配给适当大小的像素级上采样器来预测其
RGB
值。4)通过聚合每个像素的
RGB
值获得超分辨率输出。

这是首个在大图像高效
SR
背景下应用像素级分配方法的方法。通过像素级别地减少冗余计算,可以进一步提升块分配方法的效率,如图
1
所示。在推断阶段,为用户提供调节性,可以在不需要重新训练的情况下权衡性能和计算成本。虽然该方法使用户能够管理这种权衡,但论文还提供了一个额外的功能,根据
K-means
聚类算法自动分配像素,从而简化用户体验。最后,论文引入了一种后处理技术,有效消除可能由像素级计算分配引起的伪影。实验证明,论文的方法在多个基准测试中(包括
Test2K
/
4K
/
8K

Urban100
)在各种
SISR
模型的
PSNR-FLOP
权衡方面优于现有的块分配方法。论文还与基于每幅图像处理的方法进行了比较,后者是将图像作为整体而不是分解为块来处理。

Method


Preliminary

单图像超分辨率(
SISR
)是一项任务,旨在从单个低分辨率(
LR
)输入图像生成高分辨率(
HR
)图像。在神经网络的框架内,
SISR
模型旨在发现一个映射函数
\(F\)
,将给定的
LR
图像
\(I^{LR}\)
转换为
HR
图像
\(I^{HR}\)
。可以用以下方程表示:

\[\begin{equation}
I^{HR} = F(I^{LR}; \theta),
\end{equation}
\]

其中
\(\theta\)
是模型参数集合。典型模型可以分解为两个主要组件:1)从
\(I^{LR}\)
提取特征的骨干网络
\(B\)
,和2)利用这些特征重构
\(I^{HR}\)
的上采样器
\(U\)
。因此,这个过程可以进一步表示为:

\[\begin{align}
Z = B(I^{LR}; \theta_B), \quad
I^{HR} = U(Z; \theta_U).
\end{align}
\]

在这里,
\(\theta_B\)

\(\theta_U\)
分别是骨干网络和上采样器的参数,
\(Z\)
是提取的特征。在基于卷积神经网络(
CNN
)的上采样器中,除了卷积层之外,还会使用多种操作来增加正在处理的图像的分辨率。这些操作范围从简单的插值到更复杂的方法,如反卷积或子像素卷积。与使用基于
CNN
的上采样器不同,可以采用基于多层感知器(
MLP
)的上采样器以像素级方式操作。

Network Architecture

PCSR
的概述如图
3
所示,一个模型由一个骨干网络和一组上采样器组成。此外,使用一个分类器来衡量在高分辨率空间中恢复目标像素(即查询像素)的难度。低分辨率输入图像被送入骨干网络,并生成相应的低分辨率特征。然后,分类器确定每个查询像素的恢复难度,通过相应的上采样器计算其输出的
RGB
值。

  • Backbone

论文提出了一种像素级计算分布方法,用于高效的大图像超分辨率。可以使用任何现有的深度超分辨率网络作为骨干网络,以适应所需的模型大小。例如,可以采用小尺寸的
FSRCNN
,中等尺寸的
CARN
,大尺寸的
SRResNet
,以及其他模型。

  • Classifier

引入了一个基于
MLP
网络的轻量级分类器,以像素级方式获取属于每个上采样器(或类别)的概率。对于给定的查询像素坐标
\(x_q\)
,分类器根据分类概率将其分配给相应的上采样器,以预测其
RGB
值。通过将简单的像素适当地分配给轻量级上采样器而不是重型上采样器,可以在最小性能损失的情况下节省计算资源。

定义一个低分辨率输入为
\(X \in \mathbb{R}^{h \times w \times 3}\)
,其对应的高分辨率图像为
\(Y \in \mathbb{R}^{H \times W \times 3}\)
。设
\(\{y_i\}_{i=1...HW}\)
是高分辨率图像
\(Y\)
中每个像素的坐标,
\(\{Y(y_i)\}_{i=1...HW}\)
是相应的
RGB
值。首先,通过骨干网络从低分辨率输入计算出一个低分辨率特征
\(Z \in \mathbb{R}^{h \times w \times D}\)
。然后,给定类别数
\(M\)
,分类器
\(C\)
给出分类概率
\(p_i \in \mathbb{R}^M\)

\[\begin{equation}
p_i = \sigma(C(Z, y_i; \theta_C)),
\end{equation}
\]

其中,
\(\sigma\)

softmax
函数。基于
MLP
的分类器操作方式类似于一个上采样器,主要区别在于其输出维度为
\(M\)

  • Upsampler

采用
LIIF
作为上采样器,适用于像素级处理。首先,将先前定义的
\(y_i\)
从高分辨率空间归一化,将其映射到低分辨率空间中的坐标
\(\hat{y}_i \in \mathbb{R}^2\)
。给定低分辨率特征
\(Z\)
,将最接近
\(\hat{y}_i\)
(通过欧氏距离)的特征表示为
\(z_i^* \in \mathbb{R}^D\)
,并将其对应的坐标表示为
\(v_i^* \in \mathbb{R}^2\)
。然后,上采样过程总结如下:

\[\begin{align}
\label{eq:liif1}
I^{SR}(y_i) = U(Z, y_i ; \theta_U) = U([z_i^*, \hat{y}_i-v_i^*]; \theta_U),
\end{align}
\]

其中,
\(I^{SR}(y_i) \in \mathbb{R}^3\)
是在
\(y_i\)
处的
RGB
值,[
\(\cdot\)
] 表示连接操作。通过查询每个
\(\{y_i\}_{i=1...HW}\)
处的
RGB
值并组合它们,可以得到最终的输出
\(I^{SR}\)
。在论文提出的方法中,可以利用
\(M\)
个并行的上采样器
\(\{U_0, U_1, ..., U_{M-1}\}\)
来处理各种恢复难度(即从重到轻的容量)。

Training

在训练阶段,将一个查询像素通过所有
\(M\)
个上采样器进行前向传播,并将输出聚合,以有效地反向传播梯度,具体操作如下:

\[\begin{equation}
\label{eq:pcsr2}
\hat{Y}(y_i) = \sum_{j=0}^{M-1} p_{i,j} \times U_j(Z,y_i;\theta_{U_j}),
\end{equation}
\]

其中,
\(\hat{Y}(y_i) \in \mathbb{R}^3\)
是在
\(y_i\)
处的
RGB
输出,
\(p_{i,j}\)
是该查询像素位于上采样器
\(U_j\)
中的概率。

然后,利用两种类型的损失函数:重构损失
\(L_{recon}\)
以及类似于
ClassSR
中使用的平均损失
\(L_{avg}\)
。重构损失定义为预测输出的
RGB
值与目标之间的
L1
损失,目标视为
GT
高分辨率(
HR
)块与双线性上采样的低分辨率(
LR
)输入块之间的差异。这是希望分类器能够通过强调高频特征来很好地执行分类任务,即使容量非常小。因此,损失可以表达为:

\[\begin{equation}
L_{recon} = \sum_{i=1}^{HW} \lvert (Y(y_{i}) - upX(y_{i})) - \hat{Y}(y_{i}) \rvert,
\end{equation}
\]

其中,
\(upX(y_i)\)
是双线性上采样的低分辨率(
LR
)输入块在位置
\(y_i\)
处的
RGB
值。对于平均损失,通过以下方式定义损失,以鼓励每个类别内像素的均匀分配:

\[\begin{equation}
\label{eq:loss2}
L_{avg} = \sum_{j=1}^{M} \lvert \sum_{n=1}^{N} \sum_{i=1}^{HW} p_{n,i,j} - \frac{NHW}{M} \rvert,
\end{equation}
\]

其中,
\(p_{n,i,j}\)
是第
\(n\)
张高分辨率图像(即批处理维度,批量大小为
\(N\)
)中第
\(i\)
个像素属于第
\(j\)
类的概率。在这里,将每个类别的概率视为分配给该类别的像素数量的有效数量。设置目标为
\(\frac{NHW}{M}\)
,希望在总共
\(NHW\)
个像素中,将相同数量的像素分配给每个类别(或者上采样器)。

最后,总损失
\(L\)
定义为:

\[\begin{equation}
L = w_{recon} \times L_{recon} + w_{avg} \times L_{avg}.
\end{equation}
\]

由于从头开始联合训练所有模块(即主干
\(B\)
,分类器
\(C\)
,以及上采样器
\(U_{j \in [0,M)}\)
)可能导致训练不稳定,所以采用多阶段训练策略。假设上采样器的容量从
\(U_0\)
逐渐减少到
\(U_{M-1}\)
,模型性能的上限由主干
\(B\)
和最重的上采样器
\(U_0\)
决定。因此,最初仅使用重构损失训练
\(\{B,U_0\}\)
。然后,从
\(j=1\)

\(j=M-1\)
,重复以下过程:先冻结已经训练好的
\(\{B, U_0, ..., U_{j-1}\}\)
,将
\(U_j\)
连接到主干(对于
\(j=1\)
还要新连接
\(C\)
),最后联合使用总损失训练
\(\{U_j, C\}\)

Inference


PCSR
的推断阶段,整体过程与训练类似,但查询像素根据预测的分类概率被分配给唯一的上采样器分支。虽然可以将像素分配给具有最高概率的分支,但论文为用户提供了在不重新训练的情况下控制计算性能平衡的能力。为此,论文考虑了
FLOP
(浮点运算数)计数在决策过程中的影响,定义并预先计算了每个上采样器
\(U_{j \in [0,M)}\)

FLOP
影响,如下:

\[\begin{equation}
cost(U_j) = \sigma(flops(B; (h_0, w_0)) + flops(U_j; (h_0, w_0))),
\end{equation}
\]

其中,
\(\sigma\)

softmax
函数,
\(flops(\cdot)\)
是给定固定分辨率
\((h_0, w_0)\)
的模块的
FLOPs
。像素
\(y_i\)
的分支分配如下确定:

\[\begin{equation}
argmax_j \frac{p_{i,j}}{[cost(U_j)]^k},
\end{equation}
\]

其中,
\(k\)
是一个超参数,
\(p_{i,j}\)
是之前提到的查询像素被分配到
\(U_j\)
的概率。根据定义,设置较低的
\(k\)
值会导致更多像素被分配给更重的上采样器,从而最小化性能下降但增加计算负载。相反,较高的
\(k\)
值会将更多像素分配给较轻的上采样器,以降低计算需求为代价接受性能下降。

  • Adaptive Decision Making (ADM)

尽管论文的方法允许用户管理计算性能平衡,论文还提供了一种额外功能,根据整个图像统计信息的概率值自动分配像素。其步骤如下:对于单个输入图像,给定
\(\forall p_{i,j}\)
并将
\(U_{j \in [0, \lfloor(M+1)/2\rfloor)}\)
视为重型上采样器,计算
\(sum_{0 \leq j<\lfloor(M+1)/2\rfloor} p_{i,j}\)
表示该像素的恢复难度,从而得到总数为
\(i\)
的值。然后使用聚类算法将这些值分组成
\(M\)
个簇。最后,根据每个簇的中心值将每个组分配给从最重的
\(U_0\)
到最轻的
\(U_{M-1}\)
的上采样器。可以采用
K-means
聚类算法来最小化计算负载,由于均匀初始化中心值,该过程具有确定性。

  • Pixel-wise Refinement

由于每个像素的
RGB
值是由独立的上采样器预测的,当相邻像素分配给具有不同容量的上采样器时可能会产生伪影。为了解决这个问题,论文提出了一个简单的解决方案:按容量将下半部分的上采样器视为轻型上采样器,上半部分视为重型上采样器,当相邻像素分配给不同类型的上采样器时则进行细化。具体而言,对于分配给
\(U_{j}\)
的像素,其中
\(\lfloor(M+1)/2\rfloor \leq j < M\)
(即轻型上采样器),如果至少有一个相邻像素被分配给
\(U_{j}\)
,其中
\(0 \leq j<\lfloor(M+1)/2\rfloor\)
(即重型上采样器),则将其
RGB
值替换为
SR
输出中相邻像素(包括自身)的平均值。像素级细化算法无需额外的前向处理,仅通过少量的额外计算有效减少伪影,并对整体性能影响最小。

Experiments




如果本文对你有帮助,麻烦点个赞或在看呗~
更多内容请关注 微信公众号【晓飞的算法工程笔记】

work-life balance.

大家好呀,我是summo,最近遇到了一个功能需求,虽然也是CURD,但属于那种比较复杂一点的CURD,话不多说,我们先看一下需求。

需求如下:

有三张表,学生表、课程表、学生课程关联表,关联关系如下图:

要求实现的功能:

  1. 支持输入名称模糊查询,可以是学生名称也可以是课程名称,但只有一个输入框;
  2. 要求以学生为主信息,一个学生所选的多门课程聚合展示;
  3. 支持分页查询。

产品原型大致如下:

原型画的有点丑,不过应该可以看的懂,需求还是合理的,现在压力给到了后端,如何写SQL才能查出这样的数据结构来呢?

首先,我们把表建一下,初始化一些模拟数据。
学生表:t_student

-- 创建表
CREATE TABLE `t_student` (
  `id` bigint NOT NULL COMMENT '物理主键',
  `stu_name` varchar(255) DEFAULT NULL COMMENT '学生名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 添加数据
INSERT INTO `t_student` VALUES (1, '张三');
INSERT INTO `t_student` VALUES (2, '李四');
INSERT INTO `t_student` VALUES (3, '王五');

课程表:t_course

-- 创建表
CREATE TABLE `t_course` (
  `id` bigint NOT NULL COMMENT '物理主键',
  `course_name` varchar(255) DEFAULT NULL COMMENT '课程名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 添加数据
INSERT INTO `t_course` VALUES (1, '语文');
INSERT INTO `t_course` VALUES (2, '数学');
INSERT INTO `t_course` VALUES (3, '英语');

学生课程关联表:t_student_course_rel

-- 创建表
CREATE TABLE `t_student_course_rel` (
  `id` bigint NOT NULL COMMENT '物理主键',
  `stu_id` bigint DEFAULT NULL COMMENT '学生ID',
  `course_id` bigint DEFAULT NULL COMMENT '课程ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 添加数据
INSERT INTO `t_student_course_rel` VALUES (1, 1, 1);
INSERT INTO `t_student_course_rel` VALUES (2, 1, 2);
INSERT INTO `t_student_course_rel` VALUES (3, 2, 1);
INSERT INTO `t_student_course_rel` VALUES (4, 2, 2);
INSERT INTO `t_student_course_rel` VALUES (5, 2, 3);
INSERT INTO `t_student_course_rel` VALUES (6, 3, 2);
INSERT INTO `t_student_course_rel` VALUES (7, 3, 3);

这里我先不讲原理,直接放答案,大家可以先去试一下看看效果,然后再回来看原理。

聚合查询SQL如下:

SELECT
    t1.id,  -- 学生ID
    t1.stu_name,  -- 学生姓名
    GROUP_CONCAT(t3.id) AS course_ids,  -- 合并该学生所选课程的ID
    GROUP_CONCAT(t3.course_name) AS course_names  -- 合并该学生所选课程的名称
FROM
    t_student t1  -- 主表:学生信息
    LEFT JOIN t_student_course_rel t2 ON t1.id = t2.stu_id  -- 连接学生和课程关系表(左连接)
    LEFT JOIN t_course t3 ON t2.course_id = t3.id  -- 连接课程表(左连接)
WHERE
    t1.stu_name LIKE CONCAT('%', '张', '%')  -- 筛选学生姓名中包含'张'的记录
    OR t3.course_name LIKE CONCAT('%', '张', '%')  -- 或者筛选课程名称中包含'张'的记录
GROUP BY
    t1.id,  -- 按学生ID分组
    t1.stu_name  -- 按学生姓名分组
LIMIT 0,20   -- 分页查询

返回结果

从结果可以看到,course_ids和course_names将张三选择的课程聚合起来了,其中的主要功臣就是
GROUP_CONCAT
,它是 MySQL 中的一个聚合函数,主要用于将多个行的值连接成一个字符串。这在需要将某个列的多个值合并为一个结果时特别有用。比如,查询一个表中的某些记录,并将某个字段的多行值合并在一起,以便于更直观地查看。

  1. 聚合功能:与其他聚合函数(如 SUM、COUNT 等)类似,GROUP_CONCAT 将多个行的结果合并为一个单一的字符串。
  2. 分隔符:默认情况下,多个值之间用逗号 , 作为分隔符,但可以使用 SEPARATOR 关键字指定其他分隔符。
  3. 使用场景:通常用于 GROUP BY 查询中,以便将分组后的字段进行合并。

这篇文章虽然简短,但却是我日常开发的心得笔记。正所谓“千里之行,始于足下;细流汇聚,成就江海”,写作的乐趣正是在于不断积累。随着时间的推移,你会发现这些点滴已成为一笔珍贵的财富。

至此,全文结束,再会!

承接前文关于如何运用 AI 工具生成时序图的内容【1】,今天我们继续探讨 AI 驱动的 PlantUML:高效创建专业的 UML 类图与用例图。

【1】:
https://juejin.cn/post/7407637717206728755

【2】: 案例参照开源项目ruoyi-cloud:
https://gitee.com/y_project/RuoYi-Cloud

AI驱动分析类间关系并通过PlantUML生成类图

一、在Fitten Code中输入如下内容

@workspace 分析下com.ruoyi.system下岗位管理这功能各类之间的关系

得到的结果如下:
为了分析
com.ruoyi.system

岗位管理
功能各类之间的关系,我们需要查看相关的类和它们的方法。以下是基于提供的参考信息进行的分析:

1. 主要类和接口

1.1.
SysPost

  • 描述
    : 岗位实体类,包含岗位的基本信息。

  • 属性
    :


    • postId
      : 岗位ID
    • postCode
      : 岗位编码
    • postName
      : 岗位名称
    • postSort
      : 显示顺序
    • status
      : 状态
    • createBy
      : 创建者
    • createTime
      : 创建时间
    • updateBy
      : 更新者
    • updateTime
      : 更新时间
    • remark
      : 备注

1.2.
SysPostMapper
接口

  • 描述
    : MyBatis Mapper 接口,用于操作岗位数据。

  • 方法
    :


    • selectPostList
      : 查询岗位列表
    • selectPostAll
      : 查询所有岗位
    • selectPostById
      : 根据ID查询岗位
    • selectPostListByUserId
      : 根据用户ID查询岗位列表
    • selectPostsByUserName
      : 根据用户名查询岗位
    • checkPostNameUnique
      : 检查岗位名称是否唯一
    • checkPostCodeUnique
      : 检查岗位编码是否唯一
    • updatePost
      : 更新岗位信息
    • insertPost
      : 插入岗位信息
    • deletePostById
      : 根据ID删除岗位
    • deletePostByIds
      : 批量删除岗位

1.3.
SysPostService
接口

  • 描述
    : 岗位服务接口,定义岗位管理的相关业务逻辑。

  • 方法
    :


    • selectPostList
      : 查询岗位列表
    • selectPostAll
      : 查询所有岗位
    • selectPostById
      : 根据ID查询岗位
    • selectPostListByUserId
      : 根据用户ID查询岗位列表
    • selectPostsByUserName
      : 根据用户名查询岗位
    • checkPostNameUnique
      : 检查岗位名称是否唯一
    • checkPostCodeUnique
      : 检查岗位编码是否唯一
    • insertPost
      : 插入岗位信息
    • updatePost
      : 更新岗位信息
    • deletePostByIds
      : 批量删除岗位
    • export
      : 导出岗位信息

1.4.
SysPostServiceImpl

  • 描述
    :
    SysPostService
    接口的实现类,实现具体的业务逻辑。

  • 方法
    :


    • 实现
      SysPostService
      接口的所有方法

1.5.
SysPostController

  • 描述
    : 岗位管理控制器,处理HTTP请求。

  • 方法
    :


    • list
      : 查询岗位列表
    • export
      : 导出岗位信息
    • getInfo
      : 根据ID查询岗位详细信息
    • add
      : 新增岗位
    • edit
      : 修改岗位
    • remove
      : 删除岗位

2. 类之间的关系

2.1.
SysPost

SysPostMapper

  • SysPost
    是岗位实体类,
    SysPostMapper
    是操作
    SysPost
    数据的 MyBatis Mapper 接口。
  • SysPostMapper
    通过 MyBatis 映射文件 (
    SysPostMapper.xml
    ) 定义了与数据库交互的 SQL 语句。

2.2.
SysPostMapper

SysPostService

  • SysPostService
    接口定义了岗位管理的业务逻辑,
    SysPostServiceImpl
    是其实现类。
  • SysPostServiceImpl
    通过依赖注入
    SysPostMapper
    来访问数据库,实现业务逻辑。

2.3.
SysPostService

SysPostController

  • SysPostController
    是控制器类,处理HTTP请求,调用
    SysPostService
    的方法来完成业务逻辑。
  • SysPostController
    通过依赖注入
    SysPostService
    来访问业务逻辑。

3. 总结

岗位管理功能涉及的主要类和它们之间的关系如下:

  • SysPost
    是岗位实体类。
  • SysPostMapper
    是操作
    SysPost
    数据的 MyBatis Mapper 接口。
  • SysPostService
    是岗位服务接口,定义岗位管理的业务逻辑。
  • SysPostServiceImpl

    SysPostService
    的实现类,通过
    SysPostMapper
    访问数据库。
  • SysPostController
    是控制器类,处理HTTP请求,调用
    SysPostService
    的方法来完成业务逻辑。

这些类和接口通过依赖注入和方法调用,共同实现了岗位管理功能。

二、在Fitten Code中继续输入如下内容

接着上再用plantuml把岗位管理功能相关的类形成类图

分析出的结果如下:

@startuml

class SysPost {
    +Long postId
    +String postCode
    +String postName
    +Integer postSort
    +String status
    +String createBy
    +Date createTime
    +String updateBy
    +Date updateTime
    +String remark
}

interface SysPostMapper {
    +List<SysPost> selectPostList(SysPost post)
    +List<SysPost> selectPostAll()
    +SysPost selectPostById(Long postId)
    +List<Long> selectPostListByUserId(Long userId)
    +List<SysPost> selectPostsByUserName(String userName)
    +SysPost checkPostNameUnique(String postName)
    +SysPost checkPostCodeUnique(String postCode)
    +int updatePost(SysPost post)
    +int insertPost(SysPost post)
    +int deletePostById(Long postId)
    +int deletePostByIds(Long[] postIds)
}

interface SysPostService {
    +List<SysPost> selectPostList(SysPost post)
    +List<SysPost> selectPostAll()
    +SysPost selectPostById(Long postId)
    +List<Long> selectPostListByUserId(Long userId)
    +List<SysPost> selectPostsByUserName(String userName)
    +SysPost checkPostNameUnique(String postName)
    +SysPost checkPostCodeUnique(String postCode)
    +int insertPost(SysPost post)
    +int updatePost(SysPost post)
    +int deletePostByIds(Long[] postIds)
    +void export(SysPost post)
}

class SysPostServiceImpl {
    -SysPostMapper sysPostMapper
    +List<SysPost> selectPostList(SysPost post)
    +List<SysPost> selectPostAll()
    +SysPost selectPostById(Long postId)
    +List<Long> selectPostListByUserId(Long userId)
    +List<SysPost> selectPostsByUserName(String userName)
    +SysPost checkPostNameUnique(String postName)
    +SysPost checkPostCodeUnique(String postCode)
    +int insertPost(SysPost post)
    +int updatePost(SysPost post)
    +int deletePostByIds(Long[] postIds)
    +void export(SysPost post)
}

class SysPostController {
    -SysPostService sysPostService
    +ResponseEntity<TableDataInfo> list(SysPost post)
    +ResponseEntity<AjaxResult> export(SysPost post)
    +ResponseEntity<AjaxResult> getInfo(Long postId)
    +ResponseEntity<AjaxResult> add(SysPost post)
    +ResponseEntity<AjaxResult> edit(SysPost post)
    +ResponseEntity<AjaxResult> remove(Long[] postIds)
}

SysPostMapper <|-- SysPostServiceImpl : 依赖
SysPostService <|-- SysPostServiceImpl : 实现
SysPostService <|-- SysPostController : 依赖

@enduml

三、新建plantUml文件并复制如上内容

类图说明

  • SysPost
    类表示岗位实体,包含岗位的基本信息。
  • SysPostMapper
    接口定义了操作岗位数据的 MyBatis Mapper 方法。
  • SysPostService
    接口定义了岗位管理的业务逻辑。
  • SysPostServiceImpl
    类实现了
    SysPostService
    接口,并通过依赖注入
    SysPostMapper
    来访问数据库。
  • SysPostController
    类是控制器,处理HTTP请求,调用
    SysPostService
    的方法来完成业务逻辑。

通过这个类图,可以清晰地看到岗位管理功能中各个类之间的关系和依赖。
最终效果如下,可以导成图片文件。

四、在Fitten Code中继续输入如下内容

例如岗位管理主要划分为岗位新增、修改、删除和查询功能。通过plantuml生成用例图

与上同样新建一个plantUML,岗位用例图文件,复制生成的内容,岗位管理用例图就生成了,是不是很简单。

有时候我们需要再同一台机器上创建多个数据库服务(不是单纯的数据库实例),每一个数据库可以有单独的服务运行,只是在一个机器环境而已。可以在不同的端口上监听,也可以在相同端口监听

创建多个数据库步骤

安装完Oracle数据库后,会自动安装很多工具,这里我们使用Database Configuration Assistant工具来创建数据库
image
按照提示一步步确定和填写信息即可,注意第三部填写自己要创建的数据库名称:
image
整个过程和第一次创建数据库一模一样,注意按需选择字符集、连接数等即可。
创建成功后,我们的呢服务列表services.msc中会自动运行刚才创建好的数据库服务,比如我这里刚才创建的名字叫looorcl:
image

连接指定数据库

  • 一般情况下,创建成功后,直接采用sqlplus去连接就行,只不过连接字符串改成上面刚新加的就行,比如:
    sqlplus sys/nhis@looOrcl as sysdba
    我这里是本地所以没有制定ip
  • 如果连接时报错:ERROR:ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务
  1. 此时要检查,首先是否书写错误。确保你在连接时使用的服务名与 tnsnames.ora 文件中定义的服务名一致。

  2. 检查tnsnames.ora这个文件的配置,具体路径在创建数据库的时候已经有提示,不改动的话默认就是数据库目录的
    product\11.2.0\dbhome_1\NETWORK\ADMIN
    目录中,比如我的在D:\app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN\tnsnames.ora,文件内容中会多出一个节点,比如:
    image

  3. 然后再查看 相同目录中的listener.ora文件,检查监听是否已经加入,也就是我们刚创建的数据库服务名称,是不是已经加入到文件,没有的话,可以手动填写,比如像我这样子:
    image

  4. 重启监听
    lsnrctl stop
    lsnrctl start
    启动成功后重新连接即可,这样等于是相同的端口,监听了两个不同的数据库。我们打开Net Manager可以看到,我们监听了两个出具库服务
    image
    image

创建不同监听端口的数据库服务

只需在上面的Net Manager中删除刚新建的数据库配置,然后新加监听,重新制定数据库名和SID,重新指定一个端口即可。

Python 项目及依赖管理工具,类似于 Java 中的 Maven 与 Node 中的 npm + webpack,在开发和维护项目时起着重要的作用。使用适当的依赖管理工具可以显著提高开发效率,减少依赖冲突,确保项目的稳定性、可靠性和安全性。

一、常见项目及依赖管理工具需具备的功能

1. 依赖管理

(1)自动化依赖安装

依赖管理工具可以自动安装项目所需的所有依赖包,而不需要手动逐个安装。

(2)依赖版本控制

这些工具允许开发者指定和锁定依赖包的版本,确保项目在不同环境中运行时依赖的一致性

2. 虚拟环境管理

虚拟环境允许在同一台机器上运行多个项目,而不会发生依赖冲突。依赖管理工具通常会自动创建和管理虚拟环境,确保项目依赖的隔离性。

3. 依赖冲突解决

依赖管理工具可以自动解决依赖冲突,确保安装的依赖包版本兼容。例如,
pipenv

poetry
都有内置的依赖冲突解决机制。

4. 安全性检查

一些工具(如
pipenv
)提供了内置的安全性检查功能,可以扫描依赖包的已知漏洞,并提供修复建议。

# 使用 pipenv 进行安全性检查
pipenv check

5. 项目初始化和模板

一些工具(如
poetry

hatch
)提供了项目模板和脚手架功能,帮助开发者快速创建新项目。

6. 发布依赖包

一些工具(如
poetry
)内置了包发布功能,可以方便地将项目发布到 PyPI(Python Package Index)。

# 使用 poetry 发布包
poetry publish --build

7. 生成依赖配置文件

部分依赖管理工具可以生成描述项目依赖的文件,方便团队协作和部署。例如,
pip-tools
可以生成
requirements.txt
文件。

8. 版本管理

这是指如何管理和控制你的项目版本。每次发布新版本时,你需要更新项目的版本号(如从 1.0.0 到 1.1.0),并确保版本号的变化遵循一定的规则(如语义化版本控制)。

版本管理工具可以帮助你自动更新版本号、生成变更日志、创建发布标签等。

二、常见工具及其技术对比

常见 Python 项目及依赖管理工具,包括
Pipenv

Poetry

Conda

Pip-tools

Hatch
)和
venv
。以下从工具简介、特性介绍、功能对比及流行度三方面进行对比。

1. 工具简介

(1)Pipenv

Pipenv
一度被官方推荐为 Python 项目的依赖管理工具,尤其是在需要自动管理虚拟环境和依赖锁定的场景中。然而,随着时间的推移,它的热度有所下降。

(2)Poetry

Poetry
近年来越来越流行,尤其在需要现代化依赖管理和包发布的项目中。它提供了更好的用户体验和更强大的功能。

(3)Conda
Conda
在数据科学和机器学习领域非常流行,因为它不仅支持 Python,还支持 R 和其他语言,并且其环境管理功能非常强大。

(4)Pip-tools

Pip-tools
在一些需要精确控制依赖版本的项目中很受欢迎,尤其是那些仍然使用
requirements.txt
的项目。

(5)Hatch

Hatch
是一个相对较新的工具,虽然功能强大,但目前还没有达到
Poetry

Conda
的流行度。

(6)venv

venv
是 Python 标准库中的模块,用于创建轻量级的虚拟环境,方便项目间的依赖隔离。

2. 特性介绍

工具 主要使用场景 主要特性
Pipenv 一般项目,自动管理虚拟环境 自动创建和管理虚拟环境、依赖锁定文件(Pipfile.lock)、友好的 CLI 接口
Poetry 现代化项目,依赖管理和包发布 全面的依赖管理、内置虚拟环境管理、项目构建和发布、依赖解析和锁定
Conda 数据科学和机器学习 跨语言支持、强大的环境管理、包管理、支持多种平台(Windows, macOS, Linux)
Pip-tools 精确控制依赖版本的项目 生成和更新 requirements 文件、依赖锁定、与 pip 兼容
Hatch 现代化项目管理和版本控制 项目模板、环境管理、版本控制、依赖管理、灵活的插件系统
venv 基本虚拟环境管理 Python 内置模块,轻量级虚拟环境管理

3. 功能对比

功能 venv Pipenv Poetry Conda Pip-tools Hatch
创建虚拟环境
自动管理虚拟环境
依赖文件
版本锁定
安全性检查
包发布
依赖冲突解决
项目模板和脚手架
版本管理

4. 流行度

当前(2024 年 7 月 30 日)各工具流行度,如下:

工具 GitHub Stars PyPI 近半年下载量(万) Forks Open Issues Open PRs
Pipenv 24k+ 6466 1862 260 14
Poetry 30k+ 20502 2236 602 74
Conda 6k+ 97 N/A N/A N/A
Pip-tools 7k+ 7254 608 160 27
Hatch 5k+ 1163 285 239 26
venv Python 内置 N/A N/A N/A N/A

三、结论

从上述技术对比来看,无论是功能特性还是流程程度,Poetry 都是当前最适合新 Python 项目的依赖管理工具。不过,部分其他工具也有一定适用场景,如 Pip-tools 适用于有 requirements 的老项目,Conda 适用于多编程语言项目。

四、VS pip

以 poetry 为例,简要介绍上述项目及包依赖管理工具与 pip 的区别。
pip
是一个轻量级的包管理工具,适合简单的包安装和管理任务。
poetry
是一个功能强大的项目管理工具,适合需要全面管理项目依赖和配置的场景。

1. 功能对比

特性 pip poetry
功能和用途 pip
是 Python 的包管理工具,用于安装和管理 Python 包。主要用于从 Python Package Index (PyPI) 下载和安装包,不涉及项目管理。
poetry
是一个全面的 Python 项目管理工具,不仅可以安装和管理包,还可以创建和管理项目、处理依赖关系、发布包等。
配置文件 pip
使用
requirements.txt
文件来列出项目的依赖包。
requirements.txt
是一个简单的文本文件,列出所有需要安装的包及其版本。
poetry
使用
pyproject.toml
文件来管理项目的元数据和依赖关系。
pyproject.toml
是一个结构化的配置文件,包含项目的详细信息、依赖关系、脚本等。
依赖管理 pip
本身不处理依赖冲突问题,需要开发者手动解决。可以结合
pip-tools
使用,以便更好地管理依赖关系。
poetry
内置依赖解析和锁定机制,可以自动解决依赖冲突问题。会生成一个
poetry.lock
文件,确保项目在不同环境下依赖一致。
虚拟环境管理 pip
本身不管理虚拟环境,但通常与
virtualenv

venv
一起使用。开发者需要手动创建和激活虚拟环境。
poetry
内置虚拟环境管理功能,可以自动创建和管理虚拟环境。使用
poetry
时,虚拟环境的创建和激活是自动处理的。

2. 使用示例

(1)pip

# 安装包
pip install requests

# 列出安装的包
pip freeze > requirements.txt

# 从 requirements.txt 安装包
pip install -r requirements.txt

(2)poetry

# 创建新项目
poetry new myproject

# 进入项目目录
cd myproject

# 安装包
poetry add requests

# 安装所有依赖
poetry install

# 启动虚拟环境
poetry shell

3. 建议

示例项目可用 Python 自带的 pip,简单易用。大型线上生产项目需要做好依赖管理、依赖冲突解决、虚拟环境管理等工作,以保证项目在多种环境下交付一致且稳定运行,poetry 之类的项目及包管理工具更合适的选择。