定义一个函数使对称矩阵相等
Defining a function to make symmetric matrices equal
一些背景知识
我正在编写一个卷积神经网络(在 C++ 中)以在 4 x 4 网格上玩井字游戏。我想通过使用井字棋盘继承旋转和二面角对称性这一事实来优化它。我的意思是,如果你能为给定的棋盘找到一个最佳着法,即使你旋转或镜像棋盘,它也会保持不变。所以我正在寻找的是一个函数,它可以删除矩阵的任何镜像或旋转,因此网络会将所有旋转的 and/or 镜像板视为相同,并以相同的方式响应它们。换句话说,对于任何矩阵 M,让它的旋转 and/or 镜像版本为 M',对于所有 M',该函数将为 return M。
This article 讨论了网络架构中的旋转和二面角对称实现,但我认为在我的情况下,输入比图像小得多,实现起来会更容易(并且会通过仅转换输入来保持网络更小)。我没有确凿的证据证明这会提高我的网络性能,但我很想测试它。
我的做法
我的棋盘上只有零、一和二。零是空的 space,一个代表我方单位,两个代表你方单位。我一直在考虑下图所示的以下方法(绿色:友好,红色:对手):
- 计算敌方单位的平均位置和友方单位的平均位置
- 确保敌方平均线到友方平均线的顺时针角度(以圆心为第三点)在180度以下。如果不是,镜像板
- 旋转棋盘直到友好的平均点指向左侧,或指向棋盘的左上四分之一
然后当然会在需要时处理特殊情况(例如当平均值位于中心时)。
现在这种方法似乎行得通,但我怀疑这是最好的方法。我想知道是否已经有为此目的使用矩阵数学的函数,或者我是否错过了有用的数学快捷方式或类似的东西。这是一个非常关键的优化部分,因为这个操作将在每个网络移动之前完成,在我的训练计划中这意味着每秒数千次。
这个问题的一个巧妙的解决方案是在所有的棋盘上定义一个total ordering,然后给定一个棋盘,将它的"canonical"表示定义为它的8个对称版本中的"lowest" 在该顺序中。没有其他要求;任何总排序都可以。
定义全序的一种简单方法是通过映射到整数来归纳一个。由于有 16 个单元格,每个单元格具有三种状态(红色、绿色或空)中的一种,我们可以将棋盘状态映射到一个无符号的 32 位整数,其中每个单元格由两位表示:10
for红色,01
代表绿色,00
代表空,这恰好是您已经在板上的单元格中使用的数字表示。
以你的例子为例:
01 10 00 00 10 01 00 00 01 00 00 00 00 01 00 00
为原板
00 01 10 01 01 00 01 10 00 00 00 00 00 00 00 00
为顺时针旋转90度
00 00 01 00 00 00 00 01 00 00 01 10 00 00 10 01
是旋转180度
00 00 00 00 00 00 00 00 10 01 00 01 01 10 01 00
是逆时针旋转90度
00 00 10 01 00 00 01 10 00 00 00 01 00 00 01 00
为水平镜像
00 01 00 00 01 00 00 00 10 01 00 00 01 10 00 00
为垂直镜像
01 10 01 00 10 01 00 01 00 00 00 00 00 00 00 00
为东南对角镜像
00 00 00 00 00 00 00 00 01 00 01 10 00 01 10 01
为西南对角镜像
这八个中最小的数字是最后一个,所以此板的"canonical"版本是西南对角线镜像:
一些背景知识
我正在编写一个卷积神经网络(在 C++ 中)以在 4 x 4 网格上玩井字游戏。我想通过使用井字棋盘继承旋转和二面角对称性这一事实来优化它。我的意思是,如果你能为给定的棋盘找到一个最佳着法,即使你旋转或镜像棋盘,它也会保持不变。所以我正在寻找的是一个函数,它可以删除矩阵的任何镜像或旋转,因此网络会将所有旋转的 and/or 镜像板视为相同,并以相同的方式响应它们。换句话说,对于任何矩阵 M,让它的旋转 and/or 镜像版本为 M',对于所有 M',该函数将为 return M。
This article 讨论了网络架构中的旋转和二面角对称实现,但我认为在我的情况下,输入比图像小得多,实现起来会更容易(并且会通过仅转换输入来保持网络更小)。我没有确凿的证据证明这会提高我的网络性能,但我很想测试它。
我的做法
我的棋盘上只有零、一和二。零是空的 space,一个代表我方单位,两个代表你方单位。我一直在考虑下图所示的以下方法(绿色:友好,红色:对手):
- 计算敌方单位的平均位置和友方单位的平均位置
- 确保敌方平均线到友方平均线的顺时针角度(以圆心为第三点)在180度以下。如果不是,镜像板
- 旋转棋盘直到友好的平均点指向左侧,或指向棋盘的左上四分之一
然后当然会在需要时处理特殊情况(例如当平均值位于中心时)。
现在这种方法似乎行得通,但我怀疑这是最好的方法。我想知道是否已经有为此目的使用矩阵数学的函数,或者我是否错过了有用的数学快捷方式或类似的东西。这是一个非常关键的优化部分,因为这个操作将在每个网络移动之前完成,在我的训练计划中这意味着每秒数千次。
这个问题的一个巧妙的解决方案是在所有的棋盘上定义一个total ordering,然后给定一个棋盘,将它的"canonical"表示定义为它的8个对称版本中的"lowest" 在该顺序中。没有其他要求;任何总排序都可以。
定义全序的一种简单方法是通过映射到整数来归纳一个。由于有 16 个单元格,每个单元格具有三种状态(红色、绿色或空)中的一种,我们可以将棋盘状态映射到一个无符号的 32 位整数,其中每个单元格由两位表示:10
for红色,01
代表绿色,00
代表空,这恰好是您已经在板上的单元格中使用的数字表示。
以你的例子为例:
01 10 00 00 10 01 00 00 01 00 00 00 00 01 00 00
为原板00 01 10 01 01 00 01 10 00 00 00 00 00 00 00 00
为顺时针旋转90度00 00 01 00 00 00 00 01 00 00 01 10 00 00 10 01
是旋转180度00 00 00 00 00 00 00 00 10 01 00 01 01 10 01 00
是逆时针旋转90度00 00 10 01 00 00 01 10 00 00 00 01 00 00 01 00
为水平镜像00 01 00 00 01 00 00 00 10 01 00 00 01 10 00 00
为垂直镜像01 10 01 00 10 01 00 01 00 00 00 00 00 00 00 00
为东南对角镜像00 00 00 00 00 00 00 00 01 00 01 10 00 01 10 01
为西南对角镜像
这八个中最小的数字是最后一个,所以此板的"canonical"版本是西南对角线镜像: