游戏AI的创造思路-技术基础-深度学习(7)TF

重头戏TF,汽车人,变形~~~~

现在广泛应用的GPT中,数据处理的关键点就是Transformer算法,多次多层的映射“变形”造就了其对自然语言处理能力的提升,但本篇介绍的内容中,Transformer算法是用来构建游戏AI的“思考”-“预言”或者“猜想”-“证言”-输出为主

3.7.Transformer算法

3.7.1. 定义

Transformer算法是一种基于自注意力机制的神经网络结构,由Vaswani等人在2017年提出,最初应用于机器翻译任务。

它通过多层自注意力机制和前馈神经网络对输入序列和输出序列进行处理,实现序列到序列的映射转换。

3.7.2. 历史

在Transformer模型提出之前,自然语言处理(NLP)任务主要依赖于循环神经网络(RNN)和长短期记忆网络(LSTM)。

然而,这些模型在处理长序列和长距离依赖关系时存在局限性,并且难以并行化。为了解决这些问题,Vaswani等人提出了Transformer模型,它完全基于自注意力机制,极大地提高了处理长序列和并行计算的能力。

3.7.3. 运行原理

Transformer的运行原理主要基于自注意力机制(Self-Attention)(特别是多头注意力(Multi-Head Attention))编码器-解码器(Encoder-Decoder)架构,以下是对其运行原理的详细描述:

3.7.3.1. 自注意力机制(Self-Attention)

自注意力机制是Transformer模型的核心组件,它允许模型在处理序列中的每个元素时,都能够关注到序列中的其他所有元素,从而捕捉序列内部的依赖关系。具体步骤如下:

输入表示

  • 首先,将输入序列中的每个元素(如单词、图像块等)转换为固定维度的向量表示。这些向量表示可以通过嵌入层(Embedding Layer)得到,嵌入层通常是一个可学习的参数矩阵。输入首先通过一个嵌入层(Embedding Layer),将每个词转换为一个固定大小的向量。然后,通常还会加上位置编码(Positional Encoding),以保留词序信息。
import torch  
import torch.nn as nn  
import math  class PositionalEncoding(nn.Module):  def __init__(self, d_model, max_len=5000):  super(PositionalEncoding, self).__init__()  pe = torch.zeros(max_len, d_model)  position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)  div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))  pe[:, 0::2] = torch.sin(position * div_term)  pe[:, 1::2] = torch.cos(position * div_term)  pe = pe.unsqueeze(0).transpose(0, 1)  self.register_buffer('pe', pe)  def forward(self, x):  return x + self.pe[:x.size(0), :]  # 假设 embed_size 是嵌入向量的维度  
embed_size = 512  
max_len = 600  
positional_encoding = PositionalEncoding(embed_size, max_len)

生成Query、Key、Value矩阵

对于序列中的每个向量表示,通过线性变换分别生成三个新的向量:查询向量(Query, Q)、键向量(Key, K)和值向量(Value, V)。这些线性变换的参数是模型需要学习的。

输入向量通过三个不同的线性层来生成 Query(Q),Key(K),Value(V)矩阵。

class SelfAttention(nn.Module):  def __init__(self, embed_size, heads):  super(SelfAttention, self).__init__()  self.embed_size = embed_size  self.heads = heads  self.head_dim = embed_size // heads  assert self.head_dim * heads == embed_size, "Embedding size needs to be divisible by heads"  self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)  self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)  self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)  self.fc_out = nn.Linear(heads * self.head_dim, embed_size)  def forward(self, values, keys, query, mask):  N = query.shape[0]  value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1]  # 切分嵌入层到self.heads不同切块  values = values.reshape(N, value_len, self.heads, self.head_dim)  keys = keys.reshape(N, key_len, self.heads, self.head_dim)  queries = query.reshape(N, query_len, self.heads, self.head_dim)  values = self.values(values)  keys = self.keys(keys)  queries = self.queries(queries)

计算注意力分数

对于序列中的每个查询向量,计算它与所有键向量的点积,得到注意力分数。这些分数衡量了查询向量与序列中每个元素之间的相关性。

计算 Query 和 Key 的点积,得到注意力分数,然后应用 softmax 函数进行归一化。

