强化学习编程实战-5 基于时间差分的方法

         第4章中,当模型未知时,由于状态转移概率P未知,动态规划中值函数的评估方法不再适用,用蒙特卡洛的方法聘雇值函数。

        在蒙特卡洛方法评估值函数时,需要采样一整条轨迹,即需要从初始状态s0到终止状态的整个序列数据,然后根据整个序列数据的回报来估计行为-值函数。

        蒙特卡洛方法式(5.1)

        

        现在的问题是,有没有一种新的方法可以不用等到终止状态就可以对行为值函数进行评估呢?

        答案:Yes.并且这种方法已经在动态规划算法中出现了。在本节中,会重新会议动态规划方法,从而引入强化学习算法中最重要的时间差分强化学习。

5.1 从动态规划到时间差分强化学习

       在动态规划中,值评估的公式(5.2)

        在无模型的任务中,无法知道状态转移概率模型P,不能直接用式(5.2),而且在无模型任务中,需要评估的是行为-值函数,而不是值函数。下面的式(5.3)行为-值函数也不能直接使用。

        行为-值函数公式(5.3):

        暂且不管如何处理未知的模型概率,先看一下动态规划方法与蒙特卡洛方法值进行值函数评估时所用的数据的不同。

        蒙特卡洛用到了整个轨迹的数据,而动态规划的方法只用到了相邻的两个状态的数据。如式(5.2)用状态s的后继状态s‘的值函数加上回报r估计状态s处的值函数,用的更新方法称为“用自举的方法进行更新”。自举===,字面意思,用自己的手把自己举起来。

        于是,可以将自举的方法应用于无模型的行为-值函数的估计。按蒙特卡洛的思想,不是直接计算P,而是得到后继状态s'。

        我们用蒙特卡洛中同样的思想,通过采样的方法,即智能体通过策略Π直接与环境进行交互得到后继状态s’。因此式(5.3)近似为式(5.4):

        根据上式,对于状态s处动作a的行为值函数的估计,可用以下公式来计算,式(5.5):

        在更新式(5.5)中,不需要等到轨迹结束,而仅仅等到下一个时刻就可以形成学习目标,从而进行更新。更新目标与当前值只差一个时刻,因此称该方法为时间差分方法

        为了从动态规划方法中的值迭代算法引出时间差分强化学习算法,先看一下值迭代的伪代码。

        在该伪代码中,策略评估涉及第3行和第4行。在利用时间差分的方法进行策略评估时,可用式(5.5)来代替第4行。现在剩下的问题就是时间差分方法如何处理值迭代中的第3行。在值迭代算法中,第3行是要求值评估在整个状态空间进行遍历,这是值迭代算法收敛的重要保证。时间差分方法属于无模型方法,不能对状态进行遍历,但是为了保证收敛性,时间差分方法必须能保证访问到每个状态。为了满足这个条件,在时间差分方法中引入了探索-利用平衡机制。就像在蒙特卡洛算法中,采样的策略必须是柔和性的,即在每个状态处,采取每个动作的概率都大于0,最简单的采样是e-greedy策略

        根据采样策略和要评估的策略是否是同一个,将时间差分方法分为同策略强化学习算法和异策略强化学习算法。

        (1)同策略强化学习算法:SARSA算法.

        如采样策略\mu为e-greedy,要评估的策略\pi也是e-greedy策略,在值函数的评估公式中差分目标的计算为:

        同策略时间差分强化学习算法在进行策略评估是只需要利用采样相等的数据,这些数据的字母拼接起来为SARSA,因此得名。

        (2)异策略强化学习算法:Q-Learning算法。

         如采样策略\mu为e-greedy,要评估的策略\pi不是e-greedy策略。此时因为采样策略和评估策略为两个策略,所用我们只能用采样策略采集到的样本,而不能利用采样策略在该状态样本处的动作,所以可以用的数据格式为[s_t,a_t,{r_s}^a,s_{t+1}]  ,如果要对贪婪策略进行评估,则时间差分目标的计算为:

        跟SARSA 相比,Q-Learning不需要保存后继状态处的动作,只需保存后继状态。

        异策略强化学习算法由于不需保存后继状态处的动作,因此进行值函数评估可以利用任意的策略产生的数据,而且数据可以被重复利用。因此,异策略具有很好的数据样本效率

        至此,我们对于着值迭代将强化学习算法的所有要素引出来,再总结一下:

        ①利用采样的方法来求近似值迭代中的状态转移概率P;

        ②利用探索平衡策略来替代值迭代中的状态空间的遍历

        下面通过伪代码进一步比较动态规划算法和时间差分强化学习算法的联系和区别。

        

        上图所示的伪代码中,Q-Learning算法伪代码核心部分是5和6两行,其中

        ①5:利用探索-平衡策略来实现对每个状态的探索

        ②6:利用采样的方法求近似转移概率。

        注意:强化学习算法可以看成无模型下的动态规划算法。强化学习算法可以解决动态规划中遇到的维数灾难问题。这是因为当状态空间的维数增加时,状态的数目呈指数级增长,遍历状态空间不可能。而强化学习不需要遍历整个状态空间,只需要利用探索-平衡策略将计算力集中在那些对于最优解很有潜力的状态空间。当强化学习中的值函数利用函数逼近的方法进行表述的时候,强化学习算法又叫近似动态规划,由此可见强化学习算法和动态规划的渊源。

5.2 时间差分算法代码实现

        时间差分算法的实现包括同策略的SARSA算法和异策略的Q-Learning算法,两者代码实现差别不大。

      本章实现的环境类和第3章相同。只需要声明一个TD_RL类,用来构建时间差分算法。

 首先导入必要的包,从环境文件中导入环境类YuanYangEnv.

        声明一个时间差分算法类TD_RL,在初始化函数中,初始化行为-值函数qvalue为100x4的零矩阵。定义类的子函数贪婪策略greedy_policy和e-greedy策略。定义动作对应的序号函数find_num以便找到对应的动作。

5.2.2  SARSA算法

伪代码如下:

1:初始化行为值函数。

2-9:算法主体,其中2(a)利用采样策略控制智能体与环境进行交互,得到交互数据;2(b)利用时间差分的方法估计当前状态s处采取动作a时的行为-值函数;2(c)智能体往前推进一步。

10:输出最终的最优贪婪策略。

        代码如下:

        定义时间差分算法类TD_RL的子函数Sarsa来实现同策略时间差分算法。该算法包括2个循环,在外循环实现多条轨迹循环,内循环则是智能体与环境进行交互产生的一条轨迹。

        初始状态设置为0,也就是每条轨迹从初始状态0开始.接着调用算法类TD_RL的子函数greedy_test函数,该函数用来测试使用贪婪策略是否能找到目标点,如果第一次找到 目标点,则打印处为了找到目标点,算法共迭代的次数,在找到目标后继续学习,以便找到更优路径。如果找到最短路径,则打印出找到最短路径所需要迭代的次数,并结束学习。

        下面代码为第2个循环,即轨迹内循环。在该循环中,智能体通过当前策略与环境进行交互产生一条轨迹。

        如果智能体回到本次轨迹中已有的状态,则给出一个负的回报。

        为了完成算法,还需事先定义贪婪策略的测试子函数greedy_test().该子函数用于测试初始状态为0时,采用当前贪婪策略是否能找到目标点。

        如果找到目标点,flag标志位为1;如果找到目标点的步数小于21,即最短路径,则标志位设置为2.

5.2.3  Q-Learning算法

        伪代码如下:

        Q-Learning算法与SARSA算法几乎完全相同,唯一的区别在于值函数评估阶段。

