惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
S
Securelist
V
Vulnerabilities – Threatpost
C
Cyber Attacks, Cyber Crime and Cyber Security
Schneier on Security
Schneier on Security
Cyberwarzone
Cyberwarzone
Simon Willison's Weblog
Simon Willison's Weblog
Hacker News - Newest:
Hacker News - Newest: "LLM"
P
Palo Alto Networks Blog
T
Troy Hunt's Blog
SecWiki News
SecWiki News
Security Archives - TechRepublic
Security Archives - TechRepublic
T
The Blog of Author Tim Ferriss
Project Zero
Project Zero
Microsoft Security Blog
Microsoft Security Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
J
Java Code Geeks
F
Full Disclosure
阮一峰的网络日志
阮一峰的网络日志
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Attack and Defense Labs
Attack and Defense Labs
Know Your Adversary
Know Your Adversary
WordPress大学
WordPress大学
PCI Perspectives
PCI Perspectives
N
News | PayPal Newsroom
The Last Watchdog
The Last Watchdog
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Privacy & Cybersecurity Law Blog
P
Proofpoint News Feed
V
Visual Studio Blog
C
CERT Recently Published Vulnerability Notes
H
Help Net Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
云风的 BLOG
云风的 BLOG
月光博客
月光博客
T
The Exploit Database - CXSecurity.com
I
InfoQ
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
U
Unit 42
腾讯CDC
小众软件
小众软件
V2EX - 技术
V2EX - 技术
罗磊的独立博客
Cloudbric
Cloudbric
Recorded Future
Recorded Future
IT之家
IT之家
Google DeepMind News
Google DeepMind News
C
CXSECURITY Database RSS Feed - CXSecurity.com

极客兔兔

