游戏AI的创造思路-技术基础-蒙特卡洛树搜索(1)

news2024/11/15 8:29:05

本篇介绍蒙特卡洛树搜索算法,AlphaGo用于围棋计算的应用就是基于蒙特卡洛树搜索研发的~~~

目录

1. 定义

2. 发展历史

3. 公式和函数

3.1.算法的公式和函数

3.2. Python实现公式和函数

4. 运行原理

4.1. 运行原理

4.2. 各步骤用Python代码

5. 优缺点和缺陷的解决方案

5.1. 优缺点

5.1.1. 优点

5.1.2. 缺点和缺陷

5.2. 缺陷的解决方案

5.2.1. 收敛速度慢

5.2.2. 计算资源消耗大

5.2.3. 探索与利用的平衡

5.2.4. 并行化困难

6.  在游戏AI中的使用实例

6.1. 简单介绍

6.2. 围棋AI中的蒙特卡洛树搜索

Python代码实现


1. 定义

蒙特卡洛树搜索(Monte Carlo Tree Search, MCTS)是一种结合了蒙特卡洛方法和树搜索的算法,特别适用于那些通过模拟能够预测结果的问题,如棋类游戏。

MCTS通过模拟大量随机游戏来评估每个可行的行动,并基于这些模拟结果选择最优行动。

2. 发展历史

蒙特卡洛方法起源于上世纪四十年代中期,为解决当时原子能事业中的复杂问题而发展。

而蒙特卡洛树搜索的概念则是在2006年由Rémi Coulomb提出,作为围棋中的移动规划方法。

近年来,随着AlphaGo等AI系统的成功,MCTS在游戏AI领域的应用得到了广泛关注。

3. 公式和函数

3.1.算法的公式和函数

MCTS算法的核心公式通常包括UCB1(Upper Confidence Bound 1)公式,用于在树搜索过程中平衡开发与探索:

[ UCB1(S_i) = \overline{V_i} + c \sqrt{\frac{\log N}{n_i}} ]

其中,

(\overline{V_i}) 是节点 (S_i)的平均价值,

(c)是常数(通常取2),

(N) 是总探索次数,

(n_i) 是节点 (S_i) 的探索次数。

3.2. Python实现公式和函数

以下是一个简化的Python代码示例,用于实现MCTS中的选择函数,该函数使用UCB1公式来选择子节点:

import math  
  
class Node:  
    def __init__(self, state, parent=None):  
        self.state = state  
        self.parent = parent  
        self.children = []  
        self.visits = 0  
        self.wins = 0  
  
    def ucb1(self, N, c=2):  
        if self.visits == 0:  
            return float('inf')  
        return self.wins / self.visits + c * math.sqrt(math.log(N) / self.visits)  
  
def select(node, N):  
    while node.children:  
        best_child = max(node.children, key=lambda c: c.ucb1(N))  
        node = best_child  
    return node

4. 运行原理

4.1. 运行原理

MCTS的运行原理主要包括四个步骤:选择(Selection)、扩展(Expansion)、模拟(Simulation)、反向传播(BackPropagation)。

  1. 选择(Selection):从根节点开始,使用UCB1公式递归选择最优子节点直到叶子节点。

  2. 扩展(Expansion):如果当前叶子节点不是终止节点,则创建一个或多个子节点,并选择其中一个进行扩展。

  3. 模拟(Simulation):从扩展节点开始,随机模拟游戏直到结束,记录模拟结果。

  4. 反向传播(BackPropagation):将模拟结果反向传播,更新所有祖先节点的统计信息。

4.2. 各步骤用Python代码

以下是简化版的MCTS实现框架:

import math

# 节点类定义
class Node:  
    def __init__(self, state, parent=None):  
        self.state = state  
        self.parent = parent  
        self.children = []  
        self.visits = 0  
        self.wins = 0  
  
    def is_terminal(self):  
        # 实现判断节点是否为终止节点的逻辑  
        # 这里只是示例,具体实现需要根据游戏规则来  
        return False  
  
    def uct_value(self, parent_visits):  
        if self.visits == 0:  
            return float('inf')  # 未访问过的节点UCB值设为无穷大  
        win_rate = self.wins / self.visits  
        exploration_factor = 2  # 探索因子,可以调整  
        return win_rate + exploration_factor * sqrt(log(parent_visits) / self.visits) 