def qlearning(self,num_iter, alpha, epsilon):iter_num = []self.qvalue = np.zeros((len(self.yuanyang.states), len(self.yuanyang.actions)))#大循环for iter in range(num_iter):#随机初始化状态# s = yuanyang.reset()s=0flag = self.greedy_test()if flag == 1:iter_num.append(iter)if len(iter_num)<2:print("qlearning 第一次完成任务需要的迭代次数为:", iter_num[0])if flag == 2:print("qlearning 第一次实现最短路径需要的迭代次数为:", iter)breaks_sample = []#随机选初始动作# a = self.actions[int(random.random()*len(self.actions))]a = self.epsilon_greedy_policy(self.qvalue,s,epsilon)t = Falsecount = 0while False==t and count < 30:#与环境交互得到下一个状态s_next, r, t = yuanyang.transform(s, a)# print(s)# print(s_next)a_num = self.find_anum(a)if s_next in s_sample:r = -2s_sample.append(s)if t == True:q_target = relse:# 下一个状态处的最大动作,a1用greedy_policya1 = self.greedy_policy(self.qvalue, s_next)a1_num = self.find_anum(a1)# qlearning的更新公式TD(0)q_target = r + self.gamma * self.qvalue[s_next, a1_num]# 利用td方法更新动作值函数self.qvalue[s, a_num] = self.qvalue[s, a_num] + alpha * (q_target - self.qvalue[s, a_num])s = s_next#行为策略a = self.epsilon_greedy_policy(self.qvalue, s, epsilon)count += 1# print(r)return self.qvalue

        为了对这两个算法进行测试并显示轨迹,与蒙特卡洛相似,写一个主函数。首先实例化一个鸳鸯类yuanyang和时间差分算法brain,调用时间差分算法类的SARSA算法,将行为值函数赋予qvalue1,调用时间差分算法类的Q-Learning算法,将行为值函数赋予qvalue2.打印学到的行为值函数。

if __name__=="__main__":yuanyang = YuanYangEnv()brain = TD_RL(yuanyang)# qvalue1 = brain.sarsa(num_iter =5000, alpha = 0.1, epsilon = 0.8)qvalue2=brain.qlearning(num_iter=10000, alpha=0.1, epsilon=0.1)#打印学到的值函数yuanyang.action_value = qvalue2########################################### 测试学到的策略flag = 1s = 0# print(policy_value.pi)step_num = 0path = []# 将最优路径打印出来while flag:# 渲染路径点path.append(s)yuanyang.path = patha = brain.greedy_policy(qvalue2, s)# a = agent.bolzman_policy(qvalue,s,0.1)print('%d->%s\t' % (s, a), qvalue2[s, 0], qvalue2[s, 1], qvalue2[s, 2], qvalue2[s, 3])yuanyang.bird_male_position = yuanyang.state_to_position(s)yuanyang.render()time.sleep(0.25)step_num += 1s_, r, t = yuanyang.transform(s, a)if t == True or step_num > 30:flag = 0s = s_# 渲染最后的路径点yuanyang.bird_male_position = yuanyang.state_to_position(s)path.append(s)yuanyang.render()while True:yuanyang.render()

        经过运行,可以得到下面的结果。

终端打印的结果如下:

记录了几次数据

SARSA算法第1次完成任务需要的迭代次数为258,而qlearning需要192;

SARSA第1次实现最短路径需要的迭代次数为312,而Q-Learning需要244;     

         从最后的结果来看,SARSA算法第一次完成任务和实现最短路径需要的迭代次数都比Q-Learning多。回顾蒙特卡洛算法,它往往需要1000次左右的迭代才能完成任务。

        由此可见,时间差分强化学习算法比蒙特卡洛算法效率更高

yuanyang_env_td.py

