洪水预报中的序列到序列模型及其可解释性扩展

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家,觉得好请收藏。点击跳转到网站。

1. 引言

洪水预报是水文科学和灾害管理中的重要课题,准确的洪水预报可以显著减少人员伤亡和经济损失。近年来,深度学习技术在时间序列预测领域取得了显著进展,特别是序列到序列(Seq2Seq)模型在各种预测任务中表现出色。本文将详细介绍三种用于洪水预报的模型:基础Seq2Seq模型、Seq2Seq-LRP模型和Seq2Seq-LRP-Attention模型,并分析它们的实现细节和性能特点。

2. 基础Seq2Seq模型实现与问题分析

2.1 Seq2Seq模型架构

Seq2Seq模型由编码器和解码器两部分组成,通常采用RNN、LSTM或GRU作为基础单元。在洪水预报任务中,我们的输入是历史水文时间序列数据,输出是未来一段时间的水位或流量预测。

import torch
import torch.nn as nn
from torch.autograd import Variableclass Encoder(nn.Module):def __init__(self, input_size, hidden_size, num_layers=1):super(Encoder, self).__init__()self.hidden_size = hidden_sizeself.num_layers = num_layersself.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)def forward(self, x):# x shape: (batch_size, seq_len, input_size)outputs, (hidden, cell) = self.lstm(x)return hidden, cellclass Decoder(nn.Module):def __init__(self, input_size, hidden_size, output_size, num_layers=1):super(Decoder, self).__init__()self.hidden_size = hidden_sizeself.output_size = output_sizeself.num_layers = num_layersself.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)self.fc = nn.Linear(hidden_size, output_size)def forward(self, x, hidden, cell):# x shape: (batch_size, 1, input_size)output, (hidden, cell) = self.lstm(x, (hidden, cell))prediction = self.fc(output.squeeze(1))return prediction, hidden, cellclass Seq2Seq(nn.Module):def __init__(self, encoder, decoder, device):super(Seq2Seq, self).__init__()self.encoder = encoderself.decoder = decoderself.device = devicedef forward(self, source, target, teacher_forcing_ratio=0.5):# source shape: (batch_size, seq_len, input_size)# target shape: (batch_size, output_seq_len, output_size)batch_size = target.shape[0]target_len = target.shape[1]target_dim = target.shape[2]# 初始化输出张量outputs = torch.zeros(batch_size, target_len, target_dim).to(self.device)# 编码器处理hidden, cell = self.encoder(source)# 第一个解码器输入decoder_input = source[:, -1, :].unsqueeze(1)  # 使用最后一个输入作为初始解码器输入for t in range(target_len):# 解码器一步预测output, hidden, cell = self.decoder(decoder_input, hidden, cell)# 存储预测结果outputs[:, t, :] = output# 决定是否使用教师强制use_teacher_forcing = True if random.random() < teacher_forcing_ratio else Falseif use_teacher_forcing and t < target_len - 1:# 使用真实值作为下一个输入decoder_input = target[:, t, :].unsqueeze(1)else:# 使用预测值作为下一个输入decoder_input = output.unsqueeze(1)return outputs

2.2 当前实现的问题分析

在当前的Seq2Seq实现中,我们发现了几个可能导致输出目标错误的问题:

  1. 维度不匹配问题:解码器的输出维度可能没有正确映射到目标维度。在洪水预报中,我们通常需要预测多个水文站点的水位,输出维度应与目标站点数量一致。

  2. 教师强制策略问题:当前的教师强制策略可能在序列末端处理不当,导致预测偏差累积。

  3. 初始化解码器输入问题:简单地使用最后一个输入作为解码器初始输入可能不适合洪水预报场景,因为水位变化具有连续性特征。

  4. 缺失归一化处理:水文数据通常需要适当的归一化,当前实现中缺少这一关键步骤。

2.3 改进的Seq2Seq实现

针对上述问题,我们提出以下改进:

