首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >强化学习不适用于这个非常简单的游戏,为什么?Q学习

强化学习不适用于这个非常简单的游戏,为什么?Q学习
EN

Stack Overflow用户
提问于 2020-04-11 19:52:18
回答 1查看 439关注 0票数 0

我编写了一个非常简单的游戏,它的工作方式如下:

给定一个4x4方格场,玩家可以移动(上、右、下或左)。

resetted.

  • Moving
  • 在一个之前从来没有去过的广场上进行奖励1.
  • 踩上“死区”将得到-5的奖励,然后游戏将是在一个已经被访问过的球场上被奖励的-1
  • 正在进行“双赢场”(正好有一个),奖励5,游戏也将被重新审查。

现在我想要一个人工智能通过Q学习来学习玩那个游戏。

我是如何组织输入/特性工程的:

网络的输入是一个形状为1x4的数组,其中arr表示上面的字段(向上移动时),arr1表示右边的字段,arr2表示下面的字段,arr3表示左边的字段。

数组可以容纳的可能值: 0、1、2、3

0=“死区”,所以最坏的情况是

1=这将在4x4字段之外(因此您不能走到那里),或者已经访问了该字段。

2=未访问的字段(所以这是好事)

3=“赢场”,所以最好的情况是

如你所见,我是根据他们的报酬来命令他们的。

由于游戏采用相同的输入方式(0 =向上移动,1=向右移动,2=向下移动,3=向左移动),AI需要学习的唯一基本知识是:选择具有最大值的数组索引。

但坦率地说,它不起作用,网络只是不学习,即使在30.000集之后也是如此。

下面是我的代码(包括一开始的游戏):

代码语言:javascript
运行
复制
import numpy as np
import random
Import tensorflow as tf
import matplotlib.pyplot as plt

from time import sleep

episoden = 0

felder = []
schon_besucht = []

playerx = 0
playery = 0

grafik = False

def gib_zustand():
    # besonderes feature engineering:
    # input besteht nur aus einer richtung, die one-hot-encoded ist; also 4 inputneuronen
    # (glut, wand/besucht, unbesucht, sieg)
    #
    # es ist die richtung, die bewertet werden soll (also 1 outputneuron fuer eine richtung)

    # rueckgabe hier: array, shape: 4x4 (s.o.)

    global playerx
    global playery

    # oben 
    if playery == 0:
        oben = 1
    else:
        oben = felder[playery-1][playerx]

    # rechts
    if playerx == 4:
        rechts = 1
    else:
        rechts = felder[playery][playerx+1]

    # unten
    if playery == 4:
        unten = 1
    else:
        unten = felder[playery+1][playerx]

    # links
    if playerx == 0:
        links = 1
    else:
        links = felder[playery][playerx-1]

    return np.array([oben, rechts, unten, links])

def grafisch():
    if grafik:

        # encoding:
        # glut = G, besucht = b, unbesucht = , sieg = S, Spieler = X
        global felder
        global playerx
        global playery

        print('')

        for y in range(0,5):
            print('|', end='')
            for x in range(0,5):
                if felder[y][x] == 0:
                    temp = 'G'
                if felder[y][x] == 1:
                    temp = 'b'
                if felder[y][x] == 2:
                    temp = ' '
                if felder[y][x] == 3:
                    temp = 'S'
                if y == playery and x == playerx:
                    temp = 'X'

                print(temp, end='')
                print('|', end='')
            print('')

def reset():
    print('--- RESET ---')

    global playery
    global playerx
    global felder
    global schon_besucht

    playerx = 1
    playery = 3

    # anordnung
    # glut = 0, wand/besucht = 1, unbesucht = 2, sieg = 3

    felder = [[2 for x in range(0,5)] for y in range(0,5)]
    # zwei mal glut setzen
    gl1 = random.randint(1,3)
    gl1_1 = random.randint(2,3) if gl1==3 else (random.randint(1,2) if gl1==1 else random.randint(1,3))
    felder[gl1][gl1_1] = 0 # glut

    # zweites mal
    gl1 = random.randint(1,3)
    gl1_1 = random.randint(2,3) if gl1==3 else (random.randint(1,2) if gl1==1 else random.randint(1,3))
    felder[gl1][gl1_1] = 0 # glut

    # pudding
    felder[1][3] = 3

    # ruecksetzen
    schon_besucht = []

    grafisch()

    return gib_zustand()

