【AlphaFold2】Feature extraction:提取特征,为模型输入做准备|Datapipeline讲解
- 博主简介:努力学习的22级计算机科学与技术本科生一枚🌸
- 博主主页: @Yaoyao2024
- 往期回顾:【深度学习】多头注意力机制的实现|pytorch
- 每日一言🌼: 学习成绩只是表象,而学习能力才是伴随一身的结果🌺
0、前言
本期博客主要参考Youtube博主Killian Manton
AlphaFold Decoded: Feature Extraction (Lesson 4)从头实现AlphaFold2的专题视频。本期博客主要参考视频内容,主要讲解AlphaFold2的特征提取模块。特征提取是指将特定领域的数据格式(这里是蛋白质相关数据)转换为机器学习可用的张量格式。
在此也非常感谢Killian Manton!
1. AlphaFold模型输入的介绍
1.1 特征提取的定义Feature extraction
特征提取(Feature Extraction)的本质:将特定领域的数据格式(如蛋白质序列、结构等生物学数据)转换为机器学习模型能处理的张量格式(多维数组)。
要提取模型所需要的有效特征,让模型能够基于这个特征数据进行推理,先要解决这两个问题:
-
问题一:选择什么样的生物学数据?
- 需要识别哪些生物数据真正携带蛋白质结构信息(例如:氨基酸序列、进化同源序列、二级结构预测等)。
- 例子:仅用氨基酸序列(如"ACDEF")可能不够,还需MSA(多序列比对)来捕捉进化保守性。
-
问题二:如何转换为张量?
- 设计数学表示方法,将生物数据编码为数值型张量。
- 例子:用one-hot编码表示氨基酸类型(20维向量),或使用3D坐标表示原子位置。
这段话揭示了机器学习应用于科学领域的核心方法论:
- 领域知识驱动:先理解哪些数据真正有用(需生物学直觉)。
- 数学表达设计:将知识转化为适合模型处理的形式(需机器学习经验)。
1.2 :AlphaFold的3种类型输入
基于现有的蛋白质结构数据。AlphaFold选用了以下三种数据作为输入:
- 目标氨基酸序列( amino acid sequence )
原始表示形式为字符串,每个字符代表20种氨基酸种的其中一种。氨基酸序列本身也是蛋白质的一级结构。
我们也就是要预测这个目标氨基酸序列对应的三级结构!
基于蛋白质的进化史,即 基于"进化保守反映结构约束"的生物学原理,还选用了以下两种数据:
-
多序列比对数据( multiple sequence alignment data /MSA data )
是一组蛋白质序列,它们来自其他不同的生物体(organisms),但是与我们目标序列高度相似,这也就意味着这些序列有可能起源于相同的祖先。使用这些序列,我们可以获取进化信息,从进行信息种去反应未知的蛋白质结构。 -
蛋白质三维结构/模板结构( 3D structure of so called templates )
和目标蛋白质相似,但是三维结构已经确定的蛋白质。采样这些蛋白质的三维结构数据表示,也成为模板(templates)。在过去,这一直是与蛋白质结构预测最相关的数据。
但是很有趣的是,即使AlphaFold并没有使用这些template stack作为输入(特别是当MSA数据足够的多样化且提供了丰富的进化信息时候),也可以达到很好的预测。这也意味着AlphaFold并不需要模板数据作为输入。我们也不会对其进行讲解和代码实现。
2. Datapipline结构介绍
如下图Input Feature Embedding
的网络结构所示。在左侧的输入都构建好之后,它们经过输入编码器(input embedder
)进行编码。
上文说到这里我们不需要考虑template stack
,那么整个input pipeline
如下:
input embedding and the evoformer stack的实现我们将在接下来的博客进行讲解。这里,我们将实现最左边的四个输入。
其中以下两个很容易理解、确定和实现:
Residue_index
,就是表示每个氨基酸的索引, range from 0 to r-1,用作后面Evoformerd的位置编码(position encoding),shape = (r,),r是氨基酸个数target_feat
:目标氨基酸序列的每个位置氨基酸的独热编码。形状为(r,f) = (r,21)。21代表20个已知氨基酸+1个未知氨基酸。组成长度为21
的独热编码。
构建图上剩余的两个msa编码就会复杂一些:
extra_msa_feat
msa_feat
这两个输入数据都是基于msa
的,在这之前,我们需要先了解一下,什么是msa
?
4. MSA(多序列比对)基础介绍
蛋白质就是氨基酸组成的序列。我们可以从蛋白质的进化史种提取到很多信息。
比如,我们可以看在不同的蛋白质种,某个区域是否是高度保守的(Highly conserved)或变化很大。
(1) 保守性(Conservation)分析
-
高度保守区域:
- 表现:在进化过程中几乎不变的氨基酸位置
- 意义:通常对应结构或功能核心(如酶活性位点、蛋白质相互作用界面)。
- 例子:ATP结合位点的
GXGXXG
模式在激酶中高度保守。
- 例子:ATP结合位点的
-
低保守区域:
- 表现:频繁变异的氨基酸位置(如位置4的
Ser/Thr/Ala
)。 - 意义:可能是**柔性环区(loops)**或对功能非关键的区域。
- 表现:频繁变异的氨基酸位置(如位置4的
(2) 共进化(Coevolution)信号
- 现象:某些氨基酸对会协同突变(一个位置突变,另一位置随之突变)。
- 意义:暗示这些残基在3D空间中物理接近或功能耦合。
进化特征 | 结构关联 | 功能关联 |
---|---|---|
高保守残基 | 核心疏水区、稳定折叠 | 催化位点、结合位点 |
低保守区域 | 表面环区、柔性linker | 物种特异性功能适配 |
共进化残基对 | 空间邻近(<8Å) | 变构调节、信号传递 |
生物序列分析方法的重大变革——从过去依赖人工设计的显式计算转向数据驱动的机器学习模型
1. 传统方法(Explicit Calculations)
典型技术
- 保守性计算:基于序列比对计算位置熵(如Shannon熵)
- 共进化分析:直接耦合分析(DCA)、互信息(MI)
- 物理势函数:Rosetta中的能量项(如疏水势、氢键势)
局限性
- 浅层模式:只能捕捉预设的简单统计关系(如两两残基耦合)
- 手工特征工程:依赖领域专家设计算法(如定义"保守性阈值=0.8")
- 任务专用性:换一个新问题(如预测别构效应)需重新设计流程
2. 现代机器学习方法
核心优势
- 深度关联挖掘:自动学习序列中的高阶、非线性模式
- 例如:同时捕捉残基A↔B↔C的协同约束,而传统方法只能分析A↔B或B↔C
- 端到端学习:直接从原始数据(如MSA)预测结构,无需手动设计中间特征
- 通用性:同一模型架构可适应不同任务(如结构预测、功能注释)
AlphaFold的实现
- 输入处理:
- 原始MSA → Evoformer模块自动学习共进化模式
- 不再需要人工计算DCA矩阵
- 结构建模:
- 通过几何注意力(Geometric Attention)直接输出原子坐标
- 替代了传统基于片段组装+能量最小化的流程
知道进化历史对蛋白质的结构预测很有用,进化历史从MSA
数据分析而来,那第一步就是要和目标序列进行比对,找到那些和目标序列相似的序列。
因为蛋白质序列在进化过程中可能有替换substitution、插入insertion或删除deletion,这意味着我们不能一个一个氨基酸比较( compare positions pointwise)。
比如下面这个序列在白色氨基酸序列都是相同的,整个序列整体上序列结构十分相似。
但是当我们引入/添加一个新的氨基酸时,会导致错位,大部分序列都不匹配了。
所以,为了让序列尽可能对齐"alignment",尽可能多的体现出不同蛋白质之间的共同进化的信息。我们需要评估哪些地方有插入和删除。我们允许我们的算法能够在特点位置插入一个-
:gap token,表示和目标序列相比这里需要一个插入来与其尽可能好的对齐( align the sequences as best as it can)
这个比对序列进行对齐的过程主要由 Needlemann-Wunsch 算法完成。Needleman - Wunsch 算法是一种用于生物信息学中进行序列比对的经典动态规划算法,由美国科学家 Needleman 和 Wunsch 在 1970 年提出。该算法主要用于比较两个生物序列(如 DNA、RNA 或蛋白质序列)的相似性,通过在序列中插入空格(gap)来实现最佳的比对,使得相似的区域能够尽可能地对齐,从而推断它们之间的进化关系、功能相似性等。(这里我们不对算法细节进行探讨)
核心问题:序列数据库的庞大规模
-
内存需求:
- 主流蛋白质序列数据库(如UniRef、BFD)包含数十亿条序列,加载到内存中需要约 70GB RAM。
- 对比硬件限制:消费级电脑通常只有16-32GB内存,服务器可能配备128-256GB。
-
计算成本来源:
- 搜索对齐:在庞大数据库中查找同源序列(如HHblits/JackHMMER)需要:
- 扫描所有序列
- 计算序列相似性
- 构建多序列比对(MSA)
- 实时处理:AlphaFold运行时的MSA生成阶段占用了大部分计算时间和内存
- 搜索对齐:在庞大数据库中查找同源序列(如HHblits/JackHMMER)需要:
组件 | 内存占用示例 | 说明 |
---|---|---|
序列数据 | UniRef50: ~30GB | 压缩存储的序列文本 |
索引结构 | ~20GB | 加速序列搜索的哈希表/Bloom过滤器 |
中间比对结果 | 单个MSA: 100MB-1GB | 存储序列比对中的匹配/缺口信息 |
解决方案:预计算对齐(Precomputed Alignments)
-
ColabFold的实践:
- 提供预生成的MSA文件(如
.a3m
格式),跳过实时数据库搜索。 - 用户可直接下载包含以下内容的压缩包:
target_sequence.a3m # 多序列比对文件 target_sequence.pdb # 预测结构
- 提供预生成的MSA文件(如
-
优势:
- 内存效率:只需加载单个MSA文件(通常<1GB)
- 速度提升:避免耗时的序列搜索(从小时级缩短到分钟级)
- 硬件普适性:可在消费级设备上运行
解释.a3m
文件格式:
无论如何,我们最终得到的具有和目标序列对齐的序列比对数据的.a3m
文件如下:
整个文件采用交替行的结构,每条序列数据包括两行:>
开头的评分数据和紧接着的序列行。第一条序列用101
标识,它是目标序列也是query sequence。整个.a3m
文件无冗余元数据:仅包含从输入序列通过算法生成的同源序列,不附带实验条件、物种分类等额外信息。
ColabFold的默认行为
- 输入处理:当用户未提供自定义序列时,自动使用大肠杆菌互变异构酶(E. coli Tautomerase)作为示例:
# ColabFold的默认序列(UniProt P0A6K5) DEFAULT_SEQUENCE = "PIAQIHILEGRSDEQKETLIREVSEAISRSLDAPLTSVRVIITEMAKGHFGIGGELASK"
- MSA生成:调用MMseqs2快速搜索UniRef/环境数据库,输出精简的.a3m文件。
文件结构解析:
- 第一行
#59 1
:#59
表示比对中包含的序列数量(59条)1
表示第一个序列是查询序列(query sequence)
- 查询序列部分:
>101 PIAQIHILEGRSDEQKETLIREVSEAISRSLDAPLTSVRVIITEMAKGHFGIGGELASK
>101
是查询序列的标识符- 后面是查询序列的氨基酸序列
- 比对序列部分:
每个比对序列有以下格式:>UniRef100_A0A7J3FD47 90 0.508 5.402E-19 0 58 59 1 59 63 PVVTIELWEGRTPEQKRELVRAVSSAISRVLGCPEEAVHVILHEVPKANWGIGGRLASE
- 序列头信息(以
>
开头)包含多个字段:- 序列ID(如UniRef100_A0A7J3FD47)
- 序列与查询序列的相似度百分比(90)
- 序列覆盖度(0.508)
- E-value值(5.402E-19)
- 其他比对统计信息
- 然后是比对后的序列,可能与查询序列长度相同或包含gap(-)
- 序列头信息(以
继续往下,在23行,我们第一个看到了gap token:-
。它在序列的末尾,代表目标序列在此位置和当前序列相比有一个插入,所以在当前序列使用-
占位。
继续看到 393行,我们第一次看到了 deletion: 是氨基酸 glycine, glutamine and glycine, 它们用小写字符表示为 gqg,代表目标序列在此位置没有这几个氨基酸。
注意当我们谈论到插入和删除时候,我们其实不能真的说在此有插入或者删除,因为我们其实并不知道进化的历史(evolutionary history. )。如果我们的目标序列比同源的被比较的序列更老,那么插入和删除就是反过来了。不过在这里,我们规定,说到插入和删除,是指从同源序列到目标序列之间的变化。
.a3m
多序列比对结果文件在AlphaFold蛋白质结构预测的角色:
5. 特征提取步骤⭐
得到MSA文件后,我们可以从种进行特征提取两类数据:
- the types of amino acids 氨基酸类型:我们可以知道每个序列每个位置上的氨基酸类型。将其中一部分进行独热编码,其他的一部分序列进行独热编码后取平均值。
- positions and number of deletions 被删除氨基酸的位置和数量信息:我们可以知道序列种的哪些氨基酸是被删除以及有多少数量。
5.1 初始处理
第一步,统计每个残基左侧的删除数量:
对于所有的氨基酸序列,我们需要找到所有小写字母,它们表示deletions。如何我们计算当前氨基酸的左部有多少deletions
,作为当前位置氨基酸的deletion count
(如下图)。
然后,我们删除小写字母,只保留deletion的数量信息:
删除之后,可以看到,包括-
在内,所有的同源序列和目标需要都具有相同长度(same length
💐note:AlphaFold只使用在删除后唯一的序列,所以如果删除后有序列相同,我们只使用第一个序列。
对序列进行one-hot编码(22类:20氨基酸+未知+gap),并得到target-feat,shape:(r,21)
我们得到删除之后的序列(without-deletions),对其进行独热编码,每个位置的氨基酸有22类(The 20 amino acids and the unknown and gap tokens)。这些序列同时包括了第一条序列(也就是目标序列),它将独自作one-hot编码,每个位置的氨基酸有21类(20氨基酸+未知),这条序列也将构成模型输入的特征: target_feat
.
计算每个位置氨基酸的分布(取one-hot编码的均值):
经过duress编码后的序列的形状为:(N_seq, N_res, 22)
。在此基础上,我们需要另外计算在同一位置的不同氨基酸之间的分布。这个分布将被用为后续步骤中氨基酸的重采样resample 。
对于aa_distribution
的解释:它计算每条序列在同一位置的氨基酸的分布。我们可以把每个氨基酸位置的读热编码的取值表示对这个位置氨基酸的投票。将其加起来求平均可以求得氨基酸在此位置的分布(过程如下图)。
代码实现:
def initial_data_from_seqs(seqs):"""Processes raw sequences from an A3M file to extract initial feature representations.Args:seqs: A list of amino acid sequences loaded from the A3M file. Sequences are represented with single-letter amino acid codes.Lowercase letters represent deletions.Returns:A dictionary containing:* msa_aatype: A PyTorch tensor of one-hot encoded amino acid sequencesof shape (N_seq, N_res, 22), where N_seq is the number of unique sequences (with deletions removed) and N_res is the length of the sequences. The dimension 22 corresponds to the 20 amino acids, an unknown amino acid token, and a gap token. * msa_deletion_count: A tensor of shape (N_seq, N_res) where each element represents the number of deletions occurring before the corresponding residue in the MSA.* aa_distribution: A tensor of shape (N_res, 22) containing the overall amino acid distribution at each residue position across the MSA. """unique_seqs = Nonedeletion_count_matrix = Noneaa_distribution = None########################################################################### TODO: ## 1. Calculate the 'deletion_count_matrix': ## * Initialize an empty list of lists to store deletion counts. ## * Iterate through the sequences in 'seqs': ## * Create a list to track deletions for the current sequence. ## * Iterate through letters, counting lowercase letters ## as deletions. ## * Append the deletion count list to the main ## 'deletion_count_matrix' only if the sequence # # (after removing deletions) has not been seen before. ## * Convert 'deletion_count_matrix' into a PyTorch tensor. ## 2. Identify 'unique_seqs': ## * Create an empty list to store unique sequences. ## * Iterate through the sequences in 'seqs': ## * Remove lowercase letters (deletions) from the sequence. ## * If the sequence (without deletions) is not already in the ## 'unique_seqs' list, add it. ## * Apply the `onehot_encode_aa_type` function to each sequence ## in 'unique_seqs' to get a tensor of shape (N_seq, N_res, 22) ## representing the one-hot encoded amino acids. ## 3. Compute 'aa_distribution': ## * Average the one-hot encoded 'unique_seqs' tensor across the ## first dimension (representing sequences) to calculate the ## amino acid distribution. ###########################################################################deletion_count_matrix = []unique_seqs = []for seq in seqs:deletion_count_list = []deletion_counter = 0for letter in seq:if letter.islower():deletion_counter += 1else:deletion_count_list.append(deletion_counter)deletion_counter=0seq_without_deletion = re.sub('[a-z]', '', seq)if seq_without_deletion in unique_seqs:continueunique_seqs.append(seq_without_deletion)deletion_count_matrix.append(deletion_count_list)unique_seqs = torch.stack([onehot_encode_aa_type(seq, include_gap_token=True) for seq in unique_seqs], dim=0)unique_seqs = unique_seqs.float()deletion_count_matrix = torch.tensor(deletion_count_matrix).float()aa_distribution = unique_seqs.float().mean(dim=0)########################################################################### END OF YOUR CODE ###########################################################################return { 'msa_aatype': unique_seqs, 'msa_deletion_count': deletion_count_matrix, 'aa_distribution': aa_distribution}
经过上述对.asm
文件的初始处理,我们得到了
msa_aatype;shape(N_seq,N_res,22]
、msa_deletion_count;shape(N_seq,N_res)
、aa_distribution;shape(N_res,22)
基于这个,我们正式开始以下五个步骤的讲解AlphaFold中的特征提取部分:
-
首先,AlphaFold会随机选择一些数量的序列作为“聚类中心”。这些序列会被直接作为特征,而其他没有被选中的序列作为“extra" sequences,只为每一cluster的均值作出贡献。
-
完成聚类中心的选择后,作为聚类中心的这部分序列也会被随机的改变,在论文中被称为’masking’
-
然后,额外的序列会被分配到那些与之最为相近的聚类中心。
-
deletions的数量会在每一个聚类中被平均
-
最终,这些特征会被stack(堆叠)来作为
full msa_feat
特征
5.2 聚类中心选择
首先,我们会随机的选取一定数量的序列作为聚类中心(cluster centers),这之中会始终包括目标序列作为第一个中心(always including the target sequence as the first center.)。
对于每个聚类中心,我们分别提取它的 deletions and amino acids ,对于其他的序列,我们直接对其进行平均。
关键特性
特性 | 说明 |
---|---|
非均匀分布 | 簇中心是随机选择的,不保证空间均匀覆盖 |
目标序列必选 | 索引0强制包含,确保目标序列信息不被丢失 |
固定数量(512) | 平衡计算成本与表征能力(实验验证的折中点) |
Extra MSA的作用 | 未被选中的序列仍用于共进化信号提取,但计算开销更低 |
生物学合理性
虽然看似简单,但这种策略有效是因为:
- MSA冗余性:同源序列本身具有相似性,随机采样大概率覆盖主要变异模式
- 注意力机制补偿:Evoformer的self-attention能自动加权重要序列
- 计算效率优先:避免昂贵的聚类计算(如k-means需O(N^2)距离矩阵)
示例数据流
假设MSA有10,000条序列:
- 生成随机排列:
[5832, 1241, 9999, ..., 42]
- 添加目标序列:
[0, 5832, 1241, ..., 42]
- 选取前512个:
[0, 5832, 1241, ..., 511th]
→ 簇中心 - 剩余9,488条 → Extra MSA
代码实现:
def select_cluster_centers(features, max_msa_clusters=512, seed=None):"""Selects representative sequences as cluster centers from the MSA to reduce redundancy.Args:features: A dictionary containing feature representations of the MSA.max_msa_clusters: The maximum number of cluster centers to select.seed: An optional integer seed for the random number generator. Use this to ensure reproducibility.Modifies:The 'features' dictionary in-place by:* Updating the 'msa_aatype' and 'msa_deletion_count' features to contain data for the cluster centers only. * Adding 'extra_msa_aatype' and 'extra_msa_deletion_count' featuresto hold the data for the remaining (non-center) sequences. """N_seq, N_res = features['msa_aatype'].shape[:2]MSA_FEATURE_NAMES = ['msa_aatype', 'msa_deletion_count']max_msa_clusters = min(max_msa_clusters, N_seq)gen = Noneif seed is not None:gen = torch.Generator(features['msa_aatype'].device)gen.manual_seed(seed)########################################################################### TODO:# 1. **Implement Shuffling:**# * Use `torch.randperm(N_seq - 1)` with the provided `gen` (random number generator) # to shuffle the indices from 1 to (N_seq - 1). Ensure reproducibility if the seed is not None.# * Prepend a 0 to the shuffled indices to include the first sequence.# 2. **Split Features:**# * Using the shuffled indices, split the MSA feature representations (`msa_aatype` and# `msa_deletion_count`) into two sets:# * The first `max_msa_clusters` sequences will be the cluster centers.# * The remaining sequences will be stored with keys prefixed by 'extra_'. ##########################################################################shuffled = torch.randperm(N_seq-1, generator=gen) + 1shuffled = torch.cat((torch.tensor([0]), shuffled), dim=0)for key in MSA_FEATURE_NAMES:extra_key = f'extra_{key}'value = features[key]features[extra_key] = value[shuffled[max_msa_clusters:]]features[key] = value[shuffled[:max_msa_clusters]]########################################################################### END OF YOUR CODE ###########################################################################return features
5.3 聚类掩码(Cluster Masking)
接下来就是对聚类中心的序列的部分氨基酸(15%)进行聚类掩码,页就是对其进行改动。
用于增强模型鲁棒性的序列掩码正则化技术,其核心思想是通过随机扰动簇中心序列,使模型能够学习更稳健的特征表示。
💐分步掩码流程:
-
初始选择(15%概率):
- 每个簇中心的每个氨基酸位置有15%的概率被选中进行可能的替换
-
替换策略(对选中位置):
替换类型 概率 说明 随机氨基酸替换 10% 从20种标准氨基酸中均匀采样 基于MSA分布的替换 10% 根据该位置在MSA中的氨基酸频率分布采样 保持原氨基酸 10% 即使被选中也不改变 掩码标记([MASK])替换 70% 用特殊token替换,模拟数据缺失场景
代码实现
def mask_cluster_centers(features, mask_probability=0.15, seed=None):"""Introduces random masking in the cluster center sequences for data augmentation.This function modifies the 'msa_aatype' feature within the 'features' dictionary to improve model robustness in the presence of noisy or missing input data. Masking is inspired by the AlphaFold architecture.Args:features: A dictionary containing feature representations of the MSA. It is assumedthat cluster centers have already been selected.mask_probability: The probability of masking out an individual amino acid in a cluster center sequence.seed: An optional integer seed for the random number generator. Use this to ensure reproducibility.Modifies:The 'features' dictionary in-place by:* Updating the 'msa_aatype' feature with masked-out tokens as well as possible replacements based on defined probabilities. * Creating a copy of the original 'msa_aatype' feature with the key 'true_msa_aatype'. """N_clust, N_res = features['msa_aatype'].shape[:2]N_aa_categories = 23 # 20 Amino Acids, Unknown AA, Gap, masked_msa_tokenodds = { # 定义四种替换路径的权重'uniform_replacement': 0.1, # 随机替换'replacement_from_distribution': 0.1, # MSA分布替换'no_replacement': 0.1, # 保持'masked_out': 0.7, # 特殊掩码}gen = Noneif seed is not None:gen = torch.Generator(features['msa_aatype'].device)gen.manual_seed(seed)torch.manual_seed(seed)########################################################################### TODO:# 1. **Select Modification Candidates:**# * Generate a random mask (tensor of shape (N_clust, N_res) ) where each element is a # random number between 0 and 1. # * Select elements where the random number is less than the `mask_probability` for potential modification.# 2. **Replacement Logic:**# * Create tensors to represent substitution probabilities:# * `uniform_replacement`: Shape (22,) # - Set the first 20 elements (amino acids) to `1/20 * odds['uniform_replacement']`.# - Set the last 2 elements (unknown AA and gap) to 0.# * `replacement_from_distribution`: Shape (N_res, 22), calculated from 'features['aa_distribution]'. Scale by `odds['replacement_from_distribution']`# * `no_replacement`: Shape (N_clust, N_res, 22), use the existing 'features['msa_aatype']' tensor and scale by `odds['no_replacement']`.# * `masked_out`: Shape (N_clust, N_res, 1), all elements are `odds['masked_out']`.# * **Sum** the first three tensors, then **concatenate** with `masked_out` along the last dimension. This creates 'categories_with_mask_token' of shape (N_clust, N_res, 23)# * Flatten the first two dimensions of 'categories_with_mask_token' for sampling.# * Use `torch.distributions.Categorical` and the flattened 'categories_with_mask_token' tensor to # probabilistically determine replacements for the selected residues. # * Reshape the sampled replacements back to (N_clust, N_res).# 3. **Preserve Original Data:**# * Create a copy of the original 'msa_aatype' data under the key 'true_msa_atype'.# 4. **Apply Masking:**# * Update the 'msa_aatype' tensor, but *only* for the elements selected in step 1 for modification, with the sampled replacements. Leave other elements unchanged. ########################################################################### uniform_replacement has shape (22,) uniform_replacement = torch.tensor([1/20]*20+[0,0]) * odds['uniform_replacement']# replacement_from_distribution has shape (N_res, 22)replacement_from_distribution = features['aa_distribution'] * odds['replacement_from_distribution']# no_replacement has shape (N_clust, N_res, 22)no_replacement = features['msa_aatype'] * odds['no_replacement']# masked_out has shape (N_clust, N_res, 1)masked_out = torch.ones((N_clust, N_res, 1)) * odds['masked_out']uniform_replacement = uniform_replacement[None, None, ...].broadcast_to(no_replacement.shape)replacement_from_distribution = replacement_from_distribution[None, ...].broadcast_to(no_replacement.shape)# 计算联合概率分布categories_without_mask_token = uniform_replacement + replacement_from_distribution + no_replacement# (N_clust, N_res, 22) categories_with_mask_token = torch.cat((categories_without_mask_token, masked_out), dim=-1)# (N_clust, N_res, 22) + (N_clust, N_res, 1) = (N_clust, N_res, 23)categories_with_mask_token = categories_with_mask_token.reshape(-1, N_aa_categories) # (N_clust * N_res, 23)replace_with = torch.distributions.Categorical(categories_with_mask_token).sample() # 采样replace_with = nn.functional.one_hot(replace_with, num_classes=N_aa_categories)replace_with = replace_with.reshape(N_clust, N_res, N_aa_categories)replace_with = replace_with.float()# 掩码replace_mask = torch.rand((N_clust, N_res), generator=gen) < mask_probabilityfeatures['true_msa_aatype'] = features['msa_aatype'].clone()aatype_padding = torch.zeros((N_clust, N_res, 1))features['msa_aatype'] = torch.cat((features['msa_aatype'], aatype_padding), dim=-1)features['msa_aatype'][replace_mask] = replace_with[replace_mask]########################################################################### END OF YOUR CODE ###########################################################################return features
5.4 聚类分配
当对特征中心进行掩码之后,额外的氨基酸序列将被分配到这些聚类中心。通过计算有多少氨基酸和聚类中心序列中的氨基酸相似。这也被两条序列的汉明距离。(注意,我们只计算氨基酸,如果是gap则不考虑)。
每条额外的序列会被分配给与之最相似的聚类中心。这可以用argmax
来评估。另外我们会统计每个聚类中心被分配了多少个序列(cluster-size
),会用在下面计算聚类平均。
代码实现:
def cluster_assignment(features):"""Assigns sequences in the extra MSA to their closest cluster centers based on Hamming distance.Args:features: A dictionary containing feature representations of the MSA. It is assumed that cluster centers have already been selected.Returns:The updated 'features' dictionary with the following additions:* cluster_assignment: A tensor of shape (N_extra,) containing the indices of the assigned cluster centers for each extra sequence.* cluster_assignment_counts: A tensor of shape (N_clust,) where each element indicates the number of extra sequences assigned to a cluster center (excluding the cluster center itself)."""N_clust, N_res = features['msa_aatype'].shape[:2]N_extra = features['extra_msa_aatype'].shape[0]########################################################################### TODO:# 1. **Prepare Features:**# * Obtain slices of the 'msa_aatype' (shape: N_clust, N_res, 23) and 'extra_msa_aatype' (shape: N_extra, N_res, 22) tensors # that exclude the 'gap' and 'masked' tokens. This focuses the calculation on the standard amino acids.# 2. **Calculate Agreement:**# * Employ broadcasting and tensor operations on the prepared features to efficiently calculate the number of positions where # the amino acids in each extra sequence agree with those in each cluster center. The result will be an 'agreement' tensor # of shape (N_clust, N_extra). `torch.einsum` can be a useful tool here. # 3. **Assign Clusters:**# * Use `torch.argmax(agreement, dim=0)` to find the cluster center index with the highest agreement (lowest Hamming distance) for each extra sequence. # 4. **Compute Assignment Counts:** # * Use `torch.bincount` to efficiently calculate the number of extra sequences assigned to each cluster center (excluding # the cluster center itself). Ensure you set the `minlength` parameter appropriately.##########################################################################msa_aatype = features['msa_aatype'][...,:21]extra_msa_aatype = features['extra_msa_aatype'][...,:21]agreement = torch.einsum('cra,era->ce', msa_aatype, extra_msa_aatype)assignment = torch.argmax(agreement,dim=0)features['cluster_assignment'] = assignmentassignment_counts = torch.bincount(assignment, minlength=N_clust)features['cluster_assignment_counts'] = assignment_counts########################################################################### END OF YOUR CODE ###########################################################################return features
5.5 聚类平均
这里,我们会对之前提取的deletion-count
和每个位置的
1. 输入数据准备
变量 | 形状 | 含义 |
---|---|---|
cluster_features | (N_clust, N_res, C) | 初始簇中心特征(含氨基酸分布、缺失计数等) |
extra_features | (N_extra, N_res, C) | 额外序列的特征 |
cluster_assignment | (N_extra,) | 每个额外序列所属的簇索引(通过汉明距离计算得到) |
cluster_assignment_count | (N_clust,) | 每个簇分配到的额外序列数量(通过bincount 得到) |
2. 计算步骤分解
(1) 特征累加(Scatter Add)
使用torch.scatter_add
将额外序列特征按簇归属累加到簇中心:
# 扩展cluster_assignment形状以匹配extra_features
expanded_assignment = cluster_assignment.view(-1, 1, 1).expand_as(extra_features) # (N_extra, N_res, C)# 累加操作
cluster_sums = torch.zeros_like(cluster_features)
cluster_sums.scatter_add_(dim=0, index=expanded_assignment, src=extra_features) # (N_clust, N_res, C)
(2) 计算平均值
由于平均值需包含簇中心本身,分母为assignment_counts + 1
:
# 扩展计数形状以匹配特征维度
counts = (cluster_assignment_count + 1).view(-1, 1, 1) # (N_clust, 1, 1)# 计算平均特征
cluster_avg = cluster_sums / counts # (N_clust, N_res, C)
完整代码:
def cluster_average(feature, extra_feature, cluster_assignment, cluster_assignment_count):"""Calculates the average representation of each cluster center by aggregating features from the assigned extra sequences.Args:feature: A tensor containing feature representations for the cluster centers.Shape: (N_clust, N_res, *)extra_feature: A tensor containing feature representations for extra sequences.Shape: (N_extra, N_res, *). The trailing dimensions (*) must be smaller or equal to those of the 'feature' tensor.cluster_assignment: A tensor indicating the cluster assignment of each extra sequence.Shape: (N_extra,)cluster_assignment_count: A tensor containing the number of extra sequences assigned to each cluster center.Shape: (N_clust,)Returns:A tensor containing the average feature representation for each cluster. Shape: (N_clust, N_res, *) """N_clust, N_res = feature.shape[:2]N_extra = extra_feature.shape[0]########################################################################### TODO:# 1. **Prepare for Accumulation:**# * Broadcast the `cluster_assignment` tensor to have the same shape as `extra_feature`.# This is necessary for compatibility with `torch.scatter_add`.# 2. **Accumulate Features:**# * Use `torch.scatter_add` to efficiently sum (or accumulate) the `extra_feature` values for each cluster. The broadcasted `cluster_assignment` tensor will define the grouping. # 3. **Calculate Averages:**# * Divide the accumulated features by the `cluster_assignment_count` + 1 to obtain the average feature representations for each cluster. ##########################################################################unsqueezed_extra_shape = (N_extra,) + (1,) * (extra_feature.dim()-1)unsqueezed_cluster_shape = (N_clust,) + (1,) * (feature.dim()-1)cluster_assignment = cluster_assignment.view(unsqueezed_extra_shape).broadcast_to(extra_feature.shape)cluster_sum = torch.scatter_add(feature, dim=0, index=cluster_assignment, src=extra_feature)cluster_assignment_count = cluster_assignment_count.view(unsqueezed_cluster_shape).broadcast_to(feature.shape)cluster_average = cluster_sum / (cluster_assignment_count + 1)########################################################################### END OF YOUR CODE ###########################################################################return cluster_average
5.6 特征堆叠
这是最后一次真正的计算。现在,剩下要做的就是收集我们构建的特征并正确堆叠它们。
下面这张表格是AlphaFold从.a3m
文件构造的所有特征,我们将全部过一遍。
-
The feature
aatype
is a one-hot encoding of the input sequence. -
cluster_msa
is the same for all sequences that were selected as cluster centers. Note that we need two additional tokens in the one-hot encoding, for gap tokens and mask tokens. -
The feature
cluster_has_deletion
is one for every residue in the cluster centers that had a deletion on its left, zero otherwise. -
cluster_deletion_value
actually counts the number of deletions on the left of each residue, then normalizes it by 2/pi*arctan(d/3). This maps the values to a range (0, 1), which is better suited as a network input. -
The features
extra_msa
,extra_msa_has_deletion
andextra_msa_deletion_value
are identical to the ones for the cluster centers, but calculated for all sequences that were not selected. These features will be used as input through the less complex, memory-friendly Extra MSA Stack. -
For the main input, the extra sequences only contribute as averages for each cluster, by the features
cluster_deletion_mean
andcluster_profile.
They contain just what the names suggest: cluster_deletion_mean is the average number of deletions left to each residue for each sequence in the clusters, normalized to the range [0,1] using arctan again, and cluster_profile is a distribution over the amino acids at each position. Note that the averages also include the cluster centers.
我们上面的步骤其实我们已经得到了那些特征。接下来就是将他们进行处理得到模型的输入 concatenate some of them to get the final inputs:
- The feature ‘
target_feat
’ is the ‘aatype
’ feature. - The feature ‘
residue_index
’ is a range of[0, ..., N_res-1]
, to be used for positional encodings. - The feature ‘
msa_feat
’ is constructed by concatenating ‘cluster_msa
’, ‘cluster_has_deletion
’, ‘cluster_deletion_value
’, ‘cluster_deletion_mean
’ and ‘cluster_profile
’. - The feature ‘
extra_msa'feat
’ is constructed by concatenating ‘extra_msa
’, ‘extra_msa_has_deletion
’ and ‘extra_msa_deletion_value
’.
注意我们在构建这些输入的时候使用了随机性,尤其是在构建聚类中心的时候还有聚类掩码的时候。
在后面我们会看到AlphaFold会重复作几次这样完整的预测,循环预测positions和其他输出。这些输入构建的步骤会在模型每次推理的时候重新执行,这意味着每次迭代的时候都会有随机性。
–
总结
综上,这就是AlphaFold的特征提取的流程。
从相关的输入数据中进行选择,然后将其转为tensor数据类型是机器学习在新的问题背景下的关键。
相关文章:
【AlphaFold2】Feature extraction:提取特征,为模型输入做准备|Datapipeline讲解
博主简介:努力学习的22级计算机科学与技术本科生一枚🌸博主主页: Yaoyao2024往期回顾:【深度学习】多头注意力机制的实现|pytorch每日一言🌼: 学习成绩只是表象,而学习能力才是伴随一身的结果🌺…...
Android 实现一个隐私弹窗
效果图如下: 1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数 2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来 res/layout/dialog_privacy_policy.xml 文件 <?xml version"1.0" encoding"utf-8"?&…...
第三方软件测试报告如何凭借独立公正与专业权威发挥关键作用?
在软件项目里,第三方软件测试报告起着极为关键的作用。第三方有着中立客观的立场。第三方具备专业能力。凭借这些,第三方能为软件质量评估提供可靠依据。下面要从不同方面介绍第三方软件测试报告。 独立公正性 第三方测试机构与软件开发方、使用方不存…...
QT控件 参考Qt的PIMPL设计模式实现使用QWidget控件绘制3D饼状图表和3D柱状图表,使用QChartView绘制圆柱体图表
整体绘制效果就是:Qt 实现3维饼状图 中的内容, 只不过我借鉴了Qt的PIMPL模式重新封装了整个实现过程 实现效果展示 目录导读 实现效果展示前言绘制3D饼状图表PIMPL模式设计类具体实现计算圆弧中心判断点是否在某个扇区中在私有类中绘制绘制3D柱状图表PIMPL模式设计类具体实现绘…...
Android Q允许低内存启用系统弹窗
如果SYSTEM_ALERT_WINDOW权限可用,则返回true。 *从Q开始,在低ram手机上禁用SYSTEM_ALERT_WINDOW。 vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/Utils.java public static boolean isSystemAlertWindowEnabled(Co…...
Leetcode 3532. Path Existence Queries in a Graph I
Leetcode 3532. Path Existence Queries in a Graph I 1. 解题思路2. 代码实现 题目链接:3532. Path Existence Queries in a Graph I 1. 解题思路 这一题算是一个比较典型的DSU的题目,我们就是不断地根据前后节点的距离将其进行聚类,然后…...
AI Agent Protocols:现状、挑战与未来展望
一、引言 在当今人工智能飞速发展的时代,大语言模型(LLMs)的进步使得LLM智能体在各个行业得到了广泛的应用,如客户服务、内容生成、数据分析和医疗保健等领域。 然而,随着越来越多的LLM智能体被部署,一个…...
自动化立库/AGV物流仿真详细步骤
以下是一种可以在预算和周期内实现自动化立库及AGV 方案仿真分析的方法: 一、工具选择 软件工具FlexSim:这是一款流行的离散事件仿真软件。它具有直观的图形用户界面,通过简单的拖拽操作就可以构建自动化立库和 AGV 的模型。其内置的丰富的…...
【题解-Acwing】872. 最大公约数
题目:872. 最大公约数 题目描述 给定 n 对正整数 ai,bi,请你求出每对数的最大公约数。 输入 第一行包含整数 n。 接下来 n 行,每行包含一个整数对 ai,bi。 输出 输出共 n 行,每行输出一个整数对的最大公约数。 数据范围 1 ≤ n ≤ 105, 1 ≤ai, bi ≤ 2109 时空限…...
62.微服务保姆教程 (五) Seata--微服务分布式事务组件
Seata–微服务分布式事务组件 一、什么是分布式事务 1.什么是事务 事务指的是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么所有操作都成功,要么所有的操作都被撤销。 2.本地事务 本地事务是指基于关系型数据库的事务,也称为传统事务。大多数场景…...
【算法练习】归并排序和归并分治
文章目录 1.归并排序1.1 递归版本1.2 非递归版本 2.归并分治2.1 计算数组的小和2.2 计算翻转对 1.归并排序 归并排序的核心步骤是: 拆分:将无序数组不断对半拆分成小块,直到每个小块只剩一个元素(自然有序)。 合并&a…...
从SOA到微服务:架构演进之路与实践示例
一、架构演进背景 在软件开发领域,架构风格随着业务需求和技术发展不断演进。从早期的单体架构,到面向服务架构(SOA),再到如今的微服务架构,每一次变革都是为了解决当时面临的核心问题。 二、SOA架构解析 2.1 SOA核心概念 SOA&…...
vue+cesium线流动纹理
index.vue页面 <!--线流动纹理实现--> <template><div id"mapContainerFirst"></div> </template> <script lang"ts" setup> import { init as initPolylineTrailLinkMaterialProperty } from ./PolylineTrailLinkM…...
深度学习·经典模型·SwinTransformer
SwinTransformer 主要创新点:移动窗口,基于窗口的注意力计算 Patch Embedding 下采样打包为Pacth:可以直接使用Conv2d 也可以先打包后使用embedding映射。 Patch Merging 类似池化的操作,压缩图片大小,同时通道数增多ÿ…...
在开发板上如何处理curl: (60) SSL certificate problem
目录 引言 问题解析 解决方法 跳过证书验证 采用证书认证 结语 引言 最近一直推荐学生们在课程实验中使用curl及其libcurl。curl 是一个强大的命令行工具,用于在命令行中进行数据传输。它支持多种协议,如 HTTP、HTTPS、FTP、FTPS、SCP、SFTP 等。…...
Ansible 铸就 Linux 安全之盾(Ansible Builds Linux Security Shield)
Ansible 铸就 Linux 安全之盾:自动化基线检查与防护 在当今网络安全形势日益严峻的背景下,Linux 系统作为服务器和关键基础设施的核心,其安全防护显得尤为重要。Ansible 作为一款强大的自动化运维工具,能够帮助我们高效、可靠地实…...
字符串(格式化字符串字面值)进行输出
在 Python 中,print(fnew_obs:{new_obs}) 这种形式是使用 f 字符串(格式化字符串字面值) 进行输出,它可以打印 任何可转换为字符串的数据类型,并且支持在字符串中嵌入表达式。以下是详细说明: 1. 基本功能…...
微服务架构详解:从概念到实践
目录 前言1. 微服务架构概述1.1 什么是微服务?1.2 微服务的核心思想 2. 微服务的优势2.1 可扩展性2.2 高灵活性2.3 容错性和可靠性2.4 高效开发与部署 3. 微服务的挑战3.1 系统复杂性增加3.2 分布式事务和数据一致性3.3 部署和运维的复杂性 4. 微服务的实施与实践4.…...
激光驱鸟:以科技重构生态防护边界
技术原理 激光驱鸟装置的核心机制基于鸟类视觉系统特性。其发射的绿色激光束(波长通常为532纳米)处于鸟类视网膜敏感光谱范围内,当激光束在特定角度扫描时,会形成动态光斑干扰。鸟类视网膜中视锥细胞对绿色光的高敏感度使其产生应…...
【Python魔法方法(特殊方法)】
在 Python 中,许多运算符都可以进行重载,以下是一些常见运算符及其对应的魔法方法(特殊方法): 算术运算符 加法 :__add__ 用于定义对象相加的行为。例如,当你对两个自定义类的实例使用 运算符…...
centos上安装python的3.13版本
在 CentOS 上安装 Python 3.13(或其它自定义版本)最推荐的方法是通过源码编译安装,不会影响系统自带的 Python2/Python3 环境,也更灵活可控。 以下步骤适用于: ✅ CentOS 7 / 8 / 9 ✅ 安装 Python 3.13(…...
实习技能记录【4】-----消息分发中的观察者模型
观察者 观察者模式(Observer Pattern)是一种行为型设计模式,主要用于定义对象之间的一对多依赖关系,让多个观察者对象能够同时监听某个主题对象的状态变化,并在主题对象状态改变时自动通知所有观察者对象。 参考b站博…...
Linux 下编译BusyBox
一、linux下编译 1.拉取busybox源码 git clone https://github.com/mirror/busybox.git 内容如下 2.配置make,建议在linux下单独开一个终端执行 进入busybox源码目录,使用如下命令 make menuconfig 3.报错 解决办法: 安装ncurses sud…...
Linux《进程概念(中)》
在之前的Linux《进程概念(上)》当中我们已经了解了进程的基本概念以及如何去创建对应的子进程,那么接下来在本篇当中我们就继续来进程的学习,在本篇当中我们要学习到进程的状态、进程的优先级、进程切换、Linux真实的调度算法——…...
Linux Vim 使用 显示行号、替换、查找、多文件打开等骚操作
目录 简述 vim的三种模式 概述 转换方式 文本编辑 命令模式 插入(编辑)模式 底行模式 搜索关键字 显示行号 替换 多文件打开 简述 vi编辑器是Linux系统下标准的编辑器。 那么简单的理解,就像是Windows下的记事本。 补充&a…...
AimRT 从零到一:官方示例精讲 —— 三、Executor示例.md
Executor示例 官方仓库:executor 配置文件(configuration_executor.yaml) 依据官方示例项目结构自行编写YAML配置文件: # 基础信息 base_info:project_name: Logger # 项目名称build_mode_tags: ["EXAMPLE", &quo…...
只把夜莺监控当作告警来使用:一种轻量化的运维实践
只把夜莺监控当作告警来使用:一种轻量化的运维实践 在现代的 IT 运维体系中,监控和告警是两个经常被一同提及的概念。然而,在实际工作中,很多团队对监控系统的需求并不一定全面覆盖指标采集、可视化展示、告警触发等功能…...
按键精灵安卓ios辅助工具脚本:实用的文件插件(lua开源)
亮点:此lua插件可再android和ios上通用 1、获取文件的属性 2、改变当前的工作路径为dirpath 3、获取当前的工作路径 4、创建文件夹,支持多级创建 5、删除文件夹 6、递归遍历文件夹 7、设置文件的访问时间和修改时间 函数原型:lfs.Attribute(…...
水库现代化建设指南-水库运管矩阵管理系统建设方案
政策背景 2023年8月24日,水利部发布的水利部关于加快构建现代化水库运行管理矩阵的指导意见中指出,在全面推进水库工程标准化管理的基础上,强化数字赋能,加快构建以推进全覆盖、全要素、全天候、全周期“四全”管理,完…...
若依后台管理系统-v3.8.8-登录模块--个人笔记
各位编程爱好者们,你们好!今天让我们来聊聊若依系统在登录模块的一些业务逻辑,以及本人的一些简介和心得,那么废话不多说,让我们现在开始吧。 以下展示的这段代码,正是若依在业务层对应的登录代码…...
Flip PDF Plus Corp7.7.22电子书制作软件
flip pdf plus corporate7.7.22中文版由FlipBuilder官方出品的一款企业级的翻页电子书制作软件,拥有丰富的模板,主题和动画场景,每本书最大页数1000页,每本书的最大大小1GB,即可以帮助企业用户制作好丰富的电子书籍。 …...
公路安全知识竞赛主持稿串词
合 :尊敬的各位领导、各位来宾 、各位选手 : 大家上午 好! 男 :安全就是生命,安全就是效益,安全是一切工作的重中之重!安全生产只有满分,没有及格。只有安全生产这个环节不出差错,我…...
vscode 配置qt
工具:vscode、qttools、qtconfigure Search Mode改成基于cmake的。 # 在项目中指定Qt的路径 set(Qt5_DIR "/home/jp/qt-everywhere-src-5.12.9/arm-qt/lib/cmake/Qt5") # 用于指定 Qt5 的安装路径 find_package(Qt5 REQUIRED COMPONENTS Widgets)这样就…...
Node.js 事件循环和线程池任务完整指南
在 Node.js 的运行体系中,事件循环和线程池是保障其高效异步处理能力的核心组件。事件循环负责调度各类异步任务的执行顺序,而线程池则承担着处理 CPU 密集型及部分特定 I/O 任务的工作。接下来,我们将结合图示,详细剖析两者的工作…...
Java之BigDecimal
BigDecimal 是 Java 中用于高精度计算的类,特别适合需要精确十进制运算的场景,如金融计算、货币运算、概率计算等。 为什么需要 BigDecimal类 解决浮点数精度问题:float 和 double 使用二进制浮点运算,无法精确表示某些十进制小数…...
Qt5与现代OpenGL学习(四)X轴方向旋转60度
把上面两张图像放到D盘1文件夹内: shader.h #ifndef SHADER_H #define SHADER_H#include <QDebug> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QString>class Shader { public:Shader(const QString& verte…...
基于LVS+Keepalived+NFS的高可用负载均衡集群部署
目录 项目功能 2 项目的部署 2.1 部署环境介绍 2.2 项目的拓扑结构 2.3 项目环境调试 2.4 项目的部署 2.4.1 安装软件; 2.4.2 NFS服务器配置 2.4.3 Web节点配置 2.5 项目功能的验证 2.6 项目对应服务使用的日志 项目功能 负载均衡功能 实现原理:基于LVS(D…...
人工智能数学基础(四):线性代数
线性代数是人工智能领域的核心数学工具之一,广泛应用于数据表示、模型训练和算法优化等多个环节。本文将系统梳理线性代数的关键知识点,并结合 Python 实例,助力读者轻松掌握这一重要学科。资源绑定附上完整资源供读者参考学习! …...
基于C++的IOT网关和平台1:github项目ctGateway
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
LeetCode 2962.统计最大元素出现至少 K 次的子数组:滑动窗口
【LetMeFly】2962.统计最大元素出现至少 K 次的子数组:滑动窗口 力扣题目链接:https://leetcode.cn/problems/count-subarrays-where-max-element-appears-at-least-k-times/ 给你一个整数数组 nums 和一个 正整数 k 。 请你统计有多少满足 「 nums 中…...
Nginx反向代理的负载均衡配置
Nginx 负载均衡详解 在互联网应用中,随着网站访问量的不断攀升,服务器的服务模式也需要进行相应升级。诸如分离数据库服务器、将图片作为单独服务等操作,这些都属于简单的数据负载均衡,其目的是将压力分散到不同机器上。而来自 We…...
案例速成GO+Socket,个人笔记
更多个人笔记:(仅供参考,非盈利) gitee: https://gitee.com/harryhack/it_note github: https://github.com/ZHLOVEYY/IT_note 文章目录 简单知识了解实现一个TCP 服务器与客户端(聊天室&#x…...
篮球足球体育球员综合资讯网站模板
采用帝国CMS7.5新版核心。栏目和内容模板超多变换。后台操作简单,安全可靠,性能稳定。整站浏览效果高端大气,可以帮助你快速建立一个适合自己的软件下载类型的站点! 演示地址:https://www.tmuban.com/store/620.html …...
HTTP(超文本传输协议)全面总结
HTTP(HyperText Transfer Protocol,超文本传输协议)是万维网(World Wide Web)应用中的基础协议,用于客户端与服务器之间的数据传输。随着互联网技术的发展,HTTP协议也经历了多个版本的更新&…...
OpenCV 图形API(72)图像与通道拼接函数-----根据指定的方式翻转图像(GMat)函数 flip()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 翻转一个2D矩阵,围绕垂直轴、水平轴或同时围绕两个轴。 该函数以三种不同的方式之一翻转矩阵(行和列的索引是从0开始的&a…...
【报错问题】 macOS 的安全策略(Gatekeeper)阻止了未签名的原生模块(bcrypt_lib.node)加载
这个错误是由于 macOS 的安全策略(Gatekeeper)阻止了未签名的原生模块(bcrypt_lib.node)加载 导致的。以下是具体解决方案: 1. 临时允许加载未签名模块(推荐先尝试) 在终端运行以下命令&#x…...
keep-alive具体使用方法
什么是 Keep-Alive <keep-alive> 是 Vue.js 提供的一个内置组件,用于缓存动态组件实例,从而避免重复渲染已加载过的组件。它的主要功能是在切换组件时保留状态和 DOM 结构,提升性能。 工作原理 <keep-alive> 的核心在于维护一个…...
【C++11】包装器:function与bind
前言: 上文我们学了C11中一个新的表达式:Lambda表达式。Lambda表达式可以在函数内部定义,其本质是仿函数【C11】Lambda表达式-CSDN博客 本文我们来学习C11的下一个新语法:包装器 function function的定义为: templat…...
Educational Codeforces Round 178 div2(题解ABCDE)
A. Three Decks #1.由于最后三个数会相等,提前算出来和,%3判断,再判前两个数是否大于 #include<iostream> #include<vector> #include<stdio.h> #include<map> #include<string> #include<algorithm> #…...
mermaid 序列图 解析
sequenceDiagramparticipant UI as 用户界面participant Executor as 任务执行器participant StateMgr as 状态管理器participant Repo as 数据仓库UI->>Executor: 执行任务3350c74e...Executor->>StateMgr: 更新状态为"measuring"StateMgr->>Repo…...