import pygame
from load import *
import math
import time
import random
import numpy as npclass YuanYangEnv:def __init__(self):self.states=[]for i in range(0,100):self.states.append(i)self.actions = ['e', 's', 'w', 'n']self.gamma = 0.95self.action_value = np.zeros((100, 4))self.viewer = Noneself.FPSCLOCK = pygame.time.Clock()#屏幕大小self.screen_size=(1200,900)self.bird_position=(0,0)self.limit_distance_x=120self.limit_distance_y=90self.obstacle_size=[120,90]self.obstacle1_x = []self.obstacle1_y = []self.obstacle2_x = []self.obstacle2_y = []self.path = []for i in range(8):#第一个障碍物self.obstacle1_x.append(360)if i <= 3:self.obstacle1_y.append(90 * i)else:self.obstacle1_y.append(90 * (i + 2))# 第二个障碍物self.obstacle2_x.append(720)if i <= 4:self.obstacle2_y.append(90 * i)else:self.obstacle2_y.append(90 * (i + 2))self.bird_male_init_position=[0,0]self.bird_male_position = [0, 0]self.bird_female_init_position=[1080,0]#def step(self):def collide(self,state_position):flag = 1flag1 = 1flag2 = 1# 判断第一个障碍物dx = []dy = []for i in range(8):dx1 = abs(self.obstacle1_x[i] - state_position[0])dx.append(dx1)dy1 = abs(self.obstacle1_y[i] - state_position[1])dy.append(dy1)mindx = min(dx)mindy = min(dy)if mindx >= self.limit_distance_x or mindy >= self.limit_distance_y:flag1 = 0# 判断第二个障碍物second_dx = []second_dy = []for i in range(8):dx2 = abs(self.obstacle2_x[i] - state_position[0])second_dx.append(dx2)dy2 = abs(self.obstacle2_y[i] - state_position[1])second_dy.append(dy2)mindx = min(second_dx)mindy = min(second_dy)if mindx >= self.limit_distance_x or mindy >= self.limit_distance_y:flag2 = 0if flag1 == 0 and flag2 == 0:flag = 0if state_position[0] > 1080 or state_position[0] < 0 or state_position[1] > 810 or state_position[1] < 0:flag = 1return flagdef find(self,state_position):flag=0if abs(state_position[0]-self.bird_female_init_position[0])<self.limit_distance_x and abs(state_position[1]-self.bird_female_init_position[1])<self.limit_distance_y:flag=1return flagdef state_to_position(self, state):i = int(state / 10)j = state % 10position = [0, 0]position[0] = 120 * jposition[1] = 90 * ireturn positiondef position_to_state(self, position):i = position[0] / 120j = position[1] / 90return int(i + 10 * j)def reset(self):#随机产生初始状态flag1=1flag2=1while flag1 or flag2 ==1:#随机产生初始状态,0~99,randoom.random() 产生一个0~1的随机数state=self.states[int(random.random()*len(self.states))]state_position = self.state_to_position(state)flag1 = self.collide(state_position)flag2 = self.find(state_position)return statedef transform(self,state, action):#将当前状态转化为坐标current_position=self.state_to_position(state)next_position = [0,0]flag_collide=0flag_find=0#判断当前坐标是否与障碍物碰撞flag_collide=self.collide(current_position)#判断状态是否是终点flag_find=self.find(current_position)if flag_collide==1:return state, -10, Trueif flag_find == 1:return state, 10, True#状态转移if action=='e':next_position[0]=current_position[0]+120next_position[1]=current_position[1]if action=='s':next_position[0]=current_position[0]next_position[1]=current_position[1]+90if action=='w':next_position[0] = current_position[0] - 120next_position[1] = current_position[1]if action=='n':next_position[0] = current_position[0]next_position[1] = current_position[1] - 90#判断next_state是否与障碍物碰撞flag_collide = self.collide(next_position)#如果碰撞,那么回报为-10,并结束if flag_collide==1:return self.position_to_state(current_position),-10,True#判断是否终点flag_find = self.find(next_position)if flag_find==1:return self.position_to_state(next_position),10,Truereturn self.position_to_state(next_position), -0.1, Falsedef gameover(self):for event in pygame.event.get():if event.type == QUIT:exit()def render(self):if self.viewer is None:pygame.init()#画一个窗口self.viewer=pygame.display.set_mode(self.screen_size,0,32)pygame.display.set_caption("yuanyang")#下载图片self.bird_male = load_bird_male()self.bird_female = load_bird_female()self.background = load_background()self.obstacle = load_obstacle()#self.viewer.blit(self.bird_male, self.bird_male_init_position)#在幕布上画图片self.viewer.blit(self.bird_female, self.bird_female_init_position)self.viewer.blit(self.background, (0, 0))self.font = pygame.font.SysFont('times', 15)self.viewer.blit(self.background,(0,0))#画直线for i in range(11):pygame.draw.lines(self.viewer, (255, 255, 255), True, ((120*i, 0), (120*i, 900)), 1)pygame.draw.lines(self.viewer, (255, 255, 255), True, ((0, 90* i), (1200, 90 * i)), 1)self.viewer.blit(self.bird_female, self.bird_female_init_position)#画障碍物for i in range(8):self.viewer.blit(self.obstacle, (self.obstacle1_x[i], self.obstacle1_y[i]))self.viewer.blit(self.obstacle, (self.obstacle2_x[i], self.obstacle2_y[i]))#画小鸟self.viewer.blit(self.bird_male,  self.bird_male_position)# 画动作值函数for i in range(100):y = int(i / 10)x = i % 10#往东行为值函数surface = self.font.render(str(round(float(self.action_value[i,0]), 2)), True, (0, 0, 0))self.viewer.blit(surface, (120 * x + 80, 90 * y + 45))#往南的值函数surface = self.font.render(str(round(float(self.action_value[i, 1]), 2)), True, (0, 0, 0))self.viewer.blit(surface, (120 * x + 50, 90 * y + 70))# 往西的值函数surface = self.font.render(str(round(float(self.action_value[i, 2]), 2)), True, (0, 0, 0))self.viewer.blit(surface, (120 * x + 10, 90 * y + 45))# 往北的值函数surface = self.font.render(str(round(float(self.action_value[i, 3]), 2)), True, (0, 0, 0))self.viewer.blit(surface, (120 * x + 50, 90 * y + 10))# 画路径点for i in range(len(self.path)):rec_position = self.state_to_position(self.path[i])pygame.draw.rect(self.viewer, [255, 0, 0], [rec_position[0], rec_position[1], 120, 90], 3)surface = self.font.render(str(i), True, (255, 0, 0))self.viewer.blit(surface, (rec_position[0] + 5, rec_position[1] + 5))pygame.display.update()self.gameover()# time.sleep(0.1)self.FPSCLOCK.tick(30)
if __name__=="__main__":yy=YuanYangEnv()yy.render()while True:for event in pygame.event.get():if event.type == QUIT:exit()# speed = 50# clock = pygame.time.Clock()# state=0# for i in range(12):#     flag_collide = 0#     obstacle1_coord = [yy.obstacle1_x[i],yy.obstacle1_y[i]]#     obstacle2_coord = [yy.obstacle2_x[i],yy.obstacle2_y[i]]#     flag_collide = yy.collide(obstacle1_coord)#     print(flag_collide)#     print(yy.collide(obstacle2_coord))# time_passed_second = clock.tick()/1000# i= int(state/10)# j=state%10# yy.bird_male_position[0]=j*40# yy.bird_male_position[1]=i*30# time.sleep(0.2)# pygame.display.update()# state+=1# yy.render()
#        print(yy.collide())

