当前位置: 首页 > 编程日记 > 正文

Python 还能实现哪些 AI 游戏?附上代码一起来一把!

作者 | 李秋键

责编 | Carol

头图 | CSDN 付费下载自视觉中国

人工智能作为当前热门在我们生活中得到了广泛应用,尤其是在智能游戏方面,有的已经达到了可以和职业选手匹敌的效果。而DQN算法作为智能游戏的经典选择算法,其主要是通过奖励惩罚机制来迭代模型,来达到更接近于人类学习的效果。

那在强化学习中, 神经网络是如何被训练的呢? 首先, 我们需要 a1, a2 正确的Q值, 这个 Q 值我们就用之前在 Q learning 中的 Q 现实来代替. 同样我们还需要一个Q估计来实现神经网络的更新. 所以神经网络的的参数就是老的NN参数加学习率 alpha乘以Q现实和Q估计的差距。

我们通过 NN 预测出Q(s2, a1) 和 Q(s2,a2) 的值, 这就是 Q 估计. 然后我们选取 Q 估计中最大值的动作来换取环境中的奖励 reward. 而 Q 现实中也包含从神经网络分析出来的两个 Q 估计值, 不过这个 Q 估计是针对于下一步在 s’ 的估计. 最后再通过刚刚所说的算法更新神经网络中的参数.

DQN是第一个将深度学习模型与强化学习结合在一起从而成功地直接从高维的输入学习控制策略。

  • 创新点:

基于Q-Learning构造Loss Function(不算很新,过往使用线性和非线性函数拟合Q-Table时就是这样做)。

通过experience replay(经验池)解决相关性及非静态分布问题;

使用TargetNet解决稳定性问题。

  • 优点:

算法通用性,可玩不同游戏;

End-to-End 训练方式;

可生产大量样本供监督学习。

  • 缺点:

无法应用于连续动作控制;

只能处理只需短时记忆问题,无法处理需长时记忆问题(后续研究提出了使用LSTM等改进方法);

CNN不一定收敛,需精良调参。

整体的程序效果如下:

实验前的准备

首先我们使用的python版本是3.6.5所用到的库有cv2库用来图像处理;

Numpy库用来矩阵运算;TensorFlow框架用来训练和加载模型。Collection库用于高性能的数据结构。

程序的搭建

1、游戏结构设定:

我们在DQN训练前需要有自己设定好的程序,即在这里为弹珠游戏。在游戏整体框架搭建完成后,对于计算机的决策方式我们需要给他一个初始化的决策算法为了达到更快的训练效果。

程序结构的部分代码如下:

def __init__(self):self.__initGame()# 初始化一些变量self.loseReward = -1self.winReward = 1self.hitReward = 0self.paddleSpeed = 15self.ballSpeed = (7, 7)self.paddle_1_score = 0self.paddle_2_score = 0self.paddle_1_speed = 0.self.paddle_2_speed = 0.self.__reset()'''更新一帧action: [keep, up, down]'''
#     更新ball的位置self.ball_pos = self.ball_pos[0] + self.ballSpeed[0], self.ball_pos[1] + self.ballSpeed[1]# 获取当前场景(只取左半边)image = pygame.surfarray.array3d(pygame.display.get_surface())# image = image[321:, :]pygame.display.update()terminal = Falseif max(self.paddle_1_score, self.paddle_2_score) >= 20:self.paddle_1_score = 0self.paddle_2_score = 0terminal = Truereturn image, reward, terminal
def update_frame(self, action):assert len(action) == 3pygame.event.pump()reward = 0# 绑定一些对象self.score1Render = self.font.render(str(self.paddle_1_score), True, (255, 255, 255))self.score2Render = self.font.render(str(self.paddle_2_score), True, (255, 255, 255))self.screen.blit(self.background, (0, 0))pygame.draw.rect(self.screen, (255, 255, 255), pygame.Rect((5, 5), (630, 470)), 2)pygame.draw.aaline(self.screen, (255, 255, 255), (320, 5), (320, 475))self.screen.blit(self.paddle_1, self.paddle_1_pos)self.screen.blit(self.paddle_2, self.paddle_2_pos)self.screen.blit(self.ball, self.ball_pos)self.screen.blit(self.score1Render, (240, 210))self.screen.blit(self.score2Render, (370, 210))
'''游戏初始化'''def __initGame(self):pygame.init()self.screen = pygame.display.set_mode((640, 480), 0, 32)self.background = pygame.Surface((640, 480)).convert()self.background.fill((0, 0, 0))self.paddle_1 = pygame.Surface((10, 50)).convert()self.paddle_1.fill((0, 255, 255))self.paddle_2 = pygame.Surface((10, 50)).convert()self.paddle_2.fill((255, 255, 0))ball_surface = pygame.Surface((15, 15))pygame.draw.circle(ball_surface, (255, 255, 255), (7, 7), (7))self.ball = ball_surface.convert()self.ball.set_colorkey((0, 0, 0))self.font = pygame.font.SysFont("calibri", 40)'''重置球和球拍的位置'''def __reset(self):self.paddle_1_pos = (10., 215.)self.paddle_2_pos = (620., 215.)self.ball_pos = (312.5, 232.5)

