LLaMA系列模型

news2024/9/30 9:23:42

1.LLama

1.1 简介

Open and Efficient Foundation Language Models (Open但没完全Open的LLaMA)

2023年2月,Meta(原Facebook)推出了LLaMA大模型,使用了1.4T token进行训练,虽然最大模型只有65B,但在相关评测任务上的效果可以媲美甚至超过千亿级大模型,被认为是近期开源大模型百花⻬放的开端之一,“羊驼”系列模型及其生态快速发展。

LLaMA 所采用的 Transformer 结构和细节,与标准的 Transformer 架构不同的地方包括采用了前置层归一化(Pre-normalization)并使用 RMSNorm 归一化函数 (Normalizing Function)、激活函数更换为 SwiGLU,并使用了旋转位置嵌入(RoP),整体 Transformer 架构与 GPT-2 类似。

在这里插入图片描述

1.2 RMSNorm归一化函数

为了使得模型训练过程更加稳定,GPT-2 相较于 GPT 就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了 RMSNorm 归一化函数。 针对输入向量 aRMSNorm 函数计算公式如下

R M S ( a ) = 1 n ∑ i = 1 n a i 2 R M S(a)=\sqrt{\frac{1}{n} \sum_{i=1}^{n} a_{i}^{2}} RMS(a)=n1i=1nai2

a ˉ i = a i R M S ( a ) \bar{a}_{i}=\frac{a_{i}}{R M S(\boldsymbol{a})} aˉi=RMS(a)ai

此外,RMSNorm 还可以引入可学习的缩放因子 g i g_i gi 和偏移参数 b i b_i bi,从而得到 a ˉ i = a i RMS ⁡ ( a ) g i + b i \bar{a}_{i}=\frac{a_{i}}{\operatorname{RMS}(\boldsymbol{a})} g_{i}+b_{i} aˉi=RMS(a)aigi+bi。 RMSNorm 在 HuggingFace Transformer 库中代码实现如下所示:

class LlamaRMSNorm(nn.Module):
  def __init__(self, hidden_size, eps=1e-6): 
    """ 
    LlamaRMSNorm is equivalent to T5LayerNorm 
    """ 
    super().__init__() 
    self.weight = nn.Parameter(torch.ones(hidden_size)) 
    self.variance_epsilon = eps # eps 防止取倒数之后分母为 0 
  
  def forward(self, hidden_states): 
    input_dtype = hidden_states.dtype 
    variance = hidden_states.to(torch.float32).pow(2).mean(-1, keepdim=True) 
    hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) # weight 是末尾乘的可训练参数, 即 g_i 
    
    return (self.weight * hidden_states).to(input_dtype)

1.3 SwiGLU计划函数

SwiGLU激活函数是相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA 中全连接层 使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-Forward Network)的计算公式如下:

FFN ⁡ SwiGLU  ( x , W , V , W 2 ) = SwiGLU ⁡ ( x , W , V ) W 2 \operatorname{FFN}_{\text {SwiGLU }}\left(\boldsymbol{x}, \boldsymbol{W}, \boldsymbol{V}, \boldsymbol{W}_{2}\right)=\operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W}, \boldsymbol{V}) \boldsymbol{W}_{2} FFNSwiGLU (x,W,V,W2)=SwiGLU(x,W,V)W2

SwiGLU ⁡ ( x , W , V ) = Swish ⁡ β ( x W ) ⊗ x V \operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W}, \boldsymbol{V})=\operatorname{Swish}_{\beta}(x \boldsymbol{W}) \otimes \boldsymbol{x} \boldsymbol{V} SwiGLU(x,W,V)=Swishβ(xW)xV

Swish ⁡ β ( x ) = x σ ( β x ) \operatorname{Swish}_{\beta}(\boldsymbol{x})=\boldsymbol{x} \sigma(\boldsymbol{\beta} \boldsymbol{x}) Swishβ(x)=xσ(βx)