energy = torch.einsum("nqhd,nkhd->nhqk", [queries, keys])  if mask is not None:  energy = energy.masked_fill(mask == 0, float("-1e20"))  attention = torch.softmax(energy / (self.embed_size ** (1 / 2)), dim=3)

缩放点积注意力(Scaled Dot-Product Attention)

为了防止点积结果过大导致softmax函数进入饱和区,将点积结果除以一个缩放因子(通常是输入向量维度的平方根)。然后,通过softmax函数对缩放后的点积结果进行归一化,得到注意力权重。点积的结果除以维度的平方根来进行缩放,有助于梯度稳定。

加权求和

使用注意力权重对值向量进行加权求和,得到每个查询向量的上下文表示。这个上下文表示包含了序列中所有元素对当前查询向量的贡献。

用注意力分数对 Value 进行加权求和,得到最终的输出。

out = torch.einsum("nhql,nlhd->nqhd", [attention, values]).reshape(N, query_len, self.heads * self.head_dim)  out = self.fc_out(out)  return out

 这样,我们就完成了一个自注意力层的实现。在实际使用时,可以将这个层嵌入到更大的 Transformer 网络中。

3.7.3.2. 多头注意力(Multi-Head Attention)

为了提高模型的表示能力,Transformer使用多头注意力机制。具体步骤如下:

  1. 分割输入
    • 将输入向量分割成多个头(Head),每个头独立地进行自注意力计算。
  2. 并行计算
    • 每个头都有自己的查询、键、值矩阵和自注意力计算过程。这些计算过程是并行的,可以显著提高模型的计算效率。
  3. 拼接与线性变换
    • 将所有头的输出拼接在一起,然后通过一个线性变换得到最终的多头注意力输出。这个线性变换的参数也是模型需要学习的。
3.7.3.3. 编码器-解码器(Encoder-Decoder)架构

Transformer模型由编码器和解码器两部分组成,它们分别负责输入序列的编码和输出序列的生成。

3.7.3.3.1. 编码器(Encoder)
  1. 多层堆叠
    • 编码器由多个相同的编码器层堆叠而成。每个编码器层都包含自注意力子层、前馈神经网络子层以及残差连接和层归一化。
  2. 自注意力子层
    • 自注意力子层负责捕捉输入序列内部的依赖关系,生成每个元素的上下文表示。
  3. 前馈神经网络子层
    • 前馈神经网络子层是一个逐位置的前馈网络,它对自注意力子层的输出进行进一步的处理,以增强模型的表示能力。

Python代码示例

编码器层(EncoderLayer)

class EncoderLayer(nn.Module):  def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):  super(EncoderLayer, self).__init__()  self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)  self.linear1 = nn.Linear(d_model, dim_feedforward)  self.dropout = nn.Dropout(dropout)  self.linear2 = nn.Linear(dim_feedforward, d_model)  self.norm1 = nn.LayerNorm(d_model)  self.norm2 = nn.LayerNorm(d_model)  self.dropout1 = nn.Dropout(dropout)  self.dropout2 = nn.Dropout(dropout)  self.activation = nn.ReLU()  def forward(self, src):  src2 = self.norm1(src)  src = src + self.dropout1(self.self_attn(src2, src2, src2)[0])  src2 = self.norm2(src)  src = src + self.dropout2(self.linear2(self.dropout(self.activation(self.linear1(src2)))))  return src

编码器(Encoder)

class Encoder(nn.Module):  def __init__(self, layer, N):  super(Encoder, self).__init__()  self.layers = nn.ModuleList([layer for _ in range(N)])  self.norm = nn.LayerNorm(layer.self_attn.embed_dim)  def forward(self, src):  output = src  for mod in self.layers:  output = mod(output)  output = self.norm(output)  return output
3.7.3.3.2. 解码器(Decoder)
  1. 多层堆叠
    • 解码器同样由多个相同的解码器层堆叠而成。每个解码器层包含自注意力子层、编码器-解码器注意力子层、前馈神经网络子层以及残差连接和层归一化。
  2. 带掩码的自注意力子层
    • 解码器中的第一个自注意力子层是带掩码的,以防止在生成输出序列时看到未来的信息。掩码操作通常是将未来位置的注意力分数设置为负无穷大(或非常小的数),使得softmax函数将这些位置的注意力权重置为零。
  3. 编码器-解码器注意力子层
    • 编码器-解码器注意力子层负责将编码器的输出作为查询向量,与解码器中的键向量和值向量进行注意力计算。这样,解码器就能够根据编码器的输出生成相应的输出序列。
  4. 前馈神经网络子层
    • 与编码器中的前馈神经网络子层类似,解码器中的前馈神经网络子层对编码器-解码器注意力子层的输出进行进一步的处理。