2、行动决策机制:

首先在程序框架中设定不同的行动作为训练对象

# 行动paddle_1(训练对象)
if action[0] == 1:self.paddle_1_speed = 0
elif action[1] == 1:self.paddle_1_speed = -self.paddleSpeed
elif action[2] == 1:self.paddle_1_speed = self.paddleSpeed
self.paddle_1_pos = self.paddle_1_pos[0], max(min(self.paddle_1_speed + self.paddle_1_pos[1], 420), 10)

接着设置一个简单的初始化决策。根据结果判断奖励和惩罚机制,即球撞到拍上奖励,撞到墙上等等惩罚:

其中代码如下:

# 行动paddle_2(设置一个简单的算法使paddle_2的表现较优, 非训练对象)if self.ball_pos[0] >= 305.:if not self.paddle_2_pos[1] == self.ball_pos[1] + 7.5:if self.paddle_2_pos[1] < self.ball_pos[1] + 7.5:self.paddle_2_speed = self.paddleSpeedself.paddle_2_pos = self.paddle_2_pos[0], max(min(self.paddle_2_pos[1] + self.paddle_2_speed, 420), 10)if self.paddle_2_pos[1] > self.ball_pos[1] - 42.5:self.paddle_2_speed = -self.paddleSpeedself.paddle_2_pos = self.paddle_2_pos[0], max(min(self.paddle_2_pos[1] + self.paddle_2_speed, 420), 10)else:self.paddle_2_pos = self.paddle_2_pos[0], max(min(self.paddle_2_pos[1] + 7.5, 420), 10)# 行动ball#   球撞拍上if self.ball_pos[0] <= self.paddle_1_pos[0] + 10.:if self.ball_pos[1] + 7.5 >= self.paddle_1_pos[1] and self.ball_pos[1] <= self.paddle_1_pos[1] + 42.5:self.ball_pos = 20., self.ball_pos[1]self.ballSpeed = -self.ballSpeed[0], self.ballSpeed[1]reward = self.hitRewardif self.ball_pos[0] + 15 >= self.paddle_2_pos[0]:if self.ball_pos[1] + 7.5 >= self.paddle_2_pos[1] and self.ball_pos[1] <= self.paddle_2_pos[1] + 42.5:self.ball_pos = 605., self.ball_pos[1]self.ballSpeed = -self.ballSpeed[0], self.ballSpeed[1]#   拍未接到球(另外一个拍得分)if self.ball_pos[0] < 5.:self.paddle_2_score += 1reward = self.loseRewardself.__reset()elif self.ball_pos[0] > 620.:self.paddle_1_score += 1reward = self.winRewardself.__reset()#   球撞墙上if self.ball_pos[1] <= 10.:self.ballSpeed = self.ballSpeed[0], -self.ballSpeed[1]self.ball_pos = self.ball_pos[0], 10elif self.ball_pos[1] >= 455:self.ballSpeed = self.ballSpeed[0], -self.ballSpeed[1]self.ball_pos = self.ball_pos[0], 455

3、DQN算法搭建:

为了方便整体算法的调用,我们首先定义神经网络的函数,包括卷积层损失等函数定义具体如下可见:

