rumale 0.23.3 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +5 -1
- data/README.md +3 -288
- data/lib/rumale/version.rb +1 -1
- data/lib/rumale.rb +20 -131
- metadata +252 -150
- data/CHANGELOG.md +0 -643
- data/CODE_OF_CONDUCT.md +0 -74
- data/ext/rumale/extconf.rb +0 -37
- data/ext/rumale/rumaleext.c +0 -545
- data/ext/rumale/rumaleext.h +0 -12
- data/lib/rumale/base/base_estimator.rb +0 -49
- data/lib/rumale/base/classifier.rb +0 -36
- data/lib/rumale/base/cluster_analyzer.rb +0 -31
- data/lib/rumale/base/evaluator.rb +0 -17
- data/lib/rumale/base/regressor.rb +0 -36
- data/lib/rumale/base/splitter.rb +0 -21
- data/lib/rumale/base/transformer.rb +0 -22
- data/lib/rumale/clustering/dbscan.rb +0 -123
- data/lib/rumale/clustering/gaussian_mixture.rb +0 -218
- data/lib/rumale/clustering/hdbscan.rb +0 -291
- data/lib/rumale/clustering/k_means.rb +0 -122
- data/lib/rumale/clustering/k_medoids.rb +0 -141
- data/lib/rumale/clustering/mini_batch_k_means.rb +0 -139
- data/lib/rumale/clustering/power_iteration.rb +0 -127
- data/lib/rumale/clustering/single_linkage.rb +0 -203
- data/lib/rumale/clustering/snn.rb +0 -76
- data/lib/rumale/clustering/spectral_clustering.rb +0 -115
- data/lib/rumale/dataset.rb +0 -246
- data/lib/rumale/decomposition/factor_analysis.rb +0 -150
- data/lib/rumale/decomposition/fast_ica.rb +0 -188
- data/lib/rumale/decomposition/nmf.rb +0 -124
- data/lib/rumale/decomposition/pca.rb +0 -159
- data/lib/rumale/ensemble/ada_boost_classifier.rb +0 -179
- data/lib/rumale/ensemble/ada_boost_regressor.rb +0 -160
- data/lib/rumale/ensemble/extra_trees_classifier.rb +0 -139
- data/lib/rumale/ensemble/extra_trees_regressor.rb +0 -125
- data/lib/rumale/ensemble/gradient_boosting_classifier.rb +0 -306
- data/lib/rumale/ensemble/gradient_boosting_regressor.rb +0 -237
- data/lib/rumale/ensemble/random_forest_classifier.rb +0 -189
- data/lib/rumale/ensemble/random_forest_regressor.rb +0 -153
- data/lib/rumale/ensemble/stacking_classifier.rb +0 -215
- data/lib/rumale/ensemble/stacking_regressor.rb +0 -163
- data/lib/rumale/ensemble/voting_classifier.rb +0 -126
- data/lib/rumale/ensemble/voting_regressor.rb +0 -82
- data/lib/rumale/evaluation_measure/accuracy.rb +0 -29
- data/lib/rumale/evaluation_measure/adjusted_rand_score.rb +0 -74
- data/lib/rumale/evaluation_measure/calinski_harabasz_score.rb +0 -56
- data/lib/rumale/evaluation_measure/davies_bouldin_score.rb +0 -53
- data/lib/rumale/evaluation_measure/explained_variance_score.rb +0 -39
- data/lib/rumale/evaluation_measure/f_score.rb +0 -50
- data/lib/rumale/evaluation_measure/function.rb +0 -147
- data/lib/rumale/evaluation_measure/log_loss.rb +0 -45
- data/lib/rumale/evaluation_measure/mean_absolute_error.rb +0 -29
- data/lib/rumale/evaluation_measure/mean_squared_error.rb +0 -29
- data/lib/rumale/evaluation_measure/mean_squared_log_error.rb +0 -29
- data/lib/rumale/evaluation_measure/median_absolute_error.rb +0 -30
- data/lib/rumale/evaluation_measure/mutual_information.rb +0 -49
- data/lib/rumale/evaluation_measure/normalized_mutual_information.rb +0 -53
- data/lib/rumale/evaluation_measure/precision.rb +0 -50
- data/lib/rumale/evaluation_measure/precision_recall.rb +0 -96
- data/lib/rumale/evaluation_measure/purity.rb +0 -40
- data/lib/rumale/evaluation_measure/r2_score.rb +0 -43
- data/lib/rumale/evaluation_measure/recall.rb +0 -50
- data/lib/rumale/evaluation_measure/roc_auc.rb +0 -130
- data/lib/rumale/evaluation_measure/silhouette_score.rb +0 -82
- data/lib/rumale/feature_extraction/feature_hasher.rb +0 -110
- data/lib/rumale/feature_extraction/hash_vectorizer.rb +0 -155
- data/lib/rumale/feature_extraction/tfidf_transformer.rb +0 -113
- data/lib/rumale/kernel_approximation/nystroem.rb +0 -126
- data/lib/rumale/kernel_approximation/rbf.rb +0 -102
- data/lib/rumale/kernel_machine/kernel_fda.rb +0 -120
- data/lib/rumale/kernel_machine/kernel_pca.rb +0 -97
- data/lib/rumale/kernel_machine/kernel_ridge.rb +0 -82
- data/lib/rumale/kernel_machine/kernel_ridge_classifier.rb +0 -92
- data/lib/rumale/kernel_machine/kernel_svc.rb +0 -193
- data/lib/rumale/linear_model/base_sgd.rb +0 -285
- data/lib/rumale/linear_model/elastic_net.rb +0 -119
- data/lib/rumale/linear_model/lasso.rb +0 -115
- data/lib/rumale/linear_model/linear_regression.rb +0 -201
- data/lib/rumale/linear_model/logistic_regression.rb +0 -275
- data/lib/rumale/linear_model/nnls.rb +0 -137
- data/lib/rumale/linear_model/ridge.rb +0 -209
- data/lib/rumale/linear_model/svc.rb +0 -213
- data/lib/rumale/linear_model/svr.rb +0 -132
- data/lib/rumale/manifold/mds.rb +0 -155
- data/lib/rumale/manifold/tsne.rb +0 -222
- data/lib/rumale/metric_learning/fisher_discriminant_analysis.rb +0 -113
- data/lib/rumale/metric_learning/mlkr.rb +0 -161
- data/lib/rumale/metric_learning/neighbourhood_component_analysis.rb +0 -167
- data/lib/rumale/model_selection/cross_validation.rb +0 -125
- data/lib/rumale/model_selection/function.rb +0 -42
- data/lib/rumale/model_selection/grid_search_cv.rb +0 -225
- data/lib/rumale/model_selection/group_k_fold.rb +0 -93
- data/lib/rumale/model_selection/group_shuffle_split.rb +0 -115
- data/lib/rumale/model_selection/k_fold.rb +0 -81
- data/lib/rumale/model_selection/shuffle_split.rb +0 -90
- data/lib/rumale/model_selection/stratified_k_fold.rb +0 -99
- data/lib/rumale/model_selection/stratified_shuffle_split.rb +0 -118
- data/lib/rumale/model_selection/time_series_split.rb +0 -91
- data/lib/rumale/multiclass/one_vs_rest_classifier.rb +0 -83
- data/lib/rumale/naive_bayes/base_naive_bayes.rb +0 -47
- data/lib/rumale/naive_bayes/bernoulli_nb.rb +0 -82
- data/lib/rumale/naive_bayes/complement_nb.rb +0 -85
- data/lib/rumale/naive_bayes/gaussian_nb.rb +0 -69
- data/lib/rumale/naive_bayes/multinomial_nb.rb +0 -74
- data/lib/rumale/naive_bayes/negation_nb.rb +0 -71
- data/lib/rumale/nearest_neighbors/k_neighbors_classifier.rb +0 -133
- data/lib/rumale/nearest_neighbors/k_neighbors_regressor.rb +0 -108
- data/lib/rumale/nearest_neighbors/vp_tree.rb +0 -132
- data/lib/rumale/neural_network/adam.rb +0 -56
- data/lib/rumale/neural_network/base_mlp.rb +0 -248
- data/lib/rumale/neural_network/mlp_classifier.rb +0 -120
- data/lib/rumale/neural_network/mlp_regressor.rb +0 -90
- data/lib/rumale/pairwise_metric.rb +0 -152
- data/lib/rumale/pipeline/feature_union.rb +0 -69
- data/lib/rumale/pipeline/pipeline.rb +0 -175
- data/lib/rumale/preprocessing/bin_discretizer.rb +0 -93
- data/lib/rumale/preprocessing/binarizer.rb +0 -60
- data/lib/rumale/preprocessing/kernel_calculator.rb +0 -92
- data/lib/rumale/preprocessing/l1_normalizer.rb +0 -62
- data/lib/rumale/preprocessing/l2_normalizer.rb +0 -63
- data/lib/rumale/preprocessing/label_binarizer.rb +0 -89
- data/lib/rumale/preprocessing/label_encoder.rb +0 -79
- data/lib/rumale/preprocessing/max_abs_scaler.rb +0 -61
- data/lib/rumale/preprocessing/max_normalizer.rb +0 -62
- data/lib/rumale/preprocessing/min_max_scaler.rb +0 -76
- data/lib/rumale/preprocessing/one_hot_encoder.rb +0 -100
- data/lib/rumale/preprocessing/ordinal_encoder.rb +0 -109
- data/lib/rumale/preprocessing/polynomial_features.rb +0 -109
- data/lib/rumale/preprocessing/standard_scaler.rb +0 -71
- data/lib/rumale/probabilistic_output.rb +0 -114
- data/lib/rumale/tree/base_decision_tree.rb +0 -150
- data/lib/rumale/tree/decision_tree_classifier.rb +0 -150
- data/lib/rumale/tree/decision_tree_regressor.rb +0 -116
- data/lib/rumale/tree/extra_tree_classifier.rb +0 -107
- data/lib/rumale/tree/extra_tree_regressor.rb +0 -94
- data/lib/rumale/tree/gradient_tree_regressor.rb +0 -202
- data/lib/rumale/tree/node.rb +0 -39
- data/lib/rumale/utils.rb +0 -42
- data/lib/rumale/validation.rb +0 -128
- data/lib/rumale/values.rb +0 -13
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rumale/validation'
|
|
4
|
-
require 'rumale/pairwise_metric'
|
|
5
|
-
require 'rumale/base/base_estimator'
|
|
6
|
-
|
|
7
|
-
module Rumale
|
|
8
|
-
module NearestNeighbors
|
|
9
|
-
# VPTree is a class that implements the nearest neigbor searcher based on vantage point tree.
|
|
10
|
-
# This implementation, unlike the paper, does not perform random sampling with vantage point selection.
|
|
11
|
-
# This class is used internally for k-nearest neighbor estimators.
|
|
12
|
-
#
|
|
13
|
-
# @deprecated This class will be removed in ver. 0.24.0. The author recommends to use the annoy-rb gem instead.
|
|
14
|
-
#
|
|
15
|
-
# *Reference*
|
|
16
|
-
# - Yianilos, P N., "Data Structures and Algorithms for Nearest Neighbor Search in General Metric Spaces," Proc. SODA'93, pp. 311--321, 1993.
|
|
17
|
-
class VPTree
|
|
18
|
-
include Validation
|
|
19
|
-
include Base::BaseEstimator
|
|
20
|
-
|
|
21
|
-
# Return the training data.
|
|
22
|
-
# @return [Numo::DFloat] (shape: [n_samples, n_features])
|
|
23
|
-
attr_reader :data
|
|
24
|
-
|
|
25
|
-
# Create a search index with vantage point tree algorithm.
|
|
26
|
-
#
|
|
27
|
-
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The data to used generating search index.
|
|
28
|
-
# @param min_samples_leaf [Integer] The minimum number of samples at a leaf node.
|
|
29
|
-
def initialize(x, min_samples_leaf: 1)
|
|
30
|
-
check_params_numeric(min_samples_leaf: min_samples_leaf)
|
|
31
|
-
check_params_positive(min_samples_leaf: min_samples_leaf)
|
|
32
|
-
@params = {}
|
|
33
|
-
@params[:min_samples_leaf] = min_samples_leaf
|
|
34
|
-
@data = x
|
|
35
|
-
@tree = build_tree(Numo::Int32.cast(Array(0...@data.shape[0])))
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Search k-nearest neighbors of given query point.
|
|
39
|
-
#
|
|
40
|
-
# @param x [Numo::DFloat] (shape: [n_samples, n_features])
|
|
41
|
-
# @param k [Integer] The samples to be query points.
|
|
42
|
-
# @return [Array<Array<Numo::Int32, Numo::DFloat>>] The indices and distances of retrieved k-nearest neighbors.
|
|
43
|
-
def query(x, k = 1)
|
|
44
|
-
x = check_convert_sample_array(x)
|
|
45
|
-
check_params_numeric(k: k)
|
|
46
|
-
check_params_positive(k: k)
|
|
47
|
-
|
|
48
|
-
n_samples = x.shape[0]
|
|
49
|
-
rel_ids = []
|
|
50
|
-
rel_dists = []
|
|
51
|
-
|
|
52
|
-
n_samples.times do |n|
|
|
53
|
-
q = x[n, true]
|
|
54
|
-
rel_node = search(q, @tree, k)
|
|
55
|
-
dist_arr = calc_distances(q, @data[rel_node.sample_ids, true])
|
|
56
|
-
rank_ids = dist_arr.sort_index[0...k]
|
|
57
|
-
rel_ids.push(rel_node.sample_ids[rank_ids].dup)
|
|
58
|
-
rel_dists.push(dist_arr[rank_ids].dup)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
[Numo::Int32.cast(rel_ids), Numo::DFloat.cast(rel_dists)]
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
private
|
|
65
|
-
|
|
66
|
-
Node = Struct.new(:sample_ids, :n_samples, :vantage_point_id, :threshold, :left, :right) do
|
|
67
|
-
def leaf?
|
|
68
|
-
vantage_point_id.nil?
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
private_constant :Node
|
|
73
|
-
|
|
74
|
-
def search(q, node, k, tau = Float::INFINITY)
|
|
75
|
-
return node if node.leaf?
|
|
76
|
-
|
|
77
|
-
dist = Math.sqrt(((q - @data[node.vantage_point_id, true])**2).sum)
|
|
78
|
-
tau = dist if dist < tau
|
|
79
|
-
|
|
80
|
-
# :nocov:
|
|
81
|
-
if dist < node.threshold
|
|
82
|
-
if dist - tau <= node.threshold
|
|
83
|
-
node.left.n_samples < k ? node : search(q, node.left, k, tau)
|
|
84
|
-
elsif dist + tau >= node.threshold
|
|
85
|
-
node.right.n_samples < k ? node : search(q, node.right, k, tau)
|
|
86
|
-
else
|
|
87
|
-
node
|
|
88
|
-
end
|
|
89
|
-
elsif dist + tau >= node.threshold
|
|
90
|
-
node.right.n_samples < k ? node : search(q, node.right, k, tau)
|
|
91
|
-
elsif dist - tau <= node.threshold
|
|
92
|
-
node.left.n_samples < k ? node : search(q, node.left, k, tau)
|
|
93
|
-
else
|
|
94
|
-
node
|
|
95
|
-
end
|
|
96
|
-
# :nocov:
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def build_tree(sample_ids)
|
|
100
|
-
n_samples = sample_ids.size
|
|
101
|
-
node = Node.new
|
|
102
|
-
node.n_samples = n_samples
|
|
103
|
-
node.sample_ids = sample_ids
|
|
104
|
-
return node if n_samples <= @params[:min_samples_leaf]
|
|
105
|
-
|
|
106
|
-
vantage_point_id = select_vantage_point_id(sample_ids)
|
|
107
|
-
distance_arr = calc_distances(@data[vantage_point_id, true], @data[sample_ids, true])
|
|
108
|
-
threshold = distance_arr.median
|
|
109
|
-
left_flgs = distance_arr.lt(threshold)
|
|
110
|
-
right_flgs = distance_arr.ge(threshold)
|
|
111
|
-
return node if left_flgs.count < @params[:min_samples_leaf] || right_flgs.count < @params[:min_samples_leaf]
|
|
112
|
-
|
|
113
|
-
node.left = build_tree(sample_ids[left_flgs])
|
|
114
|
-
node.right = build_tree(sample_ids[right_flgs])
|
|
115
|
-
node.vantage_point_id = vantage_point_id
|
|
116
|
-
node.threshold = threshold
|
|
117
|
-
node
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def select_vantage_point_id(sample_ids)
|
|
121
|
-
dist_mat = Rumale::PairwiseMetric.euclidean_distance(@data[sample_ids, true])
|
|
122
|
-
means = dist_mat.mean(0)
|
|
123
|
-
vars = ((dist_mat - means)**2).mean(0)
|
|
124
|
-
sample_ids[vars.max_index]
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def calc_distances(q, x)
|
|
128
|
-
Rumale::PairwiseMetric.euclidean_distance(q.expand_dims(0), x).flatten.dup
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rumale/base/base_estimator'
|
|
4
|
-
|
|
5
|
-
module Rumale
|
|
6
|
-
module NeuralNetwork
|
|
7
|
-
# @!visibility private
|
|
8
|
-
# This module consists of the classes that implement optimizers adaptively tuning learning rate.
|
|
9
|
-
module Optimizer
|
|
10
|
-
# @!visibility private
|
|
11
|
-
# Adam is a class that implements Adam optimizer.
|
|
12
|
-
#
|
|
13
|
-
# *Reference*
|
|
14
|
-
# - Kingma, D P., and Ba, J., "Adam: A Method for Stochastic Optimization," Proc. ICLR'15, 2015.
|
|
15
|
-
class Adam
|
|
16
|
-
include Base::BaseEstimator
|
|
17
|
-
|
|
18
|
-
# @!visibility private
|
|
19
|
-
# Create a new optimizer with Adam
|
|
20
|
-
#
|
|
21
|
-
# @param learning_rate [Float] The initial value of learning rate.
|
|
22
|
-
# @param decay1 [Float] The smoothing parameter for the first moment.
|
|
23
|
-
# @param decay2 [Float] The smoothing parameter for the second moment.
|
|
24
|
-
def initialize(learning_rate: 0.001, decay1: 0.9, decay2: 0.999)
|
|
25
|
-
@params = {}
|
|
26
|
-
@params[:learning_rate] = learning_rate
|
|
27
|
-
@params[:decay1] = decay1
|
|
28
|
-
@params[:decay2] = decay2
|
|
29
|
-
@fst_moment = nil
|
|
30
|
-
@sec_moment = nil
|
|
31
|
-
@iter = 0
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# @!visibility private
|
|
35
|
-
# Calculate the updated weight with Adam adaptive learning rate.
|
|
36
|
-
#
|
|
37
|
-
# @param weight [Numo::DFloat] (shape: [n_features]) The weight to be updated.
|
|
38
|
-
# @param gradient [Numo::DFloat] (shape: [n_features]) The gradient for updating the weight.
|
|
39
|
-
# @return [Numo::DFloat] (shape: [n_feautres]) The updated weight.
|
|
40
|
-
def call(weight, gradient)
|
|
41
|
-
@fst_moment ||= Numo::DFloat.zeros(weight.shape)
|
|
42
|
-
@sec_moment ||= Numo::DFloat.zeros(weight.shape)
|
|
43
|
-
|
|
44
|
-
@iter += 1
|
|
45
|
-
|
|
46
|
-
@fst_moment = @params[:decay1] * @fst_moment + (1.0 - @params[:decay1]) * gradient
|
|
47
|
-
@sec_moment = @params[:decay2] * @sec_moment + (1.0 - @params[:decay2]) * gradient**2
|
|
48
|
-
nm_fst_moment = @fst_moment / (1.0 - @params[:decay1]**@iter)
|
|
49
|
-
nm_sec_moment = @sec_moment / (1.0 - @params[:decay2]**@iter)
|
|
50
|
-
|
|
51
|
-
weight - @params[:learning_rate] * nm_fst_moment / (nm_sec_moment**0.5 + 1e-8)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rumale/base/base_estimator'
|
|
4
|
-
|
|
5
|
-
module Rumale
|
|
6
|
-
# This module consists of the modules and classes for implementation multi-layer perceptron estimator.
|
|
7
|
-
module NeuralNetwork
|
|
8
|
-
# @!visibility private
|
|
9
|
-
# This module consists of the classes that implement layer functions of neural network.
|
|
10
|
-
module Layer
|
|
11
|
-
# @!visibility private
|
|
12
|
-
# Affine is a class that calculates the linear transform.
|
|
13
|
-
# This class is used internally.
|
|
14
|
-
class Affine
|
|
15
|
-
# @!visibility private
|
|
16
|
-
def initialize(n_inputs: nil, n_outputs: nil, optimizer: nil, rng: nil)
|
|
17
|
-
@weight = 0.01 * Rumale::Utils.rand_normal([n_inputs, n_outputs], rng)
|
|
18
|
-
@bias = Numo::DFloat.zeros(n_outputs)
|
|
19
|
-
@optimizer_weight = optimizer.dup
|
|
20
|
-
@optimizer_bias = optimizer.dup
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# @!visibility private
|
|
24
|
-
def forward(x)
|
|
25
|
-
out = x.dot(@weight) + @bias
|
|
26
|
-
|
|
27
|
-
backward = proc do |dout|
|
|
28
|
-
dx = dout.dot(@weight.transpose)
|
|
29
|
-
dw = x.transpose.dot(dout)
|
|
30
|
-
db = dout.sum(0)
|
|
31
|
-
|
|
32
|
-
@weight = @optimizer_weight.call(@weight, dw)
|
|
33
|
-
@bias = @optimizer_bias.call(@bias, db)
|
|
34
|
-
|
|
35
|
-
dx
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
[out, backward]
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# @!visibility private
|
|
43
|
-
# Dropout is a class that performs dropout regularization.
|
|
44
|
-
# This class is used internally.
|
|
45
|
-
class Dropout
|
|
46
|
-
# @!visibility private
|
|
47
|
-
def initialize(rate: 0.3, rng: nil)
|
|
48
|
-
@rate = rate
|
|
49
|
-
@rng = rng
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# @!visibility private
|
|
53
|
-
def forward(x)
|
|
54
|
-
rand_mat = Rumale::Utils.rand_uniform(x.shape, @rng)
|
|
55
|
-
mask = rand_mat.ge(@rate)
|
|
56
|
-
out = x * mask
|
|
57
|
-
out *= 1.fdiv(1 - @rate) if @rate < 1.0
|
|
58
|
-
|
|
59
|
-
backward = proc { |dout| dout * mask }
|
|
60
|
-
|
|
61
|
-
[out, backward]
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# @!visibility private
|
|
66
|
-
# ReLU is a class that calculates rectified linear function.
|
|
67
|
-
# This class is used internally.
|
|
68
|
-
class Relu
|
|
69
|
-
# @!visibility private
|
|
70
|
-
def forward(x)
|
|
71
|
-
mask = x.gt(0)
|
|
72
|
-
out = x * mask
|
|
73
|
-
|
|
74
|
-
backward = proc { |dout| dout * mask }
|
|
75
|
-
|
|
76
|
-
[out, backward]
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# @!visibility private
|
|
82
|
-
# This module consists of the classes that implement loss function for neural network.
|
|
83
|
-
module Loss
|
|
84
|
-
# @!visibility private
|
|
85
|
-
# MeanSquaredError is a class that calculates mean squared error for regression task.
|
|
86
|
-
# This class is used internally.
|
|
87
|
-
class MeanSquaredError
|
|
88
|
-
# @!visibility private
|
|
89
|
-
def call(out, y)
|
|
90
|
-
sz_batch = y.shape[0]
|
|
91
|
-
diff = out - y
|
|
92
|
-
loss = (diff**2).sum.fdiv(sz_batch)
|
|
93
|
-
dout = 2.fdiv(sz_batch) * diff
|
|
94
|
-
[loss, dout]
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# @!visibility private
|
|
99
|
-
# SoftmaxCrossEntropy is a class that calculates softmax cross-entropy for classification task.
|
|
100
|
-
# This class is used internally.
|
|
101
|
-
class SoftmaxCrossEntropy
|
|
102
|
-
# @!visibility private
|
|
103
|
-
def call(out, y)
|
|
104
|
-
sz_batch = y.shape[0]
|
|
105
|
-
z = softmax(out)
|
|
106
|
-
loss = -(y * Numo::NMath.log(z + 1e-8)).sum.fdiv(sz_batch)
|
|
107
|
-
dout = (z - y) / sz_batch
|
|
108
|
-
[loss, dout]
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
private
|
|
112
|
-
|
|
113
|
-
def softmax(x)
|
|
114
|
-
clip = x.max(-1).expand_dims(-1)
|
|
115
|
-
exp_x = Numo::NMath.exp(x - clip)
|
|
116
|
-
exp_x / exp_x.sum(-1).expand_dims(-1)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# @!visibility private
|
|
122
|
-
# This module consists of the classes for implementing neural network model.
|
|
123
|
-
module Model
|
|
124
|
-
# @!visibility private
|
|
125
|
-
attr_reader :layers
|
|
126
|
-
|
|
127
|
-
# @!visibility private
|
|
128
|
-
# Sequential is a class that implements linear stack model.
|
|
129
|
-
# This class is used internally.
|
|
130
|
-
class Sequential
|
|
131
|
-
# @!visibility private
|
|
132
|
-
def initialize
|
|
133
|
-
@layers = []
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# @!visibility private
|
|
137
|
-
def push(ops)
|
|
138
|
-
@layers.push(ops)
|
|
139
|
-
self
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# @!visibility private
|
|
143
|
-
def delete_dropout
|
|
144
|
-
@layers.delete_if { |node| node.is_a?(Layer::Dropout) }
|
|
145
|
-
self
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# @!visibility private
|
|
149
|
-
def forward(x)
|
|
150
|
-
backprops = []
|
|
151
|
-
out = x.dup
|
|
152
|
-
|
|
153
|
-
@layers.each do |l|
|
|
154
|
-
out, bw = l.forward(out)
|
|
155
|
-
backprops.push(bw)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
backward = proc do |dout|
|
|
159
|
-
backprops.reverse_each { |bw| dout = bw.call(dout) }
|
|
160
|
-
dout
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
[out, backward]
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# BaseMLP is an abstract class for implementation of multi-layer peceptron estimator.
|
|
169
|
-
# This class is used internally.
|
|
170
|
-
class BaseMLP
|
|
171
|
-
include Base::BaseEstimator
|
|
172
|
-
|
|
173
|
-
# Create a multi-layer perceptron estimator.
|
|
174
|
-
#
|
|
175
|
-
# @param hidden_units [Array] The number of units in the i-th hidden layer.
|
|
176
|
-
# @param dropout_rate [Float] The rate of the units to drop.
|
|
177
|
-
# @param learning_rate [Float] The initial value of learning rate in Adam optimizer.
|
|
178
|
-
# @param decay1 [Float] The smoothing parameter for the first moment in Adam optimizer.
|
|
179
|
-
# @param decay2 [Float] The smoothing parameter for the second moment in Adam optimizer.
|
|
180
|
-
# @param max_iter [Integer] The maximum number of epochs that indicates
|
|
181
|
-
# how many times the whole data is given to the training process.
|
|
182
|
-
# @param batch_size [Intger] The size of the mini batches.
|
|
183
|
-
# @param tol [Float] The tolerance of loss for terminating optimization.
|
|
184
|
-
# @param verbose [Boolean] The flag indicating whether to output loss during iteration.
|
|
185
|
-
# @param random_seed [Integer] The seed value using to initialize the random generator.
|
|
186
|
-
def initialize(hidden_units: [128, 128], dropout_rate: 0.4, learning_rate: 0.001, decay1: 0.9, decay2: 0.999,
|
|
187
|
-
max_iter: 200, batch_size: 50, tol: 1e-4, verbose: false, random_seed: nil)
|
|
188
|
-
@params = {}
|
|
189
|
-
@params[:hidden_units] = hidden_units
|
|
190
|
-
@params[:dropout_rate] = dropout_rate
|
|
191
|
-
@params[:learning_rate] = learning_rate
|
|
192
|
-
@params[:decay1] = decay1
|
|
193
|
-
@params[:decay2] = decay2
|
|
194
|
-
@params[:max_iter] = max_iter
|
|
195
|
-
@params[:batch_size] = batch_size
|
|
196
|
-
@params[:tol] = tol
|
|
197
|
-
@params[:verbose] = verbose
|
|
198
|
-
@params[:random_seed] = random_seed
|
|
199
|
-
@params[:random_seed] ||= srand
|
|
200
|
-
@n_iter = nil
|
|
201
|
-
@rng = Random.new(@params[:random_seed])
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
private
|
|
205
|
-
|
|
206
|
-
def buld_network(n_inputs, n_outputs, srng = nil)
|
|
207
|
-
adam = Rumale::NeuralNetwork::Optimizer::Adam.new(
|
|
208
|
-
learning_rate: @params[:learning_rate], decay1: @params[:decay1], decay2: @params[:decay2]
|
|
209
|
-
)
|
|
210
|
-
model = Model::Sequential.new
|
|
211
|
-
n_units = [n_inputs, *@params[:hidden_units]]
|
|
212
|
-
n_units.each_cons(2) do |n_in, n_out|
|
|
213
|
-
model.push(Layer::Affine.new(n_inputs: n_in, n_outputs: n_out, optimizer: adam, rng: srng))
|
|
214
|
-
model.push(Layer::Relu.new)
|
|
215
|
-
model.push(Layer::Dropout.new(rate: @params[:dropout_rate], rng: srng))
|
|
216
|
-
end
|
|
217
|
-
model.push(Layer::Affine.new(n_inputs: n_units[-1], n_outputs: n_outputs, optimizer: adam, rng: srng))
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def train(x, y, network, loss_func, srng = nil)
|
|
221
|
-
class_name = self.class.to_s.split('::').last
|
|
222
|
-
n_samples = x.shape[0]
|
|
223
|
-
|
|
224
|
-
@params[:max_iter].times do |t|
|
|
225
|
-
sample_ids = Array(0...n_samples)
|
|
226
|
-
sample_ids.shuffle!(random: srng)
|
|
227
|
-
until (subset_ids = sample_ids.shift(@params[:batch_size])).empty?
|
|
228
|
-
# random sampling
|
|
229
|
-
sub_x = x[subset_ids, true].dup
|
|
230
|
-
sub_y = y[subset_ids, true].dup
|
|
231
|
-
# forward
|
|
232
|
-
out, backward = network.forward(sub_x)
|
|
233
|
-
# calc loss function
|
|
234
|
-
loss, dout = loss_func.call(out, sub_y)
|
|
235
|
-
break if loss < @params[:tol]
|
|
236
|
-
|
|
237
|
-
# backward
|
|
238
|
-
backward.call(dout)
|
|
239
|
-
end
|
|
240
|
-
@n_iter = t + 1
|
|
241
|
-
puts "[#{class_name}] Loss after #{@n_iter} epochs: #{loss}" if @params[:verbose]
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
network
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
end
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rumale/base/classifier'
|
|
4
|
-
require 'rumale/neural_network/base_mlp'
|
|
5
|
-
require 'rumale/preprocessing/label_binarizer'
|
|
6
|
-
|
|
7
|
-
module Rumale
|
|
8
|
-
module NeuralNetwork
|
|
9
|
-
# MLPClassifier is a class that implements classifier based on multi-layer perceptron.
|
|
10
|
-
# MLPClassifier use ReLu as the activation function and Adam as the optimization method
|
|
11
|
-
# and softmax cross entropy as the loss function.
|
|
12
|
-
#
|
|
13
|
-
# @example
|
|
14
|
-
# estimator = Rumale::NeuralNetwork::MLPClassifier.new(hidden_units: [100, 100], dropout_rate: 0.3)
|
|
15
|
-
# estimator.fit(training_samples, traininig_labels)
|
|
16
|
-
# results = estimator.predict(testing_samples)
|
|
17
|
-
class MLPClassifier < BaseMLP
|
|
18
|
-
include Base::Classifier
|
|
19
|
-
|
|
20
|
-
# Return the network.
|
|
21
|
-
# @return [Rumale::NeuralNetwork::Model::Sequential]
|
|
22
|
-
attr_reader :network
|
|
23
|
-
|
|
24
|
-
# Return the class labels.
|
|
25
|
-
# @return [Numo::Int32] (size: n_classes)
|
|
26
|
-
attr_reader :classes
|
|
27
|
-
|
|
28
|
-
# Return the number of iterations run for optimization
|
|
29
|
-
# @return [Integer]
|
|
30
|
-
attr_reader :n_iter
|
|
31
|
-
|
|
32
|
-
# Return the random generator.
|
|
33
|
-
# @return [Random]
|
|
34
|
-
attr_reader :rng
|
|
35
|
-
|
|
36
|
-
# Create a new classifier with multi-layer preceptron.
|
|
37
|
-
#
|
|
38
|
-
# @param hidden_units [Array] The number of units in the i-th hidden layer.
|
|
39
|
-
# @param dropout_rate [Float] The rate of the units to drop.
|
|
40
|
-
# @param learning_rate [Float] The initial value of learning rate in Adam optimizer.
|
|
41
|
-
# @param decay1 [Float] The smoothing parameter for the first moment in Adam optimizer.
|
|
42
|
-
# @param decay2 [Float] The smoothing parameter for the second moment in Adam optimizer.
|
|
43
|
-
# @param max_iter [Integer] The maximum number of epochs that indicates
|
|
44
|
-
# how many times the whole data is given to the training process.
|
|
45
|
-
# @param batch_size [Intger] The size of the mini batches.
|
|
46
|
-
# @param tol [Float] The tolerance of loss for terminating optimization.
|
|
47
|
-
# @param verbose [Boolean] The flag indicating whether to output loss during iteration.
|
|
48
|
-
# @param random_seed [Integer] The seed value using to initialize the random generator.
|
|
49
|
-
def initialize(hidden_units: [128, 128], dropout_rate: 0.4, learning_rate: 0.001, decay1: 0.9, decay2: 0.999,
|
|
50
|
-
max_iter: 200, batch_size: 50, tol: 1e-4, verbose: false, random_seed: nil)
|
|
51
|
-
check_params_type(Array, hidden_units: hidden_units)
|
|
52
|
-
check_params_numeric(dropout_rate: dropout_rate, learning_rate: learning_rate, decay1: decay1, decay2: decay2,
|
|
53
|
-
max_iter: max_iter, batch_size: batch_size, tol: tol)
|
|
54
|
-
check_params_boolean(verbose: verbose)
|
|
55
|
-
check_params_numeric_or_nil(random_seed: random_seed)
|
|
56
|
-
super
|
|
57
|
-
@classes = nil
|
|
58
|
-
@network = nil
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Fit the model with given training data.
|
|
62
|
-
#
|
|
63
|
-
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
|
|
64
|
-
# @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
|
|
65
|
-
# @return [MLPClassifier] The learned classifier itself.
|
|
66
|
-
def fit(x, y)
|
|
67
|
-
x = check_convert_sample_array(x)
|
|
68
|
-
y = check_convert_label_array(y)
|
|
69
|
-
check_sample_label_size(x, y)
|
|
70
|
-
|
|
71
|
-
@classes = Numo::Int32[*y.to_a.uniq.sort]
|
|
72
|
-
n_labels = @classes.size
|
|
73
|
-
n_features = x.shape[1]
|
|
74
|
-
sub_rng = @rng.dup
|
|
75
|
-
|
|
76
|
-
loss = Loss::SoftmaxCrossEntropy.new
|
|
77
|
-
@network = buld_network(n_features, n_labels, sub_rng)
|
|
78
|
-
@network = train(x, one_hot_encode(y), @network, loss, sub_rng)
|
|
79
|
-
@network.delete_dropout
|
|
80
|
-
|
|
81
|
-
self
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Predict class labels for samples.
|
|
85
|
-
#
|
|
86
|
-
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
|
|
87
|
-
# @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
|
|
88
|
-
def predict(x)
|
|
89
|
-
x = check_convert_sample_array(x)
|
|
90
|
-
n_samples = x.shape[0]
|
|
91
|
-
decision_values = predict_proba(x)
|
|
92
|
-
predicted = Array.new(n_samples) { |n| @classes[decision_values[n, true].max_index] }
|
|
93
|
-
Numo::Int32.asarray(predicted)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Predict probability for samples.
|
|
97
|
-
#
|
|
98
|
-
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the probailities.
|
|
99
|
-
# @return [Numo::DFloat] (shape: [n_samples, n_classes]) Predicted probability of each class per sample.
|
|
100
|
-
def predict_proba(x)
|
|
101
|
-
x = check_convert_sample_array(x)
|
|
102
|
-
out, = @network.forward(x)
|
|
103
|
-
softmax(out)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
private
|
|
107
|
-
|
|
108
|
-
def one_hot_encode(y)
|
|
109
|
-
encoder = Rumale::Preprocessing::LabelBinarizer.new
|
|
110
|
-
encoder.fit_transform(y)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def softmax(x)
|
|
114
|
-
clip = x.max(-1).expand_dims(-1)
|
|
115
|
-
exp_x = Numo::NMath.exp(x - clip)
|
|
116
|
-
exp_x / exp_x.sum(-1).expand_dims(-1)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rumale/base/regressor'
|
|
4
|
-
require 'rumale/neural_network/base_mlp'
|
|
5
|
-
|
|
6
|
-
module Rumale
|
|
7
|
-
module NeuralNetwork
|
|
8
|
-
# MLPRegressor is a class that implements regressor based on multi-layer perceptron.
|
|
9
|
-
# MLPRegressor use ReLu as the activation function and Adam as the optimization method
|
|
10
|
-
# and mean squared error as the loss function.
|
|
11
|
-
#
|
|
12
|
-
# @example
|
|
13
|
-
# estimator = Rumale::NeuralNetwork::MLPRegressor.new(hidden_units: [100, 100], dropout_rate: 0.3)
|
|
14
|
-
# estimator.fit(training_samples, traininig_labels)
|
|
15
|
-
# results = estimator.predict(testing_samples)
|
|
16
|
-
class MLPRegressor < BaseMLP
|
|
17
|
-
include Base::Regressor
|
|
18
|
-
|
|
19
|
-
# Return the network.
|
|
20
|
-
# @return [Rumale::NeuralNetwork::Model::Sequential]
|
|
21
|
-
attr_reader :network
|
|
22
|
-
|
|
23
|
-
# Return the number of iterations run for optimization
|
|
24
|
-
# @return [Integer]
|
|
25
|
-
attr_reader :n_iter
|
|
26
|
-
|
|
27
|
-
# Return the random generator.
|
|
28
|
-
# @return [Random]
|
|
29
|
-
attr_reader :rng
|
|
30
|
-
|
|
31
|
-
# Create a new regressor with multi-layer perceptron.
|
|
32
|
-
#
|
|
33
|
-
# @param hidden_units [Array] The number of units in the i-th hidden layer.
|
|
34
|
-
# @param dropout_rate [Float] The rate of the units to drop.
|
|
35
|
-
# @param learning_rate [Float] The initial value of learning rate in Adam optimizer.
|
|
36
|
-
# @param decay1 [Float] The smoothing parameter for the first moment in Adam optimizer.
|
|
37
|
-
# @param decay2 [Float] The smoothing parameter for the second moment in Adam optimizer.
|
|
38
|
-
# @param max_iter [Integer] The maximum number of epochs that indicates
|
|
39
|
-
# how many times the whole data is given to the training process.
|
|
40
|
-
# @param batch_size [Intger] The size of the mini batches.
|
|
41
|
-
# @param tol [Float] The tolerance of loss for terminating optimization.
|
|
42
|
-
# @param verbose [Boolean] The flag indicating whether to output loss during iteration.
|
|
43
|
-
# @param random_seed [Integer] The seed value using to initialize the random generator.
|
|
44
|
-
def initialize(hidden_units: [128, 128], dropout_rate: 0.4, learning_rate: 0.001, decay1: 0.9, decay2: 0.999,
|
|
45
|
-
max_iter: 200, batch_size: 50, tol: 1e-4, verbose: false, random_seed: nil)
|
|
46
|
-
check_params_type(Array, hidden_units: hidden_units)
|
|
47
|
-
check_params_numeric(dropout_rate: dropout_rate, learning_rate: learning_rate, decay1: decay1, decay2: decay2,
|
|
48
|
-
max_iter: max_iter, batch_size: batch_size, tol: tol)
|
|
49
|
-
check_params_boolean(verbose: verbose)
|
|
50
|
-
check_params_numeric_or_nil(random_seed: random_seed)
|
|
51
|
-
super
|
|
52
|
-
@network = nil
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Fit the model with given training data.
|
|
56
|
-
#
|
|
57
|
-
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
|
|
58
|
-
# @param y [Numo::DFloat] (shape: [n_samples, n_outputs]) The taget values to be used for fitting the model.
|
|
59
|
-
# @return [MLPRegressor] The learned regressor itself.
|
|
60
|
-
def fit(x, y)
|
|
61
|
-
x = check_convert_sample_array(x)
|
|
62
|
-
y = check_convert_tvalue_array(y)
|
|
63
|
-
check_sample_tvalue_size(x, y)
|
|
64
|
-
|
|
65
|
-
y = y.expand_dims(1) if y.ndim == 1
|
|
66
|
-
n_targets = y.shape[1]
|
|
67
|
-
n_features = x.shape[1]
|
|
68
|
-
sub_rng = @rng.dup
|
|
69
|
-
|
|
70
|
-
loss = Loss::MeanSquaredError.new
|
|
71
|
-
@network = buld_network(n_features, n_targets, sub_rng)
|
|
72
|
-
@network = train(x, y, @network, loss, sub_rng)
|
|
73
|
-
@network.delete_dropout
|
|
74
|
-
|
|
75
|
-
self
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Predict values for samples.
|
|
79
|
-
#
|
|
80
|
-
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the values.
|
|
81
|
-
# @return [Numo::DFloat] (shape: [n_samples, n_outputs]) Predicted values per sample.
|
|
82
|
-
def predict(x)
|
|
83
|
-
x = check_convert_sample_array(x)
|
|
84
|
-
out, = @network.forward(x)
|
|
85
|
-
out = out[true, 0] if out.shape[1] == 1
|
|
86
|
-
out
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|