其中, σ ( x ) σ(x) σ(x) 是 Sigmoid 函数。下图给出了 Swish 激活函数在参数 β β β 不同取值下的形状。可以看 到当 β β β 趋近于 0 时,Swish 函数趋近于线性函数 y = x y = x y=x,当 β β β 趋近于无穷大时,Swish 函数趋近于 ReLU 函数, β β β 取值为 1 时,Swish 函数是光滑且非单调。在 HuggingFace 的 Transformer 库中 Swish1 函数使用 silu 函数代替。

在这里插入图片描述

LLaMA中直接将FFN中的ReLU替换为SwiGLU,并将维度放缩为 ( 2 / 3 ) ⋅ 4 d (2/3) ⋅ 4d (2/3)4d

在这里插入图片描述

1.4 旋转位置嵌入(RoPE)

在位置编码上,使用旋转位置嵌入(Rotary Positional Embeddings,RoPE)代替原有的绝 对位置编码。RoPE 借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给 qk 添加绝对位置信息:

q ~ m = f ( q , m ) , k ~ n = f ( k , n ) \tilde{\boldsymbol{q}}_{m}=f(\boldsymbol{q}, m), \tilde{\boldsymbol{k}}_{n}=f(\boldsymbol{k}, n) q~m=f(q,m),k~n=f(k,n)

经过上述操作后, q ~ m \tilde{\boldsymbol{q}}_{m} q~m k ~ n \tilde{\boldsymbol{k}}_{n} k~n就带有位置m和n的绝对位置信息。

最终可以得到二维情况下用复数表示的 RoPE:

f ( q , m ) = R f ( q , m ) e i Θ f ( q , m ) = ∥ q ∥ e i ( Θ ( q ) + m θ ) = q e i m θ f(\boldsymbol{q}, m)=R_{f}(\boldsymbol{q}, m) e^{i \Theta_{f}(\boldsymbol{q}, m)}=\|\boldsymbol{q}\| e^{i(\Theta(\boldsymbol{q})+m \theta)}=\boldsymbol{q} e^{i m \theta} f(q,m)=Rf(q,m)eiΘf(q,m)=qei(Θ(q)+mθ)=qeimθ

根据复数乘法的几何意义,上述变换实际上是对应向量旋转,所以位置向量称为“旋转式位置编 码”。还可以使用矩阵形式表示

f ( q , m ) = ( cos ⁡ m θ − sin ⁡ cos ⁡ m θ sin ⁡ m θ cos ⁡ m θ ) ( q 0 q 1 ) f(\boldsymbol{q}, m)=\left(\begin{array}{cc}\cos m \theta & -\sin \cos m \theta \\ \sin m \theta & \cos m \theta\end{array}\right)\left(\begin{array}{l}\boldsymbol{q}_{0} \\ \boldsymbol{q}_{1}\end{array}\right) f(q,m)=(cosmθsinmθsincosmθcosmθ)(q0q1)

根据内积满足线性叠加的性质,任意偶数维的 RoPE,都可以表示为二维情形的拼接,即:

f ( q , m ) = ( cos ⁡ m θ 0 − sin ⁡ m θ 0 0 0 ⋯ 0 0 sin ⁡ m θ 0 cos ⁡ m θ 0 0 0 ⋯ 0 0 0 0 cos ⁡ m θ 1 − sin ⁡ m θ 1 ⋯ 0 0 0 0 sin ⁡ m θ 1 cos ⁡ m θ 1 ⋯ 0 0 ⋯ ⋯ ⋯ ⋯ ⋱ ⋯ ⋯ 0 0 0 0 ⋯ cos ⁡ m θ d / 2 − 1 − sin ⁡ m θ d / 2 − 1 0 0 0 0 ⋯ sin ⁡ m θ d / 2 − 1 cos ⁡ m θ d / 2 − 1 ) ⏟ R d ( q 0 q 1 q 2 q 3 ⋯ q d − 2 q d − 1 ) f(\boldsymbol{q}, m)=\underbrace{\left(\begin{array}{ccccccc}\cos m \theta_{0} & -\sin m \theta_{0} & 0 & 0 & \cdots & 0 & 0 \\ \sin m \theta_{0} & \cos m \theta_{0} & 0 & 0 & \cdots & 0 & 0 \\ 0 & 0 & \cos m \theta_{1} & -\sin m \theta_{1} & \cdots & 0 & 0 \\ 0 & 0 & \sin m \theta_{1} & \cos m \theta_{1} & \cdots & 0 & 0 \\ \cdots & \cdots & \cdots & \cdots & \ddots & \cdots & \cdots \\ 0 & 0 & 0 & 0 & \cdots & \cos m \theta_{d / 2-1} & -\sin m \theta_{d / 2-1} \\ 0 & 0 & 0 & 0 & \cdots & \sin m \theta_{d / 2-1} & \cos m \theta_{d / 2-1}\end{array}\right)}_{\boldsymbol{R}_{d}}\left(\begin{array}{c}\boldsymbol{q}_{0} \\ \boldsymbol{q}_{1} \\ \boldsymbol{q}_{2} \\ \boldsymbol{q}_{3} \\ \cdots \\ \boldsymbol{q}_{d-2} \\ \boldsymbol{q}_{d-1}\end{array}\right) f(q,m)=Rd cosmθ0sinmθ00000sinmθ0cosmθ0000000cosmθ1sinmθ10000sinmθ1cosmθ1000000cosmθd/21sinmθd/210000sinmθd/21cosmθd/21 q0q1q2q3qd2qd1