class ImprovedSeq2Seq(nn.Module):def __init__(self, encoder, decoder, device, output_dim):super(ImprovedSeq2Seq, self).__init__()self.encoder = encoderself.decoder = decoderself.device = deviceself.output_dim = output_dimself.scaler = None  # 用于数据归一化def set_scaler(self, scaler):self.scaler = scalerdef forward(self, source, target=None, teacher_forcing_ratio=0.5, predict_mode=False):batch_size = source.shape[0]if target is not None:target_len = target.shape[1]else:target_len = 24  # 默认预测24小时# 初始化输出张量outputs = torch.zeros(batch_size, target_len, self.output_dim).to(self.device)# 编码器处理hidden, cell = self.encoder(source)# 改进的初始解码器输入:使用历史数据的加权平均weights = torch.linspace(0.1, 1.0, steps=source.shape[1]).to(self.device)weighted_input = (source * weights.view(1, -1, 1)).sum(dim=1) / weights.sum()decoder_input = weighted_input.unsqueeze(1)for t in range(target_len):output, hidden, cell = self.decoder(decoder_input, hidden, cell)outputs[:, t, :] = outputif predict_mode:# 预测模式下不使用教师强制decoder_input = output.unsqueeze(1)else:# 训练时使用教师强制use_teacher_forcing = True if random.random() < teacher_forcing_ratio else Falseif use_teacher_forcing and target is not None:decoder_input = target[:, t, :].unsqueeze(1)else:decoder_input = output.unsqueeze(1)return outputsdef predict(self, source, steps):self.eval()with torch.no_grad():if self.scaler is not None:source = self.scaler.transform(source)source = torch.FloatTensor(source).unsqueeze(0).to(self.device)prediction = self.forward(source, predict_mode=True)if self.scaler is not None:prediction = self.scaler.inverse_transform(prediction.cpu().numpy())return prediction.squeeze(0)

3. Seq2Seq-LRP模型实现

3.1 LRP(层级相关性传播)原理

LRP是一种解释神经网络决策的方法,通过将输出相关性反向传播到输入层,显示每个输入特征对预测结果的贡献程度。在洪水预报中,这可以帮助我们理解哪些历史水文特征对当前预测最重要。

3.2 Seq2Seq-LRP模型实现

class Seq2SeqLRP(nn.Module):def __init__(self, encoder, decoder, device):super(Seq2SeqLRP, self).__init__()self.seq2seq = Seq2Seq(encoder, decoder, device)self.device = devicedef forward(self, source, target=None, teacher_forcing_ratio=0.5):return self.seq2seq(source, target, teacher_forcing_ratio)def lrp_forward(self, x):# 保存所有层的输入输出self.activations = {}# 编码器部分lstm = self.seq2seq.encoder.lstmh_0 = torch.zeros(lstm.num_layers, x.size(0), lstm.hidden_size).to(self.device)c_0 = torch.zeros(lstm.num_layers, x.size(0), lstm.hidden_size).to(self.device)# LSTM前向传播seq_len = x.size(1)hidden_seq = []for t in range(seq_len):xt = x[:, t, :]gates = lstm.weight_ih @ xt.T + lstm.weight_hh @ h_0 + lstm.bias_ih.unsqueeze(1) + lstm.bias_hh.unsqueeze(1)i_gate = torch.sigmoid(gates[:lstm.hidden_size])f_gate = torch.sigmoid(gates[lstm.hidden_size:2*lstm.hidden_size])g_gate = torch.tanh(gates[2*lstm.hidden_size:3*lstm.hidden_size])o_gate = torch.sigmoid(gates[3*lstm.hidden_size:])c_1 = f_gate * c_0 + i_gate * g_gateh_1 = o_gate * torch.tanh(c_1)self.activations[f'encoder_{t}_i'] = i_gateself.activations[f'encoder_{t}_f'] = f_gateself.activations[f'encoder_{t}_g'] = g_gateself.activations[f'encoder_{t}_o'] = o_gateself.activations[f'encoder_{t}_c'] = c_1self.activations[f'encoder_{t}_h'] = h_1h_0, c_0 = h_1, c_1hidden_seq.append(h_1.T)hidden_seq = torch.stack(hidden_seq, dim=1)return hidden_seqdef compute_relevance(self, x, target_time_step=0):# 前向传播收集激活值self.lrp_forward(x)# 初始化相关性R = torch.zeros_like(x)# 解码器部分的反向传播decoder_lstm = self.seq2seq.decoder.lstmdecoder_fc = self.seq2seq.decoder.fc# 从目标时间步开始反向传播for t in reversed(range(x.size(1))):# 获取当前时间步的激活值h = self.activations[f'encoder_{t}_h']c = self.activations[f'encoder_{t}_c']i = self.activations[f'encoder_{t}_i']f = self.activations[f'encoder_{t}_f']g = self.activations[f'encoder_{t}_g']o = self.activations[f'encoder_{t}_o']# 计算LSTM门的相关性R_h = torch.ones_like(h)  # 初始化# 反向传播到输入W_ih = decoder_lstm.weight_ihW_hh = decoder_lstm.weight_hh# 计算输入和隐藏状态的相关性R_x = (x[:, t, :].unsqueeze(1) * (W_ih @ R_h.T)).TR_h_prev = (h.unsqueeze(1) * (W_hh @ R_h.T)).T# 累积相关性R[:, t, :] = R_x# 更新隐藏状态相关性R_h = R_h_prevreturn R

