git 给某个仓库单独配置SSH KEY

使用背景

服务器A上大家都是统一的账号密码,这时候要区分不同人的话,需要

  1. 每个人在A上生成自己ssh 密钥,(也可以用自己其他平台上已有的公钥私钥代替)其中私钥自己保存,公钥上传到需要连接的服务器B上

  2. 在自己的仓库中,运行git config core.sshCommand “ssh -i ~/.ssh/id_rsa_personal -F /dev/null” 配置此仓库的ssh访问密钥

  3. 在自己的仓库中 git config user.name “Your Name” git config user.email “yourname@zoom.us

Histogram Transformer

Restoring Images in Adverse Weather Conditions via Histogram Transformer

主要贡献

  1. 之前transformer都是在local windows上计算,但是雨,雾等,往往全局的有污渍的区域有相同的特征,需要相同的处理,因此本文transformer是在全局做的,并且patch不是按照像素块求的,而是按照相似像素分的。也就是按照数字大小排序,相似的分成一个bin,组成一个patch。

  2. 这个sort在新版本的pytorch里面可导,就是会记录sort路径,然后按照路径反传。

  3. 算是Unet类型的,不能完全说transformer作为backbone。

attention 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
def forward(self, x):
b,c,h,w = x.shape
x_sort, idx_h = x[:,:c//2].sort(-2)
x_sort, idx_w = x_sort.sort(-1)
x[:,:c//2] = x_sort
# 这个x的 hw 基本上等于原图的hw c 中 一半是有序的c(最小的都在左上角这种)
# 一半是对应本来位置的c feature
# q1,k1,q2,k2,v
qkv = self.qkv_dwconv(self.qkv(x))
#经过conv2d(dim,5dim)扩展到qkv:b,5c,h,w
q1,k1,q2,k2,v = qkv.chunk(5, dim=1) # q:b,c,h,w


v, idx = v.view(b,c,-1).sort(dim=-1) # 按照v大小排序 b,c,hw
q1 = torch.gather(q1.view(b,c,-1), dim=2, index=idx)
k1 = torch.gather(k1.view(b,c,-1), dim=2, index=idx)
q2 = torch.gather(q2.view(b,c,-1), dim=2, index=idx)
k2 = torch.gather(k2.view(b,c,-1), dim=2, index=idx)
# kq 也按照 v的顺序排序

out1 = self.reshape_attn(q1, k1, v, True)
out2 = self.reshape_attn(q2, k2, v, False)

# 两种attention做完,再恢复原来的形状
out1 = torch.scatter(out1, 2, idx, out1).view(b,c,h,w)
out2 = torch.scatter(out2, 2, idx, out2).view(b,c,h,w)
out = out1 * out2# 属实不知道这里为什么是乘法
out = self.project_out(out)
out_replace = out[:,:c//2]# 再恢复原来的形状
out_replace = torch.scatter(out_replace, -1, idx_w, out_replace)
out_replace = torch.scatter(out_replace, -2, idx_h, out_replace)
out[:,:c//2] = out_replace
return out

def reshape_attn(self, q, k, v, ifBox):
# self.factor = num_heads
# q: b c hw
# 此时c是特征 hw是全部token的数量,后续还会进行token合并
b, c = q.shape[:2]
q, t_pad = self.pad(q, self.factor)
k, t_pad = self.pad(k, self.factor)
v, t_pad = self.pad(v, self.factor)
hw = q.shape[-1] // self.factor
# 此时 hw的理解是特征维度 (c factor) 是分成的bin的数量
# 比较绕也不确定正确,这里就是不同的分bin方式
shape_ori = "b (head c) (factor hw)" if ifBox else "b (head c) (hw factor)"
shape_tar = "b head (c factor) hw"

q = rearrange(q, '{} -> {}'.format(shape_ori, shape_tar), factor=self.factor, hw=hw, head=self.num_heads)
k = rearrange(k, '{} -> {}'.format(shape_ori, shape_tar), factor=self.factor, hw=hw, head=self.num_heads)
v = rearrange(v, '{} -> {}'.format(shape_ori, shape_tar), factor=self.factor, hw=hw, head=self.num_heads)
q = torch.nn.functional.normalize(q, dim=-1)
k = torch.nn.functional.normalize(k, dim=-1)
attn = (q @ k.transpose(-2, -1)) * self.temperature
attn = self.softmax_1(attn, dim=-1)
out = (attn @ v)
out = rearrange(out, '{} -> {}'.format(shape_tar, shape_ori), factor=self.factor, hw=hw, b=b, head=self.num_heads)
out = self.unpad(out, t_pad)
return out

这是两种reshape的含义。大概一个是选取large-scale(面积上相近?)的信息,一个是选取频率相近的信息。

CLAHE

CLAHE 使用的一些经验

直方图包含了什么信息

两张我觉得不错的图像

两张我觉得有雾或者曝光不足的图像

单从直方图无法准确判断出一张图质量如何

一张好的图片往往拥有如下特征:

最暗值从0开始,最大值接近或者是255,每一个亮度都有一定分布。

不好的图片往往有如下特征:

某个亮度(0 或者 255)有很多很多像素

0附近亮度空缺,也就是全图缺少暗点

画面主体(人物)或者总画面平均亮度过低,过高

什么是CLAHE

原理

在一定限制下,将输入的直方图尽可能的均衡,让其每个亮度拥有差不多个数的像素。

这个限制是指,不能将映射折线的斜率过大,也就是不能将某个亮度过度放大或者缩小。

实现方式(不考虑分块)

  1. 计算输入图像的直方图

  2. 根据clip- limited 裁剪掉超过 clip-limited * total pixel / 256的像素

  3. 将裁减掉的像素均分给每一个亮度,形成新的直方图

  4. 计算新直方图的累计分布曲线(LUT)

  5. 该曲线就是CLAHE的映射曲线,使用该曲线对原图进行映射

算法本身缺陷

好的直方图不一定是均衡的。尤其是分块之后,小块内直方图不均衡很正常。

由于clip- limited的存在,算法对那种个别亮度拥有过多像素的case不合适

clip- limited选择与图像及其效果

理论上,当图像亮度分布十分均匀,每个亮度都有1/256 * totalpixel的时候,直方图均衡化算法无效,但实际中的图片哪怕曝光,色彩内容都很好很丰富,还是会存在一些不均匀的。

原图\clip limit 0.2 0.4 0.8 1 1.4 1.8 2.5
比较均匀 无改变 逐渐增加 逐渐增加 逐渐增加 逐渐增加 程度相同 程度相同
轻微不匀 逐渐增加 逐渐增加 逐渐增加 逐渐增加 逐渐增加 逐渐增加 程度相同
不均 逐渐增加 程度相同
严重不均 逐渐增加

output_yuv_clahe_04_1_histograms.jpg

output_yuv_clahe_1_1_histograms.jpg

output_yuv_clahe_2_1_histograms.jpg

随着clip limited的增加(0.4 1 2)直方图分布看似越来越均衡,但是画面质量却在下降

直观效果

当图片某段曝光缺失(比如过暗,过亮),那clahe会稍微拉会一些平均亮度

当图片主体还算正常,但是暗部亮度像素相对较少(这种情况很常见,也许原图是好图片),clahe会随着clip limited的增大,更夸张的把中暗部压暗,中亮度提亮,拉伸对比度。

由于映射是离散的,当(a-1)/255 * total < CFD(a) < (a+1)/255 * total时 a不会发生变化;当CFD(a-1) = (a-1)/255 * total , CDF(a) = (a+1)/255 * total 时,也就是a亮度有很多像素,a会被映射到a+1 而a-1还保持a-1,a亮度本身出现像素空缺。

Swin Transformer and SwinIR

图像多头注意力基础Vit

也就是固定patch的感受野是16*16像素,然后根据输入分辨率的变化,patch总数变多。

transformer分成计算MHA 和MLP

MHA把 196个 768维度patch投影到qkv 每个patch独立,但是采用相同nn.linear(dim, dim * 3, bias=qkv_bias)参数计算qkv,所有patch的qk再计算相关度的到196*196 的相关度矩阵attn,attn再和v计算,得到196 * 768维度的结果,这个结果是每个patch都考虑到了全局其他patch影响后的结果。

 class Attention(nn.Module):
 """Multi-head self-attention (MHSA)"""
 def __init__(self, dim, num_heads=8, qkv_bias=False, attn_drop=0., proj_drop=0.):
 super().__init__()
 self.num_heads = num_heads
 head_dim = dim // num_heads
 self.scale = head_dim ** -0.5 # 缩放因子 (√d_k)
    self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)  # Q, K, V 投影
    self.attn_drop = nn.Dropout(attn_drop)
    self.proj = nn.Linear(dim, dim)  # 输出投影
    self.proj_drop = nn.Dropout(proj_drop)

def forward(self, x):
    B, N, C = x.shape  # [batch_size, num_patches, embed_dim]
    # 对于每一个patch,把qkv计算出来(同patch 一样维度)
    # 再reshape成 B patch
    qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
    q, k, v = qkv.unbind(0)  # [B, num_heads, N, head_dim]

    attn = (q @ k.transpose(-2, -1)) * self.scale  # QK^T / √d_k
    attn = attn.softmax(dim=-1)
    attn = self.attn_drop(attn)

    x = (attn @ v).transpose(1, 2).reshape(B, N, C)  # 合并多头
    x = self.proj(x)
    x = self.proj_drop(x)
    return x

kqv 一开始是从 B N embed_dim 计算成 B N 3embed_dim,然后分成 B N 3 head embed_dim//3; 再之后分成q,k,v。再之后交换维度顺序,变成B heads N head_dim。每一个head独立计算。

总计算量 不算batch,假设一共有N个patch MHA中 patchpatch + patch * dimdim 在MLP模块为patch * dim*dim

Swin transformer

主要贡献

  1. 由于自然语言中,一个单词就是一个token,但是在视觉问题中,一个像素还是3*3个像素块还是更大的像素块被看作一个token不确定,所以需要层次化的,多尺度的结构,类似Unet那样,不同的感受野当作一个token,计算attention。所以本文提出了层次化的结构。

  2. 图片往往都是高清的,全局做attention计算量太大,因此提出了滑动窗口做attention,并且提出了shift windows,更好处理边缘的patch。

整体网络结构

逐步下采样,窗口的多头attention和shift 窗口的attention交替进行。

其他细节

相对位置编码

SwinIR

多个任务共用 shallow feature 和 deep feature 提取,不同任务不容的reconstruction模块,backbone是RSTL

YUV full vs limited 601 vs 709

RGB

RGB 不区分 601 709 或者 full limited, 对于sRGB来说 最亮就应该是255, 最暗就应该是0。肤色要贴近真实场景,和真实场景没有色调偏移。

RGB 2 YUV

在rgb转化成YUV的时候,存在不同的转化公式,可以将YUV转化成 full 或者 limited,色彩空间也可以是601 或者 709

1. RGB 2 YUV BT.601 full(标清)
  • 适用于 SDTV(480i/576i)、DVD 等。

  • 转换矩阵

    Y=0.299R+0.587G+0.114B

    U=−0.169R−0.331G+0.500B+128

    V=0.500R−0.419G−0.081B+128​

  • 色度(UV)范围:0-255(Full Range 下)。

2. RGB 2 YUV BT.709 full(高清)
  • 适用于 HDTV(720p/1080p)、蓝光、流媒体等。

  • 转换矩阵

    Y=0.2126R+0.7152G+0.0722B

    U=−0.1146R−0.3854G+0.500B+128

    V=0.500R−0.4542G−0.0458B+128​

  • 色度(UV)范围:0-255(Full Range 下)。

3. BT.601 Limited Range

Y=(0.299R+0.587G+0.114B)×219​/255+16

U=(−0.169R−0.331G+0.500B)×224​/255+128

V=(0.500R−0.419G−0.081B)×224​/255​+128​

注:UV 的 +128 偏移在 Limited Range 下会自动调整为 16-240。

4. BT.709 Limited Range

​Y=(0.2126R+0.7152G+0.0722B)×219/255​+16

U=(−0.1146R−0.3854G+0.500B)×224/255​+128

V=(0.500R−0.4542G−0.0458B)×224/255​+128​

为什么存在 limited
  • 广播电视行业(BT.601/BT.709/BT.2020)
    早期的模拟电视信号为了减少噪声干扰和留出余量(如同步信号),将 YUV 的亮度(Y)限制在 16~235,色度(UV)限制在 16~240(8-bit 下),而非完整的 0~255。这一规范被数字电视(如 DVD、蓝光、有线电视)沿用,称为 Limited Range 或 TV Range

  • 硬件设备优化:部分显示设备(如老式 CRT)的电路设计基于 Limited Range,直接兼容更高效。

为什么有601 709两种色彩空间
  • BT.601(1982年制定)
    针对 标清电视(SDTV) 设计,分辨率主要为 480i/576i(NTSC/PAL),用于早期的 CRT 电视和 DVD 时代。

    • 色彩空间基于当时模拟电视的技术限制,色度采样通常为 4:2:2 或 4:2:0

    • 主要目标:兼容模拟信号,优化带宽效率。

  • BT.709(1990年制定,后更新)
    针对 高清电视(HDTV) 设计,分辨率支持 720p/1080i/1080p,用于蓝光、数字电视和流媒体。

    • 色彩空间适应更高分辨率和数字显示设备(如液晶、等离子)。

    • 主要目标:提升色彩表现,匹配现代显示技术。

YUV2RGB

YUV有四种格式 分别是 full/limited 601/709,如果要转化成正确的RGB,需要采用对应的公式转化,如果采用的公式错误,可能带来色彩偏差。

常见色彩偏差

如 BT.601 内容在 BT.709 显示下偏绿或饱和度过高

709的内容在601下播放可能偏红,紫

full的数据在limited的模式下播放,暗部亮部分会损失,对比度过强

limited的数据在full的模式下播放,色彩昏暗,亮度无法达到255

git merge vs rebase

git 修改之前的某次commit 注释和常见问题和解决方法_git修改某次commit的comment-CSDN博客

git rebase 用法详解与工作原理 | Shall We Code?

git merge

有两个分支 branchA branchB ,初始时,branchA在C1 节点 基于此节点,拉出branchB

以下操作按照时间顺序

对branchB进行修改 C2

对branchA进行修改 C3

对branchB进行修改 C4

将branchB merge 到branch A

可以看出merge的树是以不同branch体现的,不能完整体现时间顺序

git rebase

此时 reset一下merge操作:

随后将branchB 通过rebase的方式合并到branchA

可以看出 先将branchA的head移动到最新的branchB,再将branchA的修改添加回branchA。合并操作不会产生新的节点

对于单独一个分支的rebase

假如我们对当前分支的某次历史提交执行 rebase,其结果就是会将这次提交之后的所有提交重新应用在当前分支,在交互模式下,即允许我们对这些提交进行更改。

git rebase -i HEAD~4

可以看到后面的提交都变了ID

git rebase -i HEAD~6

多rebase几个,但是修改还是修改同样的地方,那还是修改后的节点ID改变

利用rebase 修改历史提交的comment

对于一直使用rebase操作的代码,修改历史comment十分简单,

比如我想修改branchB C2 那次的log

git rebase -i HEAD~3

这件事不会影响branchB 也不会影响branchA的提交顺序。但是会导致branchA重新增加comment的提交以及之后的提交的hashID改变

对于使用merge的代码进行message修改,就比较复杂

此时要修改branchB 中C2 节点 9d3282c 的名字

git rebase -i HEAD~3

似乎列出的是branchA分支上最后三次的操作,当然也包含branchB上的

会失败,原因是:rebase之后相当于把branchB C2 C4两个节点的内容加入到 branchA C3这个节点后,在对比banechB C2 9d3282c 和 22279e0时 出现了不一致的问题。在此猜测 能merge成功是因为merge对比的是8f4cda7 和 22279e0。

先abort这次rebase, 恢复原样

git rebase -i HEAD~2 去修改C4节点 message 8f4cda7 也不行, 感觉是branchA已经包含了branchB那些修改。再搞个干净的分支。

新来一个分支 验证merge的代码如何修改message

现在想修改branchC newnode2 0b21277 那次message

git rebase -i HEAD~2

首先 修改了该提交的message, 其次,也运行了rebase。 将branchC的改动接到了branchA后面 (注意 如果是rebase branchC 那么是把branchA改动接到C后面。 但是我们这里运行rebase head 也就是rebase branchA 那么 就是把C的改动接到A后面。

反正本地rebase 不对劲就–abort

intptr VS int32 or int64

intptr int32
在32位机器下等同于int32 占32位,
在64位机器下等同于int64 占64位
占32位
指针偏移的时候用intptr
比如intptr strideS; pSrc += strideS
此时strideS 存储的数还是一样大小,也不会超出int32的范围,至少写汇编的时候能注意到这里
但是存储地址的时候 就得用intptr address = &(int a)
计数的时候用int32就够了。
比如for (int32 i = 0; i < (int32)120;i++)
申请内存大小的时候 buffersize也是用int32
运算的时候也是int32

CMake 简单用法

编译:

编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件( .o 文件或 .obj 文件)。

链接:

链接时,主要是链接函数和全局变量。所以,我们可以使用这些中间目标文件( .o 文件或 .obj 文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便。所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。

CMake 定位

其他Make 工具 CMake
GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp CMake
对应着不同的Makefile 采用平台统一的CMakeLists.txt 生成自适应的Makefile
make Makefile 编译 :不同产商的make各不相同,也有不同的语法,但其本质都是在 “文件依赖性”上做文章 make Makefile 编译

CMake用法

Makefile

工程编译规则,描述了整个工程的编译和链接等规则。其中包含了哪些文件需要编译,哪些文件不需要编译,哪些需要先编译,哪些需要重建等。

在生成makefile这步时 会进行语法检查么 会进行.cpp 到.o 么 ?不会。makefile只是编译规则 还没开始编译。makefile命令中就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。

Make

make工具就根据makefile中的命令进行编译和链接的。生成.o 这类文件,再进一步链接生成.exe这类文件。

参考

Makefile 简介 - Makefile基本概念介绍 - Makefile 简明教程 | 宅学部落

概述 &mdash; 跟我一起写Makefile 1.0 文档

Linux Makefile:使用CMake生成Makefile文件_cmake写makefile-CSDN博客

常见操作的耗时

在c release层面

分辨率 H*W 1280 720 耗时(MS) 包含基本操作
3*3 avg filter 普通写法 1.02 读写 +: 8  / :1
5*5 avg filter 普通写法 2.54 读写 + 24 /:1
3*3 winsum avg filter 0.93 读写 +: 2 /: 1 other prepare for window
5*5 winsum avg filter 0.94 读写 +: 2 /: 1 other prepare for window
2 to 1 down sample 0.23 读写
1/4 H*W upsample (video filter) 1.52 读写 +:4  / :5
1/16 H*W upsample(video filter) 1.51 读写 +:4  / :5
1/4 H*W upsample (specialRatio_bilinear up) 0.60 读写 +:4  / :1
1/16 H*W upsample (specialRatio_bilinear up) 0.44 读写 +:4  / :1
3*3 avg filter 1/4 HxW 普通写法 0.26
5*5 avg filter 1/4 HxW winsum 0.24

手写单指令多数据 armv8 加速效果

分辨率 H*W 1280 720 耗时(MS) 包含基本操作
3*3 avg filter 普通写法
5*5 avg filter 普通写法
3*3 winsum avg filter 0.13
5*5 winsum avg filter 0.14
2 to 1 down sample
1/4 H*W upsample (video filter)
1/16 H*W upsample(video filter)
1/4 H*W upsample (specialRatio_bilinear up)
1/16 H*W upsample (specialRatio_bilinear up)
3*3 avg filter 256x144 winsum 0.01
5*5 avg filter  256x144 winsum 0.01

单指令多数据常用操作 intrinsic

mla 乘加或者乘减比分开做要快

循环费时