def step(zug):
    # 0 = oben, 1 = rechts, 2 = unten, 3 = links
    global playerx
    global playery
    global felder
    global schon_besucht

    if zug == 0:
        if playery != 0:
            playery -= 1
    if zug == 1:
        if playerx != 4:
            playerx += 1
    if zug == 2:
        if playery != 4:
            playery += 1
    if zug == 3:
        if playerx != 0:
            playerx -= 1

    # belohnung holen
    wert = felder[playery][playerx]

    if wert==0:
        belohnung = -5
    if wert==1:
        belohnung = -1
    if wert==2:
        belohnung = 1
    if wert==3:
        belohnung = 5

    # speichern wenn nicht verloren
    if belohnung != -5:
        schon_besucht.append((playery,playerx))
        felder[playery][playerx] = 1

    grafisch()

    return gib_zustand(), belohnung, belohnung==5, 0 # 0 damits passt

episoden = 0

tf.reset_default_graph()

#These lines establish the feed-forward part of the network used to choose actions
inputs1 = tf.placeholder(shape=[1,4],dtype=tf.float32)
#W1 = tf.Variable(tf.random_uniform([16,8],0,0.01))
W2 = tf.Variable(tf.random_uniform([4,4],0,0.01))
#schicht2 = tf.matmul(inputs1,W1)
Qout = tf.matmul(inputs1,W2)
predict = tf.argmax(Qout,1)

#Below we obtain the loss by taking the sum of squares difference between the target and prediction Q values.
nextQ = tf.placeholder(shape=[1,4],dtype=tf.float32)
loss = tf.reduce_sum(tf.square(nextQ - Qout))
trainer = tf.train.GradientDescentOptimizer(learning_rate=0.1)
updateModel = trainer.minimize(loss)

init = tf.initialize_all_variables()

# Set learning parameters
y = .99
e = 0.1
num_episodes = 10_000
#create lists to contain total rewards and steps per episode
jList = []
rList = []
with tf.Session() as sess:
    sess.run(init)
    for i in range(num_episodes):             
        #Reset environment and get first new observation
        s = reset()
        rAll = 0
        d = False
        j = 0
        #The Q-Network        
        while j < 99:
            j+=1
            #Choose an action by greedily (with e chance of random action) from the Q-network
            a,allQ = sess.run([predict,Qout],feed_dict={inputs1:s.reshape(1,4)}) # berechnet prediction fuer input (input scheint hier one hot encoded zu sein)
            if np.random.rand(1) < e:
                a[0] = random.randint(0,3)                 

            #Get new state and reward from environment
            s1,r,d,_ = step(a[0])
            #Obtain the Q' values by feeding the new state through our network
            Q1 = sess.run(Qout,feed_dict={inputs1:s1.reshape(1,4)})
            #Obtain maxQ' and set our target value for chosen action.
            maxQ1 = np.max(Q1)


            targetQ = allQ
            targetQ[0,a[0]] = r + y*maxQ1
            #Train our network using target and predicted Q values

            _,W1 = sess.run([updateModel,W2],feed_dict={inputs1:s.reshape(1,4),nextQ:targetQ})
            rAll += r
            s = s1

            if r == -5 or r == 5:
                if r == 5:
                    episoden+=1

                reset()

                #Reduce chance of random action as we train the model.
                e = 1./((i/50) + 10)
                break
        jList.append(j)
        #print(rAll)
        rList.append(rAll)
print("Percent of succesful episodes: " + str((episoden/num_episodes)*100) + "%")
plt.plot(rList)
plt.plot(jList)

我在一个模拟问题中读到,Q值过高的一个原因可能是,实际上,在一场游戏中,代理人有可能获得无限的高回报。如果代理能够踩到已经访问过的字段,得到1的奖励,那么当然,可能的总奖励是无穷大的。但这里的情况并非如此:当球员这样做的时候,他会得到一个糟糕的奖励。小计:赢场奖励为5场,未访问场为1场,至少有一个死区.总共有16个字段。最大可能报酬: 14*1 + 1*5 = 19

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-12 09:42:14

我终于找到了解决办法,我花了差不多一周的时间。

关键是让我的输入是one-hot-encoded.这使我有16个输入神经元,而不是4个,但现在起作用了。在1.000集之后,我有大约91 %的成功插曲。

我仍然在想,当输入不是一个热编码的时候,它就不能工作。我知道,人工神经网络会自动使用神经元所接受的不同输入之间的更小的关系,这可能是一个缺点。但是由于我是这样安排我的输入的,如果一个输入大于另一个输入,这也意味着输出应该以相同的方式更大。因此,如果ANN使用这种关系,那么这里没有什么坏处,相反,这应该是一种优势。

因此,我认为不对输入进行一次热编码会更好,因为这样我就可以极大地降低维度(4而不是16)。

不过,这个主意显然行不通。

然而,正如我所说的,它现在有16个输入就能工作了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61162864

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档