# 算法函数定义
def mcts(root, num_iterations):  
    for _ in range(num_iterations):  
        node = root  
        # 选择Selection  
        while node.children:  
            node = select(node, node.visits)  
  
        # 扩展Expansion  
        if not node.is_terminal():  
            node = expand(node)  
  
        # 模拟Simulation  
        result = simulate(node.state)  
  
        # 反向传播Backpropagation  
        backpropagate(node, result)  

# 选择逻辑函数
def select(node, parent_visits):  
    # 实现选择逻辑,这里使用UCT(Upper Confidence Bound for Trees)  
    return max(node.children, key=lambda child: child.uct_value(parent_visits))  

# 节点扩展逻辑
def expand(node):  
    # 实现节点扩展逻辑 
    # 这里只是示例,具体实现需要根据游戏规则来生成新的状态  
    new_state = node.state.generate_next_state()  # 假设状态对象有一个生成下一个状态的方法  
    new_node = Node(new_state, node)  
    node.children.append(new_node)  
    return new_node  

# 模拟逻辑函数  
def simulate(state):  
    # 实现模拟逻辑
    # 从当前节点的状态开始模拟  
    current_state = node.state  
      
    # 模拟游戏进行,直到达到终端状态  
    while not current_state.is_terminal():  
        # 根据当前状态随机选择一个动作  
        action = current_state.sample_random_action()  
          
        # 执行动作,得到新的状态  
        current_state = current_state.apply_action(action)  
      
    # 返回模拟结果,通常是胜负标识  
    return current_state.get_result()    

# 反向传播函数  
def backpropagate(node, result):  
    while node:  
        node.visits += 1  
        if result > 0:  # 假设result为正表示胜利  
            node.wins += 1  
        node = node.parent
 
#-------------------------------------------------------  
# 示例用法  
root = Node(initial_state)  # 假设有一个初始状态  
num_iterations = 1000  
mcts(root, num_iterations)

5. 优缺点和缺陷的解决方案

5.1. 优缺点

5.1.1. 优点

  1. 高效性:MCTS通过模拟大量随机游戏来评估每个可行的行动,相比其他算法,它能够在较短的时间内找到相对较好的解决方案。这种高效性使得MCTS在实时决策系统中特别有用,如游戏AI和自动驾驶。

  2. 通用性:MCTS不需要对问题的具体特性有先验知识,因此可以灵活应用于多种领域,包括博弈游戏、组合优化、决策制定等。它的通用性使得MCTS成为许多复杂问题求解的有力工具。

  3. 自我提升:MCTS通过不断模拟和自我对弈来提升样本的利用率,从而改善状态空间建模、策略提升和探索/利用效率等方面的性能。这种自我提升机制使得MCTS能够在面对新问题时逐渐适应并找到更好的解决方案。

  4. 动态适应:MCTS能够动态地调整搜索策略,专注于那些获得高评估回报的仿真结果,并基于这些结果不断向外扩展搜索树。这种动态适应性使得MCTS在复杂多变的环境中表现出色。

5.1.2. 缺点和缺陷

  1. 收敛速度慢:对于复杂的问题,MCTS往往需要大量的模拟才能达到可靠的估值,这可能导致收敛速度较慢。在某些情况下,为了在有限时间内做出决策,可能需要牺牲一定的解的质量。

  2. 计算资源消耗大:为了达到较高的决策质量,MCTS需要进行大量的模拟,这在处理复杂的游戏或问题时,会消耗大量的CPU时间和内存资源。这限制了MCTS在某些资源受限环境中的应用。

  3. 探索与利用的平衡:传统的MCTS算法需要在搜索树的每个节点上进行平衡探索(exploration)与利用(exploitation)的决策。当搜索空间庞大时,如何有效地维持这种平衡是一个挑战。如果探索过多,可能会导致收敛速度变慢;如果利用过多,则可能陷入局部最优解。

  4. 并行化困难:尽管MCTS算法在理论上可以并行化,但在实际操作中,如何有效地管理并行计算以减少性能损失仍是一个难题。特别是如何确保每个并行计算单元都能使用最新的统计数据来进行有效的探索和利用权衡。

5.2. 缺陷的解决方案

针对蒙特卡洛树搜索(Monte Carlo Tree Search, MCTS)的缺点和缺陷,以下是一些具体的解决方案:

5.2.1. 收敛速度慢

