bilylee / SiamFC-TensorFlow

A TensorFlow implementation of the SiamFC tracker
MIT License
358 stars 112 forks source link

关于插值 #67

Closed shuida closed 5 years ago

shuida commented 5 years ago

bilylee大神: 您好!
您的代码如此简洁美观,好像一件艺术品,深感敬佩。我最近在实现一个基于SiamFC-TensorFlow的改进算法,在使用tensorflow进行双线性插值的时候遇到麻烦,想请教您。问题描述如下: 假设有一个批次的图像数据values,其shape=(N,H,W,C);有效区域边界点为points,可以认为就是图像本身的范围(实际上参数points现在用不着,只是为了以后改进方便,所以暂时保留)。 我想获得一系列不规则点coordinates的像素值,coordinates的shape=(K,2),K表示点的数量,coordinates[i,0],coordinates[i,1]分别表示第i个点的y坐标(H方向)和x坐标(W方向)。坐标(y,x)均为小数,也可以为负数, 如果坐标在values的有效区域内,就用其top-left,top-right,bottom-left,bottom-right四个整数点的像素值进行双线性插值;如果超过values的有效区域,就用fill_value=0进行填充。插值后的result其shape=(N,K,C)。 用一个函数表示这个过程就是: result = bilinear_interpolate(points, values, coordinates, fill_value) 我的bilinear_interpolate()实现如下:

def bilinear_interpolate(points, values, coordinates, fill_value):
    data_type = values.dtype
    fill_value = tf.constant(fill_value, dtype=data_type)
    coordinates = tf.cast(coordinates, dtype=data_type)
    def _bilinear(y, x, points, values, fill_value):
        bound_y_min, bound_y_max = points[0].min(), points[0].max()
        bound_x_min, bound_x_max = points[1].min(), points[1].max()
        tag = 1                                         # tag==1 means in bound, otherwise out of bound.
        tag = tf.cond(tf.less(x, bound_x_min), lambda:0, lambda:tag)
        tag = tf.cond(tf.greater_equal(x, bound_x_max), lambda:0, lambda:tag)
        tag = tf.cond(tf.less(y, bound_y_min), lambda:0, lambda:tag)
        tag = tf.cond(tf.greater_equal(y, bound_y_max), lambda:0, lambda:tag)
        def _in_bound(y,x,values):
            x_floor, y_floor = tf.cast(tf.floor(x), dtype=tf.int32), tf.cast(tf.floor(y), dtype=tf.int32)
            x_ceil, y_ceil = x_floor+1, y_floor+1
            tl_value = values[:, y_floor, x_floor, :]
            br_value = values[:, y_ceil, x_ceil, :]
            tr_value = values[:, y_floor, x_ceil, :]
            bl_value = values[:, y_ceil, x_floor, :]
            x_floor = tf.cast(x_floor, dtype=tf.float32)
            x_ceil = tf.cast(x_ceil, dtype=tf.float32)
            y_floor = tf.cast(y_floor, dtype=tf.float32)
            y_ceil = tf.cast(y_ceil, dtype=tf.float32)
            result = tl_value*(x_ceil-x)*(y_ceil-y) + tr_value*(x-x_floor)*(y_ceil - y) + bl_value*(x_ceil-x)*(y-y_floor) + br_value*(x-x_floor)*(y - y_floor)
            return result

        def _out_of_bound(fill_value, values):
            result = values[:, 0, 0, :]*0.0 + fill_value
            return result

        result = tf.cond(tf.equal(tag,1), lambda :_in_bound(y,x,values), lambda :_out_of_bound(fill_value, values))
        return result

    result = tf.map_fn(lambda coor: _bilinear(coor[0], coor[1], points, values, fill_value), coordinates, dtype=values.dtype)
    result = tf.transpose(result, perm=[1,0,2])
    return result

上述插值函数是我的项目中数据预处理的一部分,已验证其正确性。计算过程在GPU上进行,虽然使用了tf.map_fn()能够并行处理,但是速度依然太慢,比不插值慢了1000倍。(能够确定速度慢就是由插值引起的,因为使用插值的时候,速度大约是0.1examples/s,当把插值过程注释掉之后,速度恢复正常,大约100examples/s) 我的问题是: 1.tf.map_fn()不是可以并行处理的吗?为什么使用了tf.map_fn()之后,速度还是很慢? 2.怎样实现上述过程,使得计算速度加快?也许可以使用tf.gather()或者tf.gather_nd()函数,但是我不太会用。用其他可能的方法也行,只要能保证计算结果正确,并且速度越快越好。 3.tensorflow中有没有现成可调用的函数?实际上我想实现的功能类似于scipy.interpolate.interpn或者scipy.ndimage.interpolation.map_coordinates,不限于双线性插值,使用样条插值也可,但我并未找到tensorflow中类似的函数,所以只能自己实现简单的双线性插值。(tf.image.resize_images()只能对图像进行放缩,并不能得到不规则坐标点的插值,不满足我的需求。)