Python代码示例

解码器层(DecoderLayer)

class DecoderLayer(nn.Module):  def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):  super(DecoderLayer, self).__init__()  self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)  self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)  self.linear1 = nn.Linear(d_model, dim_feedforward)  self.dropout = nn.Dropout(dropout)  self.linear2 = nn.Linear(dim_feedforward, d_model)  self.norm1 = nn.LayerNorm(d_model)  self.norm2 = nn.LayerNorm(d_model)  self.norm3 = nn.LayerNorm(d_model)  self.dropout1 = nn.Dropout(dropout)  self.dropout2 = nn.Dropout(dropout)  self.dropout3 = nn.Dropout(dropout)  self.activation = nn.ReLU()  def forward(self, tgt, memory, tgt_mask, memory_mask, tgt_key_padding_mask, memory_key_padding_mask):  tgt2 = self.norm1(tgt)  tgt = tgt + self.dropout1(self.self_attn(tgt2, tgt2, tgt2, attn_mask=tgt_mask, key_padding_mask=tgt_key_padding_mask)[0])  tgt2 = self.norm2(tgt)  tgt = tgt + self.dropout2(self.multihead_attn(tgt2, memory, memory, attn_mask=memory_mask, key_padding_mask=memory_key_padding_mask)[0])  tgt2 = self.norm3(tgt)  tgt = tgt + self.dropout3(self.linear2(self.dropout(self.activation(self.linear1(tgt2)))))  return tgt

解码器(Decoder)

class Decoder(nn.Module):  def __init__(self, layer, N):  super(Decoder, self).__init__()  self.layers = nn.ModuleList([layer for _ in range(N)])  self.norm = nn.LayerNorm(layer.self_attn.embed_dim)  def forward(self, tgt, memory, tgt_mask, memory_mask, tgt_key_padding_mask, memory_key_padding_mask):  output = tgt  for mod in self.layers:  output = mod(output, memory, tgt_mask, memory_mask, tgt_key_padding_mask, memory_key_padding_mask)  output = self.norm(output)  return output

在Transformer模型中,编码器和解码器的实现都依赖于nn.MultiheadAttention模块来处理自注意力和编码器-解码器注意力。前馈神经网络子层则是由两个线性层和一个ReLU激活函数组成。每个子层后面都接有残差连接和层归一化,以帮助模型在训练过程中保持稳定并提高泛化能力。

Transformer的运行原理基于自注意力机制和编码器-解码器架构。自注意力机制允许模型捕捉序列内部的依赖关系,而多头注意力机制则提高了模型的表示能力。编码器负责将输入序列编码为上下文表示,解码器则根据编码器的输出生成相应的输出序列。通过残差连接和层归一化等技术手段,Transformer模型能够在训练过程中保持稳定并提高泛化能力。

3.7.4. 优缺点

优点

  • 长距离依赖关系建模:通过自注意力机制,Transformer能够更好地捕捉长距离依赖关系。
  • 并行计算能力:多头注意力机制的并行计算极大提高了训练和推理的效率。
  • 通用性:不仅适用于NLP任务,还适用于图像处理、时间序列分析等其他领域。

缺点

  • 高计算成本:模型的复杂性导致在训练和推理过程中需要大量的计算资源。
  • 优化难度:模型的复杂性和超参数的数量增加了优化的难度。
  • 对长文本处理挑战:在处理长文本时,由于位置编码和注意力机制的限制,可能受到内存限制和效率影响。

3.7.5. 在游戏AI中的应用、场景和典型应用实例