TD_RL.py

import numpy as np
import random
import os
import pygame
import time
import matplotlib.pyplot as plt
from yuanyang_env_td import *
from yuanyang_env_td import YuanYangEnvclass TD_RL:def __init__(self, yuanyang):self.gamma = yuanyang.gammaself.yuanyang = yuanyang#值函数的初始值self.qvalue=np.zeros((len(self.yuanyang.states),len(self.yuanyang.actions)))#定义贪婪策略def greedy_policy(self, qfun, state):amax=qfun[state,:].argmax()return self.yuanyang.actions[amax]#定义epsilon贪婪策略def epsilon_greedy_policy(self, qfun, state, epsilon):amax = qfun[state, :].argmax()# 概率部分if np.random.uniform() < 1 - epsilon:# 最优动作return self.yuanyang.actions[amax]else:return self.yuanyang.actions[int(random.random() * len(self.yuanyang.actions))]#找到动作所对应的序号def find_anum(self,a):for i in range(len(self.yuanyang.actions)):if a==self.yuanyang.actions[i]:return idef sarsa(self, num_iter, alpha, epsilon):iter_num = []self.qvalue = np.zeros((len(self.yuanyang.states),len(self.yuanyang.actions)))#第一个大循环,产生了多少次实验for iter in range(num_iter):#随机初始化状态epsilon = epsilon*0.99s_sample = []#初始状态,s0,# s = self.yuanyang.reset()s = 0flag = self.greedy_test()if flag == 1:iter_num.append(iter)if len(iter_num)<2:print("sarsa 第一次完成任务需要的迭代次数为:", iter_num[0])if flag == 2:print("sarsa 第一次实现最短路径需要的迭代次数为:", iter)break#随机选初始动作# a = self.yuanyang.actions[int(random.random()*len(self.yuanyang.actions))]a = self.epsilon_greedy_policy(self.qvalue, s, epsilon)t = Falsecount = 0#第二个循环,一个实验,s0-s1-s2-s1-s2-s_terminatewhile False==t and count < 30:#与环境交互得到下一个状态s_next, r, t = self.yuanyang.transform(s, a)a_num = self.find_anum(a)if s_next in s_sample:r = -2s_sample.append(s)#判断一下 是否是终止状态if t == True:q_target = relse:# 下一个状态处的最大动作,这个地方体现on-policya1 = self.epsilon_greedy_policy(self.qvalue, s_next, epsilon)a1_num = self.find_anum(a1)# qlearning的更新公式q_target = r + self.gamma * self.qvalue[s_next, a1_num]# 利用td方法更新动作值函数,alphaself.qvalue[s, a_num] = self.qvalue[s, a_num] + alpha * (q_target - self.qvalue[s, a_num])# 转到下一个状态s = s_next#行为策略a = self.epsilon_greedy_policy(self.qvalue, s, epsilon)count += 1return self.qvaluedef qlearning(self,num_iter, alpha, epsilon):iter_num = []self.qvalue = np.zeros((len(self.yuanyang.states), len(self.yuanyang.actions)))#大循环for iter in range(num_iter):#随机初始化状态# s = yuanyang.reset()s=0flag = self.greedy_test()if flag == 1:iter_num.append(iter)if len(iter_num)<2:print("qlearning 第一次完成任务需要的迭代次数为:", iter_num[0])if flag == 2:print("qlearning 第一次实现最短路径需要的迭代次数为:", iter)breaks_sample = []#随机选初始动作# a = self.actions[int(random.random()*len(self.actions))]a = self.epsilon_greedy_policy(self.qvalue,s,epsilon)t = Falsecount = 0while False==t and count < 30:#与环境交互得到下一个状态s_next, r, t = yuanyang.transform(s, a)# print(s)# print(s_next)a_num = self.find_anum(a)if s_next in s_sample:r = -2s_sample.append(s)if t == True:q_target = relse:# 下一个状态处的最大动作,a1用greedy_policya1 = self.greedy_policy(self.qvalue, s_next)a1_num = self.find_anum(a1)# qlearning的更新公式TD(0)q_target = r + self.gamma * self.qvalue[s_next, a1_num]# 利用td方法更新动作值函数self.qvalue[s, a_num] = self.qvalue[s, a_num] + alpha * (q_target - self.qvalue[s, a_num])s = s_next#行为策略a = self.epsilon_greedy_policy(self.qvalue, s, epsilon)count += 1# print(r)return self.qvaluedef greedy_test(self):s = 0s_sample = []done = Falseflag = 0step_num = 0while False == done and step_num < 30:a = self.greedy_policy(self.qvalue, s)# 与环境交互s_next, r, done = self.yuanyang.transform(s, a)s_sample.append(s)s = s_nextstep_num += 1if s == 9:flag = 1if s == 9 and step_num<21:flag = 2return flagif __name__=="__main__":yuanyang = YuanYangEnv()brain = TD_RL(yuanyang)# qvalue1 = brain.sarsa(num_iter =5000, alpha = 0.1, epsilon = 0.8)qvalue2=brain.qlearning(num_iter=10000, alpha=0.1, epsilon=0.1)#打印学到的值函数yuanyang.action_value = qvalue2########################################### 测试学到的策略flag = 1s = 0# print(policy_value.pi)step_num = 0path = []# 将最优路径打印出来while flag:# 渲染路径点path.append(s)yuanyang.path = patha = brain.greedy_policy(qvalue2, s)# a = agent.bolzman_policy(qvalue,s,0.1)print('%d->%s\t' % (s, a), qvalue2[s, 0], qvalue2[s, 1], qvalue2[s, 2], qvalue2[s, 3])yuanyang.bird_male_position = yuanyang.state_to_position(s)yuanyang.render()time.sleep(0.25)step_num += 1s_, r, t = yuanyang.transform(s, a)if t == True or step_num > 30:flag = 0s = s_# 渲染最后的路径点yuanyang.bird_male_position = yuanyang.state_to_position(s)path.append(s)yuanyang.render()while True:yuanyang.render()