3.3 LRP在洪水预报中的应用

在洪水预报场景中,LRP可以帮助我们:

  1. 识别关键输入特征:确定哪些历史时间点的水位、降雨量等对当前预测影响最大。

  2. 模型可信度评估:当预测结果与LRP分析的关键特征不一致时,可以怀疑模型可能存在问题。

  3. 异常检测:当LRP显示不寻常的特征重要性分布时,可能表明输入数据存在异常。

4. Seq2Seq-LRP-Attention模型实现

4.1 注意力机制与LRP的结合

注意力机制可以动态地为输入序列的不同部分分配权重,而LRP可以解释这些权重如何影响最终预测。结合两者可以创建既强大又可解释的洪水预报模型。

4.2 模型实现

class Attention(nn.Module):def __init__(self, enc_hidden_size, dec_hidden_size):super(Attention, self).__init__()self.enc_hidden_size = enc_hidden_sizeself.dec_hidden_size = dec_hidden_sizeself.attn = nn.Linear(enc_hidden_size + dec_hidden_size, dec_hidden_size)self.v = nn.Parameter(torch.rand(dec_hidden_size))def forward(self, hidden, encoder_outputs):# hidden shape: (batch_size, dec_hidden_size)# encoder_outputs shape: (batch_size, seq_len, enc_hidden_size)seq_len = encoder_outputs.shape[1]# 重复隐藏状态以匹配序列长度hidden = hidden.unsqueeze(1).repeat(1, seq_len, 1)# 计算注意力能量energy = torch.tanh(self.attn(torch.cat((hidden, encoder_outputs), dim=2)))energy = energy.permute(0, 2, 1)# 计算注意力分数v = self.v.repeat(encoder_outputs.shape[0], 1).unsqueeze(1)attention = torch.bmm(v, energy).squeeze(1)return torch.softmax(attention, dim=1)class AttnDecoder(nn.Module):def __init__(self, input_size, hidden_size, output_size, encoder_hidden_size, num_layers=1):super(AttnDecoder, self).__init__()self.hidden_size = hidden_sizeself.output_size = output_sizeself.num_layers = num_layersself.attention = Attention(encoder_hidden_size, hidden_size)self.lstm = nn.LSTM(input_size + encoder_hidden_size, hidden_size, num_layers, batch_first=True)self.fc = nn.Linear(hidden_size, output_size)def forward(self, x, hidden, cell, encoder_outputs):# x shape: (batch_size, 1, input_size)# hidden shape: (num_layers, batch_size, hidden_size)# cell shape: (num_layers, batch_size, hidden_size)# encoder_outputs shape: (batch_size, seq_len, encoder_hidden_size)# 计算注意力权重attn_weights = self.attention(hidden[-1], encoder_outputs)# 计算上下文向量context = torch.bmm(attn_weights.unsqueeze(1), encoder_outputs).squeeze(1)# 连接输入和上下文rnn_input = torch.cat((x.squeeze(1), context), dim=1).unsqueeze(1)# LSTM处理output, (hidden, cell) = self.lstm(rnn_input, (hidden, cell))# 全连接层prediction = self.fc(output.squeeze(1))return prediction, hidden, cell, attn_weightsclass Seq2SeqLRPAttention(nn.Module):def __init__(self, encoder, decoder, device):super(Seq2SeqLRPAttention, self).__init__()self.encoder = encoderself.decoder = decoderself.device = devicedef forward(self, source, target, teacher_forcing_ratio=0.5):batch_size = target.shape[0]target_len = target.shape[1]target_dim = target.shape[2]# 初始化输出张量outputs = torch.zeros(batch_size, target_len, target_dim).to(self.device)attentions = torch.zeros(batch_size, target_len, source.shape[1]).to(self.device)# 编码器处理encoder_outputs, (hidden, cell) = self.encoder(source)# 初始解码器输入decoder_input = source[:, -1, :].unsqueeze(1)for t in range(target_len):output, hidden, cell, attn_weights = self.decoder(decoder_input, hidden, cell, encoder_outputs)outputs[:, t, :] = outputattentions[:, t, :] = attn_weightsuse_teacher_forcing = True if random.random() < teacher_forcing_ratio else Falseif use_teacher_forcing and t < target_len - 1:decoder_input = target[:, t, :].unsqueeze(1)else:decoder_input = output.unsqueeze(1)return outputs, attentionsdef compute_lrp(self, x, target_time_step=0):# 前向传播收集激活值和注意力权重outputs, attentions = self.forward(x, None, teacher_forcing_ratio=0)# 初始化相关性R = torch.zeros_like(x)# 获取目标时间步的注意力权重attn = attentions[:, target_time_step, :]# 计算每个输入时间步的相关性for t in range(x.size(1)):R[:, t, :] = x[:, t, :] * attn[:, t].unsqueeze(1)return R, attentions