3.7.5.1. 应用与场景
  • 策略游戏:Transformer可用于分析游戏状态,预测对手行为,制定最优策略。通过处理游戏中的序列数据(如历史动作、资源分布等),Transformer能够捕捉长距离依赖关系,提高策略制定的准确性。
  • 实时对战游戏:在实时对战游戏中,Transformer可用于实时分析游戏画面和对手行为,快速做出反应。通过结合图像处理和自然语言处理技术,Transformer可以实现对游戏画面的深度理解和对手意图的准确预测。
3.7.5.2. 典型应用实例
  • 星际争霸2的AlphaStar:AlphaStar,DeepMind开发的人工智能。AlphaStar学会了玩《星际争霸II》,在所有三场比赛中都被评为大师级,在官方的人类玩家排名中排名前99.8%以上。2019年发表于《自然》。虽然AlphaStar主要基于深度强化学习(DRL)和蒙特卡洛树搜索(MCTS),但Transformer模型在其中可能用于处理和分析游戏录像、学习人类玩家的策略和技巧。通过自注意力机制,AlphaStar能够捕捉游戏中的长距离依赖关系,提高策略制定的深度和广度。

3.7.5.3. AlphaStar类似实现简单示例代码

实现一个类似于星际争霸2的AlphaStar的AI系统是一个庞大且复杂的工程,涉及到深度学习和强化学习的多个方面。AlphaStar使用深度神经网络和强化学习技术来玩游戏,具体技术包括但不限于深度学习模型(如卷积神经网络)、蒙特卡洛树搜索(MCTS)和序列模型等。

下面是一个非常简化的Python示例,用于说明如何实现一个基于强化学习的智能体,虽然它远远不能达到AlphaStar的复杂度。

第一步,你需要安装一些必要的库,比如Gym和tensorflowpytorch。这里我们假设使用tensorflow

pip install tensorflow gym

第二步,以下是一个使用TensorFlow和Keras实现的简单DQN(深度Q网络)模型,用于训练一个智能体在Gym环境中的CartPole游戏上玩:

import numpy as np  
import random  
import tensorflow as tf  
from collections import deque  
from tensorflow.keras.models import Sequential  
from tensorflow.keras.layers import Dense  
from tensorflow.keras.optimizers import Adam  
from gym import make  class DQN:  def __init__(self, state_size, action_size):  self.state_size = state_size  self.action_size = action_size  self.memory = deque(maxlen=2000)  self.gamma = 0.95  # discount rate  self.epsilon = 1.0  # exploration rate  self.epsilon_min = 0.01  self.epsilon_decay = 0.995  self.learning_rate = 0.001  self.model = self._build_model()  def _build_model(self):  model = Sequential()  model.add(Dense(24, input_dim=self.state_size, activation='relu'))  model.add(Dense(24, activation='relu'))  model.add(Dense(self.action_size, activation='linear'))  model.compile(loss='mse', optimizer=Adam(lr=self.learning_rate))  return model  def remember(self, state, action, reward, next_state, done):  self.memory.append((state, action, reward, next_state, done))  def act(self, state):  if np.random.rand() <= self.epsilon:  return random.randrange(self.action_size)  act_values = self.model(state)  return np.argmax(act_values[0])  def replay(self, batch_size):  minibatch = random.sample(self.memory, batch_size)  for state, action, reward, next_state, done in minibatch:  target = reward  if not done:  target = (reward + self.gamma * np.amax(self.model.predict(next_state)[0]))  target_f = self.model.predict(state)  target_f[0][action] = target  self.model.fit(state, target_f, epochs=1, verbose=0)  if self.epsilon > self.epsilon_min:  self.epsilon *= self.epsilon_decay  env = make('CartPole-v1')  
state_size = env.observation_space.shape[0]  
action_size = env.action_space.n  
agent = DQN(state_size, action_size)  # 训练智能体  
episodes = 1000  for e in range(episodes):  state = env.reset()  state = np.reshape(state, [1, state_size])  for time_t in range(500):  action = agent.act(state)  next_state, reward, done, _ = env.step(action)  reward = reward if not done else -10  next_state = np.reshape(next_state, [1, state_size])  agent.remember(state, action, reward, next_state, done)  state = next_state  if done:  print("episode: {}/{}, score: {}, e: {:.2}"  .format(e, episodes, time_t, agent.epsilon))  break  if len(agent.memory) > batch_size:  agent.replay(32)

