提交 aead18c5 authored 作者: Frederic Bastien's avatar Frederic Bastien

removed tensor.round but added tensor.round_half_{away_from_zero,to_even}.

Their is many different rounding algo. So we don't create a round fct, but one for a 2 differents version(c round fct() and numpy.round)
上级 f9b12d69
......@@ -1152,17 +1152,90 @@ class IRound(UnaryScalarOp):
return "%(z)s = round(%(x)s);" % locals()
iround = IRound(int_out_nocomplex)
class Round(UnaryScalarOp):
class RoundHalfToEven(UnaryScalarOp):
"""
This function implement the same rounding than numpy: Round half to even
c/c++ round fct IS DIFFERENT!
See http://en.wikipedia.org/wiki/Rounding for more detail
"""
def impl(self, x):
return theano._asarray(numpy.round(x), dtype = 'int64')
return numpy.round(x)
def c_code___(self, node, name, (x, ), (z, ), sub):
typ = node.outputs[0].type.dtype
if not node.outputs[0].type.dtype in ['float32', 'float64']:
Exception("The output should be float32 or float64")
return """
#ifndef ROUNDING_EPSILON
#define ROUNDING_EPSILON 0.0000001
#endif
if (%(x)s < 0.0){
// We implement the else part like that: -else( -%(x)s);
%(typ)s i;
std::modf( -%(x)s, &i );
// If %(x)s is exactly halfway between two integers
if ((-%(x)s -(i +0.5)) < epsilon){
// If 'i' is even then return 'i'
if (std::fmod( i, 2.0 ) < epsilon){
%(z)s = - i;
}else{
// Else return the nearest even integer
%(z)s = - ceil( i +0.5 );
}
}else{
// round to closest
%(z)s = - round(%(x)s+5);
}
}else{
%(typ)s i;
std::modf( %(x)s, &i );
// If %(x)s is exactly halfway between two integers
if ((%(x)s -(i +0.5)) < epsilon){
// If 'i' is even then return 'i'
if (std::fmod( i, 2.0 ) < epsilon){
%(z)s = i;
}else{
// Else return the nearest even integer
%(z)s = ceil( i +0.5 );
}
}else{
// round to closest
%(z)s = round(%(x)s+5);
}
}
#undef ROUNDING_EPSILON
"""
round_half_to_even = RoundHalfToEven(same_out_float_only)
def round_half_away_from_zero_(a):
if a>0:
return numpy.floor(a + 0.5)
else:
return numpy.ceil(a - 0.5)
round_half_away_from_zero_vec = numpy.vectorize(round_half_away_from_zero_)
class RoundHalfAwayFromZero(UnaryScalarOp):
"""
Implement the same rounding algo as c round() fct.
numpy.round fct IS DIFFERENT!
See http://en.wikipedia.org/wiki/Rounding for more detail
"""
def impl(self, x):
return vec(x)
def c_code(self, node, name, (x, ), (z, ), sub):
if node.outputs[0].type.dtype == 'float32':
return "%(z)s = fround(%(x)s);" % locals()
elif node.outputs[0].type.dtype == 'float64':
if node.outputs[0].type.dtype in ['float32', 'float64']:
return "%(z)s = round(%(x)s);" % locals()
else:
Exception("The output should be float32 or float64")
round = Round(same_out_float_only)
round_half_away_from_zero = RoundHalfAwayFromZero(same_out_float_only)
class Neg(UnaryScalarOp):
def impl(self, x):
......
......@@ -1579,8 +1579,12 @@ def iround(a):
"""int(round(a))"""
@_scal_elemwise
def round(a):
"""round(a)"""
def round_half_to_even(a):
"""round_half_to_even(a)"""
@_scal_elemwise
def round_half_away_from_zero(a):
"""round_half_away_from_zero(a)"""
@_scal_elemwise
def sqr(a):
......
......@@ -129,8 +129,12 @@ def iround_inplace(a):
"""int(round(a)) (inplace on `a`)"""
@_scal_inplace
def round_inplace(a):
"""round(a) (inplace on `a`)"""
def round_half_to_even_inplace(a):
"""round_half_to_even_inplace(a) (inplace on `a`)"""
@_scal_inplace
def round_half_away_from_zero_inplace(a):
"""round_half_away_from_zero_inplace(a) (inplace on `a`)"""
@_scal_inplace
def sqr_inplace(a):
......
......@@ -383,14 +383,19 @@ PowInplaceTester = makeBroadcastTester(op = inplace.pow_inplace,
column = (rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (2, 1)))),
inplace = True)
_good_broadcast_unary_normal_float = dict(normal = (rand_ranged(-5, 5, (2, 3)),))
#Those are corner case when rounding. Their is many rounding algo.
#c round() fct and numpy round are not the same!
corner_case = numpy.asarray([-2.5, -2., -1.5, -1., -0.5, -.51, -.49, 0., 0.49, 0.5, 0.9, 1, 1.5, 2, 2.5])
_good_broadcast_unary_normal_float = dict(normal = (rand_ranged(-5, 5, (2, 3)),),
corner_case = (corner_case,))
_good_broadcast_unary_normal = dict(normal = (rand_ranged(-5, 5, (2, 3)),),
integers = (randint_ranged(-5, 5, (2, 3)),))
integers = (randint_ranged(-5, 5, (2, 3)),),
corner_case = (corner_case,))
_grad_broadcast_unary_normal = dict(normal = (rand_ranged(-5, 5, (2, 3)),),
corner_case = (corner_case,))
_grad_broadcast_unary_normal = dict(normal = (rand_ranged(-5, 5, (2, 3)),))
AbsTester = makeBroadcastTester(op = tensor.abs_,
......@@ -448,14 +453,21 @@ IRoundInplaceTester = makeBroadcastTester(op = inplace.iround_inplace,
good = _good_broadcast_unary_normal,
inplace = True)
RoundTester = makeBroadcastTester(op = round,
RoundHalfToEvenTester = makeBroadcastTester(op = round_half_to_even,
expected = numpy.round,
good = _good_broadcast_unary_normal_float)
RoundInplaceTester = makeBroadcastTester(op = inplace.round_inplace,
RoundHalfToEvenInplaceTester = makeBroadcastTester(op = inplace.round_half_to_even_inplace,
expected = numpy.round,
good = _good_broadcast_unary_normal_float,
inplace = True)
RoundHalfAwayFromZeroTester = makeBroadcastTester(op = round_half_away_from_zero,
expected = theano.scalar.basic.round_half_away_from_zero_vec,
good = _good_broadcast_unary_normal_float)
RoundHalfAwayFromZeroInplaceTester = makeBroadcastTester(op = inplace.round_half_away_from_zero_inplace,
expected = theano.scalar.basic.round_half_away_from_zero_vec,
good = _good_broadcast_unary_normal_float,
inplace = True)
SqrTester = makeBroadcastTester(op = sqr,
expected = numpy.square,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论