load.py和背景图片参考前几章。

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

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

相关文章

探索“搭旅万物皆可搭”小程序——构建旅行搭伴平台的创新实践

摘要 随着旅游市场的不断发展和个性化需求的日益增长&#xff0c;旅行搭伴平台逐渐成为连接志同道合旅者的桥梁。本文旨在介绍“搭旅万物皆可搭”小程序的设计理念、核心功能及其背后的技术实现&#xff0c;探讨如何通过算法优化、安全保障、社交互动等手段&#xff0c;打造一…

GUI界面开发之tkinter(一)

Tkinter是一个内置的Python库&#xff0c;用于创建图形用户界面&#xff08;GUI&#xff09;。它提供了一组工具和小部件&#xff0c;用于创建窗口、对话框、按钮、菜单和其他GUI元素。 在本篇文章中&#xff0c;主要介绍了窗口等知识点。 大家好&#xff01;我是码银&#x1…

《昇思25天学习打卡营第22天|onereal》

文本解码原理--以MindNLP为例 回顾&#xff1a;自回归语言模型 根据前文预测下一个单词 一个文本序列的概率分布可以分解为每个词基于其上文的条件概率的乘积 &#x1d44a;_0:初始上下文单词序列&#x1d447;: 时间步当生成EOS标签时&#xff0c;停止生成。 MindNLP/huggi…

