Jiahong 的个人博客

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

DL——UNet

UNet最早应用与图像分割领域,目前随着Diffusion模型的应用,使用越来越广泛

  • 参考链接:
    • 原始论文:U-Net: Convolutional Networks for Biomedical Image Segmentation, 2015

最早的UNet

  • 最早的UNet网络是用作图片分割的,其输入是572x572像素,并且输出一个较小尺寸(388x388)的分割图,UNet架构图如下:

  • 可以按照编码器-解码器思想来理解UNet

  • 编码器部分:

    • 可以看到,原始的UNet网络没有用Padding,所以每次卷积(3x3的卷积)后,图片尺寸(长和宽)会缩小2,在实际实现时,可以使用Padding,保证卷积的输入和输出图片尺寸不变
    • 在编码过程中,Max Pooling操作和卷积操作使得样本长和宽逐步缩小(输入尺寸是572x572,编码结果最小尺寸为28x28),卷积输出通道逐步增加的(输入Channel为1,编码结果最大增加到1024)
  • 解码器部分:

    • 核心组件是上卷积:up-conv 2x2,该网络将通道减少为原来的 \(\frac{1}{2}\),同时将尺寸变化成原来的2倍,实际实现时,是通过上采样+带padding的卷积实现扩大尺寸为原来的两倍的

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      class up_conv(nn.Module):
      """
      Up Convolution Block
      """
      def __init__(self, in_ch, out_ch):
      super(up_conv, self).__init__()
      self.up = nn.Sequential(
      nn.Upsample(scale_factor=2),
      nn.Conv2d(in_ch, out_ch, kernel_size=3, stride=1, padding=1, bias=True),
      nn.BatchNorm2d(out_ch),
      nn.ReLU(inplace=True)
      )

      def forward(self, x):
      x = self.up(x)
      return x
    • 跳跃连接:在每次进行上卷积以后,都将编码器的中间结果Clip并Concat过来

    • 最终输出维度是388x388的,通道数为2


Diffusion模型中的UNet

  • 一个简单的Conditional Diffusion实现代码:github.com/TeaPearce/Conditional_Diffusion_MNIST
  • 以下内容参考自:扩散模型U-Net可视化理解
    • 整体框架图示:
    • 架构图解读:

      扩散模型中的U-net结构如上图所示,1X28X28表示通道数为1,长宽为28的图片。在实际训练中不是一个三阶张量而是一个四阶张量128X1X28X28,其中128表示批处理数,即128张图片同时在GPU上完成一次训练迭代
      整个计算流程如下:输入图片(A)被提取出128张特征图(B),经过第一次下采样图像缩小一半(C),经过第二次下采样图像进一步缩小为一半(D),经过平均池化得到一个向量(E),这个向量包含了图片中的所有必要特征信息。至此,输入图片已被编码。除了图片以外,时间标签、其他条件变量也可使用全链接网络进行编码,得到两个向量(F和G),为了确保后续上采样顺利,E、F、G的长度应当相同。接下来,将E、F、G合并为一个更长的向量H。H经过上采用不断恢复出I、J、K直到L。L即为最终期望输出的噪声图。用这个噪声图即可实现对图片的去噪

    • 时间片和条件信息是在编码完成后加入的,且加入时先Embedding,再将Embedding向量Concat添加到图片编码结果上

DL——VQ-VAE

  • 参考链接:
    • 原始论文:Neural Discrete Representation Learning, NeurIPS 2017, Google DeepMind
    • VQ-VAE的简明介绍:量子化自编码器:论文大部分内容参考自本博客
      • 苏神的代码实现:vq_vae_keras.py
    • 轻松理解 VQ-VAE:首个提出 codebook 机制的生成模型
    • VQVAE PyTorch 实现教程
      • 代码路径:dldemos/VQVAE

名词解释

  • VQ-VAE :Vector Quantised - Variational Auto-Encoder,用于将变量编码为离散向量,并可将离线向量恢复为原始向量
  • codebook :通常指一种将图像编码为离散向量的机制,实际上指 VQ-VAE 中的 Embedding Space(词表)
  • PixelCNN :生成离散像素的自回归模型