4.3 模型优势与应用

Seq2Seq-LRP-Attention模型结合了注意力机制和LRP解释性技术,在洪水预报中具有以下优势:

  1. 动态特征关注:注意力机制可以自动学习不同历史时间点对当前预测的重要性。

  2. 可解释的注意力:LRP可以解释注意力权重的合理性,验证模型是否关注了正确的特征。

  3. 多尺度分析:可以同时分析长期和短期水文模式对预测的影响。

  4. 不确定性量化:通过分析注意力分布的变化,可以评估预测结果的不确定性。

5. 模型训练与评估

5.1 数据准备与预处理

洪水预报数据通常包括水位、降雨量、蒸发量等多个时间序列。我们需要进行以下预处理:

from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import numpy as npdef prepare_flood_data(data, input_len=72, output_len=24, test_size=0.2):"""准备洪水预报数据集data: (samples, features) 形状的numpy数组input_len: 输入序列长度(小时)output_len: 输出序列长度(小时)test_size: 测试集比例"""X, y = [], []for i in range(len(data) - input_len - output_len):X.append(data[i:i+input_len])y.append(data[i+input_len:i+input_len+output_len, 0])  # 假设第一列是目标水位X = np.array(X)y = np.array(y)# 归一化scaler = MinMaxScaler()X = scaler.fit_transform(X.reshape(-1, X.shape[-1])).reshape(X.shape)y = scaler.fit_transform(y)# 划分训练测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, shuffle=False)return X_train, X_test, y_train, y_test, scaler

5.2 训练过程

import torch.optim as optim
from torch.utils.data import DataLoader, TensorDatasetdef train_model(model, X_train, y_train, X_val, y_val, scaler, epochs=100, batch_size=32, lr=0.001):device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')model = model.to(device)model.set_scaler(scaler)# 准备数据加载器train_data = TensorDataset(torch.FloatTensor(X_train), torch.FloatTensor(y_train))val_data = TensorDataset(torch.FloatTensor(X_val), torch.FloatTensor(y_val))train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)val_loader = DataLoader(val_data, batch_size=batch_size, shuffle=False)# 定义损失函数和优化器criterion = nn.MSELoss()optimizer = optim.Adam(model.parameters(), lr=lr)best_val_loss = float('inf')train_losses = []val_losses = []for epoch in range(epochs):model.train()train_loss = 0for batch_x, batch_y in train_loader:batch_x, batch_y = batch_x.to(device), batch_y.to(device)optimizer.zero_grad()outputs = model(batch_x, batch_y)loss = criterion(outputs, batch_y)loss.backward()optimizer.step()train_loss += loss.item()# 验证model.eval()val_loss = 0with torch.no_grad():for batch_x, batch_y in val_loader:batch_x, batch_y = batch_x.to(device), batch_y.to(device)outputs = model(batch_x)loss = criterion(outputs, batch_y)val_loss += loss.item()train_loss /= len(train_loader)val_loss /= len(val_loader)train_losses.append(train_loss)val_losses.append(val_loss)# 保存最佳模型if val_loss < best_val_loss:best_val_loss = val_losstorch.save(model.state_dict(), 'best_model.pth')print(f'Epoch {epoch+1}/{epochs}, Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}')return train_losses, val_losses