MySQL 时区问题:设置了 my.ini 并重启了服务,依旧是 0 时区

1、问题再现 在撰写 飞书 API 2-5 时&#xff0c;需要新建一些数据表&#xff0c;以便实施从数据库到多维表的数据同步。我建了2个测试数据表&#xff0c;连表查询之后&#xff0c;将时间戳转为时间格式返回&#xff0c;结果发现少了 8 小时。 具体逻辑抽象为以下&#xff0c…

S7-1200PLC 2轴直线插补(详细方案对比)

1、V90速度轴应用 速度轴V90PN总线伺服梯形加减速速度控制(标准报文1应用)_v90伺服加减速时间怎么调整-CSDN博客文章浏览阅读288次。SMART PLC斜坡函数SMART PLC斜坡函数功能块(梯形图代码)_RXXW_Dor的博客-CSDN博客斜坡函数Ramp的具体应用可以参看下面的文章链接:PID优化系…

数据库-MySQL 实战项目——书店图书进销存管理系统数据库设计与实现(附源码)

一、前言 该项目非常适合MySQL入门学习的小伙伴&#xff0c;博主提供了源码、数据和一些查询语句&#xff0c;供大家学习和参考&#xff0c;代码和表设计有什么不恰当还请各位大佬多多指点。 所需环境 MySQL可视化工具&#xff1a;navicat&#xff1b; 数据库&#xff1a;MySq…

[笔记] SEW的振动分析工具DUV40A

1.便携式振动分析仪 DUV40A 文档编号&#xff1a;26871998/EN SEW是一家国际化的大型的机械设备供应商。产品线涵盖电机&#xff0c;减速机&#xff0c;变频器等全系列动力设备。DUV40A是他自己设计的一款振动分析工具。 我们先看一下它的软硬件参数&#xff1a; 内置两路传…

防火墙综合实验之NAT和智能选路

目录 前言&#xff1a; 一、实验题目 二、实验操作 需求一 需求二 需求三 需求四、需求五 需求六 需求七 ​编辑 需求八 需求九 需求十 需求十一 三、需求测试 前言&#xff1a; 本篇文章是延续上一篇文章&#xff0c;简单来说就是防火墙实验的完善和延续&#…

CV07_深度学习模块之间的缝合教学(2)--维度转换

教学&#xff08;1&#xff09;&#xff1a;链接 1.1 预备知识 问题&#xff1a;假如说我们使用的模型张量是三维的&#xff0c;但是我们要缝合的模块是四维的&#xff0c;应该怎么办&#xff1f; 方法&#xff1a;pytorch中常用的函数&#xff1a;(1)view函数&#xff08;2…

新华三H3CNE网络工程师认证—DHCP使用场景

