分类 深度学习 下的文章

以下是使用SARSA算法修改后的代码:

# 开始训练Q表格
all_episode_reward = []  # 用于记录每次迭代的总奖励,这样就可以知道智能体是否有进步了
for i in range(num_episodes):
    ## 初始化环境,得到初始状态
    s, _= env.reset()  # 初始状态值
    rAll = 0  # 用于记录这次游戏的总奖励,这里先初始化为0
    ## The SARSA algorithm
    ## 首先,根据epsilon-greedy选择当前状态s下的动作a
    a = np.argmax(Q[s, :] + np.random.randn(1, env.action_space.n) * (1. / (i + 1)))
    for j in range(99):
        if render: env.render()
        ## 与环境交互得到下一个状态s1和即时奖励r
        s1, r, d, _, _ = env.step(a)
        ## 根据epsilon-greedy选择在状态s1下的下一个动作a1
        a1 = np.argmax(Q[s1, :] + np.random.randn(1, env.action_space.n) * (1. / (i + 1)))
        ## 使用SARSA更新Q表格
        Q[s, a] = Q[s, a] + lr * (r + lambd * Q[s1, a1] - Q[s, a])
        ## 更新当前状态和动作
        rAll += r
        s = s1
        a = a1
        if d is True:
            break
    if i == 0:
        all_episode_reward.append(rAll)
    else:
        all_episode_reward.append(all_episode_reward[-1] * 0.99 + rAll * 0.01)
    print(
    'Training  | Episode: {}/{}  | Episode Reward: {:.4f}  | all_episode_reward: {:.4f} | Running Time: {:.4f}'.format(
        i + 1, num_episodes, rAll, all_episode_reward[i], time.time() - t0
        )
    )

# 保存Q表格
path = os.path.join('model', '_'.join([alg_name, env_id]))
if not os.path.exists(path):
    os.makedirs(path)
np.save(os.path.join(path, 'Q_table.npy'), Q)

# 绘制迭代的总奖励
plt.plot(all_episode_reward)
if not os.path.exists('image'):
    os.makedirs('image')
plt.savefig(os.path.join('image', '_'.join([alg_name, env_id])))

# 打印Q表格
print("Final Q-Table Values:/n %s" % Q)

相对于原始代码,使用SARSA算法修改后的主要变化是:

在每个状态s下,先根据epsilon-greedy选择一个动作a,然后在与环境交互得到下一个状态s1后,再根据epsilon-greedy选择在状态s1下的下一个动作a1。
使用SARSA更新Q表格时,将下一个状态和动作的Q值Q[s1, a1]考虑进去。
这样就能够实现SARSA算法来训练Q表格,从而实现强化学习任务。


以下是使用SARSA算法修改后的代码:


# 模型评估
path = os.path.join('model', '_'.join([alg_name, env_id]))
Q = np.load(os.path.join(path, 'Q_table.npy'))
sum_rAll = 0
for i in range(num_episodes):
    ## 初始化环境,得到初始状态
    s, _ = env.reset()
    rAll = 0
    ## The SARSA algorithm
    ## 首先,根据epsilon-greedy选择当前状态s下的动作a
    a = np.argmax(Q[s, :] + np.random.randn(1, env.action_space.n) * (1. / (i + 1)))
    for j in range(99):
        ## 与环境交互得到下一个状态s1和即时奖励r
        s1, r, d, _, _ = env.step(a)
        ## 根据epsilon-greedy选择在状态s1下的下一个动作a1
        a1 = np.argmax(Q[s1, :] + np.random.randn(1, env.action_space.n) * (1. / (i + 1)))
        ## 更新当前状态和动作
        rAll += r
        s = s1
        a = a1
        if d is True:
            break
    print(
        'Testing  | Episode: {}/{}  | Episode Reward: {:.4f}  | Running Time: {:.4f}'.format(
            i + 1, num_episodes, rAll,
            time.time() - t0
        )
    )
    sum_rAll += rAll
