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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +9 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE +21 -0
  6. data/README.md +35 -0
  7. data/Rakefile +4 -0
  8. data/bin/console +15 -0
  9. data/bin/setup +8 -0
  10. data/changelog.md +0 -0
  11. data/lib/rubyzero/core/cast.rb +25 -0
  12. data/lib/rubyzero/core/core.rb +15 -0
  13. data/lib/rubyzero/core/device.rb +32 -0
  14. data/lib/rubyzero/core/dtypes.rb +115 -0
  15. data/lib/rubyzero/core/exceptions.rb +7 -0
  16. data/lib/rubyzero/core/functions/activations.rb +20 -0
  17. data/lib/rubyzero/core/functions/elementary_functions.rb +29 -0
  18. data/lib/rubyzero/core/functions/function.rb +29 -0
  19. data/lib/rubyzero/core/functions/functions.rb +10 -0
  20. data/lib/rubyzero/core/functions/operators.rb +112 -0
  21. data/lib/rubyzero/core/functions/tensor_functions.rb +123 -0
  22. data/lib/rubyzero/core/tensor.rb +56 -0
  23. data/lib/rubyzero/core/tensor_backward.rb +17 -0
  24. data/lib/rubyzero/core/tensor_initialize_methods.rb +78 -0
  25. data/lib/rubyzero/core/tensor_operators.rb +27 -0
  26. data/lib/rubyzero/data/data.rb +9 -0
  27. data/lib/rubyzero/data/dataloader.rb +34 -0
  28. data/lib/rubyzero/data/dataset.rb +19 -0
  29. data/lib/rubyzero/data/presets/presets.rb +7 -0
  30. data/lib/rubyzero/data/presets/xor.rb +24 -0
  31. data/lib/rubyzero/nn/functional.rb +21 -0
  32. data/lib/rubyzero/nn/layers/affine.rb +21 -0
  33. data/lib/rubyzero/nn/layers/embedding.rb +7 -0
  34. data/lib/rubyzero/nn/layers/layer.rb +5 -0
  35. data/lib/rubyzero/nn/layers/layers.rb +44 -0
  36. data/lib/rubyzero/nn/layers/modellist.rb +40 -0
  37. data/lib/rubyzero/nn/layers/modelstack.rb +20 -0
  38. data/lib/rubyzero/nn/layers/multi_layer_perceptron.rb +26 -0
  39. data/lib/rubyzero/nn/layers/relu.rb +10 -0
  40. data/lib/rubyzero/nn/load.rb +5 -0
  41. data/lib/rubyzero/nn/losses/loss.rb +5 -0
  42. data/lib/rubyzero/nn/losses/losses.rb +8 -0
  43. data/lib/rubyzero/nn/losses/mse.rb +13 -0
  44. data/lib/rubyzero/nn/model.rb +75 -0
  45. data/lib/rubyzero/nn/nn.rb +11 -0
  46. data/lib/rubyzero/nn/optimizers/momentum.rb +22 -0
  47. data/lib/rubyzero/nn/optimizers/optimizer.rb +16 -0
  48. data/lib/rubyzero/nn/optimizers/optimizers.rb +9 -0
  49. data/lib/rubyzero/nn/optimizers/sgd.rb +14 -0
  50. data/lib/rubyzero/nn/parameters.rb +36 -0
  51. data/lib/rubyzero/utils/hyper_parameter_optimizer.rb +0 -0
  52. data/lib/rubyzero/utils/trainer.rb +49 -0
  53. data/lib/rubyzero/utils/utils.rb +8 -0
  54. data/lib/rubyzero/version.rb +5 -0
  55. data/lib/rubyzero.rb +7 -0
  56. data/note.txt +29 -0
  57. data/rubyzero.gemspec +36 -0
  58. 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,9 @@
1
+ module RubyZero
2
+ module Data
3
+
4
+ end
5
+ end
6
+
7
+ require_relative './dataset.rb'
8
+ require_relative './dataloader.rb'
9
+ require_relative './presets/presets.rb'
@@ -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,19 @@
1
+ module RubyZero::Data
2
+ class Dataset
3
+ def initialize()
4
+
5
+ end
6
+ def getitem(index)
7
+
8
+ end
9
+ def length()
10
+
11
+ end
12
+ def [](index)
13
+ getitem(index)
14
+ end
15
+ def size
16
+ length()
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ module RubyZero::Data
2
+ module Presets
3
+
4
+ end
5
+ end
6
+
7
+ require_relative './xor.rb'
@@ -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,7 @@
1
+ module RubyZero::NN::Layers
2
+ class Embedding < Affine
3
+ def initialize(vocab_size, hidden_dim)
4
+ super(vocab_size, hidden_dim, bias: false)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module RubyZero::NN::Layers
2
+ class Layer < RubyZero::NN::Model
3
+
4
+ end
5
+ 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,10 @@
1
+ module RubyZero::NN::Layers
2
+ # ReLU Layer
3
+ class ReLU < Layer
4
+ def initialize()
5
+ end
6
+ def forward(x)
7
+ return RubyZero::Core::Functions::ReLU.new().call(x)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module RubyZero::NN
2
+ def self.load(filename)
3
+ return RubyZero::NN::Model.load(filename)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module RubyZero::NN::Losses
2
+ class Loss < RubyZero::NN::Model
3
+
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ module RubyZero::NN
2
+ module Losses
3
+
4
+ end
5
+ end
6
+
7
+ require_relative './loss.rb'
8
+ require_relative './mse.rb'
@@ -0,0 +1,13 @@
1
+ module RubyZero::NN::Losses
2
+ class MSE < Loss
3
+ def forward(input, target)
4
+ err = input - target
5
+ err = err * err
6
+ while err.shape.size > 1
7
+ err = err.mean(axis:0)
8
+ end
9
+ return err
10
+ end
11
+ end
12
+ MeanSquaredError = MSE
13
+ 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,9 @@
1
+ module RubyZero::NN
2
+ module Optimizers
3
+
4
+ end
5
+ end
6
+
7
+ require_relative './optimizer.rb'
8
+ require_relative './sgd.rb'
9
+ require_relative './momentum.rb'
@@ -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