解决方案及实施步骤

  • 结合领域知识
    • 步骤一:收集和分析特定领域的先验知识,如游戏规则、专家经验等。
    • 步骤二:在MCTS的模拟过程中,将这些先验知识融入模拟策略中,例如通过调整模拟动作的选择概率来引导模拟过程。
    • 步骤三:评估结合领域知识后的模拟效果,根据反馈调整先验知识的应用方式。
  • 使用渐进展开
    • 步骤一:在搜索过程中,为每个节点维护统计信息,如访问次数、胜利次数等。
    • 步骤二:根据节点的统计信息,优先扩展那些具有更高潜力的节点,即访问次数较少但胜利次数较多的节点。
    • 步骤三:随着搜索的进行,逐步展开其他节点,确保搜索过程的全面性和有效性。
  • 动态调整模拟次数
    • 步骤一:为每个节点设置初始模拟次数,并根据搜索进度和结果进行调整。
    • 步骤二:在搜索初期,增加模拟次数以充分探索搜索空间;在搜索后期,减少模拟次数以加快收敛速度。
    • 步骤三:监控搜索过程的收敛情况,根据实时反馈动态调整模拟次数。

5.2.2. 计算资源消耗大

解决方案及实施步骤

  • 并行化计算
    • 步骤一:将MCTS算法分解为可并行化的子任务,如多个模拟实例可以同时运行。
    • 步骤二:利用现代计算机的多核处理器或分布式计算资源来并行执行这些子任务。
    • 步骤三:设计有效的数据同步和通信机制,确保并行计算单元之间的协作和数据一致性。
  • 剪枝技术
    • 步骤一:分析MCTS搜索过程中的无效搜索分支,识别出可以剪枝的节点。
    • 步骤二:开发适用于MCTS的剪枝策略,如基于节点统计信息的剪枝规则。
    • 步骤三:在搜索过程中应用剪枝策略,减少不必要的搜索分支,降低计算资源消耗。
  • 自适应终止条件
    • 步骤一:为每个节点设置自适应的模拟终止条件,如基于模拟次数、时间限制或节点统计信息的终止规则。
    • 步骤二:在模拟过程中监控这些终止条件,一旦满足条件则提前终止模拟过程。
    • 步骤三:评估自适应终止条件对搜索效果和计算资源消耗的影响,根据反馈调整终止条件。

5.2.3. 探索与利用的平衡

解决方案及实施步骤

  • 使用UCB公式变体
    • 步骤一:分析传统UCB公式的优缺点,并探索其他形式的UCB公式变体。
    • 步骤二:在MCTS算法中引入新的UCB公式变体,调整其中的参数以平衡探索和利用。
    • 步骤三:评估新公式变体对搜索效果的影响,根据反馈调整参数和公式形式。
  • 渐进式调整探索率
    • 步骤一:为MCTS算法设置初始探索率,该探索率决定了随机选择动作的概率。
    • 步骤二:在搜索过程中,根据搜索进度和结果渐进式地调整探索率。例如,随着搜索的深入,逐渐降低探索率以增加利用已有信息的比重。
    • 步骤三:监控搜索过程中的探索与利用情况,确保在保持多样性的同时提高搜索效率。
  • 结合其他搜索策略
    • 将MCTS与其他搜索策略(如贪婪搜索、局部搜索等)相结合,利用各自的优势来弥补不足。
    • 例如,可以在MCTS的模拟阶段使用局部搜索策略来快速找到当前状态下的局部最优解。

5.2.4. 并行化困难

解决方案及实施步骤

  • 设计有效的并行化策略
    • 步骤一:分析MCTS算法的并行化需求,识别出可并行化的部分。
    • 步骤二:设计合理的任务划分和数据同步策略,确保并行计算单元之间的有效协作。
    • 步骤三:实现并行化MCTS算法,并在实际应用中测试其性能和效果。
  • 利用现代并行计算框架
    • 步骤一:选择合适的并行计算框架(如MPI、OpenMP、CUDA等),根据具体需求和环境进行配置。
    • 步骤二:将MCTS算法转换为适合并行计算的形式,并利用并行计算框架提供的接口和工具进行实现。
    • 步骤三:优化并行算法的性能,包括减少通信开销、平衡负载、优化数据访问模式等。
  • 处理数据一致性问题
    • 在并行化MCTS过程中,需要特别注意数据一致性问题。
    • 通过引入适当的同步机制和锁策略来确保并行计算单元之间访问共享数据时的正确性。
    • 同时,还需要优化数据访问模式以减少缓存不一致性和内存带宽瓶颈等问题的影响。