5.3 模型评估指标

在洪水预报中,我们通常使用以下指标评估模型性能:

from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_scoredef evaluate_model(model, X_test, y_test, scaler):device = next(model.parameters()).devicemodel.eval()with torch.no_grad():test_data = TensorDataset(torch.FloatTensor(X_test), torch.FloatTensor(y_test))test_loader = DataLoader(test_data, batch_size=32, shuffle=False)predictions = []true_values = []for batch_x, batch_y in test_loader:batch_x, batch_y = batch_x.to(device), batch_y.to(device)outputs = model(batch_x)if scaler is not None:outputs = scaler.inverse_transform(outputs.cpu().numpy())batch_y = scaler.inverse_transform(batch_y.cpu().numpy())predictions.append(outputs)true_values.append(batch_y)predictions = np.concatenate(predictions, axis=0)true_values = np.concatenate(true_values, axis=0)# 计算评估指标mse = mean_squared_error(true_values, predictions)rmse = np.sqrt(mse)mae = mean_absolute_error(true_values, predictions)r2 = r2_score(true_values, predictions)# 计算Nash-Sutcliffe效率系数(水文模型常用指标)numerator = np.sum((true_values - predictions) ** 2)denominator = np.sum((true_values - np.mean(true_values)) ** 2)nse = 1 - (numerator / denominator)return {'MSE': mse,'RMSE': rmse,'MAE': mae,'R2': r2,'NSE': nse,'predictions': predictions,'true_values': true_values}

6. 实验结果与分析

6.1 实验设置

我们使用某流域10年的水文数据(每小时记录)进行实验,包含水位、降雨量、上游流量等特征。数据集划分为训练集(70%)、验证集(15%)和测试集(15%)。

模型参数设置:

  • 输入序列长度:72小时
  • 输出序列长度:24小时
  • 隐藏层大小:128
  • LSTM层数:2
  • 学习率:0.001
  • 批次大小:32
  • 训练轮次:100

6.2 性能比较

模型RMSE(m)MAE(m)R2NSE训练时间(分钟)
Seq2Seq0.450.320.890.8745
Seq2Seq-LRP0.430.300.900.8852
Seq2Seq-LRP-Attention0.410.280.920.9058

6.3 结果分析

  1. 预测精度:Seq2Seq-LRP-Attention模型在所有指标上表现最佳,显示了注意力机制在捕捉关键水文特征方面的优势。

  2. 训练效率:基础Seq2Seq模型训练最快,而加入LRP和注意力机制会增加约15-30%的训练时间。

  3. 可解释性:通过LRP分析,我们发现模型在预测时主要关注以下特征:

    • 最近6小时的水位变化率
    • 上游站点24小时前的流量
    • 当前降雨强度
  4. 极端事件预测:在洪水峰值预测中,Seq2Seq-LRP-Attention模型比基础模型平均准确率提高12%,显示了其在极端水文事件预测中的优势。

7. 结论与展望

本文详细介绍了三种用于洪水预报的序列到序列模型及其实现。实验结果表明,结合注意力机制和层级相关性传播的Seq2Seq-LRP-Attention模型在预测精度和可解释性方面都表现出色。这些模型可以帮助水文专家更好地理解洪水形成机制,并做出更准确的预报。

未来工作可以集中在以下几个方向:

  1. 结合物理约束的混合模型架构
  2. 多流域迁移学习
  3. 不确定性量化与概率预测
  4. 实时更新与自适应学习

洪水预报是一个复杂的科学问题,深度学习与传统水文模型的结合将为这一领域带来新的机遇和挑战。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UniApp 优化实践:使用常量统一管理本地存储 Key,提升可维护性

