人工智能一种现代的方法 第四章 非经典搜索 上(局部搜索)

news2024/9/28 23:23:30

文章目录

    • 人工智能一种现代的方法 第四章 非经典搜索 上
    • 前言
      • 4.1 局部搜索
        • 4.1.1 爬山法
        • 4.1.2 爬山法变形
        • 4.1.3模拟退火搜索
        • 4.1.4 局部束搜索
        • 4.1.5 遗传算法
      • 4.2 连续空间的局部搜索
        • 4.2.1 梯度下降
        • 4.2.2 约束优化
      • 小结

人工智能一种现代的方法 第四章 非经典搜索 上

前言

在第三章中,环境是可观察的、确定的、已知的,问题的解是一个行动序列。本章将讨论放宽约束,本文所讲的部分是局部探索算法,考虑解的状态而不是到达该状态的路径,比如八皇后问题,不关心是怎么到目的状态的,只关心最终布局对不对,许多重要应用都有这样的性质,如作业空间调度,自动程序设计等。同时局部搜索也对最优化问题十分有用。

4.1 局部搜索

局部搜索的两大优点

  • 通常能在系统化搜索不适用的规模较大的状态空间中找到合理的解
  • 空间复杂度较低
4.1.1 爬山法

请添加图片描述

  • 求全局最大值
  • 不需要维护搜索树,当前结点只需记录当前状态和目标函数值
def hill_climbing(initial_state, generate_neighbors, evaluate):
    current = initial_state
    
    while True:
        neighbors = generate_neighbors(current)
        best_neighbor = max(neighbors, key=lambda neighbor: evaluate(neighbor))
        
        if evaluate(best_neighbor) >= evaluate(current):
            return current  # 如果最好的邻居状态比当前状态更好,则返回当前状态作为结果
        
        current = best_neighbor  # 更新当前状态为最好的邻居状态

八皇后问题
将八皇后转化为良定义问题

  • 状态:棋盘上的一个格局,表示棋盘上放置了8个皇后,且每列仅1个皇后
  • 动作:某个皇后移动到该列的其它7个位置之一
  • 启发式函数:互相攻击的皇后对数求全局最小值,0表示没有互相攻击的皇后,找到解

可以看出来与经典不同的是,局部搜索一般要有评估值来衡量搜索状态的优劣。评估值用于比较不同搜索状态之间的好坏,并指导搜索过程朝着更优的方向前进。


def generate_neighbors(state)://动作转移
    neighbors = []
    
    for i in range(8):  # 遍历每个皇后所在的行
        for j in range(8):  # 遍历每个列
            if j != state[i]:  # 如果当前位置与原始状态中皇后所在的列不同
                neighbor = state.copy()  # 创建邻居状态,为原始状态的副本
                neighbor[i] = j  # 将邻居状态中第i行的皇后移动到当前位置j
                neighbors.append(neighbor)  # 将邻居状态添加到邻居状态列表
    
    return neighbors

def evaluate(state):
    attacks = 0
    
    for i in range(8)://从第一个皇后开始遍历
        for j in range(i+1, 8)://后面的皇后与前面的皇后相对比
            if state[i] == state[j] or abs(state[i] - state[j]) == abs(i - j): // 判断行 和 对角线是否攻击
                attacks += 1
    
    return attacks

爬山的缺点

  • 局部最大值
  • 山脊:单个局部极大值
  • 高原/平原
    连续局部极大值,发生侧向移动
    侧向移动:最佳邻近结点与当前结点的目标函数值相同
    山肩,不是全局最大值
4.1.2 爬山法变形

随机爬山法

  • 思想:随机选择邻近状态(概率与陡峭程度有关)
  • 首选爬山法:随机生成邻近状态,直到生成一个优于当前状态的邻近状态