6.  在游戏AI中的使用实例

6.1. 简单介绍

蒙特卡洛树搜索(Monte Carlo Tree Search,MCTS)在游戏AI中是一个强大的算法,尤其适用于那些具有庞大状态空间和/或难以评估状态价值的游戏。

一个典型的使用实例是将其应用于围棋、国际象棋或类似的策略棋类游戏。

下面,我将通过一个简化的围棋游戏AI的实例来展示蒙特卡洛树搜索的应用,并提供相应的Python代码实现。

6.2. 围棋AI中的蒙特卡洛树搜索

在围棋中,MCTS用于搜索可能的走子序列,并评估这些序列的胜负概率。算法的核心在于通过模拟(即随机走子至游戏结束)来评估节点价值,并利用这些模拟结果来指导搜索。

Python代码实现

以下是一个围棋MCTS实现的框架:

import random  
from math import sqrt, log  
  
class GameState:  
    def __init__(self, board=None, turn=None, last_move=None):  
        self.board = board or self.create_empty_board()  
        self.turn = turn or 'X'  # 'X' 或 'O'  
        self.last_move = last_move  
  
    def create_empty_board(self):  
        # 创建一个空的围棋棋盘,例如 9x9  
        return [['.' for _ in range(9)] for _ in range(9)]  
  
    def is_terminal(self):  
        # 检查游戏是否结束(简化版本,实现基本的胜负判断)  
        # 这里只检查是否所有位置都已落子,实际游戏需要更复杂的判断  
        return all(cell != '.' for row in self.board for cell in row)  
  
    def generate_moves(self):  
        # 生成所有可能的走子  
        moves = []  
        for i in range(len(self.board)):  
            for j in range(len(self.board[0])):  
                if self.board[i][j] == '.':  
                    moves.append((i, j))  
        return moves  
  
    def apply_move(self, move):  
        # 应用走子并返回新的游戏状态  
        new_board = [row[:] for row in self.board]  
        new_board[move[0]][move[1]] = self.turn  
        return GameState(new_board, 'O' if self.turn == 'X' else 'X', move)  
  
    def get_result(self):  
        # 返回游戏结果,简化版本只返回胜负  
        if self.is_terminal():  
            # 这里应该实现真正的胜负判断,简化版本只返回 None  
            return None  # 实际上应该根据棋盘状态判断胜负  
        return None  
  
    def __str__(self):  
        # 打印棋盘状态  
        return '\n'.join(''.join(row) for row in self.board)  
  
class Node:  
    def __init__(self, game_state, parent=None):  
        self.game_state = game_state  
        self.parent = parent  
        self.children = []  
        self.visits = 0  
        self.wins = 0  
  
    def is_terminal(self):  
        return self.game_state.is_terminal()  
  
    def uct_value(self, parent_visits):  
        if self.visits == 0:  
            return float('inf')  
        win_rate = self.wins / self.visits  
        exploration_factor = sqrt(2)  # 探索与利用的权衡因子  
        return win_rate + exploration_factor * sqrt(log(parent_visits) / self.visits)  
  
    def expand(self):  
        moves = self.game_state.generate_moves()  
        for move in moves:  
            next_state = self.game_state.apply_move(move)  
            child_node = Node(next_state, self)  
            self.children.append(child_node)  
  
    def select_child(self):  
        return max(self.children, key=lambda child: child.uct_value(self.visits))  
  
def simulate(node):  
    current_node = node  
    while not current_node.is_terminal():  
        if not current_node.children:  
            current_node.expand()  
        current_node = current_node.select_child()  
    # 在这个简化版本中,我们总是返回 None,因为胜负判断未实现  
    return None  
  
def backpropagate(node, result):  
    while node:  
        node.visits += 1  
        if result is not None:  # 在这个简化版本中,我们从不更新胜利次数,因为胜负判断未实现  
            node.wins += result  # 实际上这里应该是 1 或 0,表示胜利或失败  
        node = node.parent  
  
def mcts(root, num_iterations):  
    for _ in range(num_iterations):  
        node = root  
        while not node.is_terminal():  
            if not node.children:  
                node.expand()  
            node = node.select_child()  
        result = simulate(node)  # 在这个简化版本中,simulate 总是返回 None  
        backpropagate(node, result)  
  