这段代码创建了一个简单的DQN智能体,用于在CartPole环境中学习如何玩游戏。AlphaStar的实现远比这复杂,涉及到更多的技术和计算资源,但这个例子可以作为开始探索深度学习和强化学习在游戏AI中应用的一个起点哦。

3.7.6. 小小总结下

Transformer算法以其独特的自注意力机制和编码器-解码器架构在自然语言处理领域取得了巨大成功,并逐渐扩展到图像处理、时间序列分析等其他领域。

在游戏AI中,Transformer的应用潜力巨大,有望为策略制定和实时对战提供新的解决方案。

关于Transformer算法的内容,限于篇幅太长,内容太多,后面有机会时慢慢增加更多的内容

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

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

相关文章

昇思25天学习打卡营第5天 | 神经网络构建

1. 神经网络构建 神经网络模型是由神经网络层和Tensor操作构成的&#xff0c;mindspore.nn提供了常见神经网络层的实现&#xff0c;在MindSpore中&#xff0c;Cell类是构建所有网络的基类&#xff0c;也是网络的基本单元。一个神经网络模型表示为一个Cell&#xff0c;它由不同…

Quantlab5.0:一切围绕可实盘策略驱动开发

原创文章第573篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 2024年上半年即将结束&#xff0c;开始准备星球下半年的工作。 目前设想的——Quantlab5.0&#xff0c;之所以升级一个大版本&#xff0c;与4.x有很大不同。 5.0专注策略开发&…

Python28-2 机器学习算法之SVM(支持向量机)

SVM&#xff08;支持向量机&#xff09; 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种用于分类和回归分析的监督学习模型&#xff0c;在机器学习领域中被广泛应用。SVM的目标是找到一个最佳的分割超平面&#xff0c;将不同类别的数据分开&…

【Vue】Vue.js中常见的几种语法

在 Vue.js 中&#xff0c;主要的语法可以分为以下几种&#xff1a; 插值语法 (Interpolation) 使用双大括号 {{ }} 进行文本插值。 示例&#xff1a; {{ message }} 指令语法 (Directives) 指令是特殊的标记&#xff0c;用于告诉Vue框架如何操作DOM。Vue提供了多种内置指…

【最新鸿蒙应用开发】——鸿蒙国际化

1. 国际化 鸿蒙应用开发的国际化主要是指让应用支持多种语言和适应不同地区的用户习惯。这包括对不同语言环境的支持&#xff0c;如文本和布局的本地化设置。要实现国际化&#xff0c;开发者需要准备应用程序支持的每种语言环境的一些资源&#xff0c;比如翻译后的文本、特定区…

理解论文笔记:基于贝叶斯网络和最大期望算法的可维护性研究

看了与上一篇研究方向一致的文章&#xff0c;上一篇19年的&#xff0c;这一篇22年的更新。若有侵权&#xff0c;请联系删除。 I. INTRODUCTION 介绍 主要介绍了使用贝叶斯网络和历史数据对无线传感器网络可维护性研究的重要性和必要性&#xff0c;并对下面的各章进行了…

【高性能服务器】单进程服务器

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ 单进程服务器 …

认识100种电路之稳压电路

在电子电路中&#xff0c;稳压电路扮演着至关重要的角色。那么&#xff0c;为什么电路需要稳压&#xff1f;稳压的原理又是什么&#xff1f;以及稳压需要用到哪些元器件&#xff0c;数量又有多少呢&#xff1f;今天&#xff0c;就让我们一同揭开稳压电路的神秘面纱。 【电路为什…

Apple Final Cut Pro 10.8 - 专业后期制作 (视频编辑)

Apple Final Cut Pro 10.8 - 专业后期制作 (视频编辑) Final Cut Pro 10.8 Compressor 4.8 Motion 5.8 (Universal) 请访问原文链接&#xff1a;https://sysin.org/blog/apple-final-cut-pro/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&…

供应商关系管理(SRM)中的供应商绩效评估