PixelCNN的简单介绍

  • 原始论文:Conditional Image Generation with PixelCNN Decoders, NIPS 2016, Google DeepMind
  • 假设要生成一张 \(32 \times 32 \times 3\) 的三通道图片,矩阵元素是 0-255 的整数,Pixcel将其视为长度为 3072 的句子,词表大小是 256,并用语言模型的方法自回归的生成图片
    $$
    \begin{align}
    p(\mathbf{x})=p(x_1)p(x_2|x_1)p(x_3|x_1,x_2)\dots p(x_{3n^2}|x_1,x_2,\dots,x_{3n^2-1})
    \end{align}
    $$
    • 输出类别为 256 维度
  • 自回归方法的缺点:
    • 序列太长,按照序列依次生成,生成速度慢;长程依赖不容易捕捉(不管是CNN还是RNN)
    • 像素值是有连续大小关系的(比如像素值为99时,预估为100也不是不可以,大事预估为10就不可以),但序列化的自回归方法本质是多分类建模,无法捕捉这种含义(但回过头来看,应该还好,毕竟大模型中的相似词也不需要显示建模)

AE、AVE和VQ-VAE

  • AE(Auto-Encoder) :包含一个编码器和一个解码器
    • 编码器 :将原始输入向量 \(\mathbf{x}\) 编码为一个较小的连续向量 \( \mathbf{z} = encoder(\mathbf{x}) \)
    • 解码器 :将连续向量 \(\mathbf{z}\) 解码为和原始输入差不多的向量\( \mathbf{x}’ = decoder(\mathbf{z}) \)
  • VAE(Variational Auto-Encoder) :包含一个编码器和一个解码器
    • 编码器 :将原始输入向量 \(\mathbf{x}\) 编码为一个服从标准正太分布的连续向量 \( \mathbf{z} = encoder(\mathbf{x}) \),具体实现是先用模型输出 \(\mu,\sigma^2\),再采样得到向量 \( \mathbf{z} \)
    • 解码器 :将连续向量 \(\mathbf{z}\) 解码为和原始输入差不多的向量\( \mathbf{x}’ = decoder(\mathbf{z}) \)
  • VQ-VAE(Vector Quantised Variational Auto-Encoder) :
    • 编码器 :将原始输入向量 \(\mathbf{x}\) 编码为一个较小的离散向量 \( \mathbf{z} = encoder(\mathbf{x}) \)(这里的离散向量是隐式的,是 Embedding Space 中的索引,不会直接表示出来)
    • 解码器 :将离散向量 \(\mathbf{z}\) 解码为和原始输入差不多的向量\( \mathbf{x}’ = decoder(\mathbf{z}) \)
    • 许多博主认为VQ-VAE更像是一个AE,而不是VAE,因为无法直接从已知分布中采样隐变量来生成图片,而是借助PixelCNN来实现