# 示例用法  
initial_state = GameState()  
root = Node(initial_state)  
num_iterations = 1000  
mcts(root, num_iterations)  
best_child = max(root.children, key=lambda child: child.visits)  
print("推荐走子:", best_child.game_state.last_move)  
print("棋盘状态:\n", best_child.game_state)

在这个实现中,GameState类提供了创建空棋盘、检查游戏是否结束、生成所有可能的走子、应用走子并返回新的游戏状态以及获取游戏结果的功能。

Node类和MCTS算法的实现与之前提供的示例相同。

在示例用法中,我们创建了一个初始的游戏状态,并进行了1000次MCTS迭代来选择最佳的走子。最后,我们打印了推荐的走子和当前的棋盘状态。

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

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

相关文章

免费听书TV版v1.0.1

使用非常稳定流畅,UI界面设计美观简洁,纯净无广。资源虽然不是特别多,但是日常听书还是可以满足需求。 完全免费,操作简单方便,安装即用,没有任何限制。 可以适配遥控器操作,OK键开启或关闭语…

适配各种IT场景的零信任沙箱

在当今数字化时代,网络安全威胁层出不穷,传统的安全防御策略已难以应对日益复杂的网络攻击。零信任与沙箱技术的结合,作为一种新兴的安全防护策略,正逐渐受到企业和组织的青睐。本文将深入探讨零信任结合沙箱技术所能解决的问题及…

【智能算法改进】一种混合多策略改进的麻雀搜索算法

目录 1.算法原理2.改进点3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】麻雀搜索算法(SSA)原理及实现 2.改进点 精英反向学习策略 将精英反向学习策略应用到初始化阶段, 通过反向解的生成与精英个体的选择, 不仅使算法搜索范围得到扩大, 提…

C++第四弹 -- 类与对象(中上) (构造函数 析构函数 拷贝构造函数)

目录 前言构造函数1. 概念2. 特征 析构函数1. 概念2. 特征 拷贝构造函数1. 概念2. 特征 总结 前言 让我们一起揭开 C 对象生命周期管理的神秘面纱,掌握构造函数、析构函数和拷贝构造函数的精髓! 博客主页: 酷酷学!!! 期待更多好文, 点击关注~ 构造函…

英伟达今年在华销售额预计将达120亿美元、MiniMax创始人:三年后才会出现“杀手级”AI应用

ChatGPT狂飙160天,世界已经不是之前的样子。 更多资源欢迎关注 1、英伟达今年在华销售额预计将达120亿美元 芯片咨询公司SemiAnalysis报告预估,今年英伟达有望在中国销售价值约120亿美元的人工智能芯片。黄仁勋曾表示,希望借助新的芯片使得…

SprintBoot创建遇到的问题

最近使用IDEA版本为2022.3.1&#xff0c;java版本为21.0.3&#xff0c;现在做一个创建SprintBoot3的一个大体流程 1.先下载Maven&#xff0c;解压到一个位置 maven下载 2.配置setting.xml文件 这路径自己配置&#xff0c;这里不多演示 代码如下&#xff1a; <mirror>&…

【测试开发】--安全渗透测试

1. 安全渗透 1.1 分类 web数据库安全web应用服务器安全&#xff08;文件上传漏洞、文件包含漏洞&#xff09;web客户端安全&#xff08;XSS跨站攻击&#xff09; 2. sql注入 2.1 sql注入介绍 sql注入在安全问题中排行榜首sql注入攻击是输入参数未经过滤&#xff0c;然后直…

高考完的假期想学c语言要注意那些问题?

c语言算是现代编程语言里面比较简单的一个&#xff0c;对于高考刚考完的学生来说确实很适合刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全…

防火墙之安全策略

目录 前言&#xff1a; 一、实验需求 二、需求分析 三、具体操作 1&#xff0c;在安全区域中新建拓扑图中所显示的区域 2&#xff0c;在对象模块中的时间段中添加一个9&#xff1a;00-18&#xff1a;00 3&#xff0c;写两条安全策略&#xff0c;一个是生产区&#xff0c…

构建与操作共享栈

归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言​📝既然选择了远方,当不负青春,砥砺前行! 共享栈是一种优化的栈实现方式,它允许两个或多个栈共享同一段连续的内存空间…

