使用 CNN 预测棋盘值

Predicting board values using CNN

我正在尝试在 tensorflow 中构建一个 CNN,它将向量 ex 作为输入:

x =[4, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 3],

其中整数表示标称编码。

并输出一个向量,其中值已移动,例如:

y = [0, 4, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 3]

在这种情况下,4 的位置是向量中的变化变量。

问题:

是否可以创建一个 returns 该格式输出的卷积网络?我只见过应用于分类问题的转换。

在这些情况下,我将如何 define/compute 错误?我需要知道 y 的潜在值的数量吗?

问题

如何使用 TensorFlow(可能还有卷积)来玩棋盘游戏?

具体来说,我有一个可能值为 [0,1,2,3,4] 的小棋盘(4x4 或 16x1),我想知道下一个最佳着法。

高级答案

您要求的与 what DeepMind did with AlphaGo 没有太大区别,但也许您并不需要所有花里胡哨的东西。回顾 DeepMind 如何安排他们的架构将使您深入了解如何将类似的策略应用到您的游戏中。

在高层次上,他们使用 1 个神经网络对当前棋盘配置进行评分(价值网络),并使用另一个神经网络来建议可能的下一个最佳着法(策略网络) 和搜索。

是的,你可以带着这个配置去城里,你的系统可能会玩一个很棒的游戏。

实际的后续步骤

我是一名工程师,因此我喜欢立即看到一些结果,所以这就是本节的真正内容。

我使用麻省理工学院的简单 AlphaBeta (built by following this lecture 为跳棋编写了 AI)。我会从那开始,将 AlphaBeta 应用到您的棋盘游戏并硬编码一个 值函数 。例如跳棋中的值函数可以是"have more pieces than your opponent".

如果 N+1 前瞻通常优于 N 前瞻[=17=,您就会知道自己是否实施得很好]

那么 是时候使用 TensorFlow 了!使用您的硬编码值函数和多个前瞻作为您的 good moves 训练集。从 TensorFlow 训练 CNN 以正确权衡更高的前瞻移动为高。

具体来说,对于前瞻 1 的移动 A 与前瞻 2 的移动 B 与前瞻 3 的移动 C,您的 CNN 应该为移动 C 评分最高值,然后是移动 B,然后是移动 A,然后是所有其他可能的移动移动。

如果您可以让 CNN 对您的硬编码策略进行 3 次前瞻评估,那么当您的硬编码策略具有 3 次前瞻时,您的 CNN 在一次前瞻中有效地具有您的硬编码策略的力量。

现在关掉你的硬编码策略并放入你的 CNN 版本 1。

像第 1 版一样迭代和训练 CNN 第 2 版。

进一步的后续步骤

以上内容只是为了让事情顺利进行。它不会重新创建 AlphaGo。研究玩像围棋这样非常开放的游戏的 Monte Carlo method。还要更多地研究 "policy network" 以生成可能的下一步动作,而不是仅仅在生成后对它们进行评分。

祝你好运!

最后提示

使用

之类的方法将所有这些数字 [0,1,2,3,4] 转换为 1 热编码
board = tf.constant( [4, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 3] , dtype=tf.int16 )
board_as_mask = tf.one_hot( board , 5 )
sess = tf.Session()
sess.run(board_as_mask)
array([[ 0.,  0.,  0.,  0.,  1.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  0.,  1.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  0.,  1.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  0.,  1.,  0.,  0.],
    [ 0.,  0.,  1.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  1.,  0.,  0.,  0.],
    [ 0.,  0.,  0.,  1.,  0.]], dtype=float32)

在这些情况下,我将如何 define/compute 错误?

误差通常是平方和(y_ - y )^2 或者交叉熵y_ * log(y).无需做任何比这更花哨的事情。 y_ 可能是 "is this the move that a N lookahead would choose that a N-1 wouldn't" 或者如果您使用 monte carlo,它可能是 "does this move lead to a win?"

我需要知道 y 的潜在值的数量吗?

您可以不使用 1-hot 编码,而是使用像 tf.nn.embedding_lookup 这样的 embedding_lookup 并用数千个随机初始化的项目填充它。如果在训练过程中遇到新项目,它就会开始更新相应的嵌入。

