Skip to content

Commit 10c8e9a

Browse files
committed
Update of docs/README
1 parent 9221ab6 commit 10c8e9a

File tree

13 files changed

+143
-52
lines changed

13 files changed

+143
-52
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ The aim is to make the API as model-agnostic as possible while still being user-
3434
<img src="docs/src/assets/heatmap_combination.png" width=400px>
3535
</p>
3636

37-
## Objectives (by priority)
38-
- AD Compatibility (Zygote, ForwardDiff)
39-
- Toeplitz Matrices
37+
## Packages goals (by priority)
38+
- Ensure AD Compatibility (Zygote, ForwardDiff)
39+
- Toeplitz Matrices compatibility
4040
- BLAS backend
4141

4242
Directly inspired by the [MLKernels](https://github.com/trthatcher/MLKernels.jl) package.
43+
44+
## Issues/Contributing
45+
46+
If you notice a problem or would like to contribute by adding more kernel functions or features please [submit an issue](https://github.com/theogf/KernelFunctions.jl/issues).

docs/make.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ makedocs(
66
format = Documenter.HTML(),
77
modules = [KernelFunctions],
88
pages = ["Home"=>"index.md",
9-
"User Guide" => "userguide.md",
9+
"User Guide" => "userguide.md",
10+
"Examples"=>"example.md",
1011
"Kernel Functions"=>"kernels.md",
1112
"Transform"=>"transform.md",
1213
"Metrics"=>"metrics.md",

docs/src/api.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ KernelFunctions
1818

1919
```@docs
2020
SqExponentialKernel
21-
Exponential
21+
ExponentialKernel
2222
GammaExponentialKernel
2323
ExponentiatedKernel
2424
MaternKernel
@@ -45,6 +45,7 @@ IdentityTransform
4545
ScaleTransform
4646
LowRankTransform
4747
FunctionTransform
48+
ChainTransform
4849
```
4950

5051
## Functions
@@ -54,6 +55,7 @@ kernelmatrix
5455
kernelmatrix!
5556
kerneldiagmatrix
5657
kerneldiagmatrix!
58+
kernelpdmat
5759
transform
5860
```
5961

docs/src/example.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Examples (WIP)
2+
3+
Here are a few examples of known complex kernels and how to do them. Or how to use kernels in a certain context
4+
5+
## Kernel Ridge Regression
6+
7+
Make a simple example of kernel ridge regression
8+
9+
## Gaussian Process Regression
10+
11+
Make a simple example of gaussian process regression
12+
13+
## Deep Kernel Learning
14+
15+
Put a Flux neural net in front of the kernel
16+
cf. Wilson paper
17+
18+
## Kernel Selection
19+
20+
Create a large collection of kernels and optimize the weights
21+
cf AISTATS 2018 paper

docs/src/index.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,16 @@
22

33
Model agnostic kernel functions compatible with automatic differentiation
44

5-
*** In Construction ***
5+
**KernelFunctions.jl** is a general purpose kernel package.
6+
It aims at providing a flexible framework for creating kernels and manipulating them.
7+
The main goals of this package compared to its predecessors/concurrents in [MLKernels.jl](https://github.com/trthatcher/MLKernels.jl), [Stheno.jl](https://github.com/willtebbutt/Stheno.jl), [GaussianProcesses.jl](https://github.com/STOR-i/GaussianProcesses.jl) and [AugmentedGaussianProcesses.jl](https://github.com/theogf/AugmentedGaussianProcesses.jl) are:
8+
- **Automatic Differentation** compatibility: all kernel functions should be differentiable via packages like [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) or [Zygote.jl](https://github.com/FluxML/Zygote.jl)
9+
- **Flexibility**: operations between kernels should be fluid and easy without breaking.
10+
- **Plug-and-play**: including the kernels before/after other steps should be straightforward.
11+
12+
The methodology of how kernels are computed is quite simple and is done in three phases :
13+
- A `Transform` object is applied sample-wise on every sample
14+
- The pairwise matrix is computed using [Distances.jl](https://github.com/JuliaStats/Distances.jl) by using a `Metric` proper to each kernel
15+
- The `Kernel` function is applied element-wise on the pairwise matrix
16+
17+
For a quick introduction on how to use it go to [User guide](@ref)

docs/src/theory.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See [Uncyclopedia article](https://en.wikipedia.org/wiki/Positive-definite_kernel)

docs/src/userguide.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,28 @@
1-
# Building kernel and matrices easily!
1+
# User guide
2+
3+
## Kernel creation
4+
5+
To create a kernel chose one of the kernels proposed, see [Kernels](@ref), or create your own, see [Creating Kernels](@ref)
6+
For example to create a square exponential kernel
7+
```julia
8+
k = SqExponentialKernel()
9+
```
10+
All kernels can take as argument a `Transform` object (see [Transform](@ref)) which is directly going to act on the inputs before it's processes.
11+
But it's also possible to simply give a scalar or a vector if all you are interested in is to modify the lengthscale, respectively for all dimensions or independently for each dimension.
12+
13+
## Kernel matrix creation
14+
15+
Matrix are created via the `kernelmatrix` function or `kerneldiagmatrix`.
16+
An important argument to give is the dimensionality of the input `obsdim`. It tells if the matrix is of the type `# samples X # features` (`obsdim`=1) or `# features X # samples`(`obsdim`=2) (similarly to [Distances.jl](https://github.com/JuliaStats/Distances.jl))
17+
For example:
18+
```julia
19+
k = SqExponentialKernel()
20+
A = rand(10,5)
21+
kernelmatrix(k,A,obsdim=1) # Return a 10x10 matrix
22+
kernelmatrix(k,A,obsdim=2) # Return a 5x5 matrix
23+
```
24+
25+
## Kernel manipulation
26+
27+
One can create combinations of kernels via `KernelSum` and `KernelProduct` or using simple operators `+` and `*`.
28+
For

src/KernelFunctions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module KernelFunctions
22

3-
export kernel, kernelmatrix, kernelmatrix!, kerneldiagmatrix, kerneldiagmatrix!, kappa
3+
export kernelmatrix, kernelmatrix!, kerneldiagmatrix, kerneldiagmatrix!, kappa, kernelpdmat
44
export get_params, set_params!
55

66

src/kernels/exponential.jl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
The squared exponential kernel is an isotropic Mercer kernel given by the formula:
55
66
```
7-
κ(x,y) = exp(-‖x-y‖²)
7+
κ(x,y) = exp(-ρ²‖x-y‖²)
88
```
99
1010
See also [`ExponentialKernel`](@ref) for a
@@ -19,8 +19,9 @@ struct SqExponentialKernel{T,Tr} <: Kernel{T,Tr}
1919
end
2020

2121
@inline kappa::SqExponentialKernel, d²::Real) = exp(-d²)
22+
@inline iskroncompatible(::SqExponentialKernel) = true
2223

23-
### Aliases
24+
## Aliases ##
2425
const RBFKernel = SqExponentialKernel
2526
const GaussianKernel = SqExponentialKernel
2627

@@ -30,7 +31,7 @@ const GaussianKernel = SqExponentialKernel
3031
The exponential kernel is an isotropic Mercer kernel given by the formula:
3132
3233
```
33-
κ(x,y) = exp(-‖x-y‖)
34+
κ(x,y) = exp(-ρ‖x-y‖)
3435
```
3536
3637
"""
@@ -43,8 +44,9 @@ struct ExponentialKernel{T,Tr} <: Kernel{T,Tr}
4344
end
4445

4546
@inline kappa::ExponentialKernel, d::Real) = exp(-d)
47+
@inline iskroncompatible(::ExponentialKernel) = true
4648

47-
### Aliases
49+
## Alias ##
4850
const LaplacianKernel = ExponentialKernel
4951

5052
"""
@@ -53,7 +55,7 @@ const LaplacianKernel = ExponentialKernel
5355
The γ-exponential kernel is an isotropic Mercer kernel given by the formula:
5456
5557
```
56-
κ(x,y) = exp(-‖x-y‖^)
58+
κ(x,y) = exp(-ρ^(2γ)‖x-y‖^(2γ))
5759
```
5860
"""
5961
struct GammaExponentialKernel{T,Tr,Tᵧ<:Real} <: Kernel{T,Tr}
@@ -81,3 +83,4 @@ function GammaExponentialKernel(t::Tr,gamma::T₁=2.0) where {Tr<:Transform,T₁
8183
end
8284

8385
@inline kappa::GammaExponentialKernel, d²::Real) = exp(-^κ.γ)
86+
@inline iskroncompatible(::GammaExponentialKernel) = true

src/matrix/kernelkroeneckermat.jl

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,25 @@ function kernelkronmat(
33
X::AbstractVector,
44
dims::Int
55
)
6-
@assert iskroncompatible(κ) "The kernel chosed is not compatible for kroenecker matrices"
7-
K = kernelmatrix(κ,reshape(X,:,1),obsdim=1)
8-
6+
@assert iskroncompatible(κ) "The kernel chosed is not compatible for kroenecker matrices (see `iskroncompatible()`)"
7+
k = kernelmatrix(κ,reshape(X,:,1),obsdim=1)
8+
K = kron()
99
end
1010

11+
function kernelkronmat(
12+
κ::Kernel,
13+
X::AbstractVector{<:AbstractVector};
14+
obsdim::Int=defaultobs
15+
)
16+
@assert iskroncompatible(κ) "The kernel chosed is not compatible for kroenecker matrices"
17+
Ks = kernelmatrix.(κ,X,obsdim=obsdim)
18+
K = kron(Ks)
19+
end
1120

12-
function iskroncompatible::Kernel)
1321

14-
end
22+
"""
23+
To be compatible with kroenecker constructions the kernel must satisfy
24+
the property : for x,x' ∈ ℜᴰ
25+
k(x,x') = ∏ᵢᴰ k(xᵢ,x'ᵢ)
26+
"""
27+
@inline iskroncompatible::Kernel) = false # Default return for kernels

src/matrix/kernelmatrix.jl

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,47 @@
11
"""
22
```
3-
kernelmatrix!(K::Matrix, κ::Kernel, X::Matrix; obsdim::Integer=2, symmetrize::Bool=true)
3+
kernelmatrix!(K::Matrix, κ::Kernel, X::Matrix; obsdim::Integer=2)
4+
kernelmatrix!(K::Matrix, κ::Kernel, X::Matrix, Y::Matrix; obsdim::Integer=2)
45
```
56
In-place version of `kernelmatrix` where pre-allocated matrix `K` will be overwritten with the kernel matrix.
67
"""
8+
kernelmatrix!
9+
10+
711
function kernelmatrix!(
812
K::Matrix,
913
κ::Kernel,
1014
X::AbstractMatrix;
1115
obsdim::Int = defaultobs
1216
)
17+
@assert obsdim [1,2] "obsdim should be 1 or 2 (see docs of kernelmatrix))"
1318
if !check_dims(K,X,X,feature_dim(obsdim),obsdim)
1419
throw(DimensionMismatch("Dimensions of the target array K $(size(K)) are not consistent with X $(size(X))"))
1520
end
1621
map!(x->kappa(κ,x),K,pairwise(metric(κ),transform(κ,X,obsdim),dims=obsdim))
1722
end
1823

19-
"""
20-
```
21-
kernelmatrix!(K::Matrix, κ::Kernel, X::Matrix, Y::Matrix; obsdim::Integer=2)
22-
```
23-
In-place version of `kernelmatrix` where pre-allocated matrix `K` will be overwritten with the kernel matrix.
24-
"""
2524
function kernelmatrix!(
2625
K::AbstractMatrix,
2726
κ::Kernel,
2827
X::AbstractMatrix,
2928
Y::AbstractMatrix;
3029
obsdim::Int = defaultobs
3130
)
31+
@assert obsdim [1,2] "obsdim should be 1 or 2 (see docs of kernelmatrix))"
3232
if !check_dims(K,X,Y,feature_dim(obsdim),obsdim)
3333
throw(DimensionMismatch("Dimensions $(size(K)) of the target array K are not consistent with X ($(size(X))) and Y ($(size(Y)))"))
3434
end
3535
map!(x->kappa(κ,x),K,pairwise(metric(κ),transform(κ,X,obsdim),transform(κ,Y,obsdim),dims=obsdim))
3636
end
3737

38-
"""
39-
```
40-
kernel(κ::Kernel, x, y; obsdim=2)
41-
```
42-
Apply the kernel `κ` to `x` and `y`.
43-
"""
44-
function kernel::Kernel, x::Real, y::Real)
38+
## Apply kernel on two reals ##
39+
function _kernel::Kernel, x::Real, y::Real)
4540
kernel(κ, [x], [y])
4641
end
4742

48-
function kernel(
43+
## Apply kernel on two vectors ##
44+
function _kernel(
4945
κ::Kernel,
5046
x::AbstractVector,
5147
y::AbstractVector;
@@ -57,35 +53,31 @@ end
5753

5854
"""
5955
```
60-
kernelmatrix(κ::Kernel, X::Matrix ; obsdim::Int=2, symmetrize::Bool=true)
56+
kernelmatrix(κ::Kernel, X::Matrix ; obsdim::Int=2)
57+
kernelmatrix(κ::Kernel, X::Matrix, Y::Matrix; obsdim::Int=2)
6158
```
62-
Calculate the kernel matrix of `X` with respect to kernel `κ`.
63-
`obsdim=1` means the matrix `X` has size #samples x #dimension
64-
`obsdim=2` means the matrix `X` has size #dimension x #samples
59+
Calculate the kernel matrix of `X` (and `Y`) with respect to kernel `κ`.
60+
`obsdim=1` means the matrix `X` (and `Y`) has size #samples x #dimension
61+
`obsdim=2` means the matrix `X` (and `Y`) has size #dimension x #samples
6562
"""
63+
kernelmatrix
64+
65+
6666
function kernelmatrix(
6767
κ::Kernel,
6868
X::AbstractMatrix;
69-
obsdim::Int = defaultobs,
70-
symmetrize::Bool = true
69+
obsdim::Int = defaultobs
7170
)
7271
K = map(x->kappa(κ,x),pairwise(metric(κ),transform(κ,X,obsdim),dims=obsdim))
7372
end
7473

75-
"""
76-
```
77-
kernelmatrix(κ::Kernel, X::Matrix, Y::Matrix; obsdim::Int=2)
78-
```
79-
Calculate the base matrix of `X` and `Y` with respect to kernel `κ`.
80-
`obsdim=1` means the matrices `X` and `Y` have sizes #samples x #dimension
81-
`obsdim=2` means the matrices `X` and `Y` have size #dimension x #samples
82-
"""
8374
function kernelmatrix(
8475
κ::Kernel,
8576
X::AbstractMatrix,
8677
Y::AbstractMatrix;
8778
obsdim=defaultobs
8879
)
80+
@assert obsdim [1,2] "obsdim should be 1 or 2 (see docs of kernelmatrix))"
8981
if !check_dims(X,Y,feature_dim(obsdim),obsdim)
9082
throw(DimensionMismatch("X $(size(X)) and Y $(size(Y)) do not have the same number of features on the dimension : $(feature_dim(obsdim))"))
9183
end
@@ -107,6 +99,7 @@ function kerneldiagmatrix(
10799
X::AbstractMatrix;
108100
obsdim::Int = defaultobs
109101
)
102+
@assert obsdim [1,2] "obsdim should be 1 or 2 (see docs of kernelmatrix))"
110103
if obsdim == 1
111104
[@views kernel(κ,X[i,:],X[i,:]) for i in 1:size(X,obsdim)]
112105
elseif obsdim == 2
@@ -126,6 +119,7 @@ function kerneldiagmatrix!(
126119
X::AbstractMatrix;
127120
obsdim::Int = defaultobs
128121
)
122+
@assert obsdim [1,2] "obsdim should be 1 or 2 (see docs of kernelmatrix))"
129123
if length(K) != size(X,obsdim)
130124
throw(DimensionMismatch("Dimensions of the target array K $(size(K)) are not consistent with X $(size(X))"))
131125
end

src/matrix/kernelpdmat.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
"""
2-
Guarantees to return a positive-definite matrix in the form of a `PDMat` matrix with the cholesky decomposition precomputed
2+
Compute a positive-definite matrix in the form of a `PDMat` matrix see [PDMats.jl]() with the cholesky decomposition precomputed
3+
The algorithm recursively tries to add recursively a diagonal nugget until positive definiteness is achieved or that the noise is too big
34
"""
45
function kernelpdmat(
56
κ::Kernel,
67
X::AbstractMatrix;
78
obsdim::Int = defaultobs
89
)
910
K = kernelmatrix(κ,X,obsdim=obsdim)
11+
Kmax =maximum(K)
1012
α = eps(eltype(K))
11-
while !isposdef(K+αI) && α < 0.01*maximum(K)
13+
while !isposdef(K+αI) && α < 0.01*Kmax
1214
α *= 2.0
1315
end
14-
if α >= 0.01*maximum(K)
16+
if α >= 0.01*Kmax
1517
@error "Adding noise on the diagonal was not sufficient to build a positive-definite matrix:\n - Check that your kernel parameters are not extreme\n - Check that your data is sufficiently sparse\n - Maybe use a different kernel"
1618
end
1719
return PDMat(K+αI)

0 commit comments

Comments
 (0)