Go sync.Cond | Go 语言高性能编程 Go 死码消除与调试(debug)模式 | Go 语言高性能编程 Go sync.Once | Go 语言高性能编程 Go 逃逸分析 | Go 语言高性能编程 2020 年终总结 | 极客兔兔 Go struct 内存对齐 | Go 语言高性能编程 Go 空结构体 struct{} 的使用 | Go 语言高性能编程 控制协程(goroutine)的并发数量 | Go 语言高性能编程 | 极客兔兔 如何退出协程 goroutine (其他场景) | Go 语言高性能编程 如何退出协程 goroutine (超时场景) | Go 语言高性能编程 Go 语言陷阱 - 数组和切片 | Go 语言高性能编程 减小 Go 代码编译后的二进制体积 | Go 语言高性能编程 Go Reflect 提高反射性能 | Go 语言高性能编程 读写锁和互斥锁的性能比较 | Go 语言高性能编程 | 极客兔兔 for 和 range 的性能比较 | Go 语言高性能编程 切片(slice)性能及陷阱 | Go 语言高性能编程 | 极客兔兔 字符串拼接性能及原理 | Go 语言高性能编程 | 极客兔兔 pprof 性能分析 | Go 语言高性能编程 benchmark 基准测试 | Go 语言高性能编程 Go 语言高性能编程 | 极客兔兔 Go 接口型函数的使用场景 | 极客兔兔 Python 简明教程 | 快速入门 | 极客兔兔 Go 语言笔试面试题(代码输出) | 极客面试 | 极客兔兔 动手写RPC框架 - GeeRPC第七天 服务发现与注册中心(registry) | 极客兔兔 动手写RPC框架 - GeeRPC第六天 负载均衡(load balance) 动手写RPC框架 - GeeRPC第五天 支持HTTP协议 | 极客兔兔 动手写RPC框架 - GeeRPC第四天 超时处理(timeout) | 极客兔兔 动手写RPC框架 - GeeRPC第三天 服务注册(service register) 动手写RPC框架 - GeeRPC第二天 支持并发与异步的客户端 | 极客兔兔 动手写RPC框架 - GeeRPC第一天 服务端与消息编码 | 极客兔兔 7天用Go从零实现RPC框架GeeRPC | 极客兔兔 Go 语言笔试面试题(并发编程) | 极客面试 | 极客兔兔 Go 语言笔试面试题(基础语法) | 极客面试 | 极客兔兔 Go 语言笔试面试题汇总 | 极客面试 | 极客兔兔 Go Context 并发编程简明教程 | 快速入门 Go Mmap 文件内存映射简明教程 | 快速入门 动手写ORM框架 - GeeORM第七天 数据库迁移(Migrate) | 极客兔兔 动手写ORM框架 - GeeORM第六天 支持事务(Transaction) | 极客兔兔 动手写ORM框架 - GeeORM第五天 实现钩子(Hooks) | 极客兔兔 动手写ORM框架 - GeeORM第四天 链式操作与更新删除 | 极客兔兔 动手写ORM框架 - GeeORM第三天 记录新增和查询 | 极客兔兔 动手写ORM框架 - GeeORM第二天 对象表结构映射 | 极客兔兔 动手写ORM框架 - GeeORM第一天 database/sql 基础 SQLite 常用命令 | 速查表(Cheat Sheet) 7天用Go从零实现ORM框架GeeORM | 极客兔兔 动手写分布式缓存 - GeeCache第七天 使用 Protobuf 通信 动手写分布式缓存 - GeeCache第六天 防止缓存击穿 | 极客兔兔 动手写分布式缓存 - GeeCache第五天 分布式节点 | 极客兔兔 动手写分布式缓存 - GeeCache第四天 一致性哈希(hash) | 极客兔兔 Go Mock (gomock)简明教程 | 快速入门 动手写分布式缓存 - GeeCache第三天 HTTP 服务端 动手写分布式缓存 - GeeCache第二天 单机并发缓存 | 极客兔兔 Go Test 单元测试简明教程 | 快速入门 7天用Go从零实现分布式缓存GeeCache | 极客兔兔 Go WebAssembly (Wasm) 简明教程 | 快速入门 Go RPC & TLS 鉴权简明教程 | 快速入门 Go Protobuf 简明教程 | 快速入门 Go语言动手写Web框架 - Gee第七天 错误恢复(Panic Recover) WSL, Git, Mircosoft Terminal 等常用工具配置 Rust 简明教程 | 快速入门 | 极客兔兔 Go语言动手写Web框架 - Gee第六天 模板(HTML Template) 百宝箱 - 值得收藏的工具网站 | 极客兔兔 Go语言动手写Web框架 - Gee第五天 中间件Middleware | 极客兔兔 Go语言动手写Web框架 - Gee第四天 分组控制Group | 极客兔兔 Go语言动手写Web框架 - Gee第三天 前缀树路由Router | 极客兔兔 博客折腾记(七) - Gitalk Plus | 极客兔兔 Go语言动手写Web框架 - Gee第二天 上下文Context | 极客兔兔 Go2 新特性简明教程 | 快速入门 | 极客兔兔 博客折腾记(六) - 不要为了流量忘记了初心 | 极客兔兔 Go语言动手写Web框架 - Gee第一天 http.Handler | 极客兔兔 7天用Go从零实现Web框架Gee教程 | 极客兔兔 Go Gin 简明教程 | 快速入门 Go 语言简明教程 | 快速入门 | 极客兔兔 机器学习笔试面试题 11-20 | 极客面试 | 极客兔兔 机器学习笔试面试题 1-10 | 极客面试 | 极客兔兔 机器学习笔试面试题汇总 | 极客面试 | 极客兔兔 TensorFlow 2 中文文档 - RNN LSTM 文本分类 TensorFlow 2 中文文档 - TFHub 迁移学习 TensorFlow 2 中文文档 - 卷积神经网络分类 CIFAR-10 TensorFlow 2 中文文档 - 保存与加载模型 TensorFlow 2 中文文档 - 过拟合与欠拟合 TensorFlow 2 中文文档 - 回归预测燃油效率 TensorFlow 2 中文文档 - 特征工程结构化数据分类 TensorFlow 2 中文文档 - IMDB 文本分类 TensorFlow 2 中文文档 - MNIST 图像分类 TensorFlow 2 / 2.0 中文文档 TensorFlow 2.0 (九) - 强化学习 70行代码实战 Policy Gradient 博客折腾记(五) - 友链这件事,没那么简单 | 极客兔兔 博客折腾记(四) - 原创资格是争取来的 | 极客兔兔 TensorFlow 2.0 (八) - 强化学习 DQN 玩转 gym Mountain Car 博客折腾记(三) - 主题设计、彩蛋与阅读量翻倍 | 极客兔兔 TensorFlow 2.0 (六) - 监督学习玩转 OpenAI gym game 博客折腾记(二) - 对搜索引擎的理解 | 极客兔兔 博客折腾记(一) - 极致性能的尝试 | 极客兔兔 Pandas 数据处理(三) - Cheat Sheet 中文版 TensorFlow 2.0 (五) - mnist手写数字识别(CNN卷积神经网络) TensorFlow入门(四) - mnist手写数字识别(制作h5py训练集) | 极客兔兔 TensorFlow入门(三) - mnist手写数字识别(可视化训练) | 极客兔兔 Pandas 数据处理(二) - 筛选数据 | 极客兔兔 Pandas 数据处理(一) - DataFrame 与 Series
TensorFlow 2.0 (七) - 强化学习 Q-Learning 玩转 OpenAI gym
2019-06-25 · via 极客兔兔