VQ-VAE讲解

  • VQ-VAE整体示意图如下(from Neural Discrete Representation Learning, NIPS 2017, Google DeepMind)
    • 其中 Embedding Space 是一个 \(K\times d\) 维的此表,每个向量 \(\mathbf{e}_k\) 都是 \(d\) 维向量
  • 如上图所示,从左到右,VQ-VAE的整个过程可以拆解为如下的流程:
    • 编码器 :将输入图片 \(\mathbf{x}\) 编码为 \(m\times m\) 个 \(d\) 维的连续向量,得到结果为 \(m\times m \times d\) 维,\(\mathbf{z} = z_e(\mathbf{x})\)
    • 最近邻匹配 :用 \(\mathbf{z}\) 在 Embedding Space 词表中通过最近邻匹配 ,将 \(\mathbf{z}\) 中的每个向量都映射为 Embedding Space 中的最近邻点(nearest point \(e_{k^*}\),匹配后得到的结果使用 \(z_q(\mathbf{x})\) 表示
      $$ z_q(\mathbf{x})_{i,j} = e_{k^*} = \mathop{\arg\min}_{e_k} \Vert \mathbf{z}_{i,j} - \mathbf{e}_k \Vert_2 $$
      • 最近邻搜索隐含离散的思想 :实际上,最近邻的匹配过程可以看做是,先将连续向量转化为一个离散值(索引 \(k^*\)),此时得到的是一个 \(m\times m\) 的离散矩阵,称为离散编码或离散隐变量(discrete latents),然后再将离散索引值转换为一个连续向量(索引 \(k^*\) 在 Embedding Space 中抽取向量即可)的过程
    • 解码器 :将最近邻搜索的映射结果 \(z_q(\mathbf{x})\) 解码为原始输入大小的向量 \(\hat{\mathbf{x}}\),试图重构原始输入 \(\hat{\mathbf{x}} = decoder(z_q(\mathbf{x}))\)

补充知识:Straight-Through Estimator

  • 关于 Straight-Through Estimator 的其他说明:

    from VQ-VAE的简明介绍:量子化自编码器
    VQ-VAE使用了一个很精巧也很直接的方法,称为Straight-Through Estimator,你也可以称之为“直通估计”,它最早源于Benjio的论文《Estimating or Propagating Gradients Through Stochastic Neurons for Conditional Computation》,在VQ-VAE原论文中也是直接抛出这篇论文而没有做什么讲解。但事实上直接读这篇原始论文是一个很不友好的选择,还不如直接读源代码
    事实上Straight-Through的思想很简单,就是前向传播的时候可以用想要的变量(哪怕不可导),而反向传播的时候,用你自己为它所设计的梯度

  • 博客中给了例子来说明,举例来说,设计一个如下的目标函数:
    $$ Loss = \Vert x - decoder(z + sg[z_q - z]) \Vert_2^2 $$
    • 其中 \(sg[\cdot]\) 表示 stop gradient 的含义
    • 前向传播时,上面的损失函数等价于 \(\Vert x - decoder(z_q) \Vert_2^2\)
    • 后向传播时,上面的损失函数等价于 \(\Vert x - decoder(z) \Vert_2^2\)
    • 同理,我们可以任意定义函数的梯度(实现前向和后向不一致)

VQ-VAE的损失函数

重建误差

  • 直接优化下面的重建误差是不行的,因为最近邻匹配过程梯度不可导:
    $$ L_{reconstruct} = \Vert \mathbf{x} - decoder(z_q(\mathbf{x})) \Vert_2^2 $$
  • 作者设计了下面的重建误差:
    $$ L_{reconstruct} = \Vert \mathbf{x} - decoder(z_e(\mathbf{x}) + sg[z_q(\mathbf{x}) - z_q(\mathbf{x})]) \Vert_2^2 $$
    • 前向传播时,上面的损失函数等价于 \(\Vert \mathbf{x} - decoder(z_q(\mathbf{x})) \Vert_2^2\)
    • 后向传播时,上面的损失函数等价于 \(\Vert \mathbf{x} - decoder(z_e(\mathbf{x})) \Vert_2^2\)
    • 本质上实现了将梯度从 \(z_q(\mathbf{x})\) 全部复制给了 \(z_e(\mathbf{x})\)
    • 问题:为什么可以直接这样, \(z_q(\mathbf{x})\) 和 \(z_e(\mathbf{x})\) 不相同,可以直接这样传递梯度吗?如何理解这种传递?
      • 回答:VQ-VAE中,同时会增加损失函数,保证 \(z_q(\mathbf{x})\) 和 \(z_e(\mathbf{x})\) 足够接近

Embedding Space 优化

  • Embedding Space 优化的目标 :为了保证从 \(z_q(\mathbf{x})\) 向 \(z_e(\mathbf{x})\) 复制梯度传播是OK的,我们需要 \(z_q(\mathbf{x})\) 和 \(z_e(\mathbf{x})\) 足够接近
    $$ L_{similar} = \Vert z_e(\mathbf{x}) - z_q(\mathbf{x}) \Vert_2^2$$
  • 理论上,至此已经可以了,但是原始论文中,作者将上述的损失拆解成两个了,根据博客 VQ-VAE的简明介绍:量子化自编码器 的说法,考虑到实际上 \(z_q(\mathbf{x})\) 是相对自由的,而 \(z_e(\mathbf{x})\) 则需要保证重构效果,所以希望让 \(z_q(\mathbf{x})\) 去靠近 \(z_e(\mathbf{x})\),而不是 \(z_e(\mathbf{x})\) 去靠近 \(z_q(\mathbf{x})\),所以把上面的损失函数拆解为
    $$ L_{similar} = \beta \Vert sg[z_e(\mathbf{x})] - z_q(\mathbf{x}) \Vert_2^2 + \gamma\Vert z_e(\mathbf{x}) - sg[z_q(\mathbf{x})] \Vert_2^2$$
    • 第一项相当于固定 \(z_e(\mathbf{x})\),让 \(z_q(\mathbf{x})\) 靠近 \(z_e(\mathbf{x})\),第二项同理
    • \(\beta,\gamma\) 用于调节学习比重,文章中使用 \(\gamma = 0.25\beta\)
  • codebook的其他优化方式-滑动平均方法 :
    • 实际上,对于同一个 codebook 向量 \(e_i\),可能会作为多个 \(z_e(\mathbf{x})\) 的最近邻向量而被检索,假设 \(e_i\) 的最近邻向量共 \(n_i\) 个,组合为 \(z_{i,j}\),此时有
      $$ e_i = \frac{1}{n_i}\sum_{j=1}^{n_i} z_{i,j}$$
    • 由于小批量训练时上面的公式容易出现波动,所以可以使用滑动平均(文章中使用指数移动平均(EMA))来更新 codebook,实现 codebook的在线更新

VQ-VAE损失函数的最终形式

  • VQ-VAE损失函数的最终形式可以表示如下:
    $$ L_{vq-vae} = \Vert \mathbf{x} - decoder(z_e(\mathbf{x}) + sg[z_q(\mathbf{x}) - z_q(\mathbf{x})]) \Vert_2^2 + \beta \Vert sg[z_e(\mathbf{x})] - z_q(\mathbf{x}) \Vert_2^2 + \gamma\Vert z_e(\mathbf{x}) - sg[z_q(\mathbf{x})] \Vert_2^2 $$

附录:离散化采样编码

  • 有了VQ-VAE以后,我们已经可以将图片编码为 \(m\times m\) 的离散矩阵了,此时使用 PixelCNN 来学习编码分布,然后再利用 PixelCNN 来随机生成新的编码矩阵,再映射回到 \(z_q(\mathbf{x})\),从而可通过解码器生成图片

附录:VQ-VAE与VAE的关系讨论

  • 从VAE将图片编码为一个高斯分布,然后再重建的思路看,VQ-VAE将图片编码为一个离散分布,然后再重建,只是VQ-VAE的这个离散分布不容易采样,导致需要使用一个额外的 PixelCNN 来学习
  • 相对VAE,VQ-VAE中是没有KL散度项的,但也有人推导,博客 VQ-VAE的简明介绍:量子化自编码器 中的评论

附录:VQ-VAE-2

  • 原始论文:Generating Diverse High-Fidelity Images with VQ-VAE-2, NeurIPS 2019, Google
  • 整体结构如下:
  • VQ-VAE-2 相对 VQ-VAE 的核心改进是:

    主要变化就是把 VQ-VAE 的 encoder 和 decoder 都进行了分层, bottom层对local feature进行建模,top层采取全局自注意力机制


附录:VQ-VAE中的 Codebook Collapse 问题

  • Codebook Collapse(码本坍塌) 是 VQ-VAE(Vector Quantized Variational Autoencoder)及其变体中常见的一个问题,指的是在训练过程中 ,编码本(codebook)中的大量向量从未被使用 ,只有少数几个编码向量被频繁使用的情况
  • Codebook Collapse 问题表现 :
    • 编码向量利用率低 :大部分codebook向量在训练过程中从未被选择
    • 信息损失 :由于实际使用的编码向量远少于设计容量,模型表达能力受限
    • 重建质量下降 :有限的活跃编码向量难以充分表示输入的多样性
  • Codebook Collapse 问题产生原因 :
    • 某些编码向量可能在训练早期更容易被选择,后来跟输出越来越接近,形成”富者愈富”效应;
    • VQ的硬分配机制使得未被选择的编码向量无法获得梯度更新,从而导致某些编码向量长期得不到更新
  • Codebook Collapse 问题解决方案 :
    • 定期重置未被使用的编码向量,让这些向量有机会被更新;
    • 引入一定程度的软分配(如Soft-VQ),以一定概率匹配最近邻向量;
    • 添加鼓励codebook利用的正则项;
  • 注:Codebook 向量越多,Codebook Collapse 问题就越严重
  • Codebook collapse问题直接影响VQ-VAE的性能,解决这一问题对于提高模型表现和压缩效率至关重要

Linux——Ubuntu和Centos服务器管理


Centos

配置静态IP

  • 查看网卡名称

    1
    ifconfig
    • 查看网卡信息,每行的第一项为网卡名称
    • 一般服务器可能有多个网卡,按照需求选择一个即可
    • 网卡信息包含当前网卡的ipv4和ipv6地址,MAC地址等信息
  • 根据网卡名字打开相应网卡的配置文件

    1
    2
    # 假设网卡名称为eth0
    vi /etc/sysconfig/network-scripts/ifcfg-eth0
  • 修改相关配置内容

    1
    2
    3
    4
    5
    6
    7
    IPADDR=12.12.12.12
    NETMASK=255.255.255.0
    GATEWAY=12.12.12.1
    ONBOOT=yes
    BOOTPROTO=static
    DNS1=114.114.114.114
    DNS2=8.8.8.8
    • 等号后面是具体的ip地址名称
    • DNS可以有多个,用数字标识即可
  • 重新启动网络服务

    1
    service network restart

管理用户

修改root密码

默认可远程登录root用户,只需知道密码即可(SSH默认已经安装)

  • 修改root密码

    1
    passwd
  • 若需要找回root密码,参考博客 https://blog.csdn.net/shanvlang/article/details/80385913

添加用户

假设添加用户名为test的用户

  • 添加新用户

    1
    useradd test
    • centos中,以上命令将自动为test用户分配一个属于test用户的/home/test文件夹
  • 为新用户修改密码

    1
    passwd test
  • 添加用户权限

    • 打开配置文件

    • 如果root用户没有该文件的写权限的话需要用chmod u+w /etc/sudoers, 修改完成再改回到chmod u-w /etc/sudoers

      1
      vi /etc/sudoers
    • 编辑以下内容,注意空格类型,最好复制一行修改

      1
      2
      3
      ## Allow root to run any commands anywhere
      root ALL=(ALL) ALL
      test ALL=(ALL) ALL
  • 删除用户

    1
    userdel test

Ubuntu

配置静态IP

  • 查看网卡名称

    1
    ifconfig
    • 查看网卡信息,每行的第一项为网卡名称
    • 一般服务器可能有多个网卡,按照需求选择一个即可
    • 网卡信息包含当前网卡的ipv4和ipv6地址,MAC地址等信息
  • 修改配置文件

    1
    vi /etc/network/interfaces
  • 修改相关配置内容

    1
    2
    3
    4
    5
    6
    7
    8
    # 假设网卡名称为eth0

    auto eth0
    iface eth0 inet static
    address 12.12.12.12
    netmask 255.255.255.0
    gateway 12.12.12.1
    dns-nameserver 114.114.114.114 8.8.8.8
    • dns可以有多个,以空格间隔开
  • 重新启动网络服务

    1
    sudo /etc/init.d/networking restart

管理用户

修改root密码

Ubuntu默认禁用root用户登录,需要配置root账户才能以root身份登录(SSH默认已经安装)

  • 修改root密码

    1
    passwd
  • 若需要找回root密码,参考博客 https://blog.csdn.net/shanvlang/article/details/80385913

添加用户

假设添加用户名为test的用户

  • 添加新用户

    1
    useradd test
    • Ubuntu中以上命令并不会直接为当前用户分配自己的文件夹,所以需要我们为其手动添加一个并使用chown test /home/test命令将文件家分配给test用户,这样使用test用户登录时将会自动转到/home/test文件夹下面工作
  • 为新用户修改密码

    1
    passwd test
  • 添加用户权限

    • 打开配置文件

    • 如果root用户没有该文件的写权限的话需要用chmod u+w /etc/sudoers, 修改完成再改回到chmod u-w /etc/sudoers

      1
      vi /etc/sudoers
    • 编辑以下内容,注意空格类型,最好复制一行修改

      1
      2
      3
      # User privilege specification
      root ALL=(ALL:ALL) ALL
      test ALL=(ALL:ALL) ALL
  • 删除用户

    1
    userdel test

Linux——Ubuntu和Centos服务器管理


Terminal无法访问外网

  • 问题现象 : 当在Linux上安装Clash后,浏览器可以访问而终端(Terminal)不行

  • 问题原因 :Clash设置的代理环境变量未正确配置到终端中,导致终端无法使用代理

  • 解决方法 :手动配置终端的代理环境变量。假设Clash监听的端口是7890,可以在终端中输入以下命令设置HTTP和HTTPS代理:

    1
    2
    export http_proxy=http://127.0.0.1:7890
    export https_proxy=http://127.0.0.1:7890
    • 如果使用的是Zsh shell,需要将上述命令添加到~/.zshrc文件中;
    • 如果是Bash shell,则添加到~/.bashrc文件中,然后执行source ~/.zshrc或source ~/.bashrc使配置生效

Git——GitHub开源协议


整体说明

  • GitHub上有许多开源协议,本文总结常见的开源协议及其含义

MIT License

  • 极宽松,允许自由使用、修改和分发,只需保留版权声明。无担保,作者不承担责任
  • 适用场景:适合个人项目或希望代码广泛传播的场景
  • 个人开发者常使用的协议

Apache License 2.0

  • 允许商业使用、修改和分发,需保留版权和许可证
  • 特殊条款 :专利授权,明示禁止商标使用
  • 适用场景:企业项目,需明确专利授权
  • 目前的大模型大多使用的这个协议

GNU GPL v3

  • 强Copyleft,修改和分发需开源且保持相同许可证。衍生作品必须开源,商业分发需提供源代码
  • 适用场景:确保代码及其衍生版本永远开源

GNU LGPL v3

  • 弱Copyleft,允许闭源软件通过库引用方式使用。修改LGPL库本身需开源
  • 适用场景:开发开源库,允许闭源应用调用

BSD 2-Clause “Simplified” License

  • 允许自由使用和修改,禁止用作者名义推广。需保留版权声明
  • 适用场景:类似MIT,但限制稍多

BSD 3-Clause “New” License

  • 在2-Clause基础上增加禁止使用作者商标的条款
  • 适用场景:需明确商标保护的项目

Mozilla Public License 2.0 (MPL 2.0)

  • 部分Copyleft,修改文件需开源,未修改部分可闭源
  • 适用场景:适合混合开源/闭源的组件化项目

Creative Commons Licenses

  • CC0 :放弃版权,进入公有领域
  • BY :允许商用,但需署名
  • NC :禁止商业使用
  • 适用场景:非软件类作品(如文档、设计)

Unlicense

  • 放弃所有版权,代码进入公有领域
  • 适用场景:完全开放的公共项目

选择建议

  • 希望代码广泛传播: MIT/Apache
  • 确保衍生作品开源: GPL
  • 开发开源库: LGPL
  • 非软件作品: CC系列

Git——Git环境配置


安装 Git

  • 可以命令行安装,也可以从 Git 的官方网站(https://git-scm.com/downloads)下载安装程序,然后按照安装向导的提示完成安装
    1
    git --version

配置用户名和邮箱

  • Git 在提交代码时会使用这些信息来标识提交者

  • 执行以下命令来设置用户名和邮箱:

    1
    2
    git config --global user.name "你的用户名"
    git config --global user.email "你的邮箱地址"
  • 这里使用的--global参数表示这是全局配置,在这台计算机上进行的所有Git操作都会使用这些信息

  • 如果你想为某个特定的项目设置不同的用户名和邮箱,可以在该项目的根目录下执行相同的命令 ,但不使用--global参数


查看配置信息

  • 可以通过以下命令来查看当前的 Git 配置信息:

    1
    git config --list
  • 执行该命令后,终端会列出所有的Git配置项,你可以从中找到user.name和user.email,确认它们是否是你刚刚设置的内容


SSH 配置

  • 查看 SSH 秘钥

    1
    ls -al ~/.ssh
    • 若存在,会看到类似 id_rsa.pub 或 id_ed25519.pub 的文件(.pub 为公钥,无后缀为私钥)
  • 若无秘钥,需先生成秘钥

    1
    ssh-keygen -t ed25519 -C "your_email@example.com"
    • -t ed25519:使用更安全的 Ed25519 算法(推荐使用)

附录:配置文件位置

  • Git 的配置信息存储在不同的文件中,具体取决于配置的范围:
    • 全局配置 :存储在用户主目录下的.gitconfig文件中
    • 项目配置 :存储在项目根目录下的.git/config文件中

Git——问题记录


Ubuntu 中文乱码问题

  • 解决方案
    1
    git config --global core.quotepath false

Windows 拉取项目后无法 checkout

  • 表现:拉取远程分支后无法进行 checkout 操作,具体错误表现为

    1
    fatal:unable to checkout working tree
  • 原因:一般是因为文件名命名包含非法字符导致,比如亲测文件名包含 | 就会出错(通常是有些不适用 Windows 且命名不规范的作者容易出现该错误)

  • 解决方案:修改文件名称,将非法字符去掉


文件权限导致记录更改

  • 现象:文件权限修改(如执行权限改为无执行权限)也会导致文件被默认为修改,此时文件内容没有任何修改
  • 具体细节:在使用 git diff 时看到的 old mode 100755 和 new mode 100644,核心是 Git 检测到文件的执行权限发生了变化,而非文件内容的修改
    • 755:代表文件拥有执行权限(所有者可读可写可执行,组和其他用户可读可执行),常见于脚本、可执行程序
    • 644:代表文件无执行权限(所有者可读可写,组和其他用户仅可读),是普通文论文件的默认权限
    • 注:权限位规则:755(可执行)= rwxr-xr-x,644(不可执行)= rw-r–r–
  • TLDR:有意修改则直接提交,误改可恢复权限,跨系统开发建议关闭 core.filemode 忽略权限检测

补充问题:为什么会出现这个差异?

  • 常见原因有 2 种:
    • 1)手动修改了权限:可能通过 chmod 命令(如 chmod 644 文件名)修改了文件权限
    • 2)系统/工具自动调整:不同操作系统(如 Windows 和 Linux)、Git 配置或编辑器可能自动调整权限