def hill_climbing():
    current_state = 0  # 初始状态
    current_value = evaluate_state(current_state)  # 计算初始状态的优劣程度

    while True:
        neighbour = generate_neighbour(current_state)  # 生成邻近状态
        neighbour_value = evaluate_state(neighbour)  # 计算邻近状态的优劣程度

        if neighbour_value > current_value:
            # 找到更好的邻近状态,更新当前状态
            current_state = neighbour
            current_value = neighbour_value
        else:
            # 没有找到更好的邻近状态,结束搜索
            break

    return current_state

首选爬山法旅行商问题

  • 状态x:当前路径
    初始状态x0:随机选择的任意路径
    邻近状态xn:选择当前路径中任意相邻两个城市交换访问次序得到的新路径
    邻域P:当前路径的邻近状态集
  • 评估函数h(x):当前路径的距离,若两城市无路径,设其距离为+∞
  • 动作:当前路径中任意相邻两个城市交换访问次序
import random
import math
# 一家之言,无论是经典还是非经典有两个重要的点,一是状态如何定义,二是状态如何转移
def generate_neighbour(current_path):
    # 生成邻近状态(交换两个相邻城市的访问次序)
    neighbours = []
    for i in range(len(current_path)-1):
        for j in range(i+1, len(current_path)):
            neighbour = current_path.copy()
            neighbour[i], neighbour[j] = neighbour[j], neighbour[i]  # 交换两个城市的访问次序
            neighbours.append(neighbour)
    return neighbours

def evaluate_path(path, distances):
    # 计算路径的总距离
    total_distance = 0
    for i in range(len(path)-1):
        current_city = path[i]
        next_city = path[i+1]
        distance = distances[current_city][next_city]
        total_distance += distance
    return total_distance

def hill_climbing(distances, num_cities):
    current_path = random.sample(range(num_cities), num_cities)  # 随机生成初始路径
    current_distance = evaluate_path(current_path, distances)  # 计算初始路径的总距离

    while True:
        neighbours = generate_neighbour(current_path)  # 生成所有邻近状态
        best_neighbour = min(neighbours, key=lambda x: evaluate_path(x, distances))  # 找到最好的邻近状态
        best_distance = evaluate_path(best_neighbour, distances)  # 最好邻近状态的总距离

        if best_distance <= current_distance:
            # 找到更好的邻近状态,更新当前路径和总距离
            current_path = best_neighbour
            current_distance = best_distance
        else:
            # 没有找到更好的邻近状态,结束搜索
            break

    return current_path

随机重启爬山法算法

随机生成初始状态

def random_restart(distances, num_cities, num_restarts):
    best_path = None
    best_distance = math.inf

    for _ in range(num_restarts):
        current_path, current_distance = hill_climbing(distances, num_cities)
        if current_distance < best_distance:
           
            best_path = current_path
            best_distance = current_distance

    return best_path

4.1.3模拟退火搜索
  • 爬山法不完备,因为会碰到局部极大值
  • 随机走是完备的(因为完全等概率选择后续节点,不受局部极大值影响),但是效率极低。

模拟退火算法:把爬山法和随机行走以某种方式结合,同时得到效率和完备性。

def acceptance_probability(current_energy, new_energy, temperature):
    # 计算接受新解的概率
    if new_energy < current_energy:
        return 1.0
    return math.exp((current_energy - new_energy) / temperature)

def simulated_annealing(initial_solution, evaluate_energy, generate_neighbour, initial_temperature, cooling_rate):
    current_solution = initial_solution
    current_energy = evaluate_energy(current_solution)
    best_solution = current_solution
    best_energy = current_energy
    temperature = initial_temperature

    while temperature > 0.1:
        neighbour = generate_neighbour(current_solution)  # 生成邻近解
        new_energy = evaluate_energy(neighbour)  # 计算邻近解的能量

        if acceptance_probability(current_energy, new_energy, temperature) > random.random():
            # 根据概率接受新解
            current_solution = neighbour
            current_energy = new_energy

        if new_energy < best_energy:
            # 更新最优解
            best_solution = neighbour
            best_energy = new_energy

        temperature *= cooling_rate  # 降低温度

    return best_solution
4.1.4 局部束搜索