网络服务与应用当中的技术有DHCP、Telnet和FTP。DHCP是计算机当中常用来获取地址的。比如日常使用中&#xff0c;计算机并没有接入IP&#xff0c;IP通过DHCP技术从上端服务去获取的。手动配置网络参数会出现多种问题。 文章目录 一、手动配置网络参数的问题1、参数多、理解难2、…

【零基础】学JS之APIS第四天

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

喰星云·数字化餐饮服务系统 多处 SQL注入漏洞复现

0x01 产品简介 喰星云数字化餐饮服务系统是一款专为餐饮企业设计的综合性管理软件,旨在通过信息化手段提升餐饮企业的运营效率、降低运营成本,并实现数据驱动的决策管理。该系统包括供应链管理、财务管理、巡店管理、人力资源管理等多个模块,可全面覆盖餐饮企业的日常运营需…

Zynq7000系列FPGA中的DDR内存控制器

DDR内存控制器是一个高度集成的组件&#xff0c;支持多种DDR内存类型&#xff08;DDR2、DDR3、DDR3L、LPDDR2&#xff09;&#xff0c;并通过精心设计的架构来优化内存访问效率。 DDR内存控制器架构 AXI内存端口接口&#xff08;DDRI&#xff09;&#xff1a;该部分负责处理与…

雷赛运动控制卡编程(2)限位设定与回原方式、脉冲模式设置

一、限位开关及急停开关的设置 限位开关的设置 //设置限位开关// dmc_set_el_modeushort _cardNo0;ushort _axisNo 0;ushort _enable 1; // 正负限位使能 ushort _elLogic 0; // 正负限位 低电平 有效ushort _model 0;// 正负限位停止方式为立即停止LTDMC.dmc_set_el_m…

构建实用的NLP应用程序:重塑人类与计算机的协同工作方式

文章目录 一、NLP技术的核心价值二、构建实用NLP应用程序的关键步骤三、NLP应用程序在协同工作中的创新应用《赠ChatGPT中文范例的自然语言处理入门书》编辑推荐内容简介作者简介精彩书评目录前言/序言获取方式 在数字化时代&#xff0c;自然语言处理&#xff08;NLP&#xff0…

手机数据恢复:适用于 Android 的 4 大数据恢复应用程序

没有人希望丢失设备上的重要数据。如果发生这种情况&#xff0c;请不要惊慌。以下是可帮助您恢复丢失或删除的数据的 Android 数据恢复应用程序列表。 有多种方法可以恢复已删除或丢失的 Android 数据&#xff0c;最简单、最快捷的方法是使用第三方恢复应用程序。这些应用程序会…

Transformer模型:Postion Embedding实现

前言 这是对上一篇WordEmbedding的续篇PositionEmbedding。 视频链接&#xff1a;19、Transformer模型Encoder原理精讲及其PyTorch逐行实现_哔哩哔哩_bilibili 上一篇链接&#xff1a;Transformer模型&#xff1a;WordEmbedding实现-CSDN博客 正文 先回顾一下原论文中对Posit…

[Windows] 号称最快免费小巧的远程桌面 AnyDesk v8.0.11单文件版

描述 对于经常在互联网上进行操作的学生&#xff0c;白领等&#xff01; 一款好用的软件总是能得心应手&#xff0c;事半功倍。 今天给大家带了一款高科技软件 虽然 QQ 拥有远程协助功能&#xff0c;但很多时候连接并不够流畅&#xff0c;而且被控电脑那方也必须要有人操作才行…

电脑关机被阻止

1. winR输入regedit进入注册表 2. 选择HKEY_USERS-》.DEFAULT-》Control Panel-》Desktop 3. 右键DeskTop新建字符串值&#xff0c;命名为AutoEndTasks&#xff0c;数值设置为1

C++中链表的底层迭代器实现

大家都知道在C的学习中迭代器是必不可少的&#xff0c;今天我们学习的是C中的链表的底层迭代器的实现&#xff0c;首先我们应该先知道链表的底层迭代器和顺序表的底层迭代器在实现上有什么区别&#xff0c;为什么顺序表的底层迭代器更加容易实现&#xff0c;而链表的底层迭代器…