在这里插入图片描述

RoPE 在 HuggingFace Transformer 库中代码实现如下所示:

import torch

def precompute_freqs_cis(dim: int, end: int, constant: float = 10000.0):
    '''
    计算cos和sin的值,cos值在实部,sin值在虚部,类似于 cosx+j*sinx
    :param dim: q,k,v的最后一维,一般为emb_dim/head_num
    :param end: 句长length
    :param constant: 这里指10000
    :return:
    复数计算 torch.polar(a, t)输出, a*(cos(t)+j*sin(t))
    '''
    # freqs: 计算 1/(10000^(2i/d) ),将结果作为参数theta
    # 形式化为 [theta_0, theta_1, ..., theta_(d/2-1)]
    freqs = 1.0 / (constant ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) # [d/2]

    # 计算m
    t = torch.arange(end, device=freqs.device)  # [length]
    # 计算m*theta
    freqs = torch.outer(t, freqs).float()  # [length, d/2]
    # freqs形式化为 [m*theta_0, m*theta_1, ..., m*theta_(d/2-1)],其中 m=0,1,...,length-1

    # 计算cos(m*theta)+j*sin(m*theta)
    freqs_cis = torch.polar(torch.ones_like(freqs), freqs)  # complex64
    # freqs_cis: [cos(m*theta_0)+j*sin(m*theta_0),  cos(m*theta_1)+j*sin(m*theta_1),), ..., cos(m*theta_(d/2-1))+j*sin(m*theta_(d/2-1))]
    # 其中j为虚数单位, m=0,1,...,length-1
    return freqs_cis # [length, d/2]

def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
    ndim = x.ndim
    assert 0 <= 1 < ndim
    assert freqs_cis.shape == (x.shape[1], x.shape[-1])
    shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] # (1, length, 1, d/2)
    return freqs_cis.view(*shape) # [1, length, 1, d/2]

def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor,):
    # 先将xq维度变为[bs, length, head,  d/2, 2], 利用torch.view_as_complex转变为复数
    # xq:[q0, q1, .., q(d-1)] 转变为 xq_: [q0+j*q1, q2+j*q3, ..., q(d-2)+j*q(d-1)]
    xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [bs, length, head, d/2]
    # 同样的,xk_:[k0+j*k1, k2+j*k3, ..., k(d-2)+j*k(d-1)]
    xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))

    freqs_cis = reshape_for_broadcast(freqs_cis, xq_) # [1, length, 1, d/2]
    # 下式xq_ * freqs_cis形式化输出,以第一个为例, 如下
    # (q0+j*q1)(cos(m*theta_0)+j*sin(m*theta_0)) = q0*cos(m*theta_0)-q1*sin(m*theta_0) + j*(q1*cos(m*theta_0)+q0*sin(m*theta_0))
    # 上式的实部为q0*cos(m*theta_0)-q1*sin(m*theta_0),虚部为q1*cos(m*theta_0)+q0*sin(m*theta_0)
    # 然后通过torch.view_as_real函数,取出实部和虚部,维度由[bs, length, head, d/2]变为[bs, length, head, d/2, 2],最后一维放实部与虚部
    # 最后经flatten函数将维度拉平,即[bs, length, head, d]
    # 此时xq_out形式化为 [实部0,虚部0,实部1,虚部1,..., 实部(d/2-1), 虚部(d/2-1)]
    xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3) # [bs, length, head, d]
    # 即为新生成的q

    xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
    return xq_out.type_as(xq), xk_out.type_as(xk)

