原生稀疏注意力NSA 替换transformer 注意力进行文本生成训练
DeepSeek-R1这篇文章,聚焦范围更加小,R1的重点在于提出了一个文本生成的训练策略和蒸馏策略,这篇文章则是提出了一个注意力机制NSA,主要解决的是长序列做注意力时带来的效率问题。通篇文章看下来,它的实际意义可能比较局限,因此本文仅关注其主要内容,对于具体细节和实验结果并不进一步细究。
论文标题:Native Sparse Attention: Hardware-Aligned and Natively Trainable Sparse Attention
论文链接:[2502.11089] Native Sparse Attention: Hardware-Aligned and Natively Trainable Sparse Attention
简单总结起来就是
实验效果惊艳:性能不降反升,速度大幅提升!
实验结果令人振奋!在通用基准测试、长文本任务和指令推理方面,使用 NSA 预训练的模型性能不仅没有下降,反而超越了 Full Attention 模型!
NSA 的核心亮点可以概括为以下两点:
1.动态分层稀疏策略: NSA 采用了一种动态分层的稀疏策略,结合了粗粒度的 Token 压缩 和 细粒度的 Token 选择。这种策略既能保证模型对全局上下文的感知,又能兼顾局部信息的精确性
2.关键创新:
算术强度平衡的算法设计与硬件优化: NSA 通过精巧的算法设计,并针对现代硬件进行了实现优化,显著提升了计算速度
端到端可训练: NSA 支持端到端训练,这意味着它不仅在推理阶段高效,还能减少预训练的计算量,同时不牺牲模型性能!
Attention的稀疏特性,其实从BERT时代开始就已经被广泛验证了。最早像Longformer、BigBird这些模型提出的几种稀疏Attention Pattern(比如Sliding Window、Global Attention——现在叫Attention Sink),直到今天依然被广泛使用。Attention天然的稀疏性,意味着每个词元在计算时,只需要从海量的上文中选出top-k相关的部分进行Attention计算。这个思路很简单,但难点就在于如何快速找到top-k的相关上文。如果逐token去选,计算和访存的过程又会回到Full-Attention的复杂度。
稀疏Attn为什么还能超过Full-Attn?
长文本具有天然的高稀疏性与富噪音性。处理每个token确实不要把全文都过一遍,而Full-attention机制,总是能确保每两个token之间的相关性不为0。这也就带来了计算上的噪音。所以不难理解,一个well-trained 稀疏Attn能够为每个token屏蔽掉部分噪音,效果也能带来些许提升。但效果的有限提升外,还是效率的提升更让人惊喜。
知乎上也有一篇介绍
https://zhuanlan.zhihu.com/p/24604821449
逛github时已经有大神做了论文复现,不仅提供了SparseAttention 还替换了原有Transformer 模型里的attention层
稀疏注意力SparseAttention 模型网络定义
class SparseAttention(Module):def __init__(self,dim,dim_head,heads,sliding_window_size,compress_block_size,selection_block_size,num_selected_blocks,num_compressed_mem_kv = 4,norm = True,use_diff_topk = False,):super().__init__()self.heads = headsself.scale = dim_head ** -0.5assert compress_block_size == selection_block_size, 'start off with compressed being equal to selection block sizes'dim_inner = dim_head * headsself.norm = nn.RMSNorm(dim) if norm else nn.Identity()# rotaryself.rotary_emb = RotaryEmbedding(dim_head)# qkvself.to_qkv = nn.Linear(dim, dim_inner * 3, bias = False)# sliding window strategyself.sliding_window = LocalAttention(dim = dim_head,window_size = sliding_window_size,causal = True,exact_windowsize = True,autopad = True)# compress strategyself.compress_block_size = compress_block_sizeassert num_compressed_mem_kv > 0self.compress_mem_kv = nn.Parameter(torch.zeros(2, heads, num_compressed_mem_kv, dim_head))self.k_intrablock_positions = nn.Parameter(torch.zeros(heads, compress_block_size, dim_head))self.v_intrablock_positions = nn.Parameter(torch.zeros(heads, compress_block_size, dim_head))self.k_compress = nn.Sequential(Rearrange('b h n d -> b (h d) n'),nn.Conv1d(dim_head * heads, dim_head * heads, compress_block_size, stride = compress_block_size, groups = heads),Rearrange('b (h d) nc -> b h nc d', h = heads))self.v_compress = nn.Sequential(Rearrange('b h n d -> b (h d) n'),nn.Conv1d(dim_head * heads, dim_head * heads, compress_block_size, stride = compress_block_size, groups = heads),Rearrange('b (h d) nc -> b h nc d', h = heads))# selection relatedself.use_diff_topk = use_diff_topkself.selection_block_size = selection_block_sizeself.num_selected_blocks = num_selected_blocks# they combine the three sparse branches through a learned combine with sigmoid activationself.to_strategy_combine = nn.Sequential(nn.Linear(dim, 3 * heads),nn.Sigmoid(),Rearrange('b n (h s) -> b h n s', h = heads))# split and merging headsself.split_heads = Rearrange('b n (h d) -> b h n d', h = heads)self.merge_heads = Rearrange('b h n d -> b n (h d)')# combining headsself.combine_heads = nn.Linear(dim_inner, dim, bias = False)
dim
: 输入特征的维度。dim_head
: 每个注意力头的维度。heads
: 注意力头的数量。sliding_window_size
: 滑动窗口的大小,用于局部注意力。compress_block_size
: 压缩块的大小。selection_block_size
: 选择块的大小。num_selected_blocks
: 选择的块数量。num_compressed_mem_kv
: 压缩的记忆键值对数量(默认为 4)。norm
: 是否使用归一化(默认为True
)。use_diff_topk
: 是否使用不同的 Top-k 策略(默认为False
)。
SparseAttention流程总结
-
头部和缩放:
self.heads = heads self.scale = dim_head ** -0.5
heads
保存注意力头的数量。scale
用于缩放注意力的分数,防止数值过大。
-
归一化:
self.norm = nn.RMSNorm(dim) if norm else nn.Identity()
- 使用 RMSNorm 进行归一化,或者使用身份函数(如果不需要归一化)。
-
旋转嵌入:
self.rotary_emb = RotaryEmbedding(dim_head)
- 用于实现旋转位置编码,增强模型对序列位置信息的理解。
-
QKV 线性变换:
self.to_qkv = nn.Linear(dim, dim_inner * 3, bias = False)
- 将输入特征映射到查询(Q)、键(K)和值(V)的线性空间。
-
滑动窗口注意力:
self.sliding_window = LocalAttention(...)
- 实现局部注意力机制,限制注意力计算在滑动窗口内,以减少计算复杂度。
-
压缩策略:
self.compress_mem_kv = nn.Parameter(torch.zeros(2, heads, num_compressed_mem_kv, dim_head))
- 初始化压缩后的键值存储。
-
内块位置参数:
self.k_intrablock_positions = nn.Parameter(torch.zeros(heads, compress_block_size, dim_head)) self.v_intrablock_positions = nn.Parameter(torch.zeros(heads, compress_block_size, dim_head))
- 用于保存每个头部在压缩块中的位置。
-
压缩操作:
self.k_compress = nn.Sequential(...) self.v_compress = nn.Sequential(...)
- 使用卷积层对键和值进行压缩,减少计算量。
-
选择策略:
self.to_strategy_combine = nn.Sequential(...)
- 通过线性层和 Sigmoid 激活函数对不同的注意力策略进行组合。
-
头部的分割与合并:
self.split_heads = Rearrange('b n (h d) -> b h n d', h = heads) self.merge_heads = Rearrange('b h n d -> b n (h d)')
split_heads
将输入张量拆分为多个头部。merge_heads
将多个头部合并回一个张量。
-
组合头部输出:
self.combine_heads = nn.Linear(dim_inner, dim, bias = False)
- 将多个头部的输出通过线性层组合成最终的输出。
结合论文分析SparseAttention
结合上述代码,以下是具体神经网络层如何体现 NSA 的核心亮点:
1. 动态分层稀疏策略
- 压缩层 (
self.k_compress
和self.v_compress
):self.k_compress = nn.Sequential(Rearrange('b h n d -> b (h d) n'),nn.Conv1d(dim_head * heads, dim_head * heads, compress_block_size, stride=compress_block_size, groups=heads),Rearrange('b (h d) nc -> b h nc d', h=heads) )self.v_compress = nn.Sequential(Rearrange('b h n d -> b (h d) n'),nn.Conv1d(dim_head * heads, dim_head * heads, compress_block_size, stride=compress_block_size, groups=heads),Rearrange('b (h d) nc -> b h nc d', h=heads) )
- 说明:这些层实现了粗粒度的 Token 压缩。使用卷积层对键和值进行压缩,从而减少计算量,同时保持重要信息。这种设计使模型能够动态调整处理的 Token 数量,兼顾全局上下文和局部信息的捕捉。
2. 关键创新
-
算术强度平衡的算法设计与硬件优化:
- 局部注意力层 (
self.sliding_window
):- 说明:局部注意力机制通过限制注意力计算在滑动窗口内,显著降低了计算复杂度。这种设计不仅提高了计算速度,还优化了内存使用,特别是在处理长序列时。
self.sliding_window = LocalAttention(dim=dim_head,window_size=sliding_window_size,causal=True,exact_windowsize=True,autopad=True )
- 局部注意力层 (
-
组合头部输出 (
self.combine_heads
):self.combine_heads = nn.Linear(dim_inner, dim, bias=False)
- 说明:通过线性层组合多个头部的输出,保持了模型的灵活性和表达能力,同时减少了冗余计算,进一步提升了算术强度的平衡。
3. 端到端可训练
-
归一化层 (
self.norm
):self.norm = nn.RMSNorm(dim) if norm else nn.Identity()
- 说明:归一化层的使用确保了模型在训练过程中的稳定性,支持端到端的训练方式,使得模型能够在推理阶段高效,同时优化了预训练和微调过程,从而减少计算量。
-
策略组合层 (
self.to_strategy_combine
):self.to_strategy_combine = nn.Sequential(nn.Linear(dim, 3 * heads),nn.Sigmoid(),Rearrange('b n (h s) -> b h n s', h=heads) )
- 说明:这一层通过组合不同的稀疏策略,确保模型在训练过程中能够灵活适应不同的任务和数据,支持端到端训练,提升了模型的实用性和效率。
Transformer模型结构, attn 使用了SparseAttention
class Transformer(Module):def __init__(self,num_tokens,dim,depth,dim_head = 64,heads = 8,ff_expansion_factor = 4.,use_sparse_attn = True,sparse_attn_kwargs: dict = dict(sliding_window_size = 32,compress_block_size = 4,selection_block_size = 4,num_selected_blocks = 4,)):super().__init__()self.token_emb = nn.Embedding(num_tokens, dim)layers = []for _ in range(depth):if use_sparse_attn:attn = SparseAttention(dim = dim,dim_head = dim_head,heads = heads,**sparse_attn_kwargs)else:attn = Attention(dim = dim, dim_head = dim_head, heads = heads)ff = FeedForward(dim = dim, expansion_factor = ff_expansion_factor)layers.append(ModuleList([attn, ff]))self.layers = ModuleList(layers)self.norm = RMSNorm(dim)self.to_logits = Linear(dim, num_tokens, bias = False)def forward(self,ids,return_loss = False):if return_loss:ids, labels = ids[:, :-1], ids[:, 1:]tokens = self.token_emb(ids)for attn, ff in self.layers:tokens = attn(tokens) + tokenstokens = ff(tokens) + tokensembed = self.norm(tokens)logits = self.to_logits(embed)if not return_loss:return logitsreturn F.cross_entropy(rearrange(logits, 'b n l -> b l n'), labels)
使用wiki百科中文语料来训练下Transformer + NSA 注意力模型
Index of /zhwiki/latest/ 下载 zhwiki-latest-abstract.xml.gz
安装opencc
pip install opencc-python-reimplemented
把繁体转发简体中文
import gzip
import opencc
import os
from tqdm import tqdm# 检查 OpenCC 配置文件的路径
opencc_path = os.path.join(os.path.dirname(opencc.__file__), 'config', 't2s.json'
)# 初始化 OpenCC 转换器
converter = opencc.OpenCC(opencc_path)# 计算文件行数以便显示进度条
with gzip.open('zhwiki-latest-abstract.xml.gz', 'rt', encoding='utf-8') as infile:total_lines = sum(1 for _ in infile) # 计算总行数infile.seek(0) # 重置文件指针# 压缩为新的 gz 文件
with gzip.open('zhwiki-latest-abstract-simplified.xml.gz', 'wt', encoding='utf-8') as outfile:with gzip.open('zhwiki-latest-abstract.xml.gz', 'rt', encoding='utf-8') as infile:for line in tqdm(infile, total=total_lines, desc="Processing"):simplified_line = converter.convert(line)outfile.write(simplified_line)print("转换完成,已保存为 zhwiki-latest-abstract-simplified.xml.gz")
加载数据集,中文处理需要使用tokenizer
tokenizer = BertTokenizer.from_pretrained('./base_model/bert-base-chinese')
print(f"Vocabulary size: {len(tokenizer.vocab)}")
model = Transformer(num_tokens=len(tokenizer.vocab),dim=512,depth=6,use_sparse_attn=USE_SPARSE_ATTN,sparse_attn_kwargs=dict(sliding_window_size=16, # 调整为更小的块大小compress_block_size=16,selection_block_size=16,num_selected_blocks=4,use_diff_topk=False)
).cuda()# Data processing
with gzip.open('./data/zhwiki-latest-abstract-simplified.xml.gz', 'rb') as file:data = np.frombuffer(file.read(int(10e6)), dtype=np.uint8).copy()decoded_string = data.tobytes().decode('utf-8')tokens = []chunk_size = 10000vocab_size = len(tokenizer.vocab)for i in range(0, len(decoded_string), chunk_size):chunk = decoded_string[i:i + chunk_size]tokens.extend(tokenizer.tokenize(chunk))token_ids = tokenizer.convert_tokens_to_ids(tokens)token_ids = [tid for tid in token_ids if 0 <= tid < vocab_size]token_tensor = torch.tensor(token_ids)split_idx = int(len(token_tensor) * 0.8)data_train = token_tensor[:split_idx]data_val = token_tensor[split_idx:]print("Train shape:", data_train.shape)
print("Validation shape:", data_val.shape)class TextSamplerDataset(Dataset):def __init__(self, data, seq_len):super().__init__()self.data = dataself.seq_len = seq_lendef __len__(self):return (self.data.size(0) - self.seq_len) // self.seq_lendef __getitem__(self, index):rand_start = index * self.seq_lenif rand_start + self.seq_len + 1 > self.data.size(0):raise IndexError("Index out of range for dataset.")full_seq = self.data[rand_start: rand_start + self.seq_len + 1]return full_seq.long().cuda()
解码使用
def decode_tokens(tokens):if isinstance(tokens, torch.Tensor):tokens = tokens.cpu().tolist()token_list = tokenizer.convert_ids_to_tokens(tokens)filtered_tokens = [token for token in token_list if token not in ['[CLS]', '[SEP]', '[PAD]']]return ''.join(filtered_tokens)
训练epoch 代码
for i in tqdm.tqdm(range(NUM_BATCHES), mininterval=10.0, desc="training"):model.train()for _ in range(GRAD_ACCUM_EVERY):data = next(train_loader)input_data = data[:, :-1]target_data = data[:, 1:]logits = model(input_data)loss = F.cross_entropy(logits.reshape(-1, logits.size(-1)), target_data.reshape(-1))(loss / GRAD_ACCUM_EVERY).backward()wandb.log(dict(loss=loss.item()), step=i)print(f"training loss: {loss.item():.3f}")torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)optim.step()optim.zero_grad()if i % VALIDATE_EVERY == 0:model.eval()with torch.no_grad():valid_data = next(val_loader)input_data = valid_data[:, :-1]target_data = valid_data[:, 1:]logits = model(input_data)loss = F.cross_entropy(logits.reshape(-1, logits.size(-1)), target_data.reshape(-1))wandb.log(dict(valid_loss=loss.item()), step=i)print(f"validation loss: {loss.item():.3f}")if loss.item() < min_loss:min_loss = loss.item()torch.save(model.state_dict(), f'model_min_loss.pt')print(f'Model saved at validation loss: {min_loss:.3f}')if i % GENERATE_EVERY == 0:model.eval()inp = random.choice(val_dataset)[:PRIME_LENGTH]inp = inp.cuda()print(f"Input token IDs: {inp}")prime = decode_tokens(inp)print(f"\nprime: {prime}\n")prompt = inp[None, ...]sampled = base_decoding(model, prompt, GENERATE_LENGTH)base_decode_output = decode_tokens(sampled[0])decoded_str = urllib.parse.unquote(base_decode_output)print(f'output: {decoded_str}')
在loss最小的时候保存模型, 训练过程同步到wandb
训练中生成测试
training loss: 0.026
training loss: 0.018
validation loss: 0.787
Input token IDs: tensor([ 110, 130, 8168, 110, 12888, 110, 8416, 110, 144, 8129,
110, 147, 8159, 110, 10322, 110, 10322, 108, 1146, 2357,
133, 120, 9025, 135, 133, 120, 11541, 8204, 9989, 135,
133, 11541, 8204, 9989, 9025, 11085, 134, 107, 11469, 8225,
107, 135, 133, 9064, 8370, 8372, 135, 4495, 3833, 133,
120, 9064, 8370, 8372, 135, 133, 9025, 135, 8532, 131,
120, 120, 9998, 119], device='cuda:0')prime: %9##d%e7%94%b##0%e##4%ba%ba#分布</link></su##b##link><su##b##linklink##type="na##v"><an##ch##or>生活</an##ch##or><link>https://zh.
output: wikipedia.org/wiki/�%8##c��%b##0%e##4��#生活</link></su##b##link><su##b##linklink##type="na##v"><an##ch##or>理论</an##ch##or><link>https://zh.wikipedia.org/wiki/�%8##c�_(�%b##0%e##4%b##f��%8##c�#理论</link></su##b##link><su##b##linklink##type="na##v"><an##ch##or>参考文献</an##ch##or><link>https://zh.wikipedia.org/wiki/�%8##c��%b##0%e##4%b##f�#参考
结束训练后调用模型进行推理输出
import torch
from pytorch_pretrained_bert import BertTokenizer
from native_sparse_attention_pytorch.transformer import Transformer# 常量(与训练时一致)
PRIME_LENGTH = 64
GENERATE_LENGTH = 256
SEQ_LEN = 256
USE_SPARSE_ATTN = True# 采样辅助函数
def log(t, eps=1e-20):return torch.log(t.clamp(min=eps))def gumbel_noise(t):noise = torch.zeros_like(t).uniform_(0, 1)return -log(-log(noise))def gumbel_sample(t, temperature=1., dim=-1, keepdim=True):return ((t / max(temperature, 1e-10)) + gumbel_noise(t)).argmax(dim=dim, keepdim=keepdim)def top_k(logits, thres=0.9):k = math.ceil((1 - thres) * logits.shape[-1])val, ind = torch.topk(logits, k)probs = torch.full_like(logits, float('-inf'))probs.scatter_(-1, ind, val)return probsdef base_decoding(net, prompt: torch.Tensor, seq_len: int, temperature=1., filter_thres=0.9):prompt_seq_len, out = prompt.shape[-1], prompt.clone()sample_num_times = max(0, seq_len - prompt_seq_len)for _ in range(sample_num_times):logits = net(out)logits = logits[:, -1]logits = top_k(logits, thres=filter_thres)sample = gumbel_sample(logits, temperature=temperature, dim=-1)out = torch.cat((out, sample), dim=-1)return out[..., prompt_seq_len:]# 解码函数
def decode_tokens(tokens, tokenizer):if isinstance(tokens, torch.Tensor):tokens = tokens.cpu().tolist()token_list = tokenizer.convert_ids_to_tokens(tokens)filtered_tokens = [token for token in token_list if token not in ['[CLS]', '[SEP]', '[PAD]']]return ''.join(filtered_tokens)# 加载 tokenizer 和模型
tokenizer = BertTokenizer.from_pretrained('./base_model/bert-base-chinese')
vocab_size = len(tokenizer.vocab)
print(f"Vocabulary size: {vocab_size}")model = Transformer(num_tokens=vocab_size,dim=512,depth=6,use_sparse_attn=USE_SPARSE_ATTN,sparse_attn_kwargs=dict(sliding_window_size=16,compress_block_size=16,selection_block_size=16,num_selected_blocks=4,use_diff_topk=False)
)# 加载训练好的模型权重
model_path = 'model_min_loss.pt'
state_dict = torch.load(model_path, map_location='cpu')
model.load_state_dict(state_dict)
model = model.cuda()
model.eval()# 输入示例
input_text = "阿氏吻鳐"
input_tokens = tokenizer.convert_tokens_to_ids(tokenizer.tokenize(input_text))
min_length = max(PRIME_LENGTH, 16) # 确保长度 >= compress_block_size
if len(input_tokens) < min_length:pad_id = tokenizer.convert_tokens_to_ids(['[PAD]'])[0]input_tokens = input_tokens + [pad_id] * (min_length - len(input_tokens))
input_tensor = torch.tensor(input_tokens[:PRIME_LENGTH], dtype=torch.long).cuda()
prompt = input_tensor[None, :]# 进行推理
print(f"Input text: {input_text}")
print(f"Input token IDs: {input_tensor}")with torch.no_grad():generated_tokens = base_decoding(model, prompt, GENERATE_LENGTH, temperature=0.7, filter_thres=0.9)generated_text = decode_tokens(generated_tokens[0], tokenizer)# 输出结果
print(f"\nGenerated text: {generated_text}")
Generated text: 为软骨鱼纲鳐目鳐科吻鳐属的一种[1],分布于中西大西洋美国佛罗里达州到墨西哥犹加敦半岛海域,深度32至384米,本鱼体盘宽圆形,上表面颜色苍白并有暗斑,每个胸鳍上的眼斑通常为椭圆形,下表面白色,无深色斑纹
相关文章:
原生稀疏注意力NSA 替换transformer 注意力进行文本生成训练
DeepSeek-R1这篇文章,聚焦范围更加小,R1的重点在于提出了一个文本生成的训练策略和蒸馏策略,这篇文章则是提出了一个注意力机制NSA,主要解决的是长序列做注意力时带来的效率问题。通篇文章看下来,它的实际意义可能比较…...
读书笔记:《百年孤独》
《百年孤独》加西亚.马尔克斯 著 范晔 译 读出了阅读障碍。 记不得书中的人,记不得书中的事,更不知何为孤独,只记得马孔多,这个陌生的地方,还有那个猪尾巴婴儿。 百年:故事跨越了百年 孤独&#…...
TVS管学习记录
文章目录 前言一、TVS是什么?二、TVS关键参数1.反向截至电压**实际意义** 2.钳位电压**定义与作用****选择依据** **4. 实际应用示例****场景:通信端口的ESD保护** 3.反向截至电压和钳位电压的关联和区别**. 小结** 三、实际应用电路举例总结 前言 TVS管…...
网络安全系统概述 网络安全系统分为几级
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 5级 网络信息系统安全等级保护分为五级,一级防护水平最低,最高等保为五级。分别是用户自主保护级、系统审计保护级、安全标记保护级、结构…...
基于 DeepSeek LLM 本地知识库搭建开源方案(AnythingLLM、Cherry、Ragflow、Dify)认知
写在前面 博文内容涉及 基于 Deepseek LLM 的本地知识库搭建使用 ollama 部署 Deepseek-R1 LLM知识库能力通过 Ragflow、Dify 、AnythingLLM、Cherry 提供理解不足小伙伴帮忙指正 😃,生活加油 我站在人潮中央,思考这日日重复的生活。我突然想,…...
Apache Flink架构深度解析:任务调度、算子数据同步与TaskSlot资源管理机制
Apache Flink是一个分布式流处理框架,其核心架构设计围绕有界与无界数据流的统一处理能力展开。以下从任务分配、算子数据同步、TaskManager与JobManager的TaskSlot机制三个维度展开详细分析: 一、任务分配机制 Flink的任务分配基于并行度(P…...
Linux 常见命令全解析
一、文件操作命令 1. ls ls是列出目录内容的命令。简单输入ls,会展示当前目录下的文件和目录列表。想要获取更详细的信息,比如文件权限、所有者、大小、修改时间等,使用ls -l。若要显示所有文件,包括以点(.ÿ…...
k8s集群部署
集群结构 角色IPmaster192.168.35.135node1192.168.35.136node2192.168.35.137 部署 #需在三台主机上操作 //关闭防火墙 [rootmaster ~]# systemctl disable --now firewalld//关闭selinux [rootmaster ~]# sed -i s/enforcing/disabled/ /etc/selinux/config//关闭swap分区…...
springboot005学生心理咨询评估系统(源码+数据库+文档)
源码地址:学生心理咨询评估系统 文章目录 1.项目简介2.部分数据库结构与测试用例3.系统功能结构4.包含的文件列表(含论文)后台运行截图 1.项目简介 使用旧方法对学生心理咨询评估信息进行系统化管理已经不再让人们信赖了,把现…...
LeetCode37
LeetCode37 目录 题目描述示例思路分析代码段代码逐行讲解复杂度分析总结的知识点整合总结...
2025年02月24日Github流行趋势
项目名称:mastra 项目地址url:https://github.com/mastra-ai/mastra 项目语言:TypeScript 历史star数:5735 今日star数:1140 项目维护者:adeleke5140, abhiaiyer91, TheIsrael1, adeniyii, Joshuafolorunsh…...
Spring Boot 中的日志管理
一、日志框架选择 1. 主流框架对比 框架特点Spring Boot 默认支持Logback- 性能优异,Spring Boot 默认集成- 支持自动热更新配置文件✅ (默认)Log4j2- 异步日志性能更强- 支持插件扩展- 防范漏洞能力更好❌ (需手动配置)JUL (JDK自带)- 无需额外依赖- 功能简单&am…...
后端之JPA(EntityGraph+JsonView)
不同表之间的级联操作或者说关联查询是很多业务场景都会用到的。 对于这种需求最朴素的方法自然是手动写关联表,然后对被关联的表也是手动插入数据。但是手写容易最后写成一堆shit代码,而且修改起来也是非常麻烦的。 学会使用现成的工具还是非常有利的…...
点击修改按钮图片显示有问题
问题可能出在表单数据的初始化上。在 ave-form.vue 中,我们需要处理一下从后端返回的图片数据,因为它们可能是 JSON 字符串格式。 vue:src/views/tools/fake-strategy/components/ave-form.vue// ... existing code ...Watch(value)watchValue(v: any) …...
Linux第一个小程序-进度条 (linux第七课)
目录 知识补充: 随机数的使用,先用srand(time(NULL))种时间种子 函数指针 模拟进度条代码 知识补充: \r只是回车 \r\n是回车加换行,其中\n带有强制换行的功能 如果只使用\r ,还需要刷新缓冲区(fflush(stdout)) %2d是左对齐 %-2d是右对齐 %.1lf是小数点后保留一位 随机数的使…...
iOS指纹归因详解
iOS 指纹归因(Fingerprint Attribution)详解 1. 指纹归因的概念 指纹归因(Fingerprint Attribution)是一种无 ID 归因(ID-less Attribution)技术,主要用于广告跟踪、用户识别或流量分析。它基…...
【Erdas实验教程】009:非监督分类及分类后评价
文章目录 一、分类过程二、分类评价ERDAS 的 ISODATA 算法是基于最小光谱距离来进行的非监督分类,聚类过程始于任意聚类平均值或一个已有分类模板的平均值;聚类每重复一次,聚类的平均值就更新一次,新聚类的均值再用于下次聚类循环。这个过程不断重复,直到最大的循环次数已…...
DeepSeek+Kimi生成高质量PPT
DeepSeek与Kimi生成PPT全流程解析 一、工具分工原理 DeepSeek核心作用:生成结构化PPT大纲(擅长逻辑构建与内容优化)Kimi核心作用:将文本转换为视觉化PPT(提供模板库与排版引擎) 二、操作步骤详解 1. 通…...
conda 基本命令
1、查询当前所有的环境 conda env list 2、创建虚拟环境 conda create -n 环境名 [pythonpython版本号] 其中[pythonpython版本号]可以不写 conda create -n test python3.12 我们输入conda env list看到我们的环境创建成功了,但是发现他是创建在我们默认的C盘的…...
网站搭建wp
前置准备工作 需要下载Git,note.js,在官网上可以搜索并安装 搭建过程 这里借助hexo工具 1. 本地博客搭建 首先创建本地文件夹,并在该文件夹里面创建一个叫做hexo的文件夹在该文件夹中选择Git Bash 进入hexo官网将五条指令用bash运行运行…...
什么是图传技术?
1.什么是图传技术? 图传技术(图像传输技术)是指将摄像头或其他图像采集设备捕获的实时画面,通过无线通信方式传输到接收端(如遥控器、显示屏、云端服务器等)的技术。它广泛应用于无人机、安防监控、直播设…...
Python数据结构高级:图的表示与遍历
Python数据结构高级:图的表示与遍历 一、图的基本概念 1.1 图的定义与分类 图(Graph)是由顶点(Vertex)集合和边(Edge)集合组成的数据结构,形式化表示为 G (V, E) 主要分类&…...
登录-10.Filter-登录校验过滤器
一.登录校验过滤器的实现思路 我们要实现登录校验过滤器,就要首先明白登录校验过滤器的实现思路。登录校验过滤器是用来实现登录校验的。那么首先思考第一个问题,所有的请求都需要校验吗? 答案是否定的,因为login请求就不需要过滤…...
《Keras 3 : 使用迁移学习进行关键点检测》:此文为AI自动翻译
《Keras 3 :使用迁移学习进行关键点检测》 作者:Sayak Paul,由 Muhammad Anas Raza 转换为 Keras 3 创建日期:2021/05/02 最后修改时间:2023/07/19 描述:使用数据增强和迁移学习训练关键点检测器。 (i) 此示例使用 Keras 3 在 Colab 中查看 GitHub 源 关键点检测包…...
【Deepseek】AnythingLLM + Ollama
1. 下载安装 anythingllm 下载地址:https://anythingllm.com/desktop 2. 启动anything 点击 Get started 3.创建工作空间 4.选择Ollama大语言模型 聊天设置 当前只有一个1.5b的模型 下载完成7b模型后 选择后记得点击更新到工作空间!&…...
VMware17下Ubuntu22.04设置本地共享文件夹
VMware17下使用Ubuntu22.04设置共享文件夹 在日常的开发与学习中,我们常常需要在主机(通常是Windows系统)和虚拟机(如Ubuntu 22.04)之间进行文件交换。为了简化这一过程,VMware提供了共享文件夹的功能&…...
【GreenHills】GHS合并库文件
1、 文档目标 解决Green Hills对于多个库文件合并问题 2、 问题场景 客户具有多个工程库文件。但是,客户想要在项目最终交付的时候,通过将多个库文件打包成一个库文件,进行交付。 3、软硬件环境 1)、软件版本:MULTI…...
mysql-统计表占内存大小
在 MySQL 中,统计表占用的内存大小(或者更准确地说,是表占用的磁盘空间大小)并非一个简单的任务,因为MySQL的数据存储涉及多种文件,包括数据文件、索引文件等。不过,有几种方法可以帮助你估算一…...
基于SpringBoot和Leaflet的邻省GDP可视化实战
目录 前言 一、技术实现路径 1、空间数据检索 2、数据展示检索流程 二、SpringBoot后台实现 1、模型层实现 2、控制层实现 三、WebGIS前端实现 1、控制面展示 2、成果展示 四、总结 前言 在数字化浪潮席卷全球的今天,数据已成为驱动社会经济发展、指导政策…...
DeepSeek-R1本地部署保姆级教程
一、DeepSeek-R1本地部署配置要求 (一)轻量级模型 ▌DeepSeek-R1-1.5B 内存容量:≥8GB 显卡需求:支持CPU推理(无需独立GPU) 适用场景:本地环境验证测试/Ollama集成调试 (二&a…...
DeepSeek + Mermaid编辑器——常规绘图
下面这张图出自:由清华大学出品的 《DeepSeek:从入门到精通》。 作为纯文本生成模型,DeepSeek虽不具备多媒体内容生成接口,但其开放式架构允许通过API接口与图像合成引擎、数据可视化工具等第三方系统进行协同工作,最终…...
推送项目 之 解决冲突
文章目录 为什么会发生冲突?如何解决这些冲突?1. **查看冲突文件**2. **解决二进制文件冲突**3. **解决文本文件冲突**4. **标记冲突已解决**5. **完成合并**6. **推送更改** 注意事项总结 问题:我们在git pusll拉取远程仓库的代码到本地对比…...
蓝桥杯——lcd显示
一:复制文件 从官方参考文件中复制相关文件,Src中的lcd.c,Inc中的lcd.h,fonts.h复制到自己创建的文件中 二:lcd初始化 在lcd.h中找到四个初始化函数,将其写到main文件中 三:写lcd显示函数 在…...
1_安装JDK和Hadoop
一、解压jdk和hadoop安装包 下载 通过百度网盘分享的文件:jdk-8u172-linux-x64.tar.gz 链接:https://pan.baidu.com/s/1VjhdpfyqdC7ivEBIjTn8tA 提取码:iz25 二、配置环境变量 vi /root/.bashrc添加 #set java environment export JAVA_H…...
angular简易计算器
说明: 用angular实现计算器效果,ui风格为暗黑 效果图: step1: C:\Users\Administrator\WebstormProjects\untitled4\src\app\calnum\calnum.component.ts import { Component } from angular/core;Component({selector: app-calnum,import…...
python 程序
gif调整尺寸.py import sys from PIL import Image,ImageSequence import os ##print(sys.argv[0]) ##print(sys.argv[1]) def gifresize(file_name): gf Image.open(file_name) ## lifetime gf.info[duration] imglist [] imgnew [] for i in ImageSequence.…...
vue3响应式数据原理
Vue 3 的响应式系统与 Vue 2 有显著不同,Vue 3 使用了 Proxy 替代了 Vue 2 中的 Object.defineProperty,这使得 Vue 3 的响应式系统更加灵活和强大 Vue 3 响应式原理的核心 Proxy: Vue 3 使用 Proxy 来拦截对象的操作(如读取、赋值…...
【Godot4.3】自定义圆角容器
概述 Godot控件想要完全实现现代UI风格,需要进行大量的自定义组件设计。本篇就依托于笔者自己对现代UI设计中的圆角面板元素模仿来制作圆角容器组件。 圆角容器 圆角元素在现代的扁平UI设计中非常常见,在Godot中可以通过改进PanelContainer来或者自定…...
远程部署 Qt 应用程序套件错误原因
构建套件报红色警告错误: 图一: 改图二:...
vue3学习4-pinia+组件通信
集中式状态管理,vue2用vuex,vue3用pinia,相当于react中的redux 引入pinia pinia的具体存储都放到src/store目录下,每个store.js具体存储实现如下: 修改pinia中的数据 3种方式: 1、可以直接修改从pinia中读…...
GEE中的Map对象
在Google Earth Engine (GEE) 中,Map 是一个非常重要的对象,它用于显示地理数据和控制地图的交互。Map 对象提供了一系列函数,允许你操作和控制地图显示。以下是一些常用的 Map 函数及其使用方法: 1. Map.addLayer() 功能&#x…...
【AI学习笔记】2月10日李飞飞巴黎AI峰会演讲:探索 AI 的历史、现状与未来
【AIGC学习笔记】2月10日李飞飞巴黎AI峰会演讲:探索 AI 的历史、现状与未来 AI 的历史根基与发展历程 生命起源与智能诞生:5 亿年前视觉概念的出现推动了智能的诞生。最初的感知仅仅是被动的体验,只是但随着神经系统的活跃,视觉…...
Vue.js组件开发:从基础到进阶
在现代前端开发中,Vue.js因其简洁、灵活和易上手的特点,成为了众多开发者首选的框架之一。组件化是Vue.js的核心思想之一,它让我们能够更高效、模块化地开发应用。在本文中,我们将从Vue.js的组件开发的基础知识开始,逐…...
Elasticsearch索引设计与分片策略深度优化-手记
一、索引设计的黄金法则(从踩坑到精通的必经之路) 1. 字段类型显式声明原则 动态映射是新手最易踩的坑,某金融平台曾因金额字段被自动识别为text类型,导致聚合查询时触发OOM。正确做法应显式声明核心字段: PUT /fin…...
嵌入式学习|C语言篇进程间通信(IPC)全面解析与示例
一、进程通信基础概念 1.1 进程隔离原理 现代操作系统通过虚拟内存技术为每个进程创建独立的地址空间,这种隔离机制保障了系统的安全性,但也导致进程无法直接访问彼此的内存数据。进程间通信(IPC)正是为解决这一矛盾而设计的核心…...
2020年蓝桥杯Java B组第二场题目+部分个人解析
#A:门牌制作 624 解一: public static void main(String[] args) {int count0;for(int i1;i<2020;i) {int ni;while(n>0) {if(n%102) {count;}n/10;}}System.out.println(count);} 解二: public static void main(String[] args) {…...
3. Spring Cloud LoadBalancer 入门与使用
一、什么是 LoadBalancer? LoadBalancer(负载均衡器)是一种网络设备或软件机制,用于分发传入的网络流量负载(请求)到多个后端目标服务器上,从而实现系统资源的均衡利用和提高系统的可用性和性能。 1.1 负载均衡分类 服务器负载均衡是在服务端通过硬件…...
基于TensorFlow.js与Web Worker的智能证件照生成方案
功能简介 本文基于TensorFlow.js与Web Worker实现了常用的“证件照”功能,可以对照片实现抠图并替换背景。值得一提的是,正常抠图的操作应该由后端进行,这里只是主要演示该功能实现步骤,并不建议该功能由前端全权处理。 限于个人技…...
jupyterhub on k8s 配置用户名密码 简单版
如果只是小组内使用 不想共用密码 也不想搞复杂认证方案 那么就直接通过map(用户名,密码md5值)来制定密码 config.yaml部分内容 hub:config:JupyterHub:shutdown_on_logout: true # 用户logout 自动stop jupyter pod,家目录下所有文件会被保存到pvc 即启动后之前家目录下…...
Logic-RL:Unleashing LLM Reasoning with Rule-Based Reinforcement learning
1.Introduction deepseek-r1,kimi-k1.5和openai-o1效果都很好。deepseek-r1引入了一种简单而有效的基于规则的强化学习,无需依赖传统的支撑技术,如蒙特卡洛书树搜索MCTS或者过程奖励模型PRM,便能出现新兴的推理模式。deepseek-r1开源了权重,但是并未发布训练或数据集,这…...