基于Tensorflow的无向图二维顶点坐标生成
基于Tensorflow的无向图二维顶点坐标生成
本文将介绍如何导入并处理无向图和设计Tensorflow神经层各项参数,仅使用训练过程,最终导出训练的中间结果,即无向图中所有顶点的二维坐标点(x, y)。
无向图可视化
目前,实现无向图的可视化,笔者使用过使用D3中的力引导实现的方法,也有用python的networkx库,随机选点进行连线,可以在其中的边上标注权重值,但都无法直观的显示出权重值的相对大小。
无向图可视化局限:
1. 以无向图中3个顶点为例,当3个顶点两两相连形成无向图时,当无法构成三角形时,则该三角形无法在二维空间中绘制出来。当无向图的顶点增多时,原本能构成三角形的三个顶点也可能无法与第4个顶点构成四面体,因此这将是一个高维空间的问题,很难在二维空间中显示出来(除非无向图中的所有两两相连的3个顶点都能形成三角形,但是这种情况少之又少)。
2. 使用D3对无向图进行可视化:
可以显示出顶点之间的边的连接状况,但是无法表现出其中的权重相对大小情况(亲测无效……)
可视化效果如下:
D3实现图可视化(js)图片截自D3的官网上的一个项目,虽然可能主要是体现使用了鱼眼,但是使用力引导方式确实无法表现出权重的大小甚至不能体现大小的相对状况。
3. 使用python的networkx进行绘制:
networkx实现无向图原理
本文是基于Tensorflow人工智能框架,使用Python实现由无向图顶点之间的权重生成二维坐标下的各顶点的坐标(x, y)。
无向图中含有顶点以及顶点之间的权重信息,本文实现方法中的权重值的取值范围为0~1的范围的小数(非该范围的权重值可以将所有数据与最大数据相除得到小数)。
基本原理就是使用简单的概率思想。在Tensorflow中,我们可以根据最终的计算输出和label得到loss,具体的loss计算方式并不唯一。
原始数据的处理
1. 对原始的数据进行校验是否正确:
条件:
可出现重复边(例:0->1和1->0若同时出现值需相等,否则报错)
只有入度但没有出度的顶点标号需出现在图中(考虑到原始数据可能不仅为无向图)(内容需置为None或为{})
def data_verify(origin_data):
keys = origin_data.keys()
for s in origin_data:
if origin_data[s] is None:
continue
for e in origin_data[s]:
if e not in keys:
raise KeyError('终边在图中未出现')
if origin_data[e] is None:
continue
tmp_keys = origin_data[e].keys()
if s not in tmp_keys:
continue
if origin_data[s][e] == origin_data[e][s]:
del origin_data[e][s]
else:
raise ValueError('边值不相等:%d->%d & %d->%d' % (s, e, e, s))
return origin_data
2. 对校验后的数据进行格式变换:
例:
{
0:
{1: 0.3,
2: 0.3},
1:
{2: 0.5,
3: 0.9},
2:
{1: 0.5,
3: 0.8}
}
处理后得到:
# 0->1: 0.3 0->2: 0.3 ...
[ [1, 0, 0], [1, 0, 0], ...
[ [0, 1, 0], [0, 0, 1], ...
[ [0.3], [0.3], ...
def format_transform(verified_data):
size = len(verified_data)
s = []
e = []
out = []
for start in verified_data:
if verified_data[start] is None:
continue
for end in verified_data[start]:
if verified_data[start][end] is None:
continue
s.append(start)
e.append(end)
out.append(verified_data[start][end])
for index in range(len(s)):
tmp_s = np.zeros([size], dtype=np.float32)
tmp_e = np.zeros([size], dtype=np.float32)
start_ = s[index]
end_ = e[index]
tmp_s[start_] = 1
tmp_e[end_] = 1
s[index] = tmp_s
e[index] = tmp_e
out = [[tmp] for tmp in out]
return [s, e, out]
神经网络设计
虽说是神经网络,但是只用一个神经层就足够进行训练,最终的得出的结果也是不唯一的,但是始终尽可能满足条件:两顶点坐标之间距离==两顶点之间的权重值。(当无法构成三角形的时候按照正常操作也是无法画出图形,但可以尽可能逼近该图形)
def tf_get_points(data, train_times=500):
# 默认train_times训练次数为500次,可修改,但不可以太小,次数太少可能不能训练到最佳状态
[s, e, out] = data
size = len(s[0]) # s[0]或者e[0]都表示总定点数
start = tf.placeholder(tf.float32, shape=[None, size]) # start表示该边的起点(或终点)
end = tf.placeholder(tf.float32, shape=[None, size]) # end表示该边的终点(或起点)
length = tf.placeholder(tf.float32, shape=[None, 1]) # length用于存储应为的权重值
x = tf.Variable(tf.random_normal([size, 1])) # x变量表示所有点的x坐标
y = tf.Variable(tf.random_normal([size, 1])) # y变量表示所有点的y坐标
x1 = tf.matmul(start, x) # 处理后的s与x矩阵相乘后就只剩相应的对应该顶点号的x坐标值
x2 = tf.matmul(end, x) # 功能与x1类似
y1 = tf.matmul(start, y) # 得到对应顶点号的y坐标值
y2 = tf.matmul(end, y) # 功能与y1类似
x_ = tf.squared_difference(x1, x2) # 相当于△x
y_ = tf.squared_difference(y1, y2) # 相当于△y
outputs = tf.sqrt(tf.add(x_, y_)) # 输出为(△x+△y)^0.5 (两个顶点之间的距离)
loss = tf.reduce_mean(tf.reduce_sum(tf.squared_difference(outputs, length)))
# loss表示误差,写法不唯一
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
for i in range(train_times):
sess.run(train_step, feed_dict={start: s, end: e, length: out})
# 将训练出来的所有的点的坐标以及误差值导出
# (当不可能构成三角形时,误差会相对较大;若均能构成三角形,误差几乎为0)
xx, yy, loss = sess.run((x, y, loss), feed_dict={start: s, end: e, length: out})
points = []
xx = [list(tmp)[0] for tmp in xx]
yy = [list(tmp)[0] for tmp in yy]
if len(xx) != len(yy):
raise RuntimeError
for index in range(len(xx)):
points.append([xx[index], yy[index]])
sess.close()
return points, loss
函数使用
例:main
from graph import *
if __name__ == '__main__':
data = {
0:
{1: 0.3,
2: 0.3},
1:
{2: 0.5,
3: 0.9},
2:
{1: 0.5,
3: 0.8,
4: 0.1,
5: 0.7},
3: None,
4: None,
5: None,
6:
{0: 0.9}}
data = data_verify(data)
data = format_transform(data)
total_points, loss = tf_get_points(data)
for tmp in total_points:
print(tmp)
print(loss)
训练结果:
输出点坐标由训练结果可以看出:
得到的顶点坐标的顺序是按照输入的图中的点标号的先后顺序决定的
注:由结果中loss可得,当无向图中的两两相连的均能构成三角形时误差极小(当不能构成三角形且训练次数足够大的情况下,误差会相对较大,且几乎无法减小)
Version
Python 3.6.5
Tensorflow 1.12.0
第一次写文章,如果有不对的地方还请各位大佬们多多指正!
计算顶点坐标的算法的源码都在我的github上,希望大家多多支持多多指正,觉得还可以的希望大家可以留个星,谢谢\(@ ^ 0 ^ @)/!
网友评论