解法1:接受权限变更并提交(如果是有意修改)

  • 如果这个权限修改是刻意想要的,直接正常提交即可:
    1
    2
    3
    4
    5
    # 添加权限变更的文件到暂存区
    git add 你的文件名

    # 提交变更(备注说明权限修改)
    git commit -m "调整xxx文件权限:从100755改为100644,移除执行权限"

忽略权限变更(避免 Git 追踪权限)

  • 如果只是误操作,或不想让 Git 检测权限变化(比如跨系统开发时),可以配置 Git 忽略文件权限:

    1
    2
    3
    4
    5
    6
    7
    8
    # 临时忽略(仅当前仓库生效,关闭终端/切换仓库失效)
    git config core.filemode false

    # 永久忽略(当前仓库全局生效)
    git config --local core.filemode false

    # 全局忽略(所有Git仓库生效)
    git config --global core.filemode false
    • 配置后,Git 就不会再检测文件权限的变化,git diff 也不会再显示这类差异

恢复原有权限(撤销误改的权限)

  • 如果想把文件权限改回原来的(如 100755),执行:
    1
    2
    3
    4
    5
    # 恢复为可执行权限(755)
    chmod 755 你的文件名

    # 验证权限是否恢复
    ls -l 你的文件名 # 输出中权限列会显示 -rwxr-xr-x

