Skip to content

Commit

Permalink
Julia: split ndarray.jl into several snippets (apache#14001)
Browse files Browse the repository at this point in the history
- `ndarray/type.jl`
- `ndarray/context.jl`
- `ndarray/show.jl`
- `ndarray/remap.jl`
- `ndarray/array.jl`
- `ndarray/arithmetic.jl`
- `ndarray/comparison.jl`
- `ndarray/io.jl`
- `ndarray/reduction.jl`
- `ndarray/statistic.jl`
- `ndarray/linalg.jl`
- `ndarray/trig.jl`
- `ndarray/activation.jl`
- `ndarray/autoimport.jl`
  • Loading branch information
iblislin authored and stephenrawls committed Feb 16, 2019
1 parent bf77635 commit 679f9cd
Show file tree
Hide file tree
Showing 15 changed files with 2,061 additions and 1,813 deletions.
1,827 changes: 14 additions & 1,813 deletions julia/src/ndarray.jl

Large diffs are not rendered by default.

87 changes: 87 additions & 0 deletions julia/src/ndarray/activation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

# activation functions

@doc doc"""
σ.(x::NDArray)
sigmoid.(x::NDArray)
Computes sigmoid of x element-wise.
```math
σ(x) = \frac{1}{(1 + exp(-x))}
```
The storage type of `sigmoid` output is always dense.
"""
function σ end
const sigmoid = σ
_nddoc[] = false
@_remap broadcasted(::typeof(σ), x::NDArray) sigmoid(x)

@doc doc"""
relu.(x::NDArray)
Computes rectified linear.
```math
\max(x, 0)
```
"""
function relu end
_nddoc[:relu] = false
@_remap broadcasted(::typeof(relu), x::NDArray) relu(x)

@doc doc"""
softmax.(x::NDArray, [dim = ndims(x)])
Applies the softmax function.
The resulting array contains elements in the range `(0, 1)`
and the elements along the given axis sum up to 1.
```math
softmax(\mathbf{z})_j = \frac{e^{z_j}}{\sum_{k=1}^K e^{z_k}}
```
"""
function softmax end
_nddoc[:softmax] = false
@_remap broadcasted(::typeof(softmax), x::NDArray) softmax(x; axis = -ndims(x))
@_remap broadcasted(::typeof(softmax), x::NDArray, dim::Int) softmax(x; axis = -dim)

"""
log_softmax.(x::NDArray, [dim = ndims(x)])
Computes the log softmax of the input.
This is equivalent to computing softmax followed by log.
julia> x
2×3 mx.NDArray{Float64,2} @ CPU0:
1.0 2.0 0.1
0.1 2.0 1.0
julia> mx.log_softmax.(x)
2×3 mx.NDArray{Float64,2} @ CPU0:
-1.41703 -0.41703 -2.31703
-2.31703 -0.41703 -1.41703
"""
function log_softmax end
_nddoc[:log_softmax] = false
@_remap broadcasted(::typeof(log_softmax), x::NDArray) log_softmax(x; axis = -ndims(x))
@_remap broadcasted(::typeof(log_softmax), x::NDArray, dim::Int) log_softmax(x; axis = -dim)

291 changes: 291 additions & 0 deletions julia/src/ndarray/arithmetic.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

import Base: +

"""
+(args...)
.+(args...)
Summation. Multiple arguments of either scalar or `NDArray` could be
added together. Note at least the first or second argument needs to be an
`NDArray` to avoid ambiguity of built-in summation.
"""
+(x::NDArray) = x
+(x::NDArray, y::NDArray) = _plus(x, y)
+(x::NDArray, y::Real) = _plus_scalar(x, scalar = y)
+(y::Real, x::NDArray) = _plus_scalar(x, scalar = y)

broadcasted(::typeof(+), x::NDArray{T,N}, y::NDArray{T,M}) where {T,N,M} =
_broadcast_add(x, y)

"""
sub_from!(dst::NDArray, args::NDArrayOrReal...)
Subtract a bunch of arguments from `dst`. Inplace updating.
"""
function sub_from!(dst::NDArray, arg::NDArrayOrReal)
@assert dst.writable
if isa(arg, Real)
_minus_scalar(dst, scalar = arg, out = dst)
else
_minus!(dst, arg)
end
dst
end

import Base: -

"""
-(x::NDArray)
-(x, y)
.-(x, y)
Subtraction `x - y`, of scalar types or `NDArray`.
Or create the negative of `x`.
"""
-(x::NDArray) = _mul_scalar(x, scalar = -one(eltype(x)))
-(x::NDArray, y::NDArray) = _minus(x, y)
-(x::NDArray, y::Real) = _minus_scalar(x, scalar = y)
-(y::Real, x::NDArray) = _rminus_scalar(x, scalar = y)

broadcasted(::typeof(-), x::NDArray{T,N}, y::NDArray{T,M}) where {T,N,M} =
_broadcast_minus(x, y)

"""
mul_to!(dst::NDArray, arg::NDArrayOrReal)
Elementwise multiplication into `dst` of either a scalar or an `NDArray` of the same shape.
Inplace updating.
"""
function mul_to!(dst::NDArray, arg::NDArrayOrReal)
@assert dst.writable
if isa(arg, Real)
_mul_scalar(dst, scalar = arg, out = dst)
else
_mul(dst, arg, out = dst)
end
dst
end

import Base: *

"""
.*(x, y)
Elementwise multiplication for `NDArray`.
"""
*(x::NDArray, y::Real) = _mul_scalar(x, scalar = y)
*(y::Real, x::NDArray) = _mul_scalar(x, scalar = y)

broadcasted(::typeof(*), x::NDArray{T,N}, y::NDArray{T,N}) where {T,N} =
_mul(x, y)
broadcasted(::typeof(*), x::NDArray{T,N}, y::NDArray{T,M}) where {T,N,M} =
_broadcast_mul(x, y)

"""
*(A::NDArray, B::NDArray)
Matrix/tensor multiplication.
"""
*(x::NDArray{T}, y::NDArray{T}) where T = x y

LinearAlgebra.adjoint(x::NDArray{T,1}) where T = transpose(x)
LinearAlgebra.adjoint(x::NDArray{T,2}) where T = transpose(x)

"""
div_from!(dst::NDArray, arg::NDArrayOrReal)
Elementwise divide a scalar or an `NDArray` of the same shape from `dst`. Inplace updating.
"""
function div_from!(dst::NDArray, arg::NDArrayOrReal)
@assert dst.writable
if isa(arg, Real)
_div_scalar(dst, scalar = arg, out = dst)
else
_div(dst, arg, out = dst)
end
dst
end

function div_from!(dst::NDArray{T}, arg::Real) where {T<:Integer}
@assert dst.writable
@assert(round(T, arg) != zero(T), "Integer divided by zero")
_div_scalar(dst, scalar = arg, out = dst)
dst
end

"""
rdiv_from!(x:: Real, y::NDArray)
Elementwise divide a scalar by an `NDArray`. Inplace updating.
"""
function rdiv_from!(x::Real, y::NDArray)
@assert y.writable
_rdiv_scalar(y, scalar = x, out = y)
y
end

import Base: /

"""
./(x::NDArray, y::NDArray)
./(x::NDArray, y::Real)
./(x::Real, y::NDArray)
* Elementwise dividing an `NDArray` by a scalar or another `NDArray`
of the same shape.
* Elementwise divide a scalar by an `NDArray`.
* Matrix division (solving linear systems) is not implemented yet.
"""
/(x::NDArray, y::Real) = _div_scalar(x, scalar = y)

broadcasted(::typeof(/), y::Real, x::NDArray) = _rdiv_scalar(x, scalar = y)
broadcasted(::typeof(/), x::NDArray{T,N}, y::NDArray{T,N}) where {T,N} =
_div(x, y)
broadcasted(::typeof(/), x::NDArray{T,N}, y::NDArray{T,M}) where {T,N,M} =
_broadcast_div(x, y)

function broadcasted(::typeof(/), x::NDArray{T}, y::Real) where {T<:Integer}
@assert(round(T, y) != zero(T), "Integer divided by zero")
_div_scalar(x, scalar = y)
end

"""
mod_from!(x::NDArray, y::NDArray)
mod_from!(x::NDArray, y::Real)
Elementwise modulo for `NDArray`.
Inplace updating.
"""
mod_from!(x::NDArray, y::NDArray) = _mod!(x, y)
mod_from!(x::NDArray, y::Real) = _mod_scalar!(x, y)

"""
rmod_from!(y::Real, x::NDArray)
Elementwise modulo for `NDArray`.
Inplace updating.
"""
rmod_from!(y::Real, x::NDArray) = _rmod_scalar!(x, y)

import Base: %

"""
.%(x::NDArray, y::NDArray)
.%(x::NDArray, y::Real)
.%(x::Real, y::NDArray)
Elementwise modulo for `NDArray`.
"""
%(x::NDArray, y::Real) = _mod_scalar(x, y)

broadcasted(::typeof(%), y::Real, x::NDArray) = _rmod_scalar(x, y)
broadcasted(::typeof(%), x::NDArray{T,N}, y::NDArray{T,N}) where {T,N} =
_mod(x, y)
broadcasted(::typeof(%), x::NDArray{T,N}, y::NDArray{T,M}) where {T,N,M} =
_broadcast_mod(x, y)

# document of `.^` is merged into SymbolicNode's

broadcasted(::typeof(Base.literal_pow), ::typeof(^), x::NDArray, ::Val{s}) where {s} =
_power_scalar(x, scalar = s)
broadcasted(::typeof(^), x::NDArray, s::Real) = _power_scalar(x, scalar = s)
broadcasted(::typeof(^), s::Real, x::NDArray) = _rpower_scalar(x, scalar = s)

broadcasted(::typeof(^), ::Irrational{:ℯ}, x::NDArray) = exp(x)
broadcasted(::typeof(^), x::NDArray, s::Irrational) = _power_scalar(x, scalar = s)
broadcasted(::typeof(^), s::Irrational, x::NDArray) = _rpower_scalar(x, scalar = s)

broadcasted(::typeof(^), x::NDArray{T,N}, y::NDArray{T,N}) where {T,N} =
_power(x, y)
broadcasted(::typeof(^), x::NDArray{T,N}, y::NDArray{T,M}) where {T,N,M} =
_broadcast_power(x, y)

_nddoc[:clip] = _nddoc[:clip!] =
"""
clip(x::NDArray, min, max)
clip!(x::NDArray, min, max)
Clips (limits) the values in `NDArray`.
Given an interval, values outside the interval are clipped to the interval edges.
Clipping `x` between `min` and `x` would be:
```julia
clip(x, min_, max_) = max(min(x, max_), min_))
```
```jldoctest
julia> x = NDArray(1:9);
julia> mx.clip(x, 2, 8)'
1×9 mx.NDArray{Int64,2} @ CPU0:
2 2 3 4 5 6 7 8 8
```
The storage type of clip output depends on storage types of inputs and the
`min`, `max` parameter values:
- clip(default) = default
- clip(row_sparse, min <= 0, max >= 0) = row_sparse
- clip(csr, min <= 0, max >= 0) = csr
- clip(row_sparse, min < 0, max < 0) = default
- clip(row_sparse, min > 0, max > 0) = default
- clip(csr, min < 0, max < 0) = csr
- clip(csr, min > 0, max > 0) = csr
"""
@_remap clip(x::NDArray, min::Real, max::Real) clip(x; a_min = min, a_max = max)
@_remap clip!(x::NDArray, min::Real, max::Real) clip(x; a_min = min, a_max = max)

################################################################################
# remapping to solving type unstablility
################################################################################

@_remap _plus(x::NDArray, y::NDArray) _plus(x, y)
@_remap _plus!(x::NDArray, y::NDArray) _plus(x, y)

@_remap _minus(x::NDArray, y::NDArray) _minus(x, y)
@_remap _minus!(x::NDArray, y::NDArray) _minus(x, y)

@_remap _mod(x::NDArray, y::NDArray) _mod(x, y)
@_remap _mod!(x::NDArray, y::NDArray) _mod(x, y)

@_remap _mod_scalar(x::NDArray, y::Real) _mod_scalar(x; scalar = y)
@_remap _mod_scalar!(x::NDArray, y::Real) _mod_scalar(x; scalar = y)

@_remap _rmod_scalar(x::NDArray, y::Real) _rmod_scalar(x; scalar = y)
@_remap _rmod_scalar!(x::NDArray, y::Real) _rmod_scalar(x; scalar = y)

@_remap _broadcast_add(x::NDArray, y::NDArray) broadcast_add(x, y)
@_remap _broadcast_add!(x::NDArray, y::NDArray) broadcast_add(x, y)

@_remap _broadcast_minus(x::NDArray, y::NDArray) broadcast_minus(x, y)
@_remap _broadcast_minus!(x::NDArray, y::NDArray) broadcast_minus(x, y)

@_remap _broadcast_mul(x::NDArray, y::NDArray) broadcast_mul(x, y)
@_remap _broadcast_mul!(x::NDArray, y::NDArray) broadcast_mul(x, y)

@_remap _broadcast_div(x::NDArray, y::NDArray) broadcast_div(x, y)
@_remap _broadcast_div!(x::NDArray, y::NDArray) broadcast_div(x, y)

@_remap _broadcast_mod(x::NDArray, y::NDArray) broadcast_mod(x, y)
@_remap _broadcast_mod!(x::NDArray, y::NDArray) broadcast_mod(x, y)

@_remap _broadcast_power(x::NDArray, y::NDArray) broadcast_power(x, y)
@_remap _broadcast_power!(x::NDArray, y::NDArray) broadcast_power(x, y)
Loading

0 comments on commit 679f9cd

Please sign in to comment.