print('游戏中成功闯关比例: {:.4f}'.format(sum_rAll/num_episodes))

相对于原始代码,使用SARSA算法修改后的主要变化是:

在每个状态s下,先根据epsilon-greedy选择一个动作a,然后在与环境交互得到下一个状态s1后,再根据epsilon-greedy选择在状态s1下的下一个动作a1。
在模型评估时,使用SARSA算法更新当前状态和动作,并且在选择动作时也根据epsilon-greedy进行选择。

from os import mkdir, listdir
from os.path import isdir, basename
from random import choice, randrange
from string import digits
from PIL import Image, ImageDraw # pillow
from PIL.ImageFont import truetype
from sklearn import svm
from sklearn.model_selection import train_test_split

图像尺寸、图片中的数字字体大小、噪点比例

width, height = 30, 60
fontSize = 40
noiseRate = 8

def generateDigits(dstDir='datasets', num=4000):

# 生成num个包含数字的图片文件存放于当前目录下的datasets子目录
if not isdir(dstDir):
    mkdir(dstDir)
# digits.txt用来存储每个图片对应的数字
with open(dstDir+'\\digits.txt', 'w') as fp:
    for i in range(num):
        # 随机选择一个数字,生成对应的彩色图像文件
        digit = choice(digits)
        im = Image.new('RGB', (width,height), (255,255,255))
        imDraw = ImageDraw.Draw(im)
        font = truetype('c:\\windows\\fonts\\TIMESBD.TTF',
                          fontSize)
        imDraw.text((0,0), digit, font=font, fill=(0,0,0))
        # 加入随机干扰
        for j in range(int(noiseRate*width*height)):
            w, h = randrange(1, width-1), randrange(height)
            # 水平交换两个相邻像素的颜色
            c1 = im.getpixel((w,h))
            c2 = im.getpixel((w+1,h))                
            imDraw.point((w,h), fill=c2)
            imDraw.point((w+1,h), fill=c1)
        im.save(dstDir+'\\'+str(i)+'.jpg')
        fp.write(digit+'\n')

def loadDigits(dstDir='datasets'):

# 获取所有图像文件名
digitsFile = [dstDir+'\\'+fn for fn in listdir(dstDir)
               if fn.endswith('.jpg')]
# 按编号排序
digitsFile.sort(key=lambda fn: int(basename(fn)[:-4]))
# digitsData用于存放读取的图片中数字信息
# 每个图片中所有像素值存放于digitsData中的一行数据
digitsData = []
for fn in digitsFile:
    with Image.open(fn) as im:
        data = [sum(im.getpixel((w,h)))/len(im.getpixel((w,h)))
                 for w in range(width)
                 for h in range(height)]
        digitsData.append(data)
# digitsLabel用于存放图片中数字的标准分类
with open(dstDir+'\\digits.txt') as fp:
    digitsLabel = fp.readlines()
digitsLabel = [label.strip() for label in digitsLabel]
return (digitsData, digitsLabel)

生成图片文件

generateDigits(num=4000)

加载数据

data = loadDigits()
print('数据加载完成。')

随机划分训练集和测试集,其中参数test_size用来指定测试集大小

X_train, X_test, y_train, y_test = train_test_split(data[0],

                                                data[1],
                                                test_size=0.1)

创建并训练模型

svcClassifier = svm.SVC(kernel="linear", C=1000, gamma=0.001)
svcClassifier.fit(X_train, y_train)
print('模型训练完成。')

使用测试集对模型进行评分

score = svcClassifier.score(X_test, y_test)
print('模型测试得分:', score)

import numpy as np
from sklearn import tree
X = np.array([[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]])
y = [0,1,1,1,2,3,3,4]
clf = tree.DecisionTreeClassifier()
clf.fit(X,y)

clf.predict([[1,0,0]])

import graphviz
dot_data = tree.export_graphviz(clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.render('result')

result.pdf