Q-Learning以及.NET环境下的实现
- 写在前面
- 机器学习
- Q-Learning
- 环境准备
- 试题准备
- 解题过程
- 写在结尾
写在前面
看过我的文章的朋友应该都知道,我之前一直在研究视觉相关的知识,也看了一些卷积神经网络(CNN),深度学习相关的文章。但说实话,大部分知识点和例子,我都是一知半解,明白他这样做能达到什么效果,但是不知道他为什么这么做,这样肯定不行啊!所以也是借着过年的这段时间学习了一些机器学习的基础知识,其实现在大家熟悉的深度学习也属于机器学习中的一部分。
机器学习
机器学习是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。它是人工智能核心,是使计算机具有智能的根本途径。
– 摘抄自百度百科
Q-Learning
Q-Learning则是机器学习中的一个分支强化学习中的一个算法。我们今天也是窥一斑而见全豹,见一叶而知深秋,通过学习这个算法来感受一下深度学习的伟大。
这里我用我自己的理解再介绍一下强化学习,强化学习顾名思义,突出的就是一个强化,好像听起来抽象,这样一个词怎么转换成一串表达式呢?这里其实有一个很重要的概念就是反馈,通过结果去强化原因这就是反馈,听起来更抽象了吧!但其实医学实验上经常会用到这个概念,比如在小白鼠面前放置两个可以被触发的开关,第一个开关被触发会电击小白鼠,这就是负反馈。第二个开关被触发会投放食物,这就是正反馈,同时强化了老鼠对这两个开关的认识,在不断的电击和投食后,老鼠对第一个开关的负反馈达到阈值,他将永远不会再触发第一个开关,这就是我们要用代码实现的。好吧你还是很迷茫,不过不要紧,继续往下看就行。
环境准备
环境的话就是我们最熟悉的.NET换进,只要能开发控制台程序就行。
试题准备
试题也是我再网上找的范例,比较简单。
这张图上一共有6个房间(我们将外面5也看成一个大房间的话),我们需要用强化学习让机器人能进入房间5(也就是外面)。
解题过程
-
对于机器人来说,当前房间就相当于所处的环境State,他要打开门进入下一个房间Action。由此我们稍微简化一下我们的例图
因为门都是可以进出的,所以两个环境之间的箭头也是双向的。 -
因为我们的目标是房间5,所以我们对指向房间5的箭头要有一些正反馈,其他正常的箭头就无反馈
这里要注意一点,房间5有个指向他自己的箭头,这是为了让机器人停留在目标房间,当然你也可以用其他方式来实现,比如不停的判断机器人当前所处的房间(这样真的太low了) -
下面我们就要把这张图转化成代码了,这里说实话,让我自己想我估计永远想不明白该怎么转换,但谁叫咱们都站在巨人的肩膀上呢。这里我们要这张图转换成一个二位数组
-1,代表不存在这个箭头,0表示无反馈,100表示正反馈,简单理解一下就是房间0到房间0这个箭头是没有的,房间5到房间5这个箭头的鼓励的,房间0到房间4这个箭头是无反馈的。同时这个数组我们记作R。
int[][] R = new int[6][] {
new int[]{ -1, -1, -1, -1, 0, -1 },
new int[]{ -1, -1, -1, 0, -1, 100 },
new int[]{ -1, -1, -1, 0, -1, -1 },
new int[]{ -1, 0, 0, -1, 0, -1 },
new int[]{ 0, -1, -1, 0, -1, 100 },
new int[]{ -1, 0, -1, -1, 0, 100 } };
- 再来一个行列相等的数据,来储存机器学习的结果,我们记作Q
static double[][] Q = new double[6][] { new double[6], new double[6], new double[6], new double[6], new double[6], new double[6] };
- 然后引入我们的公式
这里需要注意的就是两个我们可以控制的参数:
一个就是的α学习效率,它定义了一个旧的Q值将从新的Q值哪里学到的新Q占自身的多少比重。值为0意味着代理不会学到任何东西(旧信息是重要的),值为1意味着新发现的信息是唯一重要的信息。
一个就是γ折扣因子,它定义了未来奖励的重要性。值为0意味着只考虑短期奖励,其中1的值更重视长期奖励。
说实话,这个公式不太好理解,我们稍微给它删减一下,保留他最核心的内容,至于这个公式是怎么推到得出的,哥们我只能说我就是个搬运工高数也忘的差不多了。
Q[state][stateNext] = myMath(R, stateNext, state);
static double myMath(int[][] R, int newstate, int oldstate)
{
double y = 0.8; //学习率
// 选出不为负数的行为
List<int> action = new List<int>();
for (int i = 0; i < R[newstate].Length; i++)
{
if (R[newstate][i] >= 0)
{
action.Add(i);
}
}
// 根据这些行为,获取奖励值
List<double> actionQ = new List<double>();
for (int i = 0; i < action.Count; i++)
{
actionQ.Add(Q[newstate][action[i]]);
}
// 获取最大值
double max = actionQ.Max();
// 根据这些行为计算上一个state的奖励值
return R[oldstate][newstate] + (y * max);
}
- 现在可以开始了,先将机器人随机放到一个房间作为State,然后从与他相连的房间里选一间作为Action,也就是先确实R数组中的行数,再从那一行中非负列中随机选择一行,这样我们就完成了第一步,上代码
int stateInit = random.Next(0, 6);
test(R, stateInit);
// 进入一次运算
static Random random = new Random();
static int stateNext = -1;
// 选出不为负数的行为
static List<int> action = new List<int>();
// 选出奖励最大的行为,可能为多个
static List<int> actionM = new List<int>();
static void test(int[][] R, int state)
{
action.Clear();
actionM.Clear();
for (int i = 0; i < R[state].Length; i++)
{
if (R[state][i] >= 0)
{
action.Add(i);
}
if (R[state][i] == R[state].Max())
{
actionM.Add(i);
}
}
stateNext = action[random.Next(0, action.Count)];
Q[state][stateNext] = myMath(R, stateNext, state);
if (stateNext != 5)
{
test(R, stateNext);
}
else
{
Q[state][stateNext] = myMath(R, stateNext, state);
}
}
- 我们通过代码还原了算法,然后通过算法训练出了模型,你可以把你自己比作那个笨笨的机器人,看看在你的模型下,是否能很快去到房间5。
写在结尾
最近在研究机器学习相关的知识点,后面可能还会更新一两篇文章,在这里我要说一下,我的文章虽然是原创,但这是我在看了其他大佬的文章后理解其中内容得到的一些感悟,也有一些自己的实践创新,如果有问题的话,希望大家一起探讨,天道酬勤,与君共勉。