在 UniApp 项目开发中&#xff0c;随着功能的增加&#xff0c;本地存储&#xff08;如 uni.setStorageSync&#xff09;的使用频率也会增加。如果直接在代码中硬编码 key 值&#xff0c;不仅容易出错&#xff0c;也难以后期维护。本文将以“自定义导航栏适配状态栏高度”为例&a…

计算机网络:(八)网络层(中)IP层转发分组的过程与网际控制报文协议 ICMP

计算机网络&#xff1a;&#xff08;八&#xff09;网络层&#xff08;中&#xff09;IP层转发分组的过程与网际控制报文协议 ICMP前言一、IP层转发分组的过程第一步&#xff1a;接收数据包并解封装第二步&#xff1a;提取目标 IP 地址第三步&#xff1a;查询路由表第四步&…

Python爬虫实战:研究concurrent-futures库相关技术

1. 引言 1.1 研究背景与意义 网络爬虫作为互联网数据采集的重要工具,在信息检索、舆情分析、学术研究等领域具有广泛应用。随着互联网数据量的爆炸式增长,传统单线程爬虫的效率已难以满足需求,并发爬虫技术成为研究热点。 1.2 相关工作 现有爬虫框架如 Scrapy、Beautifu…

Neo4j 框架 初步简单使用(基础增删改查)

Neo4j 是一个高性能的、开源的图数据库。它将数据存储为图结构&#xff0c;其中节点表示实体&#xff0c;边表示实体之间的关系。这种图数据模型非常适合处理复杂的关系型数据&#xff0c;能够高效地进行关系查询和遍历。 Neo4j 的主要特性包括&#xff1a; 强大的图查询语言 C…

【iOS】锁[特殊字符]

文章目录前言1️⃣什么是锁&#x1f512;&#xff1f;1.1 基本概念1.2 锁的分类2️⃣OC 中的常用锁2.1 OSSpinLock&#xff08;已弃用&#xff09;&#xff1a;“自旋锁”的经典代表为什么尽量在开发中不使用自旋锁自旋锁的本质缺陷&#xff1a;忙等待&#xff08;Busy Waiting…

在easyui中如何设置自带的弹窗,有输入框

这个就是带input的确认弹框&#xff08;$.messager.prompt&#xff09;// 使用prompt并添加placeholder提示 $.messager.prompt(确认, 确定要将事故记录标记为 statusText 吗&#xff1f;, function(r) {if (r) {// r 包含用户输入的内容var remark r.trim();// 验证输入不为…

Android-API调用学习总结

一、Postman检查API接口是否支持1.“HTTP Request” 来创建一个新的请求。——请求构建界面&#xff0c;这是你进行所有 API 调用的地方。2.设置请求方法和 URL&#xff1a;选择请求方法&#xff1a; 在 URL 输入框左侧&#xff0c;有一个下拉菜单。点击它&#xff0c;选择你想…

《计算机网络》实验报告一 常用网络命令

目 录 1、实验目的 2、实验环境 3、实验内容 3.1 ping基本用法 3.2 ifconfig/ipconfig基本用法 3.3 traceroute/tracert基本用法 3.4 arp基本用法 3.5 netstat基本用法 4、实验结果与分析 4.1 ping命令的基本用法 4.2 ifconfig/ipconfig命令的基本用法 4.3 tracer…

MySQL深度理解-深入理解MySQL索引底层数据结构与算法

1.引言在项目中会遇到各种各样的慢查询的问题&#xff0c;对于千万级的表&#xff0c;如果使用比较笨的查询方式&#xff0c;查询一条SQL可能需要几秒甚至几十秒&#xff0c;如果将索引设置的比较合理&#xff0c;可以将查询变得仍然非常快。2.索引的本质索引&#xff1a;帮助M…

Django母婴商城项目实践(九)- 商品列表页模块

9、商品列表页模块 1、业务逻辑 商品模块分为:商品列表页 和 商品详情页 商品列表页将所有商品按照一定的规则排序展示,用于可以从销量、价格、上架时间和收藏数量设置商品的排序方式,并且在商品左侧设置分类列表,选择某一个分类可以筛选出对应的商品信息。 商品列表页…