(TGRS,2024)KG-ZSL:利用基于知识图谱的零样本学习模型识别未知灾难场景

文章目录 Recognizing Unknown Disaster Scenes With Knowledge Graph-Based Zero-Shot Learning (KG-ZSL) Model相关资料摘要引言方法总体框架视觉-语义特征提取过程TransD交互式注意力模块 多特征整合用于零样本推理 实验 Recognizing Unknown Disaster Scenes With Knowledg…

我以为我对Spring MVC很了解,直到我遇到了...

点赞再看&#xff0c;Java进阶一大半 所有人都知道Spring MVC是Rod Johnson是开发的&#xff0c;却鲜有人知道Spring MVC的理论基础来自于1978 年提出MVC模式的一个老头子&#xff0c;他就是Trygve Mikkjel Heyerdahl Reenskaug&#xff0c;挪威计算机科学家&#xff0c;奥斯陆…

【笔记】从零开始做一个精灵龙女-画贴图阶段(上)

此文只是我的笔记&#xff0c;不包全看懂&#xff0c;有问题可评论 PS贴图加工 1.打开ps 拖入uv图&#xff0c;新建图层&#xff0c;设置背景色为灰色&#xff0c;改一下图层名字 2.按z缩小一下uv图层&#xff0c;拖入实体uv图片&#xff08;目的是更好上色&#xff0c;比如…

第二证券:70万手封单,超3亿元资金盯上这只绩优股

今天A股商场收盘共50股涨停&#xff0c;剔除9只ST股后&#xff0c;41股涨停&#xff1b;25股封板未遂&#xff0c;全体封板率为67.78%。 涨停战场&#xff1a; 超3亿元资金封板盛屯矿业 据证券时报数据宝核算&#xff0c;从收盘涨停板封单量来看&#xff0c;盛屯矿业封单量最…

洛杉矶裸机云大宽带服务器的特性和优势

洛杉矶裸机云大宽带服务器是结合了物理服务器性能和云服务灵活性的高性能计算服务&#xff0c;为用户提供高效、安全的计算和存储能力。在了解如何使用洛杉矶裸机云大宽带服务器之前&#xff0c;需要了解其基本特性和优势。以下是对洛杉矶裸机云大宽带服务器的具体分析&#xf…

短信验证码研究:公开的短信验证码接口、不需要注册的短信验证码接口

短信验证码研究&#xff1a;公开的短信验证码接口、不需要注册的短信验证码接口 0 说明 本文提供了一个短信验证码接口&#xff0c;主要用于以下场景&#xff1a; 1、用于开发调试 2、用于申请验证码困难的企业和个人 3、用于短信验证码认证还没有通过&#xff0c;但是着急…

“论面向方面的编程技术及其应用”写作框架,软考高级论文,系统架构设计师论文

论文真题 针对应用开发所面临的规模不断扩大、复杂度不断提升的问题&#xff0c;面向方面的编程&#xff08;Aspect Oriented Programming,AOP&#xff09;技术提供了一种有效的程序开发方法。为了理解和完成一个复杂的程序&#xff0c;通常要把程序进行功能划分和封装。一般系…

uni-app三部曲之三: 路由拦截

1.引言 路由拦截&#xff0c;个人理解就是在页面跳转的时候&#xff0c;增加一级拦截器&#xff0c;实现一些自定义的功能&#xff0c;其中最重要的就是判断跳转的页面是否需要登录后查看&#xff0c;如果需要登录后查看且此时系统并未登录&#xff0c;就需要跳转到登录页&…

Dify工作流中的迭代节点

一.定义 迭代节点的本质就是对数组内容循环处理。对数组执行多次步骤直至输出所有结果。 迭代步骤在列表中的每个条目&#xff08;item&#xff09;上执行相同的步骤。使用迭代的条件是确保输入值已经格式化为列表对象。迭代节点允许 AI 工作流处理更复杂的处理逻辑&#xff…

衣服、帽子、鞋子相关深度学习数据集大合集(2)

继续为大家分享关于衣帽鞋子的深度学习数据集&#xff0c;主要有衣服、帽子、鞋子、短裤、短袖、T恤等。 1、人头上带着各种帽子图片数据集 数据格式&#xff1a;图片 是否标注&#xff1a;已标注 标注格式&#xff1a;yolov8 图片数量&#xff1a;1853张 数据查看地址&a…