源代码/数据集已上传到 Github - tensorflow-tutorial-samples

Geektutu Q-Learning MountainCar Failed

这篇文章是 TensorFlow 2.0 Tutorial 入门教程的第七篇文章,介绍如何使用强化学习(Reinforcement Learning, RL)的一个经典算法(Q-Learning),玩转 OpenAI gym game。

代码仅50行~

MountainCar-v0 游戏简介

今天我们选取的游戏是MountainCar-v0,这个游戏很简单,将车往不同的方向推,最终让车爬到山顶。和上一篇文章 TensorFlow 2.0 (六) - 监督学习玩转 OpenAI gym game一样,我们先介绍几个比较关键的概念,以及这几个概念在这个游戏中的具体含义。

概念 解释 示例
State list: 状态,[位置,速度] [0.5,-0.01]
Action int: 动作(0向左推,1不动,2向右推) 2
Reward float: 每回合-1分 -1
Done bool: 是否爬到山顶(True/False),上限200回合 -1

如果200回合还没到达山顶,说明游戏失败,-200是最低分。每个回合得-1,分数越高,说明尝试回合数越少,意味着越早地到达山顶。比如得分-100分,表示仅经过了100回合就到达了山顶。

初始化 Q-Table(Q表)

如果有如下这样一张表,告诉我在某个状态(State)下, 执行每一个动作(Action)产生的价值(Value),那就可以通过查询表格,选择产生价值最大的动作了。

State Action 0 Action 1 Action 2
[0.2, -0.01] 10 -20 -30
[-0.3, 0.01] 100 0 0
[-0.1, -0.01] 0 -10 20

价值(Value)怎么计算呢?游戏的最终目标是爬到山顶,爬到山顶前的每一个动作都为最终的目标贡献了价值,因此每一个动作的价值计算,和最终的结果,也就是与未来(Future)有关。这就是强化学习的经典算法 Q-Learning 设计的核心。Q-Learning中的Q,代表的是 Action-Value,也可以理解为 Quality。而上面这张表,就称之为 Q表(Q-Table)

到这里,你应该可以理解了,Q-Learning的目的是创建Q-Table。有了Q-Table,自然能知道选择哪一个Action了。

我们先初始化一张Q表(Q-Table)

1
2
3
4
5
6
7
8
9


import pickle
from collections import defaultdict
import gym
import numpy as np


Q = defaultdict(lambda: [0, 0, 0])

连续状态映射

但是这个Q-Table有一个问题,我们用字典来表示Q-Table,State中的值是浮点数,是连续的,意味着有无数种状态,这样更新Q-Table的值是不可能实现。因此,我们需要对State进行线性转换,归一化处理。即,将State中的值映射到[0, 40]的空间中。这样,就将无数种状态映射到40x40种状态了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17


env = gym.make('MountainCar-v0')

def transform_state(state):
"""将 position, velocity 通过线性转换映射到 [0, 40] 范围内"""
pos, v = state
pos_low, v_low = env.observation_space.low
pos_high, v_high = env.observation_space.high

a = 40 * (pos - pos_low) / (pos_high - pos_low)
b = 40 * (v - v_low) / (v_high - v_low)

return int(a), int(b)



更新 Q-Table

那怎么更新Q-Table呢?下面这个简化版的公式就是关键了。