供应商绩效评估是供应商关系管理&#xff08;SRM&#xff09;的核心组成部分&#xff0c;它涉及到对供应商在合作过程中的表现进行全面的分析和评价。一个有效的供应商绩效评估系统不仅可以帮助企业识别和解决供应链中的潜在问题&#xff0c;还可以促进供应商的持续改进和优化&…

Java学习 - Redis缓存问题与优化

缓存收益与成本 收益 加速读写降低后端、持久层的负载和压力 成本 可能导致数据不一致代码运维成本redis节点运维成本 缓存更新策略 策略一致性维护成本介绍LRU/LIRS算法剔除最差底剔除最近最少使用的数据超时剔除较差底定时删除、惰性删除主动更新最好高持久层更新&#x…

监控 Promethus的监控告警Alertmanager、Grafana

Promethus的监控告警Alertmanager Alertmanager 介绍 Prometheus的一个组件&#xff0c;用于定义和发送告警通知&#xff0c;内置多种第三方告警通知方式&#xff0c;同时还提供了对Webhook通知的支持基于警报规则对规则产生的警报进行分组、抑制和路由&#xff0c;并把告警发…

vue如何引入图标

方法1&#xff1a;iconify/vue pnpm add iconify/vue -D 网址&#xff1a;https://icon-sets.iconify.design/ 使用哪个需要安装 如下截图,安装指令&#xff1a; > npm install iconify/icons-gg在使用的页面引入 import { Icon } from “iconify/vue”; <template>…

Mysql存储过程用法:使用存储过程编程,来判断数据库中数据表中的字段是否重复,避免重复插入记录

目录 一、mysql的存储过程介绍 二、. 创建存储过程 1、准备 2、创建插入记录的存储过程 三. 调用存储过程 四. 删除存储过程 五. 修改存储过程&#xff0c;避免数据表的姓名出现重复 1、修改存储过程的方式 2、重新创建存储过程 六. 验证新的存储过程 1、插入新的记…

高考后的抉择:专业优先还是学校优先?

随着2024年高考的帷幕落下&#xff0c;高考生们面临的一个重要抉择再度浮上心头&#xff1a;在分数受限的情况下&#xff0c;是选择一个心仪的专业&#xff0c;还是选择一个知名度更高的学校&#xff1f;这是一个困扰了众多考生和家长的长期难题。在这个关键的时刻&#xff0c;…

好用的导航网站有哪些

网址导航网站是我们日常上网的一个重要工具。它们不仅可以帮助我们快速找到所需的资源和信息&#xff0c;还能提高我们的工作效率。以下是小编收藏的几个好用的导航网站&#xff0c;涵盖了办公、学习、娱乐等多个领域&#xff0c;分享给大家。 1. 办公人导航 办公人导航是一个…

Drag Select Compose:实现多平台图片多选功能的利器

Drag Select Compose:实现多平台图片多选功能的利器 在现代移动应用开发中,图片多选功能是一个常见且实用的需求。而实现这种功能可能涉及到复杂的手势处理和状态管理。今天,我将介绍一款强大的Compose多平台库——Drag Select Compose,它能够轻松实现类似于Google Photos…

BGP中的TCP连接源地址问题

3.TCP连接源地址&#xff08;用loop back地址是最优选择&#xff09; 应用场景与理论&#xff1a; 由于BGP应用于大型网络中&#xff0c;为了避免单点失败&#xff0c;往往需要通过多条链路连接&#xff0c;当一条链路故障时候就用另一条链路继续工作&#xff0c;但是BGP又无法…

螺旋模型:结合瀑布模型和增量模型的项目管理利器

目录 前言1. 螺旋模型概述1.1 螺旋模型的核心理念1.2 螺旋模型的四个阶段 2. 螺旋模型的详细步骤2.1 计划阶段2.2 风险分析阶段2.3 工程阶段2.4 评估阶段 3. 螺旋模型在大型项目中的应用3.1 应对需求变化3.2 有效的风险管理3.3 增强的客户参与3.4 灵活的资源分配 4. 螺旋模型的…

【Python】已解决:FileNotFoundError: [Errno 2] No such file or directory: ‘配置信息.csv‘

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;FileNotFoundError: [Errno 2] No such file or directory: ‘配置信息.csv’ 一、分析问题背景 在编写Python代码进行文件操作时&#xff0c;开发者可能会遇到…