嵌入查找示例

如果你想进行嵌入查找(这可能有很大的优势),你可以从这样的事情开始:

board = tf.constant( [4, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 3] , dtype=tf.int32 )

index_max = 10
features = 3
embeddings = tf.Variable( tf.truncated_normal( [index_max, features] , dtype=tf.float32 ) )
board_as_embeddings = tf.nn.embedding_lookup(embeddings, board)

sess = tf.Session()
sess.run(tf.global_variables_initializer() )

print sess.run(board_as_embeddings)

和输出

[[-0.29756528  1.25859058 -1.68821394]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 1.07770884 -1.47092581 -1.85934114]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 1.07770884 -1.47092581 -1.85934114]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 1.07770884 -1.47092581 -1.85934114]
 [ 1.07770884 -1.47092581 -1.85934114]
 [ 0.19683863  1.09903252 -1.12252223]
 [ 0.19683863  1.09903252 -1.12252223]
 [-0.34236383  1.67817557 -1.54652882]]

这会将每个游戏位置转换为特征的语义字段,在本例中为 3。

Frozen Lake 的实际实施

这是一些代码,它用 frozen lake

做原始请求

进口

import tensorflow as tf

index_max = 10
features = 5
width = 4
size = width*width

x_data = [[4, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 3],
    [0, 1, 1, 1, 1, 2, 1, 4, 1, 1, 1, 2, 2, 1, 1, 3]]

y_data = [[0, 4, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 3],
    [0, 1, 1, 1, 1, 2, 1, 0, 1, 1, 1, 2, 2, 4, 1, 3]]

x_input = tf.placeholder( shape=[None,size] , dtype=tf.int32 )
y_ground = tf.placeholder( shape=[None,size] , dtype=tf.int32 )


embedding_vector = tf.Variable( tf.truncated_normal( [index_max, features] , dtype=tf.float32 ) )
embedding_vector_3_ranks = tf.reshape(embedding_vector, [1,index_max, features])

x_embedding = tf.nn.embedding_lookup(embedding_vector, x_input)

def conv_layer( x , layers_in=features , layers_out=features ):
  strides = [1, 1, 1, 1]
  w = tf.Variable( tf.truncated_normal([3,3,layers_in, layers_out], stddev=0.1, dtype=tf.float32) )
  b = tf.Variable( tf.constant(0.1, shape=[layers_out], dtype=tf.float32) )
  h = tf.nn.conv2d( x, w, strides=[1, 1, 1, 1], padding='SAME' ) + b
  return h # tf.nn.relu( h )

hidden = tf.reshape( x_embedding, [-1,width,width,features] )
hidden = tf.nn.relu( conv_layer( hidden ) )
hidden = tf.nn.relu( conv_layer( hidden ) )
hidden = tf.nn.relu( conv_layer( hidden ) )
y_output = tf.reshape( conv_layer( hidden ) , [-1,features] )


item_as_embedding = tf.tile( y_output , tf.constant([1,index_max]) )
item_as_embedding = tf.reshape( item_as_embedding , [-1,index_max,features] )

item_distance_to_embedding = tf.square( embedding_vector_3_ranks - item_as_embedding )
item_distance_to_embedding = tf.reduce_mean( item_distance_to_embedding , -1 )
item_distance_to_embedding = tf.reshape( item_distance_to_embedding, [-1,index_max] )

y_estimate = tf.arg_max( -1.0 * tf.reduce_mean( tf.square( tf.reshape( embedding_vector, [1,index_max, features]) - item_as_embedding ) , -1 ) , 1 )
mask = tf.reshape( tf.one_hot(y_ground,index_max, dtype=tf.float32) , [-1,index_max] )
error = tf.reduce_sum( mask * item_distance_to_embedding , -1 )
learn = tf.train.AdamOptimizer(0.001).minimize(error)


sess = tf.Session()
sess.run(tf.global_variables_initializer() )

for _ in range(20) :
    feed_dict = { x_input : x_data, y_ground : y_data }
    print sess.run(y_estimate,feed_dict).reshape([-1,size]) , sess.run(tf.reduce_sum(error,-1),feed_dict)
    for _ in range(20) :
      sess.run(learn,feed_dict)