局部束搜索

  • 只记录k个状态
  • 从k个随机状态开始,每步生成k个状态的所有后继状态,如果存在目标状态则结束,否则只选取k个最佳的后继状态,重复上述过程
  • 与k个局部搜索并行执行不同

局部束搜索的变体——随机束搜索
随机选取k个后继状态,状态的选择概率与状态的目标函数值一致

4.1.5 遗传算法

请添加图片描述

  • 随机束搜索的变体——遗传算法
  • 通过两个状态的结合生成后继状态
  • 种群:目前的所有状态,从k个随机状态开始
  • 个体:每个状态,通常用长度有限的字符串表示


def select_parents(population, num_parents):
    # 选择父代
    parents = []
    for _ in range(num_parents):
        parent = random.choice(population)
        parents.append(parent)
    return parents
    
def crossover(parents, population_size):
    # 交叉操作
    offspring = []
    while len(offspring) < population_size:
        parent1, parent2 = random.sample(parents, 2)
        crossover_point = random.randint(1, len(parent1)-1)
        child1 = parent1[:crossover_point] + parent2[crossover_point:]
        child2 = parent2[:crossover_point] + parent1[crossover_point:]
        offspring.extend([child1, child2])
    return offspring[:population_size]

def mutate(chromosome, mutation_rate):
    # 变异操作
    for i in range(len(chromosome)):
        if random.random() < mutation_rate:
            chromosome[i] = 1 - chromosome[i]
    return chromosome

