rubyzero 0.1.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 +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +9 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +35 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/changelog.md +0 -0
- data/lib/rubyzero/core/cast.rb +25 -0
- data/lib/rubyzero/core/core.rb +15 -0
- data/lib/rubyzero/core/device.rb +32 -0
- data/lib/rubyzero/core/dtypes.rb +115 -0
- data/lib/rubyzero/core/exceptions.rb +7 -0
- data/lib/rubyzero/core/functions/activations.rb +20 -0
- data/lib/rubyzero/core/functions/elementary_functions.rb +29 -0
- data/lib/rubyzero/core/functions/function.rb +29 -0
- data/lib/rubyzero/core/functions/functions.rb +10 -0
- data/lib/rubyzero/core/functions/operators.rb +112 -0
- data/lib/rubyzero/core/functions/tensor_functions.rb +123 -0
- data/lib/rubyzero/core/tensor.rb +56 -0
- data/lib/rubyzero/core/tensor_backward.rb +17 -0
- data/lib/rubyzero/core/tensor_initialize_methods.rb +78 -0
- data/lib/rubyzero/core/tensor_operators.rb +27 -0
- data/lib/rubyzero/data/data.rb +9 -0
- data/lib/rubyzero/data/dataloader.rb +34 -0
- data/lib/rubyzero/data/dataset.rb +19 -0
- data/lib/rubyzero/data/presets/presets.rb +7 -0
- data/lib/rubyzero/data/presets/xor.rb +24 -0
- data/lib/rubyzero/nn/functional.rb +21 -0
- data/lib/rubyzero/nn/layers/affine.rb +21 -0
- data/lib/rubyzero/nn/layers/embedding.rb +7 -0
- data/lib/rubyzero/nn/layers/layer.rb +5 -0
- data/lib/rubyzero/nn/layers/layers.rb +44 -0
- data/lib/rubyzero/nn/layers/modellist.rb +40 -0
- data/lib/rubyzero/nn/layers/modelstack.rb +20 -0
- data/lib/rubyzero/nn/layers/multi_layer_perceptron.rb +26 -0
- data/lib/rubyzero/nn/layers/relu.rb +10 -0
- data/lib/rubyzero/nn/load.rb +5 -0
- data/lib/rubyzero/nn/losses/loss.rb +5 -0
- data/lib/rubyzero/nn/losses/losses.rb +8 -0
- data/lib/rubyzero/nn/losses/mse.rb +13 -0
- data/lib/rubyzero/nn/model.rb +75 -0
- data/lib/rubyzero/nn/nn.rb +11 -0
- data/lib/rubyzero/nn/optimizers/momentum.rb +22 -0
- data/lib/rubyzero/nn/optimizers/optimizer.rb +16 -0
- data/lib/rubyzero/nn/optimizers/optimizers.rb +9 -0
- data/lib/rubyzero/nn/optimizers/sgd.rb +14 -0
- data/lib/rubyzero/nn/parameters.rb +36 -0
- data/lib/rubyzero/utils/hyper_parameter_optimizer.rb +0 -0
- data/lib/rubyzero/utils/trainer.rb +49 -0
- data/lib/rubyzero/utils/utils.rb +8 -0
- data/lib/rubyzero/version.rb +5 -0
- data/lib/rubyzero.rb +7 -0
- data/note.txt +29 -0
- data/rubyzero.gemspec +36 -0
- metadata +101 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
module RubyZero::Core
|
2
|
+
# Tensor class
|
3
|
+
class Tensor
|
4
|
+
attr_accessor :data, :grad_fn, :grad, :device, :requires_grad
|
5
|
+
def initialize(data, dtype: nil, device: nil)
|
6
|
+
@device = device || RubyZero.device(:cpu)
|
7
|
+
@grad_fn = nil
|
8
|
+
@grad = nil
|
9
|
+
@requires_grad = false
|
10
|
+
|
11
|
+
# check data type
|
12
|
+
if data.is_a?(Array)
|
13
|
+
if dtype
|
14
|
+
@data = dtype.get_type_on_calculator(device)[*data]
|
15
|
+
else
|
16
|
+
@data = @device.caluculator::NArray[*data]
|
17
|
+
end
|
18
|
+
elsif data.is_a?(Numeric)
|
19
|
+
if dtype
|
20
|
+
@data = dtype.get_type_on_calculator(device)[data]
|
21
|
+
else
|
22
|
+
@data = @device.caluculator::NArray[data]
|
23
|
+
end
|
24
|
+
elsif data.is_a?(Numo::NArray)
|
25
|
+
@data = data
|
26
|
+
else
|
27
|
+
raise Execptions::TypeNotSupported, "Tensor data type not supported: #{data.class}"
|
28
|
+
end
|
29
|
+
@dtype = DataTypes.from_xmo_dtype(@data.class)
|
30
|
+
end
|
31
|
+
# get data type
|
32
|
+
# @return [DataTypes::DataType]
|
33
|
+
def dtype
|
34
|
+
@dtype
|
35
|
+
end
|
36
|
+
# get shape
|
37
|
+
# @return [Array<Integer>]
|
38
|
+
def shape
|
39
|
+
@data.shape
|
40
|
+
end
|
41
|
+
# get tensor summary
|
42
|
+
# @return [String]
|
43
|
+
def inspect
|
44
|
+
numo_inspect = @data.inspect.split("\n")[1..nil].join("\n")
|
45
|
+
return "#{dtype}#shape=#{shape.to_a}\n#{numo_inspect}\ngrad_fn=#{@grad_fn.class}"
|
46
|
+
end
|
47
|
+
# @return [Boolean]
|
48
|
+
def requires_grad?
|
49
|
+
@requires_grad
|
50
|
+
end
|
51
|
+
# detach from graph
|
52
|
+
def detach
|
53
|
+
@grad_fn = nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RubyZero::Core
|
2
|
+
class Tensor
|
3
|
+
def backward()
|
4
|
+
return unless @grad_fn
|
5
|
+
@grad ||= ones_like
|
6
|
+
dx = @grad_fn.backward(@grad)
|
7
|
+
self.grad_fn.inputs.each_with_index do |input, i|
|
8
|
+
if input.grad
|
9
|
+
input.grad += dx[i]
|
10
|
+
else
|
11
|
+
input.grad = dx[i]
|
12
|
+
end
|
13
|
+
input.backward()
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module RubyZero::Core
|
2
|
+
class Tensor
|
3
|
+
# initialize new tensor with given shape which filled with zeros.
|
4
|
+
def self.zeros(shape, dtype: RubyZero::Core::DataTypes::Float64, device: RubyZero.device(:cpu))
|
5
|
+
dtype = dtype.get_type_on_calculator(device)
|
6
|
+
data = dtype.zeros(shape)
|
7
|
+
Tensor.new(data, dtype:dtype, device:device)
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
# initialize new tensor with given another tensor's shape which filled with zeros.
|
12
|
+
def zeros_like()
|
13
|
+
Tensor.zeros(self.shape, dtype:self.dtype, device:self.device)
|
14
|
+
end
|
15
|
+
|
16
|
+
# initialize new tensor with given shape which filled with ones.
|
17
|
+
def self.ones(shape, dtype: RubyZero::Core::DataTypes::Float64, device: RubyZero.device(:cpu))
|
18
|
+
dtype = dtype.get_type_on_calculator(device)
|
19
|
+
data = dtype.ones(shape)
|
20
|
+
Tensor.new(data, dtype:dtype, device:device)
|
21
|
+
end
|
22
|
+
|
23
|
+
# initialize new tensor with given another tensor's shape which filled with ones.
|
24
|
+
def ones_like()
|
25
|
+
Tensor.ones(self.shape, dtype:self.dtype, device:self.device)
|
26
|
+
end
|
27
|
+
|
28
|
+
# initialize new tensor with given shape which filled with random values.
|
29
|
+
def self.randn(shape, dtype: RubyZero::Core::DataTypes::Float64, device: RubyZero.device(:cpu))
|
30
|
+
dtype = dtype.get_type_on_calculator(device)
|
31
|
+
data = dtype.new(shape).rand_norm
|
32
|
+
Tensor.new(data, dtype:dtype, device:device)
|
33
|
+
end
|
34
|
+
|
35
|
+
# initialize new tensor with given another tensor's shape which filled with random values.
|
36
|
+
def randn_like()
|
37
|
+
Tensor.randn(self.shape, dtype:self.dtype, device:self.device)
|
38
|
+
end
|
39
|
+
|
40
|
+
# initialize new tensor with given shape which filled with random values.
|
41
|
+
def self.rand(shape, dtype: RubyZero::Core::DataTypes::Float64, device: RubyZero.device(:cpu))
|
42
|
+
dtype = dtype.get_type_on_calculator(device)
|
43
|
+
data = dtype.new(shape).rand
|
44
|
+
Tensor.new(data, dtype:dtype, device:device)
|
45
|
+
end
|
46
|
+
|
47
|
+
# initialize new tensor with given another tensor's shape which filled with random values.
|
48
|
+
def rand_like()
|
49
|
+
Tensor.rand(self.shape, dtype: self.dtype, device:self.device)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.stack(tensors, axis:0)
|
53
|
+
t = Tensor.new(tensors.map{|t| t.data})
|
54
|
+
return t
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module DataTypes
|
59
|
+
class DataType
|
60
|
+
def self.zeros(*args)
|
61
|
+
Tensor.zeros(*args, dtype: self)
|
62
|
+
end
|
63
|
+
def self.ones(*args)
|
64
|
+
Tensor.ones(*args, dtype: self)
|
65
|
+
end
|
66
|
+
def self.randn(*args)
|
67
|
+
Tensor.randn(*args, dtype: self)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
module RubyZero
|
74
|
+
FloatTensor = RubyZero::Core::DataTypes::Float32
|
75
|
+
DoubleTensor = RubyZero::Core::DataTypes::Float64
|
76
|
+
IntTensor = RubyZero::Core::DataTypes::Int32
|
77
|
+
LongTensor = RubyZero::Core::DataTypes::Int64
|
78
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RubyZero::Core
|
2
|
+
class Tensor
|
3
|
+
def +(other)
|
4
|
+
RubyZero::Core::Functions::Add.new().call(self, other)
|
5
|
+
end
|
6
|
+
def -(other)
|
7
|
+
RubyZero::Core::Functions::Sub.new().call(self, other)
|
8
|
+
end
|
9
|
+
def *(other)
|
10
|
+
if other.is_a?(Numeric)
|
11
|
+
RubyZero::Core::Functions::MulScalar.new(other).call(self)
|
12
|
+
else
|
13
|
+
RubyZero::Core::Functions::Mul.new().call(self, other)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
def /(other)
|
17
|
+
if other.is_a?(Numeric)
|
18
|
+
RubyZero::Core::Functions::DivScalar.new(other).call(self)
|
19
|
+
else
|
20
|
+
RubyZero::Core::Functions::Div.new().call(self, other)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def -@
|
24
|
+
RubyZero::Core::Functions::Neg.new().call(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RubyZero::Data
|
2
|
+
class DataLoader
|
3
|
+
def initialize(dataset, batch_size: 1, shuffle: false)
|
4
|
+
@dataset = dataset
|
5
|
+
@batch_size = batch_size > dataset.size ? dataset.size : batch_size
|
6
|
+
@shuffle = shuffle
|
7
|
+
end
|
8
|
+
include Enumerable
|
9
|
+
def each
|
10
|
+
shuffled_index = nil
|
11
|
+
shuffled_index = (0..(@dataset.length-1)).to_a.shuffle if @shuffle
|
12
|
+
batched_index = shuffled_index.each_slice(@batch_size).to_a
|
13
|
+
batched_index.each do |batch_idx_arr|
|
14
|
+
datas = []
|
15
|
+
batch_idx_arr.each do |idx|
|
16
|
+
datas << @dataset[idx]
|
17
|
+
end
|
18
|
+
# transpose 2d array
|
19
|
+
args = datas.transpose
|
20
|
+
args = args.map do |arg|
|
21
|
+
if arg.class == Array
|
22
|
+
if arg[0].is_a?(RubyZero::Core::Tensor)
|
23
|
+
next RubyZero::Core::Tensor.stack(arg)
|
24
|
+
elsif arg[0].is_a?(Array)
|
25
|
+
next RubyZero::Core::Tensor.new(arg)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
next arg
|
29
|
+
end
|
30
|
+
yield(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RubyZero::Data::Presets
|
2
|
+
class Xor < RubyZero::Data::Dataset
|
3
|
+
def initialize
|
4
|
+
@inputs = [
|
5
|
+
[0, 0],
|
6
|
+
[0, 1],
|
7
|
+
[1, 0],
|
8
|
+
[1, 1]
|
9
|
+
]
|
10
|
+
@targets = [
|
11
|
+
[0],
|
12
|
+
[1],
|
13
|
+
[1],
|
14
|
+
[0]
|
15
|
+
]
|
16
|
+
end
|
17
|
+
def getitem(idx)
|
18
|
+
return @inputs[idx], @targets[idx]
|
19
|
+
end
|
20
|
+
def length
|
21
|
+
return 4
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubyZero::NN
|
2
|
+
module Functional
|
3
|
+
def self.relu(x)
|
4
|
+
return RubyZero::Core::Functions::ReLU.new().call(x)
|
5
|
+
end
|
6
|
+
def self.log(x)
|
7
|
+
return RubyZero::Core::Functions::Log.new().call(x)
|
8
|
+
end
|
9
|
+
def self.sigmoid(x)
|
10
|
+
return RubyZero::Core::Functions::Sigmoid.new().call(x)
|
11
|
+
end
|
12
|
+
def self.exp(x)
|
13
|
+
return RubyZero::Core::Functions::Exp.new().call(x)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
module RubyZero
|
20
|
+
F = RubyZero::NN::Functional
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubyZero::NN::Layers
|
2
|
+
# Affine layer
|
3
|
+
class Affine < Layer
|
4
|
+
# @param input_size [Integer] input size
|
5
|
+
# @param output_size [Integer] output size
|
6
|
+
# @param bias [Boolean] whether to use bias
|
7
|
+
def initialize(input_size, output_size, bias: true)
|
8
|
+
@weight = RubyZero::Float32.randn([input_size, output_size])
|
9
|
+
@bias = RubyZero::Float32.randn([output_size]) if bias
|
10
|
+
end
|
11
|
+
# Forward pass
|
12
|
+
# @param x [RubyZero::Float32] input
|
13
|
+
# @return [RubyZero::Float32] output
|
14
|
+
def forward(x)
|
15
|
+
x = x.dot(@weight)
|
16
|
+
if @bias
|
17
|
+
x += @bias.repeat(x.shape[0], axis: 0)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RubyZero::NN
|
2
|
+
module Layers
|
3
|
+
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
require_relative './layer.rb'
|
9
|
+
require_relative './affine.rb'
|
10
|
+
require_relative './relu.rb'
|
11
|
+
require_relative './modellist.rb'
|
12
|
+
require_relative './modelstack.rb'
|
13
|
+
require_relative './multi_layer_perceptron.rb'
|
14
|
+
require_relative './embedding.rb'
|
15
|
+
|
16
|
+
module RubyZero::NN
|
17
|
+
module LayersInitializeAliases
|
18
|
+
def self.affine(*args)
|
19
|
+
RubyZero::NN::Layers::Affine.new(*args)
|
20
|
+
end
|
21
|
+
def self.relu(*args)
|
22
|
+
RubyZero::NN::Layers::ReLU.new(*args)
|
23
|
+
end
|
24
|
+
def self.model_list(*args)
|
25
|
+
RubyZero::NN::Layers::ModelList.new(*args)
|
26
|
+
end
|
27
|
+
def self.model_stack(*args)
|
28
|
+
RubyZero::NN::Layers::ModelStack.new(*args)
|
29
|
+
end
|
30
|
+
def self.multi_layer_perceptron(*args)
|
31
|
+
RubyZero::NN::Layers::MultiLayerPerceptron.new(*args)
|
32
|
+
end
|
33
|
+
def self.mlp(*args)
|
34
|
+
RubyZero::NN::Layers::MultiLayerPerceptron.new(*args)
|
35
|
+
end
|
36
|
+
def embedding(*args)
|
37
|
+
RubyZero::NN::Layers::Embedding.new(*args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module RubyZero
|
43
|
+
L = RubyZero::NN::LayersInitializeAliases
|
44
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RubyZero::NN::Layers
|
2
|
+
# The list of models that can be used in the neural network.
|
3
|
+
# This class supports to containing different Model classes.
|
4
|
+
class ModelList < Layer
|
5
|
+
def initialize(list=nil)
|
6
|
+
if list
|
7
|
+
@models = list
|
8
|
+
else
|
9
|
+
@models = []
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def parameters
|
13
|
+
params = []
|
14
|
+
@models.each do |model|
|
15
|
+
params += model.parameters.elements
|
16
|
+
end
|
17
|
+
return RubyZero::NN::Parameters.new(params)
|
18
|
+
end
|
19
|
+
def <<(model)
|
20
|
+
@models << model
|
21
|
+
end
|
22
|
+
def elements
|
23
|
+
return @models
|
24
|
+
end
|
25
|
+
def +(modellist)
|
26
|
+
return ModelList.new(@models + modellist.elements)
|
27
|
+
end
|
28
|
+
def each(&block)
|
29
|
+
@models.each(&block)
|
30
|
+
end
|
31
|
+
def __get_str__(num_indents)
|
32
|
+
indents = " " * num_indents
|
33
|
+
s = "#{indents}#{self.class.name} #{parameters.size} params\n"
|
34
|
+
@models.each do |child|
|
35
|
+
s += child.__get_str__(num_indents + 1)
|
36
|
+
end
|
37
|
+
return s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RubyZero::NN::Layers
|
2
|
+
# The stack of layers
|
3
|
+
# This class don't supports to containing different Model classes.
|
4
|
+
class ModelStack < ModelList
|
5
|
+
def <<(layer)
|
6
|
+
if @models.size > 0
|
7
|
+
if layer.class != @models.last.class
|
8
|
+
raise TypeError, "Layer type mismatch"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
super(layer)
|
12
|
+
end
|
13
|
+
def forward(*args)
|
14
|
+
@models.each do |model|
|
15
|
+
args = model.forward(*args)
|
16
|
+
end
|
17
|
+
return args
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubyZero::NN::Layers
|
2
|
+
class MultiLayerPerceptron < ModelStack
|
3
|
+
# @option opts [Integer] :dims The dimensions of the input, hidden and output
|
4
|
+
#
|
5
|
+
# @note [5, 3] -> 5 inputs, 3 outputs
|
6
|
+
# [5, 3, 2] -> 5 inputs, 3 hidden, 2 outputs
|
7
|
+
#
|
8
|
+
def initialize(*dims, activation: RubyZero::NN::Layers::ReLU)
|
9
|
+
super()
|
10
|
+
if dims.length < 2
|
11
|
+
raise ArgumentError, "Layer must have at least 2 dimensions"
|
12
|
+
end
|
13
|
+
@dims = dims
|
14
|
+
@activation_function = activation
|
15
|
+
|
16
|
+
(@dims.size-1).times do |i|
|
17
|
+
dim_i = @dims[i]
|
18
|
+
dim_o = @dims[i+1]
|
19
|
+
@models << RubyZero::NN::Layers::Affine.new(dim_i, dim_o)
|
20
|
+
if i != @dims.size-2
|
21
|
+
@models << activation.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module RubyZero::NN
|
2
|
+
# Model class
|
3
|
+
class Model
|
4
|
+
def initialize
|
5
|
+
end
|
6
|
+
def forward
|
7
|
+
raise RubyZero::Core::Exceptions::NoInplementError, "#{self.class}.forward() method is not implemented"
|
8
|
+
end
|
9
|
+
def call(*args)
|
10
|
+
return forward(*args)
|
11
|
+
end
|
12
|
+
def parameters
|
13
|
+
param_keys = instance_variables
|
14
|
+
params = []
|
15
|
+
param_keys.each do |key|
|
16
|
+
obj = instance_variable_get(key)
|
17
|
+
if obj.is_a?(RubyZero::Core::Tensor)
|
18
|
+
obj.requires_grad = true
|
19
|
+
params << obj
|
20
|
+
elsif obj.is_a?(RubyZero::NN::Parameters)
|
21
|
+
params += obj.elements
|
22
|
+
else obj.is_a?(RubyZero::NN::Model)
|
23
|
+
params += obj.parameters.elements
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return Parameters.new(params)
|
27
|
+
end
|
28
|
+
def __get_str__(num_indents)
|
29
|
+
keys = instance_variables
|
30
|
+
children = []
|
31
|
+
keys.each do |key|
|
32
|
+
obj = instance_variable_get(key)
|
33
|
+
if obj.is_a?(RubyZero::NN::Model)
|
34
|
+
children << obj
|
35
|
+
end
|
36
|
+
end
|
37
|
+
indents = " " * num_indents
|
38
|
+
s = "#{indents}#{self.class.name} #{parameters.size} params\n"
|
39
|
+
children.each do |child|
|
40
|
+
s += child.__get_str__(num_indents + 1)
|
41
|
+
end
|
42
|
+
return s
|
43
|
+
end
|
44
|
+
def inspect
|
45
|
+
return __get_str__(0)
|
46
|
+
end
|
47
|
+
def train()
|
48
|
+
self.parameters.map do |param|
|
49
|
+
param.requires_grad = true
|
50
|
+
end
|
51
|
+
return self
|
52
|
+
end
|
53
|
+
def eval()
|
54
|
+
def train()
|
55
|
+
self.parameters.map do |param|
|
56
|
+
param.requires_grad = false
|
57
|
+
end
|
58
|
+
return self
|
59
|
+
end
|
60
|
+
end
|
61
|
+
def save(path)
|
62
|
+
self.parameters.map do |param|
|
63
|
+
param.grad = nil
|
64
|
+
end
|
65
|
+
File.open(path, "wb") do |f|
|
66
|
+
Marshal.dump(self, f)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
def self.load(path)
|
70
|
+
File.open(path, "rb") do |f|
|
71
|
+
return Marshal.load(f)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module RubyZero
|
2
|
+
module NN
|
3
|
+
|
4
|
+
end
|
5
|
+
end
|
6
|
+
require_relative './parameters.rb'
|
7
|
+
require_relative './model.rb'
|
8
|
+
require_relative './layers/layers.rb'
|
9
|
+
require_relative './losses/losses.rb'
|
10
|
+
require_relative './optimizers/optimizers.rb'
|
11
|
+
require_relative './functional.rb'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RubyZero::NN::Optimizers
|
2
|
+
class Momentum < Optimizer
|
3
|
+
def initialize(parameters, lr: 0.001, alpha: 0.9)
|
4
|
+
@lr = lr
|
5
|
+
@parameters = parameters
|
6
|
+
@alpha = alpha
|
7
|
+
@velocities = []
|
8
|
+
end
|
9
|
+
def update()
|
10
|
+
@parameters.each_with_index do |tensor, index|
|
11
|
+
if @velocities[index].nil?
|
12
|
+
@velocities[index] = 0
|
13
|
+
else
|
14
|
+
vel = @velocities[index] * @alpha
|
15
|
+
uparam = tensor.grad.data + vel
|
16
|
+
tensor.data -= uparam * @lr
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
alias :step :update
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RubyZero::NN::Optimizers
|
2
|
+
# base of optimizer classes
|
3
|
+
class Optimizer
|
4
|
+
def initialize(parameters, lr:0.01)
|
5
|
+
|
6
|
+
end
|
7
|
+
def update()
|
8
|
+
|
9
|
+
end
|
10
|
+
def zero_grad()
|
11
|
+
@parameters.each do |parameter|
|
12
|
+
parameter.grad = parameter.zeros_like()
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RubyZero::NN::Optimizers
|
2
|
+
class SGD < Optimizer
|
3
|
+
def initialize(parameters, lr: 0.01)
|
4
|
+
@lr = lr
|
5
|
+
@parameters = parameters
|
6
|
+
end
|
7
|
+
def update()
|
8
|
+
@parameters.each do |tensor|
|
9
|
+
tensor.data -= tensor.grad.data * @lr
|
10
|
+
end
|
11
|
+
end
|
12
|
+
alias :step :update
|
13
|
+
end
|
14
|
+
end
|