Python——PyCharm使用笔记


PyCharm使用技巧记录

  • PyCharm IDE 卡顿,可考虑 Help->VM Options 增加虚拟机内存
  • PyCharm IDE 显示连字形式,<= 仅显示一个 \(\le\),修改 File-> Settings -> Editor -> General -> Font 可以切换回来,亲测 Monaco 可以
  • PyCharm IDE 显示当前代码所在路径:View -> Appearance -> Navigation Bar
  • PyCharm IDE 显示当前文件结构:View -> Tool Windows -> Structure
  • PyCharm IDE 显示当前行所属类和函数: 在 Settings 全局搜索 Breadcrumbs 并打开
  • PyCharm IDE 识别指定子目录下的项目,比如第三方项目(./sub_module/my_project/)等,直接将该项目的文件夹设置为 Root Source

Python——Pydantic库简单学习


整体说明

  • Pydantic 库可利用 Python 类型提示对数据进行验证、解析、转换以及管理,确保数据的完整性、规范性和一致性
  • Pydantic 库还方便数据在不同格式间的序列化与反序列化

安装

  • 使用以下命令安装 Pydantic:
    1
    pip install pydantic

基本使用

定义数据模型

  • 通过继承BaseModel来定义数据模型类,类中的字段使用类型注解来指定数据类型
    1
    2
    3
    4
    5
    6
    7
    from pydantic import BaseModel

    class User(BaseModel):
    id: int
    name: str
    age: int
    is_active: bool = True