def genetic_algorithm(population_size, chromosome_length, num_generations, mutation_rate):
    population = initialize_population(population_size, chromosome_length)

    for _ in range(num_generations):
        # 计算适应度
        fitness_values = [evaluate_fitness(chromosome) for chromosome in population]

        # 选择父代
        parents = select_parents(population, population_size // 2)

        # 交叉操作
        offspring = crossover(parents, population_size)

        # 变异操作
        mutated_offspring = [mutate(chromosome, mutation_rate) for chromosome in offspring]

        # 更新种群
        population = mutated_offspring

    # 返回最优解
    best_chromosome = max(population, key=evaluate_fitness)
    return best_chromosome

4.2 连续空间的局部搜索

在讨论过的算法里面,除了首选爬山法和模拟退火,没有一个能够处理连续的状态和动作空间,因为连续空间的分支因子是无限的。 本部分将介绍在连续状态空间寻找最优解的技术

4.2.1 梯度下降

梯度下降的核心思想是通过迭代地更新参数,沿着目标函数的梯度方向逐步接近最优解。梯度表示了函数在当前参数值处的变化率,因此沿着梯度的反方向更新参数可以使目标函数的值减小。通过不断迭代,梯度下降算法可以找到目标函数的局部最小值或全局最小值。

梯度下降以线性回归为例

# 初始化参数
theta = [0, 0]  # 参数向量
learning_rate = 0.01  # 学习率
num_iterations = 1000  # 迭代次数

# 梯度下降
for _ in range(num_iterations):
    # 计算梯度
    gradient = [0, 0]  # 梯度向量
    for i in range(len(X)):
        x = X[i]
        y = y[i]
        gradient[0] += (theta[0] + theta[1]*x - y)  # 对theta0求偏导数
        gradient[1] += (theta[0] + theta[1]*x - y) * x  # 对theta1求偏导数
    gradient[0] /= len(X)
    gradient[1] /= len(X)

    # 更新参数
    theta[0] -= learning_rate * gradient[0]
    theta[1] -= learning_rate * gradient[1]

# 最优参数
print("最优参数:", theta)
4.2.2 约束优化

约束优化问题:min f(x),s.t. g(x) ≥0, x∈D.其中,x是一个n维向量,D是问题的定义域

小结

局部搜索是求的是解节点而不是路径,所以不必维护搜索树。同时局部搜索搜索的是局部,往往需要启发式函数。好的启发式搜索能大大提高搜索性能
好的搜索策略应该引起,运动—避免原地踏步,系统—避免兜圈,运用启发函数—缓解组合爆炸。

本章下一部分,将不再强求环境的确定性和可观察性以及未知性,是不是很大胆?所以还是敬请期待吧!不要走开,马上回来。

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

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

相关文章

ASUS华硕灵耀X2 Duo UX481FA(FL,FZ)_UX4000F工厂模式原装出厂Windows10系统

下载链接&#xff1a;https://pan.baidu.com/s/1sRHKBOyc3zu1v0qw4dSASA?pwd7nb0 提取码&#xff1a;7nb0 带有ASUS RECOVERY恢复功能、自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办公软件、MyASUS华硕电脑管家等预装程序所需要工具&#xff1a;16G或以上…

2023 年最佳 Android 数据恢复软件工具

Android 数据恢复软件将使您能够从 Android 智能手机中检索所有已删除的文件。您需要此类软件的原因是由于不同情况下会丢失数据。例如&#xff0c;病毒攻击会导致数据损坏和文件丢失。 Android 数据恢复软件工具清单 以下是十个最佳 Android 数据恢复软件工具&#xff0c;用于…

有哪些你直呼好用的科研效率神器?

今天来分享几款科研免费小工具&#xff0c;帮你读懂外刊、追踪文献、搞定翻译、解除限制……甚至轻松制作PPT。一身好装备&#xff0c;提高科研效率。 一、 浏览器插件 1.1 easyScholar 一款助力科研的浏览器扩展 一款助力科研的浏览器扩展 - easyScholar | 显示期刊等级\SC…

从0到1的Springcloud Alibaba项目,一篇入门!!!

1、新建项目 我们用maven管理项目 第一步&#xff1a;选择maven 第二步&#xff1a;项目命名&#xff0c;项目路径 第三步&#xff1a;进入项目&#xff0c;把src文件夹删掉&#xff08;不删也没事&#xff0c;主要是用不到这个文件夹&#xff09; 2、引入项目依赖 在父项目…

matlab 读写ENVI标准数据

本博客主要讲解如何读、生成ENVI标准格式的数据。主要分为四部分&#xff1a;读取ENVI头文件、读取ENVI数据、写入ENVI头文件、生成ENVI标准数据&#xff0c;最后附加讲解了本人写的生成hdr文本文件代码。此外&#xff0c;文中还具体介绍写代码的一些思路。 一、读取ENVI头文件…

【数据结构】单链表之--无头单向非循环链表

前言&#xff1a;前面我们学习了动态顺序表并且模拟了它的实现&#xff0c;今天我们来进一步学习&#xff0c;来学习单链表&#xff01;一起加油各位&#xff0c;后面的路只会越来越难走需要我们一步一个脚印&#xff01; &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x…

kafka可视化工具

Offset Explorer kafka可视化工具

Spring Boot 统一处理功能

目录 1.用户登陆权限验证 1.1 每个方法验证 1.2 Spring AOP 用户统一登陆验证 1.3 拦截器 1.3.1 自定义拦截器 1.3.2 将自定义拦截器配置到系统设置中&#xff0c;并且设置拦截规则 1.3.3 排除所有的静态资源 1.4 登录拦截器&#xff08;练习&#xff09; 1.5 拦截器原…

二叉树—相关计算题

目录 一、概念题 二、计算题 1、节点数 2、深度 3、遍历序列 一、概念题 1、在用树表示的目录结构中&#xff0c;从根目录到任何数据文件&#xff0c;有&#xff08; &#xff09;通道 答案&#xff1a;唯一一条&#xff0c;树的特点是不相交&#xff0c;所以不可能有多…

CAN总线数据采集工具PCAN的使用教程

系列文章目录 文章目录 系列文章目录pcan使用PCAN-Explorer 5安装PCAN-USB Pro安装如下PEAK-System_Driver-Setup安转如下PCAN-View操作步骤 通讯测试检查安装成果trace 文件下载 pcan使用 PCAN-Explorer 5安装 默认路径——all user——yes——next——finish PCAN-USB Pro…

洛谷P1024 [NOIP2001 提高组] 一元三次方程求解(优雅的暴力+二分,干净利落)

P1024 [NOIP2001 提高组] 一元三次方程求解 前言题目题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 题目分析注意事项 代码后话额外测试用例样例输入 #2样例输出 #2 王婆卖瓜 题目来源 前言 没有前言&#xff0c;可能因为作者忘了编辑 题目 题目描述 有形如&…

异常断电文件损坏docker服务异常处理

问题场景 我们在某地部署信控平台&#xff0c;当初是在产品研发早期&#xff0c;采取的还是Windows服务器部署虚拟机的方式使用virtualbox导入centos7虚拟机&#xff0c;虚拟机里运行docker服务&#xff0c;使用docker-compose统一管理客户今天上午反馈&#xff0c;昨天断电了…

Pygame游戏实战四:打砖块

介绍模块 本游戏使用的是由Pycharm中的pygame模块来实现的&#xff0c;也可以在python中运行。通过Pygame制作一个打砖块&#xff0c;通过击打砖块来得到更多的分数&#xff0c;看看这个是你小时候玩的游戏吗&#xff1f; 最小开发框架 详情请看此文章&#xff1a;Pygame游戏…

界面组件Telerik UI for WinForms中文教程 - 如何自定义应用程序文件窗口?

Telerik UI for WinForms包含了一个高度可定制的组件&#xff0c;它取代了.NET中默认的OpenFileDialog。在下一个更新版本中&#xff0c;会发布一个向对话框浏览器提那家自定义位置的请求功能&#xff0c;本文演示了这个和另一个自定义功能&#xff0c;它可以帮助用户在浏览文件…

【题解】2023 DTS算法竞赛集训 第1次

比赛地址&#xff1a;https://www.luogu.com.cn/contest/143650 P1319 压缩技术 https://www.luogu.com.cn/problem/P1319 简单的签到模拟题 #include <iostream>//c标准库 using namespace std; int main(){int a,n,t0,i0,b,s0;//t判断有没有回车&#xff0c;i判断输…

分支限界法求解迷宫问题

问题描述 从入口出发&#xff0c;按某一方向向前探索&#xff0c;若能走通(未走过的&#xff09;&#xff0c;即某处可以到达&#xff0c;则到达新点&#xff0c;否则试探下一方向&#xff1b;若该点所有的方向均没有通路&#xff0c;则沿原路返回到前一点&#xff0c;换下一个…

一台抵得上多种测量仪器-B1500A半导体参数分析仪

一台抵得上多种测量仪器-B1500A半导体参数分析仪 B1500A 半导体器件分析仪 卓越的测量能力&#xff0c; 完美的一体化解决方案&#xff0c; 经济高效, 出色的软件。 #B1500A 3步表征设备 使用B1500A半导体参数分析仪或PC上随附的EasyEXPERT group 表征软件。EasyEXPERT …

如何卸载在linux下通过rpm安装的mysql

目录 1.先关闭MySQL服务并查看运行状态 2.使用 rpm 管道命令的方式查看已安装的mysql 3. 使用rpm -ev 命令移除安装 4. 删除MySQL数据库内容 1.先关闭MySQL服务并查看运行状态 如果之前安装过并已经启动&#xff0c;则需要卸载前请先关闭MySQL服务 systemctl stop mysqld…

Juniper Networks Junos OS EX远程命令执行漏洞(CVE-2023-36845)

Juniper Networks Junos OS EX远程命令执行漏洞&#xff08;CVE-2023-36845&#xff09; 免责声明漏洞描述漏洞影响漏洞危害网络测绘Fofa: body"J-web" || title"Juniper Web Device Manager" 漏洞复现1. 构造poc2. 查看文件3. 执行命令 免责声明 仅用于技…

【编译原理】LL(1)文法

文章目录 语法分析基本概念自上而下语法分析自上而下语法分析的问题 消除文法左递归消除直接左递归消除间接左递归消除左递归的算法 解决回溯问题FIRST集与提出公共左因子FIRST集提取左公共因子 FOLLOW集合 构造FIRST集和FOLLOW集构造FIRST集合构造每个文法符号的FIRST集合构造…