'''获得初始化weight权重'''def init_weight_variable(self, shape):return tf.Variable(tf.truncated_normal(shape, stddev=0.01))'''获得初始化bias权重'''def init_bias_variable(self, shape):return tf.Variable(tf.constant(0.01, shape=shape))'''卷积层'''def conv2D(self, x, W, stride):return tf.nn.conv2d(x, W, strides=[1, stride, stride, 1], padding="SAME")'''池化层'''def maxpool(self, x):return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')'''计算损失'''def compute_loss(self, q_values, action_now, target_q_values):tmp = tf.reduce_sum(tf.multiply(q_values, action_now), reduction_indices=1)loss = tf.reduce_mean(tf.square(target_q_values - tmp))return loss'''下一帧'''def next_frame(self, action_now, scene_now, gameState):x_now, reward, terminal = gameState.update_frame(action_now)x_now = cv2.cvtColor(cv2.resize(x_now, (80, 80)), cv2.COLOR_BGR2GRAY)_, x_now = cv2.threshold(x_now, 127, 255, cv2.THRESH_BINARY)x_now = np.reshape(x_now, (80, 80, 1))scene_next = np.append(x_now, scene_now[:, :, 0:3], axis=2)return scene_next, reward, terminal'''计算target_q_values'''def compute_target_q_values(self, reward_batch, q_values_batch, minibatch):target_q_values = []for i in range(len(minibatch)):if minibatch[i][4]:target_q_values.append(reward_batch[i])else:target_q_values.append(reward_batch[i] + self.gamma * np.max(q_values_batch[i]))return target_q_values

然后定义整体的类变量DQN,分别定义初始化和训练函数,其中网络层哪里主要就是神经网络层的调用。然后在训练函数里面记录当前动作和数据加载入优化器中达到模型训练效果。

其中代码如下:

def __init__(self, options):self.options = optionsself.num_action = options['num_action']self.lr = options['lr']self.modelDir = options['modelDir']self.init_prob = options['init_prob']self.end_prob = options['end_prob']self.OBSERVE = options['OBSERVE']self.EXPLORE = options['EXPLORE']self.action_interval = options['action_interval']self.REPLAY_MEMORY = options['REPLAY_MEMORY']self.gamma = options['gamma']self.batch_size = options['batch_size']self.save_interval = options['save_interval']self.logfile = options['logfile']self.is_train = options['is_train']'''训练网络'''def train(self, session):x, q_values_ph = self.create_network()action_now_ph = tf.placeholder('float', [None, self.num_action])target_q_values_ph = tf.placeholder('float', [None])# 计算lossloss = self.compute_loss(q_values_ph, action_now_ph, target_q_values_ph)# 优化目标trainStep = tf.train.AdamOptimizer(self.lr).minimize(loss)# 游戏gameState = PongGame()# 用于记录数据dataDeque = deque()# 当前的动作action_now = np.zeros(self.num_action)action_now[0] = 1# 初始化游戏状态x_now, reward, terminal = gameState.update_frame(action_now)x_now = cv2.cvtColor(cv2.resize(x_now, (80, 80)), cv2.COLOR_BGR2GRAY)_, x_now = cv2.threshold(x_now, 127, 255, cv2.THRESH_BINARY)scene_now = np.stack((x_now, )*4, axis=2)# 读取和保存checkpointsaver = tf.train.Saver()session.run(tf.global_variables_initializer())checkpoint = tf.train.get_checkpoint_state(self.modelDir)if checkpoint and checkpoint.model_checkpoint_path:saver.restore(session, checkpoint.model_checkpoint_path)print('[INFO]: Load %s successfully...' % checkpoint.model_checkpoint_path)else:print('[INFO]: No weights found, start to train a new model...')prob = self.init_probnum_frame = 0logF = open(self.logfile, 'a')while True:q_values = q_values_ph.eval(feed_dict={x: [scene_now]})action_idx = get_action_idx(q_values=q_values, prob=prob, num_frame=num_frame, OBSERVE=self.OBSERVE, num_action=self.num_action)action_now = np.zeros(self.num_action)action_now[action_idx] = 1prob = down_prob(prob=prob, num_frame=num_frame, OBSERVE=self.OBSERVE, EXPLORE=self.EXPLORE, init_prob=self.init_prob, end_prob=self.end_prob)for _ in range(self.action_interval):scene_next, reward, terminal = self.next_frame(action_now=action_now, scene_now=scene_now,                                                            gameState=gameState)scene_now = scene_nextdataDeque.append((scene_now, action_now, reward, scene_next, terminal))if len(dataDeque) > self.REPLAY_MEMORY:dataDeque.popleft()loss_now = Noneif (num_frame > self.OBSERVE):minibatch = random.sample(dataDeque, self.batch_size)scene_now_batch = [mb[0] for mb in minibatch]action_batch = [mb[1] for mb in minibatch]reward_batch = [mb[2] for mb in minibatch]scene_next_batch = [mb[3] for mb in minibatch]q_values_batch = q_values_ph.eval(feed_dict={x: scene_next_batch})target_q_values = self.compute_target_q_values(reward_batch, q_values_batch, minibatch)trainStep.run(feed_dict={target_q_values_ph: target_q_values,action_now_ph: action_batch,x: scene_now_batch})loss_now = session.run(loss, feed_dict={target_q_values_ph: target_q_values,action_now_ph: action_batch,x: scene_now_batch})num_frame += 1if num_frame % self.save_interval == 0:name = 'DQN_Pong'saver.save(session, os.path.join(self.modelDir, name), global_step=num_frame)log_content = '<Frame>: %s, <Prob>: %s, <Action>: %s, <Reward>: %s, <Q_max>: %s, <Loss>: %s' % (str(num_frame), str(prob), str(action_idx), str(reward), str(np.max(q_values)), str(loss_now))logF.write(log_content + '\n')print(log_content)logF.close()'''创建网络'''def create_network(self):'''W_conv1 = self.init_weight_variable([9, 9, 4, 16])b_conv1 = self.init_bias_variable([16])W_conv2 = self.init_weight_variable([7, 7, 16, 32])b_conv2 = self.init_bias_variable([32])W_conv3 = self.init_weight_variable([5, 5, 32, 32])b_conv3 = self.init_bias_variable([32])W_conv4 = self.init_weight_variable([5, 5, 32, 64])b_conv4 = self.init_bias_variable([64])W_conv5 = self.init_weight_variable([3, 3, 64, 64])b_conv5 = self.init_bias_variable([64])'''W_conv1 = self.init_weight_variable([8, 8, 4, 32])b_conv1 = self.init_bias_variable([32])W_conv2 = self.init_weight_variable([4, 4, 32, 64])b_conv2 = self.init_bias_variable([64])W_conv3 = self.init_weight_variable([3, 3, 64, 64])b_conv3 = self.init_bias_variable([64])# 5 * 5 * 64 = 1600W_fc1 = self.init_weight_variable([1600, 512])b_fc1 = self.init_bias_variable([512])W_fc2 = self.init_weight_variable([512, self.num_action])b_fc2 = self.init_bias_variable([self.num_action])# input placeholderx = tf.placeholder('float', [None, 80, 80, 4])'''conv1 = tf.nn.relu(tf.layers.batch_normalization(self.conv2D(x, W_conv1, 4) + b_conv1, training=self.is_train, momentum=0.9))conv2 = tf.nn.relu(tf.layers.batch_normalization(self.conv2D(conv1, W_conv2, 2) + b_conv2, training=self.is_train, momentum=0.9))conv3 = tf.nn.relu(tf.layers.batch_normalization(self.conv2D(conv2, W_conv3, 2) + b_conv3, training=self.is_train, momentum=0.9))conv4 = tf.nn.relu(tf.layers.batch_normalization(self.conv2D(conv3, W_conv4, 1) + b_conv4, training=self.is_train, momentum=0.9))conv5 = tf.nn.relu(tf.layers.batch_normalization(self.conv2D(conv4, W_conv5, 1) + b_conv5, training=self.is_train, momentum=0.9))flatten = tf.reshape(conv5, [-1, 1600])'''conv1 = tf.nn.relu(self.conv2D(x, W_conv1, 4) + b_conv1)pool1 = self.maxpool(conv1)conv2 = tf.nn.relu(self.conv2D(pool1, W_conv2, 2) + b_conv2)conv3 = tf.nn.relu(self.conv2D(conv2, W_conv3, 1) + b_conv3)flatten = tf.reshape(conv3, [-1, 1600])fc1 = tf.nn.relu(tf.layers.batch_normalization(tf.matmul(flatten, W_fc1) + b_fc1, training=self.is_train, momentum=0.9))fc2 = tf.matmul(fc1, W_fc2) + b_fc2return x, fc2

到这里,我们整体的程序就搭建完成,下面为我们程序的运行结果:

源码地址:

https://pan.baidu.com/s/1ksvjIiQ0BfXOah4PIE1arg

提取码:p74p

作者简介:

李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等等。

推荐阅读
  • 利用 AssemblyAI 在 PyTorch 中建立端到端的语音识别模型

  • 京东姚霆:推理能力,正是多模态技术未来亟需突破的瓶颈

  • 性能超越最新序列推荐模型,华为诺亚方舟提出记忆增强的图神经网络

  • FPGA 无解漏洞 “StarBleed”轰动一时,今天来扒一下技术细节!

  • 真惨!连各大编程语言都摆起地摊了

  • 发送0.55 ETH花费近260万美元!这笔神秘交易引发大猜想

你点的每个“在看”,我都认真当成了AI

相关文章:

一起谈.NET技术,专访微软MVP衣明志:走进ASP.NET MVC 2框架开发

日前微软已经发布ASP.NET MVC 2框架RC版&#xff0c;究竟这次RC版本的发布对于WEB开发者带来怎样的改变&#xff1f;以及未来ASP.NET MVC 2正式版还会有哪些改进&#xff1f;带着这样的问题&#xff0c;我们51CTO记者彭凡专门采访了微软MVP衣明志老师。ASP.NET MVC是微软官方提…

Entity Framework:Code-First Tutorial开篇

这个系列文章是关于Entity Framework Code-First的英文系列文章&#xff0c;内容不错&#xff0c;每篇一个主题知识点介绍&#xff0c;特转载过来 原文地址&#xff1a;http://www.entityframeworktutorial.net/code-first/entity-framework-code-first.aspx转载于:https://www…

Android开发者指南(22) —— Accessing Resources

前言   本章内容为Android开发者指南的Framework Topics/Application Resources/Accessing Resources章节&#xff0c;译为"资源调用"&#xff0c;版本为Android 3.2 r1&#xff0c;翻译来自&#xff1a;"CodeGuy"&#xff0c;欢迎访问他的博客&#xff…

如何快速实现HTML编辑器.NET组件

作者&#xff1a;未知 请作者速与本人联系得到“素材”首先我们需要得到一个HTML编辑器的原始代码&#xff0c;网上有不少这类的编辑器&#xff0c;如大名鼎鼎的RichTextBox&#xff0c;为了避免版权纠纷&#xff0c;以我所做得为例&#xff08;暂名&#xff1a;UltraTextBox…

罗永浩力荐,丁磊豪送的学习神器:手机查词真不如这支AI词典笔?

销量确实称得上火爆。尽管999元的直播优惠价价格并不低&#xff0c;但这支有道词典笔专业版在快手直播间还是经历了返场&#xff0c;最终20000多台一抢而空。 为这款产品站台的正是网易CEO丁磊&#xff0c;6月11日是他网上卖货的首秀&#xff0c;不过更重要的是&#xff0c;那天…

Thinking in java中关于Exception的一道面试题.

今天看到Thinking in Java中一个关于Exception的例子:最后看到有一篇总结的比较好的文章, 这里拿来记录下, 文章地址是:http://blog.csdn.net/salerzhang/article/details/46581457 感谢原作者. 1 class Annoyance extends Exception {}2 class Sneeze extends Annoyance {}3 …

使用 .NET 框架轻松开发完美的 Web 窗体控件

作者&#xff1a;David S. Platt 出自&#xff1a;微软 本文假定您熟悉 Visual Basic .NET、C# 和 HTML 下载本文的代码&#xff1a; WebC.exe (274KB) 摘要 预建的自定义控件可以简化和加快应用程序的设计&#xff0c;并使您能够维护 UI 的一致性。但是&#xff0c;预先打…

史上最强女游戏程序员

也许你听说过John Carmack 和Tim Sweeney等大牛的名字&#xff0c;而向来游戏工业都是阳盛阴衰&#xff0c;适逢国际妇女节&#xff0c;今天我为大家介绍游戏业界一位史上最强女游戏程序员&#xff1a;Corrinne Yu。 简历 以下是她在游戏业界内的简历 微软Halo团队首席引擎架构…

重磅日程公布!与百名大咖在线交流技术,2天20个AI论坛不可错过

当全球都在面向 AI 变革时&#xff0c;AI 不再是触不可及&#xff0c;它需要产业化落地&#xff0c;为社会创造价值。在这一轮技术革命、技术浪潮中&#xff0c;开发者们成为构建任何一家AI企业的核心竞争力。不过&#xff0c;不同于此前只懂开发语言、数据结构便可轻松躲过新技…

Python取出列表相应值的位置(表处理)

#需求在一个列表中&#xff0c;取出相应值的位置方法1&#xff1a;#脚本示例[rootlocalhost opt]# cat list.py #!/usr/bin/env python #_*_ coding:utf-8 _*_ name[!,#,*,Eric,wsyht,jack,jack,a,b,c,d,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,2332,4,2,6,2] first_pos 0 for …

rhel5.5安装xwindow

rhel5.5安装xwindow 1安装xwindow yum groupinstall "X Window System" 2、安装GNOME桌面环境 yum groupinstall "GNOME Desktop Environment" 3、卸载GNOME桌面环境 yum groupremove "GNOME Desktop Environment"转载于:https://blog.51cto…

使用 ASP.NET 加密口令

作者&#xff1a;未知 请作者速与本人联系当我们在网站上建立数据库时&#xff0c;保护用户的信息安全是非常必要的。多数用户不愿意让别人知道自己的信息&#xff0c;同时网管也不想因为安全问题而丢失网站的信誉。无论对于谁&#xff0c;安全问题都是非常重要的。为了解决这…

算法鼻祖高德纳,82 岁仍在写《计算机程序设计的艺术》

作者 | 年素清编辑 | 伍杏玲出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;高德纳&#xff08;Donald Ervin Knuth&#xff09;被誉为现代计算机科学的鼻祖&#xff0c;毕生致力于编译程序、属性文法和运算法则等领域的前沿研究&#xff0c;共出版专著17部&#x…

centos查看特定程序占用端口情况

ps axu |grep 程序名&#xff0c;找到特定程序的pidnetstat -nltp |grep pid即可。转载于:https://blog.51cto.com/zhukeqiang/1811735

关于页面刷新的问题

在做.net开发时&#xff0c;经常能碰到这样的情况&#xff0c;页面很长&#xff0c;而我们一般用的都是服务器端控件&#xff0c;用服务器端控件有这样一个缺点&#xff0c;就是控件每次都要和服务器交互&#xff0c;而产生页面的刷新&#xff0c;试想一下&#xff0c;如果页面…

技术直播:程序员副业的修炼指南!(限免报名)

面试造飞机&#xff0c;上班拧螺丝&#xff0c;每天想辞职&#xff0c;但无奈副业还“大器晚成”的样子&#xff01;那可能是你还没有选对副业&#xff01;滴滴 ~福利卡&#xff01;&#xff01;&#xff01;CSDN学院邀请汤小洋老师开设技术直播课《程序员副业之路-三大终极秘籍…

Linux 双网卡绑定测试

Linux 双网卡绑定测试 先介绍一下情况&#xff0c;服务器A和服务器B都是CentOS 4.6的系统&#xff0c;现在要做HA Cluster&#xff0c;为了避免裂脑的发生&#xff0c;要提高心跳链路的可靠性&#xff0c;下图是现时的连接情况&#xff0c;服务器A的eth2、eth3分别和服务器B的e…

第六章练习题和知识面扩充

作业题&#xff1a;1. 自动获取IP地址的命令是什么&#xff1f;您知道在什么情况下&#xff0c;您的Linux才可以自动获取IP地址&#xff1f;2. 远程连接Linux服务器&#xff0c;需要Linux服务器开启sshd服务&#xff0c;那么sshd服务默认监听哪个端口&#xff1f;这个端口是否可…

一文详解面向多级多模态场景的召回引擎

作者| 阿里文娱开发专家 崇懿、阿里文娱开发专家慧善责编 | 屠敏头图 | CSDN 下载自视觉中国出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;优酷视频搜索在文本搜索系统的基础上&#xff0c;不断探索视频搜索的方案&#xff0c;在多模态输入、多级多模态索引、跨模…

对比.Net PetShop和Duwamish来探讨Ado.Net的数据库编程模式

作者:卢彦.NET PetShop和Duwamish简单介绍相信大家一定听说过有名的"宠物店大战"&#xff0c;没错&#xff0c;本文的主角之一就是获胜方.NET PetShop&#xff0c;微软号称以27倍的速度和1/4的代码量遥遥领先于基于J2EE的PetStore宠物商店。虽然SUN也曾对此抱怨过不满…

如何直接将HTML代码加载到TWebBrowser

wbRecvContent//为 webbrowser控件 procedure TFrmMain.ShowHtmlCentent(slt: TStrings); var aMemory: TMemoryStream; pbuf: PAnsiChar; begin aMemory : TMemoryStream.Create(); try aMemory.Clear; slt.SaveToStream(aMemory); aMemory.Seek(0, soBeginning); wbRecvConte…

JavaScript基础(一) 数据类型

动态类型 JavaScript 是一种弱类型或者说动态语言。这意味着你不用提前声明变量的类型&#xff0c;在程序运行过程中&#xff0c;类型会被自动确定。 数据类型 最新的 ECMAScript 标准定义了 7 种数据类型: 6 种 原始类型: BooleanNullUndefinedNumberStringSymbol (ECMAScript…

DataGrid入门经典(C#)

作者&#xff1a;未知 请作者速与本人联系这篇文章主要介绍如何在DataGrid控件中实现编辑、删除、分类以及分页操作。为了实现我们的意图&#xff0c;我们使用SqlServer2000自带的NorthWind数据库。程序分为两部分&#xff1a; 1.包含HTML代码的.ASPX文件 2.包含所有逻辑及…

(札记)Altera Stratix IV系列FPGA TRUE LVDS RX input termination 在Quartus工程中的设置方法...

Altera Stratix IV系列FPGA Row bank的TRUE LVDS_RX支持oct&#xff08;on chip termination),所以设计的时候不需要外接一个100ohm电阻。备注&#xff1a;我使用的是友晶科技&#xff08;Terasic&#xff09;的DE4。 所以当我们使用到Stratix iv系列FPGA的row bank的lvds的时候…

直播:AI时代,普通程序员该如何转人工智能(限免报名)

常常有小伙伴在后台反馈&#xff1a;想了解人工智能&#xff0c;但是该怎么学&#xff1f;自学难度大又没有效果&#xff0c;该怎么办&#xff1f;CSDN为了解决这个难题&#xff0c;联合唐宇迪老师为大家带来了一场精彩的直播【年薪百万AI工程师亲授&#xff1a;小白实战培养计…

沃通免费SSL证书申请指南

我们在做一些exchange或lync项目的时候很多时候都会用到公网证书&#xff0c;比如&#xff1a;我们做exchange2013和Office 365混合部署&#xff0c;或者通过SEM暂存迁移或CEM直接转换迁移的时候都需要用到公网证书,下面为大家介绍1个免费的SSL证书及申请的方法&#xff0c;希望…

使用VS.NET2003编写存储过程

作者&#xff1a;未知 请作者速与本人联系数据表定义了如何在数据库中存储数据&#xff0c;但没有说明如何存取数据。我们还需要了解读写记录以便从表中再次调用选定行和列的详细信息。开发人员通常会在其代码中编写一些特殊的查询语句&#xff0c;用于读写数据。这不仅会导致…

谈Linux的安全设置

如今系统的安全变的越来越重要了&#xff0c;这里我想把我平时比较常使用的一些linux下的基本的安全措施写出来和大家探讨一下&#xff0c;让我们的Linux系统变得可靠。 1、BIOS的安全设置 这是最基本的了&#xff0c;也是最简单的了。一定要给你的BIOS设置密码&#…

亮风台提出用完全可训练的图匹配方法,优于最新SOTA | CVPR 2020

出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 6月14日-19日&#xff0c;CVPR 2020在线上举行&#xff0c;据了解&#xff0c;本届大会共收到6656篇投稿&#xff0c;接收论文1470篇&#xff0c;录用率约22%&#xff0c;低于ICCV 2019论文录用率&#xff08;25%&…

数组与纠结的排序篇

数组之纠结的排序 1.数组是什么&#xff1f; 数组&#xff1a;所谓数组&#xff0c;就是相同数据类型的元素按一定顺序排列的集合&#xff0c;就是把有限个类型相同的变量用一个名字命名&#xff0c;然后用编号区分他们的变量的集合&#xff0c;这个名字称为数组名&#xff0c;…