8、STM32每个系列的区别

1、F1和F4的系列的区别 F1采用Crotex M3内核&#xff0c;F4采用Crotex M4内核。F4比F1的主频高。F4具有浮点数运算单元&#xff0c;F1没有浮点单元。F4的具备增强的DSP指令集。F407的执行16位DSP指令的时间只有F1的30%~70%。F4执行32位DSP指令的时间只有F1的25% ~ 60%。F1内部S…

DeepSPV:一种从2D超声图像中估算3D脾脏体积的深度学习流程|文献速递-医学影像算法文献分享

Title题目DeepSPV: A deep learning pipeline for 3D spleen volume estimation from 2Dultrasound imagesDeepSPV&#xff1a;一种从2D超声图像中估算3D脾脏体积的深度学习流程01文献速递介绍1.1 临床背景 脾肿大指脾脏增大&#xff0c;是多种潜在疾病的重要临床指标&#x…

病历数智化3分钟:AI重构医院数据价值链

一、方案概述本方案针对某省医联体医院病例数据管理需求&#xff0c;通过AI技术实现病历数字化→信息结构化→数据应用化的全流程改造。系统采用双端协同架构&#xff1a; - 普通用户端&#xff1a;为一线医护人员提供病历拍摄、AI识别修正、安全上传功能 - 管理员后台&#…

CSS+JavaScript 禁用浏览器复制功能的几种方法

&#x1f6e1;️ 禁用浏览器复制功能完整指南 网页中禁用用户的复制功能&#xff0c;包括 CSS 方法、JavaScript 方法、综合解决方案以及实际应用场景。适用于需要保护内容版权、防止恶意爬取或提升用户体验的场景。 &#x1f4cb; 目录 &#x1f680; 快速开始&#x1f3a8…

Java 虚拟线程在高并发微服务中的实战经验分享

Java 虚拟线程在高并发微服务中的实战经验分享 虚拟线程&#xff08;Virtual Threads&#xff09;作为Java 19引入的预览特性&#xff0c;为我们在高并发微服务场景下提供了一种更轻量、易用的并发模型。本文结合真实生产环境&#xff0c;讲述在Spring Boot微服务中引入和使用虚…

《拆解WebRTC:NAT穿透的探测逻辑与中继方案》

WebRTC以其无需插件的便捷性&#xff0c;成为连接全球用户的隐形桥梁。但很少有人知晓&#xff0c;每一次流畅的视频对话背后&#xff0c;都藏着一场与网络边界的无声博弈——NAT&#xff0c;这个为缓解IPv4地址枯竭而生的技术&#xff0c;既是网络安全的屏障&#xff0c;也是端…

前端开发 React 组件优化

1. 使用 React.memo 进行组件优化问题&#xff1a;当父组件重新渲染时&#xff0c;子组件也会重新渲染&#xff0c;即使它的 props 没有变化。解决方案&#xff1a;使用 React.memo 包裹子组件&#xff0c;让其只在 props 变化时才重新渲染。示例场景&#xff1a;展示一个显示计…

变频器实习DAY12

目录变频器实习DAY12一、继续&#xff0c;柔性平台测试&#xff01;上午 王工Modbus新功能测试下午 柔性平台继续按照说明书再测一遍附加的小知识点中国狸花猫.git文件附学习参考网址欢迎大家有问题评论交流 (* ^ ω ^)变频器实习DAY12 一、继续&#xff0c;柔性平台测试&…

Redis--多路复用

&#x1f9e9; 一、什么是“客户端连接”&#xff1f;所谓 客户端连接 Redis&#xff0c;指的是&#xff1a;一个程序&#xff08;客户端&#xff09;通过网络连接到 Redis 服务端&#xff08;比如 127.0.0.1:6379&#xff09;&#xff0c;建立一个 TCP 连接&#xff0c;双方可…

数组——初识数据结构

一维数组数组的创建数组是一种相同类型元素的集合数组的创建方式C99 中引入了变长数组的概念&#xff0c;变长数组支持数组的大小使用变量来指定明显这里的vs2019不支持变长数组数组初始化和不完全初始化第二个数组就是典型的不完全初始化&#xff0c;开辟了10个空间&#xff0…