if __name__=='__main__':
    # (bs, length, head, d)
    q = torch.randn((2, 10, 12, 32))  # q=[q0, q1, .., qd-1]
    k = torch.randn((2, 10, 12, 32))
    v = torch.randn((2, 10, 12, 32))
    freqs_cis= precompute_freqs_cis(dim=32, end=10, constant= 10000.0)
    # print(freqs_cis.detach().numpy())

    q_new, k_new = apply_rotary_emb(xq=q, xk=k, freqs_cis=freqs_cis)
    print()

2.Alpaca

2.1 简介

Stanford Alpaca: An Instruction-following LLaMA Model

Alpaca是在LLaMA基础上使用52K指令数据精调的预训练模型,作者只用了不到600美元的成本训练出了该模型(数据$500 + 机器$100)。初步实验结果表明Alpaca可以达到与OpenAI text-davinci-003相匹敌的效果

2.2 微调方法

  1. 第一步:构造175条self-instruct 种子示例任务
  2. 第二步:基于上述种子任务,利 用text-davinci-003爬取指令数据
  3. 第三步:使用爬取下来的52K指令 数据在LLaMA上进行精调,最终 得到Alpaca

在这里插入图片描述

2.3 Self-instruct数据构造

首先由人工构造175条种子数据

{
  "id": "seed_task_25", 
  "name": "perfect_numbers", 
  "instruction": "Find the four smallest perfect numbers.", 
  "instances": [{ "input": "", "output": "6, 28, 496, and 8128}], 
  "is_classification": false
}

将“爬取要求”和种子数据进行适当组合,送入textdavinci-003,要求生成类似的指令数据。要求包括:提升指令多样性、包含真实数据、字数 要求、语言要求、拒绝不合适指令等

2.4 指令数据格式

  • instruction: 描述模型需要执行的指令内容
  • input(可选): 任务上下文或输入信息,例如当指令是“对文章进行总结”,则input是文章内容
  • output: 由text-davinci-003生成的针对指令的回复

在这里插入图片描述

3.Llama-2

3.1 简介

Llama 2: Open Foundation and Fine-Tuned Chat Models

2023年7月,Meta推出了Llama-2开源大模型,并且推出了Llama-2-Chat对话模型

与一代LLaMA主要区别体现在更多的训练数据、更⻓的上下文窗口、GQA技术

在这里插入图片描述

模型结构的变动主要是体现在GQAFFN缩放上

  • MHA改成GQA:整体参数量会有减少
  • FFN模块矩阵维度有扩充:增强泛化能力,整体参数量增加
  • 上下文长度是llama两倍(长度从2048->4096) 训练语料增加约 40%,体现在1.4T->2.0T的Tokens llama2-34B和llama2-70B使用了GQA,加速模型训练和推理速度

3.2 GQA

GQA和MQA都是注意力的变体,其中多个查询头关注相同的键和值头,以减少推理过程中 KV 缓存的大小,并可以显著提高推理吞吐量。

MHA、GQA、MQA的区别和联系,具体的优点如下:

  • Mutil-Head Attention 因为自回归模型生成回答时,需要前面生成的KV缓存起来,来加速计算。
  • Multi-Query Attention 多个头之间可以共享KV对,因此速度上非常有优势,实验验证大约减少30-40%吞吐。
  • Group Query Attention 没有像MQA那么极端,将query分组,组内共享KV,效果接近MQA,速度上与MQA可比较。

在这里插入图片描述

Llama-2中使用了8个KV映射,即GQA-8,GQA在多数任务上与MHA效果相当,且平均效果优于MQA;GQA和MQA均比MHA有更好的吞吐量

3.3 源码

在这里插入图片描述

4.Code Llama

4.1 简介

2023年8月24日,Meta推出了面向代码的可商用大模型Code Llama,包含三个大小版本(7B/13B/34B)

支持多种编程语言,包括Python、C++、Java、PHP、Typescript (Javascript)、C#和Bash

亮点:

  • 免费供学术研究和商用
  • 支持100K上下文
  • “神秘”34B版接近GPT-4效果

4.2 模型训练流程

在这里插入图片描述

4.3 Code Infilling Task (7B/13B only)

任务目标:根据代码的上下文,预测残缺部分的代码

方法:

  • 从完整的代码中选择一部分进行掩码(mask)并替换为<MASK>符号,构成上下文
  • 利用自回归的方法,根据上下文信息预测解码出被mask的代码部分

在这里插入图片描述

5.总结

LLaMA

  • 开源大模型繁荣发展的开端,一系列相关工作均基于LLaMA开展
  • 模型规模7B、13B、33B、65B满足了开发者和研究者的不同需求

Alpaca:通过少量的指令精调赋予LLaMA指令理解与执行的能力

Llama-2

  • LLaMA的二代模型,相关模型性能进一步提升,模型可商用
  • 推出官方对⻬的Chat版本模型,采用了完整的RLHF链条

Code Llama:专注于代码能力的LLaMA模型,最好的模型代码能力接近GPT-4效果,模型可商用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1322793.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python实战:信用卡客户历史数据挖掘与分析

Python实战&#xff1a;信用卡客户历史数据挖掘与分析 引言数据获取与预处理描述性分析模型建立与评估结果分析Web应用展示&#xff08;可选&#xff09; 引言 信用卡客户历史数据分析是金融领域中的重要课题之一。通过对公开数据集的挖掘&#xff0c;本文将利用Python编程语言…

51单片机LED与无源蜂鸣器模块

IO口的使用1 本文主要对51单片机的LED灯的使用以及蜂鸣器的使用进行介绍&#xff0c;其中包括一些实例分析&#xff1a; 1.实现发光二极管的从左到右的流水点亮 2.左右来回循环的流水灯 3.蜂鸣器以一定频率响 文章目录 IO口的使用1一、LED灯举个栗子一举个栗子二 二、蜂鸣器2.1…

华为OD机试 - 连续出牌数量 - 深度优先搜索dfs算法(Java 2023 B卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述1、输入2、输出3、说明 四、解题思路1、题目解读2、具体步骤 五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08…

Linux--学习记录(3)

G重要编译参数 -g&#xff08;GDB调试&#xff09; -g选项告诉gcc产生能被GNU调试器GDB使用的调试信息&#xff0c;以调试程序编译带调试信息的可执行文件g -g hello.c -o hello编译过程&#xff1a; -E&#xff08;预处理&#xff09; g -E hello.c -o hello.i-S&#xff08;编…

基于springboot+vue 的智能物流管理系统

简介 基于springbootvue 的智能物流管理系统 适用于 设计&#xff0c;课程设计参考与学习用途。仅供学习参考。 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料 **项目编号&#xff1a;springboot074 ** **…

C++刷题 -- KMP算法

C刷题 – KMP算法 文章目录 C刷题 -- KMP算法1.算法讲解2.算法实现 https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/ 1.算法讲解 KMP算法是一种字符串匹配算法&#xff0c;当出现字符串不匹配时&#xff0c;可以记录一部分之…

数据可视化---箱线图

类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统计学检验箱…

【MySQL】Sql优化之索引的使用方式(145)

索引分类 1.单值索引 单的意思就是单列的值&#xff0c;比如说有一张数据库表&#xff0c;表内有三个字段&#xff0c;分别是 id name numberNo&#xff0c;我给name 这个字段加一个索引&#xff0c;这就是单值索引&#xff0c;因为只有name 这一列是索引&#xff1b; 一个表…

k8s-ingress特性 9

TLS加密 创建证书 测试访问 auth认证 创建认证文件 rewrite重定向 进入域名时&#xff0c;会自动重定向到hostname.html 示例&#xff1a; 测试 版本的升级迭代&#xff0c;之前利用控制器进行滚动更新&#xff0c;在升级过程中无法做到快速回滚 更加平滑的升级&#xff1…

猫头虎带您探索StringUtils3之StringUtils.isEmpty()和StringUtils.isBlank()的区别 ‍

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

低代码汹涌澎湃,真的是风口?

“中国的下一个风口是什么&#xff1f;低代码&#xff1f;你赞同吗&#xff1f;” 可以肯定的是&#xff0c;企业想站上未来产业的风口&#xff0c;”数字化“是必经之路。而低代码是企业向制高点突进的手段。产业的风口&#xff0c;就是产业发展的趋势&#xff0c;只有尽力站上…

SQL面试题挑战01:打折日期交叉问题

目录 问题&#xff1a;SQL解答&#xff1a;第一种方式&#xff1a;第二种方式&#xff1a; 问题&#xff1a; 如下为某平台的商品促销数据&#xff0c;字段含义分别为品牌名称、打折开始日期、打折结束日期&#xff0c;现在要计算每个品牌的打折销售天数&#xff08;注意其中的…

JNI 注册

一、 JNI 静态注册 ① 在 Android 的 Java 层定义方法 : 在 MainActivity 类中定义 如下 Native 方法 ; public native String stringFromJNI();② Native 方法实现 : 下面是一个 Native 方法实现的示例 ; extern "C" JNIEXPORT jstring JNICALL Java_kim_hsl_jni_…

VuePress安装及使用——使用 Markdown 创建你自己的博客网站和电子书

目录 前言一、依赖环境二、vuepress 安装和使用1.初始化2.将 VuePress 安装为本地依赖3. package.json 中添加脚本4. 新建 docs 文件夹5.启动6. 效果 三、进阶使用1.新增配置文件2.安装搜索插件3.config.js 中增加配置4.效果展示5.注意 四、使用主题1.安装2. 目录结构说明&…

fastjson反序列化 CVE-2017-18349

fastjson fastjson 是阿里巴巴开发的 java语言编写的高性能 JSON 库,用于将数据在 Json 和 Java Object之间相互转换。它没有用java的序列化机制,而是自定义了一套序列化机制。 提供两个主要接口&#xff1a; JSON.toJSONString 和 JSON.parseObject/JSON.parse 分别实现序列化…

双指针——找到字符串中的所有字母异位词

https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/?envTypestudy-plan-v2&envIdtop-100-liked 双指针&#xff0c;每次都统计出来p长度的滑动窗口里的数字,拿Arrays.equals进行对比,然后滑动一小格&#xff0c;减1加1继续比对即可。 class Solut…

AngularJS

理解实现代码的逻辑为主要&#xff0c;代码怎么写为次要。 参考资料&#xff1a; 《AngularJS入门与进阶》&#xff0c;江荣波著 前端开发常用框架 React&#xff1a;由Facebook开发&#xff0c;用于构建用户界面的JavaScript库&#xff0c;以组件化和虚拟DOM著称。 Angular&…

Github项目推荐-30天Python教程

项目地址 GitHub - Asabeneh/30-Days-Of-Python 项目简述 这是一个非常棒的python入门教程&#xff0c;图文并茂&#xff0c;讲解清晰&#xff0c;十分值得推荐。 项目截图

在 Kubernetes 上部署 Python 3.7、Chrome 和 Chromedriver(版本 114.0.5735.90)的完整指南

一、构建基础镜像 docker build -f /u01/isi/DockerFile . -t thinking_code.com/xhh/crawler_base_image:v1.0.2docker push thinking_code.com/xhh/crawler_base_image:v1.0.2 二、K8s运行Pod 三、DockerFile文件 # 基于镜像基础 FROM python:3.7# 设置代码文件夹工作目录…

删除win10服务

之前工作需要在我电脑上安装了一个天气的服务&#xff0c;我想删掉但是在任务管理器里删不掉&#xff0c;请教了大佬 删除方法是&#xff0c;在开始菜单里找到命令提示符 右键-以管理员方式打开命令提示符 输入sc 按enter键&#xff0c;可以查看一些操作命令 删除服务的话&a…