Q[s][a] = (1 - lr) * Q[s][a] + lr * (reward + factor * max(Q[next_s]))

看见公式先别紧张,我们逐步来看。

表达式 含义 简介
s, a,next_s - 当前状态,当前动作,下一个状态
reward 奖励 执行a动作的奖励
Q[s][a] 价值 状态s下,动作a产生的价值
max(Q[next_s]) 最大价值 下一个状态下,所有动作价值的最大值
lr 学习速率(learning_rate) lr越大,保留之前训练效果越少。lr为0,Q[s, a]值不变;lr为1时,完全抛弃了原来的值。
factor 折扣因子(discount_factor) factor 越大,表示越重视历史的经验; factor 为0时,只关心当前利益(reward)

为什么是max(Q[next_s])而不是min(Q[next_s])呢?在Q-Table中,状态 next_s 有3个动作可选,即[0, 1, 2],对应价值 **Q[next_s][0],Q[next_s][1],Q[next_s][2]**。Q[s][a]的值应由产生的最大价值的动作决定。

我们想象一个极端场景:五子棋,最后一步,下在X位置赢,100分;其他位置输,0分。那怎么衡量倒数第二步的价值呢?当然是由最后一步的最大价值决定,不能因为最后一步走错了,就否定前面动作的价值。

开始训练

接下来我们就把这个公式嵌入到OpenAI gym中吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


lr, factor = 0.7, 0.95
episodes = 10000
score_list = []
for i in range(episodes):
s = transform_state(env.reset())
score = 0
while True:
a = np.argmax(Q[s])

if np.random.random() > i * 3 / episodes:
a = np.random.choice([0, 1, 2])

next_s, reward, done, _ = env.step(a)
next_s = transform_state(next_s)

Q[s][a] = (1 - lr) * Q[s][a] + lr * (reward + factor * max(Q[next_s]))
score += reward
s = next_s
if done:
score_list.append(score)
print('episode:', i, 'score:', score, 'max:', max(score_list))
break
env.close()


with open('MountainCar-v0-q-learning.pickle', 'wb') as f:
pickle.dump(dict(Q), f)
print('model saved')

接下来我们来看一看训练效果。因为Q表的状态比较多,因而训练到3000次的时候,仍旧没能成功到达山顶。最终训练结束的时候,分数保持在-150左右,最大分数达到-119。代码中的参数都是随便选取的,如果有时间优化下,肯定能有更好的结果。

1
2
3
4
5
6
7
8
9
$ python q_learning.py
episode: 3080 score: -200.0 max: -200
episode: 3081 score: -200.0 max: -200
...
episode: 9996 score: -169.0 max: -119.0
episode: 9997 score: -141.0 max: -119.0
episode: 9998 score: -160.0 max: -119.0
episode: 9999 score: -161.0 max: -119.0
model saved

测试模型

最终,我们写一下测试代码,加载模型,顺便感受下真实的游戏画面吧~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27


import time
import pickle
import gym
import numpy as np


with open('MountainCar-v0-q-learning.pickle', 'rb') as f:
Q = pickle.load(f)
print('model loaded')

env = gym.make('MountainCar-v0')
s = env.reset()
score = 0
while True:
env.render()
time.sleep(0.01)

s = transform_state(s)
a = np.argmax(Q[s]) if s in Q else 0
s, reward, done, _ = env.step(a)
score += reward
if done:
print('score:', score)
break
env.close()

运行一下,你就知道。

1
2
3
$ python test_q_learning.py
model loaded
score: -151.0

Geektutu Q-Learning MountainCar Success

代码已经上传到Github - tensorflow-tutorial-samplesq_learning.py只有50行,不妨试一试吧~

我们这里的预测模型保存在了Q-Table中,输入是State,输出是3个Action的价值,Q-Table是一个字典,有着准确的映射关系,那如果我们用深度神经网络(Deep Neural Network, DNN)模拟这个字典呢?那这就被称为 DQN(Deep Q-Learning Network)。好,那我们下一篇文章,就借助TensorFlow 2.0用神经网络替换掉Q-Table吧。

附 推荐



上一篇 « 博客折腾记(三) - 主题设计、彩蛋与阅读量翻倍 下一篇 » TensorFlow 2.0 (八) - 强化学习 DQN 玩转 gym Mountain Car