数据验证和解析

  • 创建数据模型的实例时,Pydantic 会自动进行数据验证和解析
    • 如果数据符合模型定义,就可以正常创建实例;
    • 如果数据无效,会抛出ValidationError异常
  • 示例如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    data = {
    "id": 1,
    "name": "Alice",
    "age": 30
    }
    user = User(**data)
    print(user)

    invalid_data = {
    "id": "invalid", # id应该是int类型
    "age": "thirty" # age应该是int类型
    }
    try:
    user = User(**invalid_data)
    except ValidationError as e:
    print(e)

高级特性

  • 可选字段 :使用Optional类型来定义可选字段。例如:

    1
    2
    3
    4
    5
    6
    7
    from typing import Optional
    from pydantic import BaseModel

    class User(BaseModel):
    id: int
    name: str
    age: Optional[int]
  • 默认值 :可以在定义字段时直接设置默认值。例如:

    1
    2
    3
    4
    5
    6
    from pydantic import BaseModel

    class User(BaseModel):
    id: int
    name: str = "Jane Doe"
    age: int = 18
  • 允许多种数据类型 :通过类型提示允许字段接受多种数据类型。例如:

    1
    2
    3
    4
    5
    6
    from typing import Union
    from pydantic import BaseModel

    class User(BaseModel):
    id: Union[int, str]
    name: str
  • 枚举类型 :Pydantic支持枚举类型,用于限制字段的值只能是预定义的一组值之一。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from enum import Enum
    from pydantic import BaseModel

    class Gender(str, Enum):
    MALE = "male"
    FEMALE = "female"

    class User(BaseModel):
    id: int
    name: str
    gender: Gender
  • 嵌套模型 :可以定义嵌套的模型来表示复杂的数据结构。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from pydantic import BaseModel

    class Address(BaseModel):
    street: str
    city: str
    zip_code: str

    class User(BaseModel):
    id: int
    name: str
    address: Address
  • 自定义验证器 :使用validator装饰器可以在数据被解析后进行额外的验证。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from pydantic import BaseModel, validator

    class User(BaseModel):
    age: int

    @validator('age')
    def check_age(cls, value):
    if value < 0:
    raise ValueError('Age must be a non - negative integer')
    return value

