Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
19f7768f
提交
19f7768f
authored
10月 26, 2011
作者:
David Warde-Farley
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
in range() -> in xrange() where possible
上级
94349257
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
91 行增加
和
91 行删除
+91
-91
vm.py
theano/gof/vm.py
+3
-3
basic_ops.py
theano/sandbox/cuda/basic_ops.py
+5
-5
elemwise.py
theano/sandbox/cuda/elemwise.py
+14
-14
opt.py
theano/sandbox/cuda/opt.py
+2
-2
neighbourhoods.py
theano/sandbox/neighbourhoods.py
+5
-5
basic.py
theano/scalar/basic.py
+4
-4
sp.py
theano/sparse/sandbox/sp.py
+2
-2
basic.py
theano/tensor/basic.py
+19
-19
blas.py
theano/tensor/blas.py
+1
-1
elemwise_cgen.py
theano/tensor/elemwise_cgen.py
+3
-3
conv.py
theano/tensor/nnet/conv.py
+17
-17
opt.py
theano/tensor/opt.py
+12
-12
raw_random.py
theano/tensor/raw_random.py
+4
-4
没有找到文件。
theano/gof/vm.py
浏览文件 @
19f7768f
...
...
@@ -94,7 +94,7 @@ class VM(object):
profile
.
apply_cimpl
[
node
]
=
hasattr
(
thunk
,
'cthunk'
)
# clear the timer info out of the buffers
for
i
in
range
(
len
(
self
.
call_times
)):
for
i
in
x
range
(
len
(
self
.
call_times
)):
self
.
call_times
[
i
]
=
0.0
self
.
call_counts
[
i
]
=
0
...
...
@@ -459,9 +459,9 @@ class VM_Linker(link.LocalLinker):
# put storage_map and compute_map into a int-based scheme
n_applies
=
len
(
nodes
)
storage_map_list
=
[
storage_map
[
vars_idx_inv
[
i
]]
for
i
in
range
(
len
(
vars_idx_inv
))]
for
i
in
x
range
(
len
(
vars_idx_inv
))]
compute_map_list
=
[
compute_map
[
vars_idx_inv
[
i
]]
for
i
in
range
(
len
(
vars_idx_inv
))]
for
i
in
x
range
(
len
(
vars_idx_inv
))]
if
nodes
:
assert
type
(
storage_map_list
[
0
])
is
list
assert
type
(
compute_map_list
[
0
])
is
list
...
...
theano/sandbox/cuda/basic_ops.py
浏览文件 @
19f7768f
...
...
@@ -803,8 +803,8 @@ class GpuSum(Op):
assert
N
in
[
1
,
2
,
3
]
makecall
=
self
.
_makecall
(
node
,
name
,
x
,
z
,
fail
)
N_pattern
=
''
.
join
([
'1'
]
*
N
)
param_dim
=
","
.
join
([
"CudaNdarray_HOST_DIMS(
%(x)
s)[
%(i)
s]"
%
locals
()
for
i
in
range
(
N
+
1
)])
strides_dim
=
","
.
join
([
"CudaNdarray_HOST_STRIDES(
%(x)
s)[
%(i)
s]"
%
locals
()
for
i
in
range
(
N
+
1
)])
param_dim
=
","
.
join
([
"CudaNdarray_HOST_DIMS(
%(x)
s)[
%(i)
s]"
%
locals
()
for
i
in
x
range
(
N
+
1
)])
strides_dim
=
","
.
join
([
"CudaNdarray_HOST_STRIDES(
%(x)
s)[
%(i)
s]"
%
locals
()
for
i
in
x
range
(
N
+
1
)])
threads_y
=
"""
//get as many y threads as we can fit
while (n_threads.x * (n_threads.y+1) <= NUM_VECTOR_OP_THREADS_PER_BLOCK)
...
...
@@ -1326,8 +1326,8 @@ class GpuSum(Op):
for_i3
=
"for (int i3 = threadIdx.x; i3 < d3; i3 += blockDim.x)"
reducebuf
=
self
.
_k_reduce_buf
(
'Z[i0 * sZ0]'
)
param_dim
=
","
.
join
([
"const int d
%(i)
s"
%
locals
()
for
i
in
range
(
nd_in
)])
param_strides
=
","
.
join
([
"const int sA
%(i)
s"
%
locals
()
for
i
in
range
(
nd_in
)])
param_dim
=
","
.
join
([
"const int d
%(i)
s"
%
locals
()
for
i
in
x
range
(
nd_in
)])
param_strides
=
","
.
join
([
"const int sA
%(i)
s"
%
locals
()
for
i
in
x
range
(
nd_in
)])
decl
=
self
.
_k_decl
(
node
,
nodename
)
init
=
self
.
_k_init
(
node
,
nodename
)
print
>>
sio
,
"""
...
...
@@ -1988,7 +1988,7 @@ class GpuContiguous(Op):
Py_INCREF(
%(z)
s);
} else if ((NULL ==
%(z)
s)"""
%
locals
()
for
i
in
range
(
len
(
node
.
inputs
[
0
]
.
type
.
broadcastable
)):
for
i
in
x
range
(
len
(
node
.
inputs
[
0
]
.
type
.
broadcastable
)):
str
+=
"
\n
|| (CudaNdarray_HOST_DIMS(
%(input)
s)[
%(i)
s] != CudaNdarray_HOST_DIMS(
%(z)
s)[
%(i)
s])"
%
locals
()
str
+=
""")
{
...
...
theano/sandbox/cuda/elemwise.py
浏览文件 @
19f7768f
...
...
@@ -552,9 +552,9 @@ class NaiveAlgo(object):
print
>>
sio
,
'std::cerr << "
\\
n";'
for
ipos
in
xrange
(
len
(
node
.
inputs
)):
print
>>
sio
,
'std::cerr << " local_str inputs
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_str[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
range
(
nd
)])
+
'<<"
\\
n";'
print
>>
sio
,
'std::cerr << " local_str inputs
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_str[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
x
range
(
nd
)])
+
'<<"
\\
n";'
for
ipos
in
xrange
(
len
(
node
.
outputs
)):
print
>>
sio
,
'std::cerr << " local_ostr inputs
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_ostr[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
range
(
nd
)])
+
'<<"
\\
n";'
print
>>
sio
,
'std::cerr << " local_ostr inputs
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_ostr[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
x
range
(
nd
)])
+
'<<"
\\
n";'
print
>>
sio
,
"""
for(int id=0;id<nd_collapse;id++){
...
...
@@ -593,17 +593,17 @@ class NaiveAlgo(object):
print
>>
sio
,
'std::cerr << "
\\
n";'
for
ipos
in
xrange
(
len
(
node
.
inputs
)):
print
>>
sio
,
'std::cerr << " local_str
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_str[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
range
(
nd
)])
+
'<<"
\\
n";'
print
>>
sio
,
'std::cerr << " local_str
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_str[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
x
range
(
nd
)])
+
'<<"
\\
n";'
for
ipos
in
xrange
(
len
(
node
.
outputs
)):
print
>>
sio
,
'std::cerr << " local_ostr
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_ostr[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
range
(
nd
)])
+
'<<"
\\
n";'
print
>>
sio
,
'std::cerr << " local_ostr
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_ostr[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
x
range
(
nd
)])
+
'<<"
\\
n";'
# collapse contiguous dimensions (ignoring scalars, generic version(collapse any dimensions, right, left, middle))
# this is a good idea because we make less index calculation in the gpu.
print
>>
sio
,
"int nd_collapse_[
%(nd)
s] = {"
%
locals
()
+
','
.
join
([
'1'
for
x
in
range
(
nd
)])
+
"};"
print
>>
sio
,
"int nd_collapse_[
%(nd)
s] = {"
%
locals
()
+
','
.
join
([
'1'
for
x
in
x
range
(
nd
)])
+
"};"
for
ipos
in
xrange
(
len
(
node
.
inputs
)):
if
not
_logical_scalar
(
node
.
inputs
[
ipos
]):
print
>>
sio
,
"""
int nd_collapse_
%(ipos)
s[
%(nd)
s] = {"""
%
locals
()
+
','
.
join
([
'1'
for
x
in
range
(
nd
)])
+
"};"
int nd_collapse_
%(ipos)
s[
%(nd)
s] = {"""
%
locals
()
+
','
.
join
([
'1'
for
x
in
x
range
(
nd
)])
+
"};"
print
>>
sio
,
"""
can_collapse_
%(nodename)
s(nd_collapse, local_dims, local_str[
%(ipos)
s], nd_collapse_
%(ipos)
s);
for(int i=0;i<nd_collapse;i++){
...
...
@@ -615,12 +615,12 @@ nd_collapse_[i]=0;
print
>>
sio
,
"""
std::cerr<< "nd_collapse_
%(ipos)
s "<<
"""
%
locals
()
print
>>
sio
,
' << " " << '
.
join
([
"nd_collapse_
%(ipos)
s["
%
locals
()
+
str
(
i
)
+
"]"
for
i
in
range
(
nd
)])
print
>>
sio
,
' << " " << '
.
join
([
"nd_collapse_
%(ipos)
s["
%
locals
()
+
str
(
i
)
+
"]"
for
i
in
x
range
(
nd
)])
print
>>
sio
,
'<< "
\\
n";'
print
>>
sio
,
"""
std::cerr<< "nd_collapse_ "<<
"""
%
locals
()
print
>>
sio
,
' << " " << '
.
join
([
"nd_collapse_["
%
locals
()
+
str
(
i
)
+
"]"
for
i
in
range
(
nd
)])
print
>>
sio
,
' << " " << '
.
join
([
"nd_collapse_["
%
locals
()
+
str
(
i
)
+
"]"
for
i
in
x
range
(
nd
)])
print
>>
sio
,
'<< "
\\
n";'
# update the local stride.
...
...
@@ -664,8 +664,8 @@ nd_collapse_[i]=0;
if(nd_collapse_[i]==1)nd_collapse--;
}
if(nd_collapse == 1 """
%
locals
()
l
=
[
"local_str[
%(ipos)
s][nd_collapse-1]==1 "
%
locals
()
for
ipos
in
range
(
len
(
node
.
inputs
))
if
not
_logical_scalar
(
node
.
inputs
[
ipos
])]
l
+=
[
"local_ostr[
%(ipos)
s][nd_collapse-1]==1 "
%
locals
()
for
ipos
in
range
(
len
(
node
.
outputs
))
if
not
_logical_scalar
(
node
.
outputs
[
ipos
])]
l
=
[
"local_str[
%(ipos)
s][nd_collapse-1]==1 "
%
locals
()
for
ipos
in
x
range
(
len
(
node
.
inputs
))
if
not
_logical_scalar
(
node
.
inputs
[
ipos
])]
l
+=
[
"local_ostr[
%(ipos)
s][nd_collapse-1]==1 "
%
locals
()
for
ipos
in
x
range
(
len
(
node
.
outputs
))
if
not
_logical_scalar
(
node
.
outputs
[
ipos
])]
if
len
(
l
)
>
0
:
print
>>
sio
,
" && "
,
" && "
.
join
(
l
)
print
>>
sio
,
"""){nd_collapse=0;} """
...
...
@@ -679,9 +679,9 @@ nd_collapse_[i]=0;
print
>>
sio
,
'std::cerr << "
\\
n";'
for
ipos
in
xrange
(
len
(
node
.
inputs
)):
print
>>
sio
,
'std::cerr << " local_str
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_str[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
range
(
nd
)])
+
'<<"
\\
n";'
print
>>
sio
,
'std::cerr << " local_str
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_str[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
x
range
(
nd
)])
+
'<<"
\\
n";'
for
ipos
in
xrange
(
len
(
node
.
outputs
)):
print
>>
sio
,
'std::cerr << " local_ostr
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_ostr[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
range
(
nd
)])
+
'<<"
\\
n";'
print
>>
sio
,
'std::cerr << " local_ostr
%(ipos)
s: " <<'
%
locals
()
+
' << " " << '
.
join
([
"local_ostr[
%(ipos)
s][
%(x)
s]"
%
locals
()
for
x
in
x
range
(
nd
)])
+
'<<"
\\
n";'
def
launch_Ccontiguous
(
nodename
,
scalar_op
,
sync
=
True
):
...
...
@@ -784,7 +784,7 @@ nd_collapse_[i]=0;
print
>>
sio
,
"case 0: {"
launch_Ccontiguous
(
nodename
,
scalar_op
,
self
.
sync
)
print
>>
sio
,
" } break;"
for
i
in
range
(
1
,
nd
+
1
):
for
i
in
x
range
(
1
,
nd
+
1
):
print
>>
sio
,
"case "
+
str
(
i
)
+
": {"
launch_General
(
nodename
,
scalar_op
,
i
,
self
.
sync
)
print
>>
sio
,
" } break;"
...
...
@@ -800,7 +800,7 @@ nd_collapse_[i]=0;
def
c_support_code_apply
(
self
,
node
,
nodename
):
nd
=
node
.
outputs
[
0
]
.
type
.
ndim
return
""
.
join
(
[
self
.
c_src_kernel
(
node
,
nodename
,
x
)
for
x
in
range
(
1
,
nd
+
1
)]
+
[
self
.
c_src_kernel
(
node
,
nodename
,
x
)
for
x
in
x
range
(
1
,
nd
+
1
)]
+
[
self
.
c_src_kernel_Ccontiguous
(
node
,
nodename
),
self
.
c_src_callkernel
(
node
,
nodename
),
...
...
theano/sandbox/cuda/opt.py
浏览文件 @
19f7768f
...
...
@@ -478,7 +478,7 @@ def local_gpu_sum(node):
new_in_shp
=
[
x_shape
[
0
]]
new_mask
=
[
reduce_mask
[
0
]]
for
i
in
range
(
1
,
x
.
type
.
ndim
):
for
i
in
x
range
(
1
,
x
.
type
.
ndim
):
if
reduce_mask
[
i
]
==
reduce_mask
[
i
-
1
]:
new_in_shp
[
-
1
]
*=
x_shape
[
i
]
else
:
...
...
@@ -993,7 +993,7 @@ def split_huge_add_or_mul(node):
return
False
while
len
(
node
.
inputs
)
>
max_nb_inputs
:
inner_op
=
[]
for
i
in
range
(
0
,
len
(
node
.
inputs
),
max_nb_inputs
):
for
i
in
x
range
(
0
,
len
(
node
.
inputs
),
max_nb_inputs
):
inner_op
.
append
(
node
.
op
(
*
node
.
inputs
[
i
:
i
+
max_nb_inputs
]))
node
=
node
.
op
(
*
inner_op
)
.
owner
return
node
...
...
theano/sandbox/neighbourhoods.py
浏览文件 @
19f7768f
...
...
@@ -76,9 +76,9 @@ class NeighbourhoodsFromImages(Op):
self
.
code_string
,
self
.
code
=
self
.
make_py_code
()
def
_compute_neigh_strides
(
self
):
neigh_strides
=
[
1
for
i
in
range
(
len
(
self
.
strides
))]
neigh_strides
=
[
1
for
i
in
x
range
(
len
(
self
.
strides
))]
cur_stride
=
1
for
i
in
range
(
len
(
self
.
strides
)
-
1
,
-
1
,
-
1
):
for
i
in
x
range
(
len
(
self
.
strides
)
-
1
,
-
1
,
-
1
):
neigh_strides
[
i
]
=
cur_stride
cur_stride
*=
self
.
dims_neighbourhoods
[
i
]
return
neigh_strides
...
...
@@ -107,7 +107,7 @@ class NeighbourhoodsFromImages(Op):
def
out_shape
(
self
,
input_shape
):
dims
=
list
(
input_shape
[:
self
.
n_dims_before
])
num_strides
=
[
0
for
i
in
range
(
len
(
self
.
strides
))]
num_strides
=
[
0
for
i
in
x
range
(
len
(
self
.
strides
))]
neigh_flattened_dim
=
1
for
i
,
ds
in
enumerate
(
self
.
dims_neighbourhoods
):
cur_stride
=
self
.
strides
[
i
]
...
...
@@ -238,13 +238,13 @@ class NeighbourhoodsFromImages(Op):
def
_py_flattened_idx
(
self
):
return
"+"
.
join
([
"neigh_strides[
%
d]*neigh_idx_
%
d"
%
(
i
,
i
)
\
for
i
in
range
(
len
(
self
.
strides
))])
for
i
in
x
range
(
len
(
self
.
strides
))])
def
_py_assignment
(
self
):
input_idx
=
""
.
join
([
"outer_idx_
%
d,"
%
(
i
,)
\
for
i
in
xrange
(
self
.
n_dims_before
)])
input_idx
+=
""
.
join
([
"dim_
%
d_offset+neigh_idx_
%
d,"
%
\
(
i
,
i
)
for
i
in
range
(
len
(
self
.
strides
))])
(
i
,
i
)
for
i
in
x
range
(
len
(
self
.
strides
))])
out_idx
=
""
.
join
(
\
[
"outer_idx_
%
d,"
%
(
i
,)
for
i
in
\
range
(
self
.
n_dims_before
)]
+
\
...
...
theano/scalar/basic.py
浏览文件 @
19f7768f
...
...
@@ -1958,9 +1958,9 @@ class Composite(ScalarOp):
raise
ValueError
(
"The env to Composite must be exclusively composed of ScalarOp instances."
)
subd
=
dict
(
zip
(
inputs
,
[
"
%%
(i
%
i)s"
%
i
for
i
in
range
(
len
(
inputs
))])
+
[
"
%%
(i
%
i)s"
%
i
for
i
in
x
range
(
len
(
inputs
))])
+
zip
(
outputs
,
[
"
%%
(o
%
i)s"
%
i
for
i
in
range
(
len
(
outputs
))]))
[
"
%%
(o
%
i)s"
%
i
for
i
in
x
range
(
len
(
outputs
))]))
for
orphan
in
env
.
variables
:
#env.orphans:
if
orphan
.
owner
is
None
and
orphan
not
in
env
.
inputs
:
...
...
@@ -2048,9 +2048,9 @@ class Composite(ScalarOp):
raise
NotImplementedError
(
"grad is not implemented for Composite"
)
def
c_code
(
self
,
node
,
name
,
inames
,
onames
,
sub
):
d
=
dict
(
zip
([
"i
%
i"
%
i
for
i
in
range
(
len
(
inames
))],
d
=
dict
(
zip
([
"i
%
i"
%
i
for
i
in
x
range
(
len
(
inames
))],
inames
)
+
zip
([
"o
%
i"
%
i
for
i
in
range
(
len
(
onames
))],
zip
([
"o
%
i"
%
i
for
i
in
x
range
(
len
(
onames
))],
onames
),
**
sub
)
d
[
'name'
]
=
name
...
...
theano/sparse/sandbox/sp.py
浏览文件 @
19f7768f
...
...
@@ -382,8 +382,8 @@ class ConvolutionIndices(Op):
# of the column values (order in which you write the values determines how the
# vectorized data will get used later one)
for
fmapi
in
range
(
inshp
[
0
]):
# loop over input features
for
n
in
range
(
nkern
):
# loop over number of kernels (nkern=1 for weight sharing)
for
fmapi
in
x
range
(
inshp
[
0
]):
# loop over input features
for
n
in
x
range
(
nkern
):
# loop over number of kernels (nkern=1 for weight sharing)
# FOR EACH OUTPUT PIXEL...
for
oy
in
N
.
arange
(
lbound
[
0
],
ubound
[
0
],
dy
):
# loop over output image height
...
...
theano/tensor/basic.py
浏览文件 @
19f7768f
...
...
@@ -1815,7 +1815,7 @@ class SpecifyShape(Op):
def
infer_shape
(
self
,
node
,
shapes
):
xshape
,
sshape
=
shapes
new_shape
=
[]
for
dim
in
range
(
node
.
inputs
[
0
]
.
ndim
):
for
dim
in
x
range
(
node
.
inputs
[
0
]
.
ndim
):
try
:
s
=
get_constant_value
(
node
.
inputs
[
1
][
dim
])
s
=
as_tensor_variable
(
s
)
...
...
@@ -2677,7 +2677,7 @@ def var(input, axis = None):
#make a pattern that will undo the reduction of dimensions caused by mean
pattern
=
[]
next_dim
=
0
for
i
in
range
(
input_ndim
):
for
i
in
x
range
(
input_ndim
):
if
i
in
axis
:
pattern
.
append
(
'x'
)
else
:
...
...
@@ -3928,7 +3928,7 @@ class Rebroadcast(Op):
if
len
(
self
.
axis
)
==
0
:
broadcast_pattern
=
[]
else
:
broadcast_pattern
=
[
'?'
for
i
in
range
(
1
+
numpy
.
max
(
self
.
axis
.
keys
()))]
broadcast_pattern
=
[
'?'
for
i
in
x
range
(
1
+
numpy
.
max
(
self
.
axis
.
keys
()))]
for
k
,
v
in
self
.
axis
.
iteritems
():
broadcast_pattern
[
k
]
=
str
(
int
(
v
))
return
'
%
s{
%
s}'
%
(
self
.
__class__
.
__name__
,
','
.
join
(
broadcast_pattern
))
...
...
@@ -3955,7 +3955,7 @@ class Rebroadcast(Op):
assert
len
(
ishapes
)
==
1
l
=
[]
one
=
constant
(
1
)
for
ax
in
range
(
len
(
ishapes
[
0
])):
for
ax
in
x
range
(
len
(
ishapes
[
0
])):
if
self
.
axis
.
get
(
ax
,
False
):
l
.
append
(
one
)
else
:
...
...
@@ -3994,7 +3994,7 @@ def patternbroadcast(x, broadcastable):
We apply the opt here not to pollute the graph especially during the gpu optimization
"""
rval
=
Rebroadcast
(
*
[(
i
,
broadcastable
[
i
])
for
i
in
range
(
len
(
broadcastable
))])(
x
)
rval
=
Rebroadcast
(
*
[(
i
,
broadcastable
[
i
])
for
i
in
x
range
(
len
(
broadcastable
))])(
x
)
return
theano
.
tensor
.
opt
.
apply_rebroadcast_opt
(
rval
)
class
Join
(
Op
):
...
...
@@ -4158,7 +4158,7 @@ class Join(Op):
# 'axis' dimension.
return
[
gz
[[
slice
(
None
)]
*
axis
+
[
slice
(
idx
[
k
],
idx
[
k
+
1
])]
+
\
[
slice
(
None
)]
*
(
n_dims
-
axis
-
1
)]
\
for
k
in
range
(
len
(
sizes_along_axis
))]
for
k
in
x
range
(
len
(
sizes_along_axis
))]
def
vec_length
(
self
,
node
):
"""Guess the length of a Join Variable"""
...
...
@@ -4235,7 +4235,7 @@ def shape_padleft(t, n_ones=1):
"""
_t
=
as_tensor_variable
(
t
)
pattern
=
[
'x'
]
*
n_ones
+
[
i
for
i
in
range
(
_t
.
type
.
ndim
)]
pattern
=
[
'x'
]
*
n_ones
+
[
i
for
i
in
x
range
(
_t
.
type
.
ndim
)]
return
DimShuffle
(
_t
.
broadcastable
,
pattern
)(
_t
)
@constructor
...
...
@@ -4246,7 +4246,7 @@ def shape_padright(t, n_ones=1):
"""
_t
=
as_tensor_variable
(
t
)
pattern
=
[
i
for
i
in
range
(
_t
.
type
.
ndim
)]
+
[
'x'
]
*
n_ones
pattern
=
[
i
for
i
in
x
range
(
_t
.
type
.
ndim
)]
+
[
'x'
]
*
n_ones
return
DimShuffle
(
_t
.
broadcastable
,
pattern
)(
_t
)
@constructor
...
...
@@ -4382,7 +4382,7 @@ if 0: #vertical and horizontal stacking are deprecated. Better to use stack() a
out
,
=
out_
assert
x
.
ndim
==
y
.
ndim
# Make sure every dimension (save the first) is the same
for
i
in
range
(
x
.
ndim
):
assert
i
==
0
or
x
.
shape
[
i
]
==
y
.
shape
[
i
]
for
i
in
x
range
(
x
.
ndim
):
assert
i
==
0
or
x
.
shape
[
i
]
==
y
.
shape
[
i
]
out
[
0
]
=
numpy
.
vstack
([
x
,
y
])
def
grad
(
self
,
inp
,
grads
):
"""
...
...
@@ -4390,7 +4390,7 @@ if 0: #vertical and horizontal stacking are deprecated. Better to use stack() a
that way we can do more sanity-checking::
assert x.ndim == y.ndim
# Make sure every dimension (save the first) is the same
for i in range(x.data.ndim): assert i == 0 or x.data.shape[i] == y.shape[i]
for i in
x
range(x.data.ndim): assert i == 0 or x.data.shape[i] == y.shape[i]
etc...
"""
x
,
y
=
inp
...
...
@@ -4482,13 +4482,13 @@ class Reshape(Op):
#return [tuple([switch(eq(node.inputs[1][i], -1),
# theano.tensor.opt.Shape_i(i)(node.outputs[0]),
# node.inputs[1][i])
# for i in range(self.ndim)]
# for i in
x
range(self.ndim)]
# )]
# Here, we only simplify if the shape (node.inputs[1]) is a constant,
# ideally it would suffice to check that it is always non-negative.
oshape
=
[]
for
i
in
range
(
self
.
ndim
):
for
i
in
x
range
(
self
.
ndim
):
default_os_i
=
theano
.
tensor
.
opt
.
Shape_i
(
i
)(
node
.
outputs
[
0
])
try
:
os_i
=
get_constant_value
(
node
.
inputs
[
1
][
i
])
.
item
()
...
...
@@ -4801,15 +4801,15 @@ class PermuteRowElements(Op):
xs0
=
x
.
shape
[
0
]
ys0
=
y
.
shape
[
0
]
if
xs0
==
ys0
:
for
i
in
range
(
xs0
):
for
i
in
x
range
(
xs0
):
self
.
_rec_perform
(
node
,
x
[
i
],
y
[
i
],
inverse
,
out
[
i
],
curdim
+
1
)
elif
ys0
==
1
and
node
.
inputs
[
1
]
.
type
.
broadcastable
[
curdim
]:
# Broadcast y
for
i
in
range
(
xs0
):
for
i
in
x
range
(
xs0
):
self
.
_rec_perform
(
node
,
x
[
i
],
y
[
0
],
inverse
,
out
[
i
],
curdim
+
1
)
elif
xs0
==
1
and
node
.
inputs
[
0
]
.
type
.
broadcastable
[
curdim
]:
# Broadcast x
for
i
in
range
(
ys0
):
for
i
in
x
range
(
ys0
):
self
.
_rec_perform
(
node
,
x
[
0
],
y
[
i
],
inverse
,
out
[
i
],
curdim
+
1
)
else
:
raise
ValueError
(
'Dimension mismatch:
%
s,
%
s'
%
(
xs0
,
ys0
))
...
...
@@ -4850,7 +4850,7 @@ class PermuteRowElements(Op):
# If x has been broadcasted along some axes, we need to sum
# the gradient over these axes, but keep the dimension (as
# broadcastable)
broadcasted_dims
=
[
dim
for
dim
in
range
(
gz
.
type
.
ndim
)
\
broadcasted_dims
=
[
dim
for
dim
in
x
range
(
gz
.
type
.
ndim
)
\
if
x
.
type
.
broadcastable
[
dim
]
and
not
gz
.
type
.
broadcastable
[
dim
]]
gx
=
Sum
(
axis
=
broadcasted_dims
)(
gx
)
...
...
@@ -4858,7 +4858,7 @@ class PermuteRowElements(Op):
# so we need to put them back.
newdims
=
[]
i
=
0
for
dim
in
range
(
gz
.
type
.
ndim
):
for
dim
in
x
range
(
gz
.
type
.
ndim
):
if
dim
in
broadcasted_dims
:
newdims
.
append
(
'x'
)
else
:
...
...
@@ -5348,13 +5348,13 @@ class TensorDotGrad(Op):
_gx
=
numpy
.
tensordot
(
gz
,
y
,
[
range
(
x
.
ndim
-
len
(
self
.
axes
[
0
]),
gz
.
ndim
),
sum_over_y
])
idx
=
numpy
.
hstack
((
sum_over_x
,
self
.
axes
[
0
]))
newshapex
=
numpy
.
zeros
(
x
.
ndim
)
newshapex
[[
newpos
for
newpos
in
idx
]]
=
[
i
for
i
in
range
(
x
.
ndim
)]
newshapex
[[
newpos
for
newpos
in
idx
]]
=
[
i
for
i
in
x
range
(
x
.
ndim
)]
gx
[
0
]
=
numpy
.
transpose
(
_gx
,
newshapex
)
_gy
=
numpy
.
tensordot
(
x
,
gz
,
[
sum_over_x
,
range
(
x
.
ndim
-
len
(
self
.
axes
[
0
]))])
idy
=
numpy
.
hstack
((
self
.
axes
[
1
],
sum_over_y
))
newshapey
=
numpy
.
zeros
(
y
.
ndim
)
newshapey
[[
newpos
for
newpos
in
idy
]]
=
[
i
for
i
in
range
(
y
.
ndim
)]
newshapey
[[
newpos
for
newpos
in
idy
]]
=
[
i
for
i
in
x
range
(
y
.
ndim
)]
gy
[
0
]
=
numpy
.
transpose
(
_gy
,
newshapey
)
tensordot_grad
=
TensorDotGrad
...
...
theano/tensor/blas.py
浏览文件 @
19f7768f
...
...
@@ -1603,7 +1603,7 @@ def local_dot22_to_dot22scalar(node):
# I'm asserting there are no such inputs here:
assert
dot22_idx
!=
mul_idx
assert
all
((
i
in
(
dot22_idx
,
mul_idx
))
for
i
in
range
(
len
(
node
.
inputs
)))
for
i
in
x
range
(
len
(
node
.
inputs
)))
return
[
T
.
mul
(
m
.
owner
.
inputs
[
1
-
i
],
dot
)]
elif
m
.
owner
and
m
.
owner
.
op
==
T
.
mul
:
...
...
theano/tensor/elemwise_cgen.py
浏览文件 @
19f7768f
...
...
@@ -315,7 +315,7 @@ def make_reordered_loop(init_loop_orders, olv_index, dtypes, inner_task, sub):
%(ovar)
s_loops_it =
%(ovar)
s_loops.begin();
"""
%
locals
()
for
i
in
range
(
nnested
):
for
i
in
x
range
(
nnested
):
declare_totals
+=
"""
int TOTAL_
%(i)
i = init_totals[
%(ovar)
s_loops_it->second];
++
%(ovar)
s_loops_it;
...
...
@@ -357,7 +357,7 @@ def make_reordered_loop(init_loop_orders, olv_index, dtypes, inner_task, sub):
std::vector< std::pair<int, int> >::reverse_iterator
%(ovar)
s_loops_rit;
"""
%
locals
()
for
i
in
range
(
nvars
):
for
i
in
x
range
(
nvars
):
var
=
sub
[
"lv
%
i"
%
i
]
declare_strides_jumps
+=
"""
%(ovar)
s_loops_rit =
%(ovar)
s_loops.rbegin();"""
%
locals
()
...
...
@@ -382,7 +382,7 @@ def make_reordered_loop(init_loop_orders, olv_index, dtypes, inner_task, sub):
iterv
=
'ITER_
%
i'
%
i
total
=
'TOTAL_
%
i'
%
i
update
=
''
for
j
in
range
(
nvars
):
for
j
in
x
range
(
nvars
):
var
=
sub
[
"lv
%
i"
%
j
]
update
+=
"
%(var)
s_iter +=
%(var)
s_jump_l
%(i)
i;
\n
"
%
locals
()
...
...
theano/tensor/nnet/conv.py
浏览文件 @
19f7768f
...
...
@@ -73,14 +73,14 @@ def conv2d(input, filters, image_shape=None, filter_shape=None,
#accept Constant value for image_shape and filter_shape.
if
image_shape
is
not
None
:
image_shape
=
list
(
image_shape
)
for
i
in
range
(
len
(
image_shape
)):
for
i
in
x
range
(
len
(
image_shape
)):
if
image_shape
[
i
]
is
not
None
:
image_shape
[
i
]
=
get_constant_value
(
as_tensor_variable
(
image_shape
[
i
]))
assert
str
(
image_shape
[
i
]
.
dtype
)
.
startswith
(
'int'
)
image_shape
[
i
]
=
int
(
image_shape
[
i
])
if
filter_shape
is
not
None
:
filter_shape
=
list
(
filter_shape
)
for
i
in
range
(
len
(
filter_shape
)):
for
i
in
x
range
(
len
(
filter_shape
)):
if
filter_shape
[
i
]
is
not
None
:
filter_shape
[
i
]
=
get_constant_value
(
as_tensor_variable
(
filter_shape
[
i
]))
assert
str
(
filter_shape
[
i
]
.
dtype
)
.
startswith
(
'int'
)
...
...
@@ -450,7 +450,7 @@ class ConvOp(Op):
else
:
time_unroll_patch
=
self
.
speed_unroll_patch_noshape
[
mode_idx
]
time_unroll_batch_kern
=
9999999
for
i
in
range
(
len
(
self
.
speed_unroll_batch_kern
)):
for
i
in
x
range
(
len
(
self
.
speed_unroll_batch_kern
)):
if
bsize
%
self
.
speed_unroll_batch_kern
[
i
][
0
]
==
0
and
nkern
%
self
.
speed_unroll_batch_kern
[
i
][
1
]
==
0
:
if
self
.
speed_unroll_batch_kern
[
i
][
2
+
mode_idx
]
<
time_unroll_batch_kern
:
time_unroll_batch_kern
=
self
.
speed_unroll_batch_kern
[
i
][
2
+
mode_idx
]
...
...
@@ -506,9 +506,9 @@ class ConvOp(Op):
else
:
#full mode not implemented
self
.
flops
=
0
for
out_row
in
range
(
self
.
outshp
[
0
]):
#loop over output row
for
out_col
in
range
(
self
.
outshp
[
0
]):
#loop over output col
for
row
in
range
(
self
.
kshp
[
0
]):
#loop over kern row
for
out_row
in
x
range
(
self
.
outshp
[
0
]):
#loop over output row
for
out_col
in
x
range
(
self
.
outshp
[
0
]):
#loop over output col
for
row
in
x
range
(
self
.
kshp
[
0
]):
#loop over kern row
if
(
row
+
out_row
-
self
.
kshp
[
0
]
+
1
<
0
or
row
+
out_row
-
self
.
kshp
[
0
]
+
1
>=
self
.
imshp
[
1
]):
...
...
@@ -664,10 +664,10 @@ class ConvOp(Op):
val
=
_valfrommode
(
self
.
out_mode
)
bval
=
_bvalfromboundary
(
'fill'
)
for
b
in
range
(
bsize
):
for
n
in
range
(
nkern
):
for
b
in
x
range
(
bsize
):
for
n
in
x
range
(
nkern
):
zz
[
b
,
n
,
...
]
.
fill
(
0
)
for
im0
in
range
(
stacklen
):
for
im0
in
x
range
(
stacklen
):
zz
[
b
,
n
,
...
]
+=
_convolve2d
(
\
img2d
[
b
,
im0
,
...
],
filtersflipped
[
n
,
im0
,
...
],
1
,
val
,
bval
,
0
)
...
...
@@ -681,12 +681,12 @@ class ConvOp(Op):
img2d
=
img2d2
#N_image_shape = image_data.shape
for
b
in
range
(
bsize
):
for
n
in
range
(
nkern
):
for
b
in
x
range
(
bsize
):
for
n
in
x
range
(
nkern
):
zz
[
b
,
n
,
...
]
.
fill
(
0
)
for
im0
in
range
(
stacklen
):
for
row
in
range
(
0
,
zz
.
shape
[
2
],
self
.
dx
):
for
col
in
range
(
0
,
zz
.
shape
[
3
],
self
.
dy
):
for
im0
in
x
range
(
stacklen
):
for
row
in
x
range
(
0
,
zz
.
shape
[
2
],
self
.
dx
):
for
col
in
x
range
(
0
,
zz
.
shape
[
3
],
self
.
dy
):
zz
[
b
,
n
,
row
,
col
]
+=
(
img2d
[
b
,
im0
,
row
:
row
+
kshp
[
0
],
col
:
col
+
kshp
[
1
]]
*
\
filtersflipped
[
n
,
im0
,::
-
1
,::
-
1
])
.
sum
()
...
...
@@ -1555,16 +1555,16 @@ def gen_conv_code_unroll_batch_kern(d,unroll_bsize=1, unroll_ksize=1):
d
[
"unroll_ksize"
]
=
unroll_ksize
def
my_dup
(
st
,
size
):
s
=
""
for
i
in
range
(
size
):
for
i
in
x
range
(
size
):
d
[
"unroll_iter"
]
=
i
s
+=
st
%
d
return
s
+
"
\n
"
def
my_dup2
(
st
):
s
=
""
iter
=
0
for
i
in
range
(
unroll_bsize
):
for
i
in
x
range
(
unroll_bsize
):
d
[
"unroll_biter"
]
=
i
for
j
in
range
(
unroll_ksize
):
for
j
in
x
range
(
unroll_ksize
):
d
[
"unroll_kiter"
]
=
j
d
[
"unroll_iter"
]
=
iter
iter
+=
1
...
...
theano/tensor/opt.py
浏览文件 @
19f7768f
...
...
@@ -1043,7 +1043,7 @@ class Assert(T.Op):
out
=
onames
[
0
]
check
=
[]
fail
=
sub
[
'fail'
]
for
idx
in
range
(
len
(
inames
)
-
1
):
for
idx
in
x
range
(
len
(
inames
)
-
1
):
i
=
inames
[
idx
+
1
]
dtype
=
node
.
inputs
[
idx
+
1
]
.
dtype
check
.
append
(
'if(!((npy_
%(dtype)
s*)PyArray_DATA(
%(i)
s))[0]){PyErr_SetString(PyExc_AssertionError,"Theano Assert failed!");
%(fail)
s}'
%
locals
())
...
...
@@ -1138,7 +1138,7 @@ def local_alloc_elemwise(node):
assert
i
.
type
.
ndim
==
cmp_op
.
ndim
if
theano
.
config
.
experimental
.
local_alloc_elemwise_assert
:
assert_op
=
assert_
(
assert_op
,
*
[
T
.
eq
(
i
.
shape
[
idx
],
cmp_op
.
shape
[
idx
])
\
for
idx
in
range
(
i
.
type
.
ndim
)
\
for
idx
in
x
range
(
i
.
type
.
ndim
)
\
if
not
i
.
type
.
broadcastable
[
idx
]])
new
.
append
(
i
.
owner
.
inputs
[
0
])
elif
i
.
owner
and
isinstance
(
i
.
owner
.
op
,
T
.
DimShuffle
)
and
i
.
owner
.
inputs
[
0
]
.
owner
\
...
...
@@ -1146,7 +1146,7 @@ def local_alloc_elemwise(node):
assert
i
.
type
.
ndim
==
cmp_op
.
type
.
ndim
if
theano
.
config
.
experimental
.
local_alloc_elemwise_assert
:
assert_op
=
assert_
(
assert_op
,
*
[
T
.
eq
(
i
.
shape
[
idx
],
cmp_op
.
shape
[
idx
])
for
idx
\
in
range
(
i
.
type
.
ndim
)
if
not
i
.
type
.
broadcastable
[
idx
]])
in
x
range
(
i
.
type
.
ndim
)
if
not
i
.
type
.
broadcastable
[
idx
]])
new
.
append
(
i
.
owner
.
inputs
[
0
]
.
owner
.
inputs
[
0
])
else
:
new
.
append
(
i
)
new
[
no_broad_idx
]
=
assert_op
...
...
@@ -1322,7 +1322,7 @@ def local_subtensor_lift(node):
Handles the following unary ops:
elemwise(x,...)[idx] -> elemwise(x[idx],...)
when x,... are broadcasted scalar or not broadcasted at all
rebroadcast(x)[idx] => rebroadcast(x[idx])
rebroadcast(x)[idx] => rebroadcast(x[idx])
"""
if
isinstance
(
node
.
op
,
T
.
Subtensor
):
u
=
node
.
inputs
[
0
]
...
...
@@ -1375,7 +1375,7 @@ def local_subtensor_lift(node):
if
isinstance
(
x
,
slice
):
new_axis
+=
[(
j
,
u
.
broadcastable
[
i
])]
j
+=
1
# now keep the broadcastable pattern of all
# now keep the broadcastable pattern of all
# items not appearing in subtensor list
for
i
in
xrange
(
len
(
node
.
op
.
idx_list
),
len
(
u
.
broadcastable
)):
new_axis
+=
[(
j
,
u
.
broadcastable
[
i
])]
...
...
@@ -1897,7 +1897,7 @@ def local_remove_switch_const_cond(node):
out
=
T
.
cast
(
out
,
node
.
outputs
[
0
]
.
dtype
)
if
out
.
type
.
broadcastable
!=
node
.
outputs
[
0
]
.
type
.
broadcastable
:
# We need to copy data to the new dimensions during execution
out
=
T
.
alloc
(
out
,
*
[
node
.
outputs
[
0
]
.
shape
[
i
]
for
i
in
range
(
out
.
ndim
)])
out
=
T
.
alloc
(
out
,
*
[
node
.
outputs
[
0
]
.
shape
[
i
]
for
i
in
x
range
(
out
.
ndim
)])
return
[
out
]
return
False
...
...
@@ -2723,11 +2723,11 @@ def local_sum_alloc(node):
val
=
get_constant_value
(
input
)
assert
val
.
size
==
1
val
=
val
.
reshape
(
1
)[
0
]
to_prod
=
[
shapes
[
i
]
for
i
in
range
(
len
(
shapes
))
if
i
in
node
.
op
.
axis
]
to_prod
=
[
shapes
[
i
]
for
i
in
x
range
(
len
(
shapes
))
if
i
in
node
.
op
.
axis
]
if
to_prod
:
val
*=
T
.
mul
(
*
to_prod
)
return
[
T
.
alloc
(
T
.
cast
(
val
,
dtype
=
node
.
outputs
[
0
]
.
dtype
),
*
[
shapes
[
i
]
for
i
in
range
(
len
(
shapes
))
if
i
not
in
node
.
op
.
axis
])]
*
[
shapes
[
i
]
for
i
in
x
range
(
len
(
shapes
))
if
i
not
in
node
.
op
.
axis
])]
except
TypeError
,
e
:
pass
...
...
@@ -2905,7 +2905,7 @@ def local_pow_specialize_device(node):
pow2
=
[
xsym
]
pow2_scal
=
[
theano
.
scalar
.
Scalar
(
xsym
.
dtype
)()]
y_to_do
=
abs
(
y
)
for
i
in
range
(
int
(
numpy
.
log2
(
y_to_do
))):
for
i
in
x
range
(
int
(
numpy
.
log2
(
y_to_do
))):
pow2
.
append
(
T
.
sqr
(
pow2
[
i
]))
pow2_scal
.
append
(
theano
.
scalar
.
sqr
(
pow2_scal
[
i
]))
rval1
=
None
...
...
@@ -3546,7 +3546,7 @@ def local_grad_log_erfc_neg(node):
mul_inputs
=
check_input
(
mul_neg
.
owner
.
inputs
)
#put the constant first
for
i
in
range
(
len
(
mul_inputs
)):
for
i
in
x
range
(
len
(
mul_inputs
)):
if
isinstance
(
i
,
Constant
):
if
i
==
0
:
break
...
...
@@ -3636,7 +3636,7 @@ a64=[x*((1-1/(2*x**2)+3/(4*x**4)-15/(8*x**6))**(-1))*numpy.sqrt(numpy.pi) for x
a32=[x*((1-1/(2*x**2)+3/(4*x**4)-15/(8*x**6))**(-1))*numpy.float32(numpy.sqrt(numpy.pi)) for x in numpy.asarray(r,dtype='float32')]
for idx,(a,b,c,d,e) in enumerate(zip(r,p64,p32,a64,a32)):print a,b,c,d,e,c-b,e-b,numpy.absolute(c-b)<numpy.absolute(e-b)
for i in range(1,len(p32)): print r[i], p32[i]-p32[i-1]#, show that the value don't look stable at some point before inf.
for i in
x
range(1,len(p32)): print r[i], p32[i]-p32[i-1]#, show that the value don't look stable at some point before inf.
#float64 threshold is 26.63 the approx seam more precise at that point.
r = numpy.arange(26.2,26.7,.001)
...
...
@@ -3649,7 +3649,7 @@ a128=[x*((1-1/(2*x**2)+3/(4*x**4)-15/(8*x**6))**(-1))*numpy.float128(numpy.sqrt(
a64=[x*((1-1/(2*x**2)+3/(4*x**4)-15/(8*x**6)+63/(7*x**8))**(-1))*numpy.sqrt(numpy.pi) for x in r]
for a,b,c,d in zip(r,p128,p64,a64):print a,b,c,d,c-b,d-b
for i in range(1,len(p64)): print i, 64[i]-p64[i-1]
for i in
x
range(1,len(p64)): print i, 64[i]-p64[i-1]
"""
# ###############
...
...
theano/tensor/raw_random.py
浏览文件 @
19f7768f
...
...
@@ -357,7 +357,7 @@ def _generate_broadcasting_indices(out_shape, *shapes):
# Will contain the return value: a list of indices for each argument
ret_indices
=
[
[()]
for
shape
in
all_shapes
]
for
dim
in
range
(
len
(
out_shape
)):
for
dim
in
x
range
(
len
(
out_shape
)):
# Temporary list to generate the indices
_ret_indices
=
[
[]
for
shape
in
all_shapes
]
...
...
@@ -377,7 +377,7 @@ def _generate_broadcasting_indices(out_shape, *shapes):
for
prev_index
in
zip
(
*
ret_indices
):
for
dim_index
in
zip
(
*
ranges
):
for
i
in
range
(
len
(
all_shapes
)):
for
i
in
x
range
(
len
(
all_shapes
)):
_ret_indices
[
i
]
.
append
(
prev_index
[
i
]
+
(
dim_index
[
i
],))
ret_indices
=
_ret_indices
...
...
@@ -488,7 +488,7 @@ def random_integers_helper(random_state, low, high, size):
out_size
=
tuple
(
size
)
else
:
out_size
=
()
for
dim
in
range
(
out_ndim
):
for
dim
in
x
range
(
out_ndim
):
dim_len
=
max
(
low
.
shape
[
dim
],
high
.
shape
[
dim
])
out_size
=
out_size
+
(
dim_len
,)
...
...
@@ -602,7 +602,7 @@ def multinomial_helper(random_state, n, pvals, size):
size
=
tuple
(
size
)
else
:
size
=
()
for
dim
in
range
(
ndim
):
for
dim
in
x
range
(
ndim
):
dim_len
=
max
(
n
.
shape
[
dim
],
pvals
.
shape
[
dim
])
size
=
size
+
(
dim_len
,)
out_size
=
size
+
(
pvals
.
shape
[
-
1
],)
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论