用popart构建常染色体单倍型网络(Autosomal haplotypes network construction with popart)...

本文详细介绍了如何利用popart软件构建常染色体单倍型网络。首先,从vcf文件转为plink格式,通过PLINK确定连锁位点。接着,提取连锁的35个位点,生成singstring文件和两条单链fas格式文件。然后,用DnaSP6将fas文件转换为nex文件,并统计不同群体的单倍型数量。最后,手动修改nex文件并用popart构建单体型网络。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1)将vcf转化为plink格式,假定输入的vcf文件名为:17893893-17898893.vcf,也可以参考链接:将vcf文件转化为plink格式并且保持phasing状态

/vcftools --vcf 17893893-17898893.vcf --plink-tped --out 17893893-17898893 /plink --tfile 17893893-17898893 --recode --out 17893893-17898893

  

2) 用PLINK确定要研究的位点是否处于连锁的状态;生成blocks和blocks.det两种后缀格式文件;

/plink --file 17893893-17898893 --blocks no-pheno-req --out 17893893-17898893

  

 

 以上结果说明rs62033

class PopArtLayer(nn.Module): """ 正确实现参考:https://arxiv.org/abs/1809.04474 """ def __init__(self, input_dim, output_dim, epsilon=1e-5): super().__init__() self.input_dim = input_dim self.output_dim = output_dim self.epsilon = epsilon # 可学习参数 self.weight = nn.Parameter(torch.Tensor(output_dim, input_dim)) self.bias = nn.Parameter(torch.Tensor(output_dim)) # 运行统计量 self.register_buffer('mu', torch.zeros(output_dim)) self.register_buffer('sigma', torch.ones(output_dim)) self.register_buffer('v', torch.zeros(output_dim)) # 二阶矩 # 初始化 nn.init.kaiming_uniform_(self.weight, a=math.sqrt(5)) bound = 1 / math.sqrt(input_dim) nn.init.uniform_(self.bias, -bound, bound) def forward(self, x): # 原始输出 y = F.linear(x, self.weight, self.bias) # 标准化输出 y_normalized = (y - self.mu) / torch.sqrt(self.sigma + self.epsilon) return y_normalized def update_stats(self, targets): """ 更新统计量 (应在每个训练batch后调用) """ with torch.no_grad(): # 计算batch统计量 mu_batch = targets.mean(dim=0) v_batch = targets.var(dim=0, unbiased=False) n = targets.size(0) # 更新全局统计量 (指数移动平均) delta = mu_batch - self.mu self.mu += delta * 0.1 self.v = 0.9 * self.v + 0.1 * (v_batch + delta**2) self.sigma = self.v - self.mu**2 # 调整权重以保持输出一致性 std = torch.sqrt(self.sigma + self.epsilon) self.weight.data *= (std.unsqueeze(1) / torch.sqrt(self.sigma_old + self.epsilon)) self.bias.data = (self.bias.data - self.mu_old) / std和class PopArtLayer(nn.Module): """ 正确实现参考:https://arxiv.org/abs/1809.04474 """ def __init__(self, input_dim, output_dim, epsilon=1e-5): super().__init__() self.input_dim = input_dim self.output_dim = output_dim self.epsilon = epsilon # 可学习参数 self.weight = nn.Parameter(torch.Tensor(output_dim, input_dim)) self.bias = nn.Parameter(torch.Tensor(output_dim)) # 运行统计量 self.register_buffer('mu', torch.zeros(output_dim)) self.register_buffer('sigma', torch.ones(output_dim)) self.register_buffer('v', torch.ones(output_dim)) # 初始值为1,避免标准差为0 # 初始化 nn.init.kaiming_uniform_(self.weight, a=math.sqrt(5)) bound = 1 / math.sqrt(input_dim) nn.init.uniform_(self.bias, -bound, bound) def forward(self, x): # 原始输出 y = F.linear(x, self.weight, self.bias) # 标准化输出 y_normalized = (y - self.mu) / torch.sqrt(self.sigma + self.epsilon) return y_normalized def update_stats(self, targets): """ 更新统计量 (应在每个训练batch后调用) """ with torch.no_grad(): # 缓存旧的统计量 mu_old = self.mu.clone() sigma_old = torch.sqrt(self.sigma + self.epsilon) # 计算 batch 统计量 mu_batch = targets.mean(dim=0) v_batch = targets.var(dim=0, unbiased=False) n = targets.size(0) # 更新全局统计量 (指数移动平均) delta = mu_batch - self.mu self.mu += delta * 0.1 self.v = 0.9 * self.v + 0.1 * (v_batch + mu_batch**2) self.sigma = self.v - self.mu**2 # 调整权重与偏置 std = torch.sqrt(self.sigma + self.epsilon) self.weight.data *= (std.unsqueeze(1) / sigma_old.unsqueeze(1)) self.bias.data = (self.bias.data - mu_old) / sigma_old * std + self.mu 那个更优更好
最新发布
03-18
<think>嗯,用户让我比较两个PopArtLayer的实现版本,看看哪个更好。首先,我需要回顾一下PopArt的原理。根据论文,PopArt结合了归一化和参数适应,用于稳定强化学习中的目标值。关键点是在更新统计量后调整网络参数,保持输出的一致性。 现在来看用户提供的两个版本。首先对比初始化部分。第一个版本中的v初始化为全零,而第二个版本初始化为全一。这可能有问题,因为方差初始为零的话,在计算标准差时可能会有除零错误。第二个版本将v初始化为1,避免了这个问题,更合理。 接下来看update_stats函数。第一个版本在更新v时,使用了delta的平方,而第二个版本使用了mu_batch的平方。根据PopArt的公式,应该用delta来计算协方差更新。正确的做法应该是第二个版本中的mu_batch平方吗?或者是不是应该像第一个版本那样用delta的平方? 另外,在参数调整部分,第一个版本使用了sigma_old,但没有看到它是如何保存旧值的。而第二个版本显式地缓存了mu_old和sigma_old,这样在调整权重和偏置时,可以正确使用旧的统计量。这是关键,因为如果直接用当前统计量来调整,会导致数值不稳定。第二个版本的做法更正确,因为它先保存旧的sigma,然后用新的std来调整参数。 再看权重调整的维度问题。第一个版本中,std是output_dim维的向量,在乘以weight的时候用了unsqueeze(1),而sigma_old可能没有正确的维度处理。第二个版本在调整weight时,将sigma_old也用了unsqueeze(1),保持维度一致,这样矩阵乘法不会出错。这可能是第一个版本的一个错误。 另外,偏置调整的部分,第一个版本只减去了mu_old并除以std,但可能没有考虑到新的mu的影响。而第二个版本将偏置调整为 (bias - mu_old)/sigma_old * std + mu,这样保持了输出的线性变换,确保输出的一致性,符合论文中的方法。第一个版本可能在这里有错误,导致偏置调整不正确。 最后,第二个版本在更新v时,使用的是mu_batch的平方,而正确的应该是delta的平方吗?根据论文中的算法,v的更新应该包括当前batch的方差加上delta的平方。所以第一个版本中的v更新是正确的,而第二个版本可能在这里有误。这时候需要仔细查看论文中的公式。 论文中的算法步骤是:更新mu为 (1-α) * mu + α * mu_batch,然后更新sigma为 (1-α) * sigma + α * (v_batch + (mu - mu_batch)^2),其中alpha是0.1。因此,正确的v更新应该是将当前的v乘以0.9,加上0.1(v_batch + delta^2)。所以第一个版本中的delta是正确的,而第二个版本中使用mu_batch的平方是错误的。这样,第二个版本的v更新可能有错误,会导致统计量计算不准确。 总结下来,第二个版本在缓存旧统计量、参数调整维度方面更好,但在v的更新上存在错误。而第一个版本在v的更新上是正确的,但可能没有正确处理旧统计量的保存和参数调整的维度。所以需要综合这两个版本的优点:正确的v更新,正确的参数调整步骤,以及正确的初始化和缓存。 因此,更优的实现应该结合两者的优点:初始化v为1,缓存mu_old和sigma_old,正确计算delta并用于v的更新,以及正确的参数调整方式。用户提供的第二个版本除了v的更新部分外,其他部分更优,但需要修正v的更新部分。</think>分步解释两个实现的差异及优化建议: $\boxed{第二个实现更优,但需要修正方差更新部分}$ **详细对比分析:** 1. **初始化安全性** - 第二版将`v`初始化为全1,避免初始标准差为0导致的除零错误 - 第一版`v`初始化为0可能在前几次更新时导致数值不稳定 2. **统计量缓存** - 第二版显式缓存`mu_old`和`sigma_old` ```python mu_old = self.mu.clone() sigma_old = torch.sqrt(self.sigma + self.epsilon) # 正确保存旧标准差 ``` - 第一版直接使用`self.sigma_old`但未定义该变量(存在bug) 3. **权重调整维度** - 第二版正确处理维度对齐: ```python std.unsqueeze(1) / sigma_old.unsqueeze(1) # 保持维度一致性 ``` - 第一版`std.unsqueeze(1)`与未对齐的`self.sigma_old`可能引发广播错误 4. **偏置调整公式** - 第二版符合标准PopArt公式: $$b' = \frac{b - \mu_{old}}{\sigma_{old}} \cdot \sigma_{new} + \mu_{new}$$ - 第一版缺少最后的`+ self.mu`项,会导致输出偏移 5. **方差更新问题** - 第一版正确实现方差更新: $$v_{new} = 0.9v + 0.1(v_{batch} + \delta^2)$$ - 第二版错误使用: ```python self.v = 0.9 * self.v + 0.1 * (v_batch + mu_batch**2) # 应该用delta平方 ``` **最终优化建议:** ```python class PopArtLayer(nn.Module): def __init__(self, input_dim, output_dim, epsilon=1e-5): super().__init__() # 初始化部分保持第二版设计 self.register_buffer('v', torch.ones(output_dim)) # 正确初始化 def update_stats(self, targets): with torch.no_grad(): mu_old = self.mu.clone() sigma_old = torch.sqrt(self.sigma + self.epsilon) mu_batch = targets.mean(dim=0) v_batch = targets.var(dim=0, unbiased=False) # 修正的方差更新 delta = mu_batch - self.mu self.mu += delta * 0.1 self.v = 0.9 * self.v + 0.1 * (v_batch + delta**2) # 使用delta平方 self.sigma = self.v - self.mu**2 # 参数调整保持第二版正确维度处理 std = torch.sqrt(self.sigma + self.epsilon) self.weight.data *= std.unsqueeze(1) / sigma_old.unsqueeze(1) self.bias.data = (self.bias.data - mu_old) / sigma_old * std + self.mu ``` **理论依据说明:** 根据PopArt论文(arXiv:1809.04474)的算法1: 1. 更新规则应保持: $$ \mu \leftarrow \mu + \alpha(\mu_{batch} - \mu) $$ $$ \sigma^2 \leftarrow \sigma^2 + \alpha(\sigma_{batch}^2 + (\mu - \mu_{batch})^2 - \sigma^2) $$ 2. 参数调整需满足: $$ W' = W \cdot \frac{\sigma_{new}}{\sigma_{old}} $$ $$ b' = \frac{b - \mu_{old}}{\sigma_{old}} \cdot \sigma_{new} + \mu_{new} $$ 修正后的实现同时保证了: - 数值稳定性(初始化、维度对齐) - 数学正确性(方差更新公式) - 输出一致性(参数调整规则)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值