其他功能

  • 数据模型实例具有一些属性和方法,如dict()返回模型字段和值的字典,json()返回JSON字符串表示,copy()创建模型的副本等
  • 使用create_model方法可以动态创建模型(不常用):
    1
    2
    3
    from pydantic import create_model

    DynamicModel = create_model('DynamicModel', foo=(str, ...), bar=123)

Python——Pylint库简单学习


Pylint 整体说明

  • Pylint 是面向 Python 的静态代码分析工具(linter),在不运行代码的前提下检查错误、执行编码规范、识别代码异味,并给出重构建议;
  • Pylint 可与 flake8(轻量快检)、mypy/pyright/pyre(类型检查)、bandit(安全检查)、black/isort(格式化)、autoflake/pyupgrade(清理/升级)等配合使用
  • 大部分 IDE 会自动集成该功能
  • Pylint 高度可配置,支持编写自定义插件,适配内部库或框架(如 pylint-django)

Pylint 能做什么

  • 语法/语义错误与未使用变量/导入
  • 命名、缩进、行长度等风格与 PEP 8 一致性
  • 复杂度与设计问题(长函数、深嵌套等)
  • 未显式类型时的节点值推断(基于 astroid),能识别别名导入带来的误用风险
  • 提供代码质量评分与报告,并支持生成包/类图(pyreverse)、查找重复代码(symilar)

Pylint 安装与使用

  • 安装:pip install pylint
  • 命令行:pylint your_module.py 或 pylint your_package/
  • 可集成到 VS Code、PyCharm、Emacs 等编辑器/IDE
  • 首次使用:先开 --errors-only,再按需启用样式/重构提示,逐步收紧规则
1…464748…67
Joe Zhou

Joe Zhou

Stay Hungry. Stay Foolish.

662 posts
53 tags
GitHub E-Mail
© 2026 Joe Zhou
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4