torch-rb 0.1.2 → 0.1.3
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/CHANGELOG.md +10 -0
- data/LICENSE.txt +46 -22
- data/README.md +14 -5
- data/ext/torch/ext.cpp +248 -31
- data/lib/torch.rb +80 -9
- data/lib/torch/ext.bundle +0 -0
- data/lib/torch/inspector.rb +4 -3
- data/lib/torch/nn/alpha_dropout.rb +9 -0
- data/lib/torch/nn/conv2d.rb +12 -24
- data/lib/torch/nn/convnd.rb +41 -0
- data/lib/torch/nn/dropout.rb +9 -0
- data/lib/torch/nn/dropout2d.rb +9 -0
- data/lib/torch/nn/dropout3d.rb +9 -0
- data/lib/torch/nn/dropoutnd.rb +15 -0
- data/lib/torch/nn/embedding.rb +52 -0
- data/lib/torch/nn/feature_alpha_dropout.rb +9 -0
- data/lib/torch/nn/functional.rb +54 -12
- data/lib/torch/nn/linear.rb +2 -2
- data/lib/torch/nn/module.rb +30 -0
- data/lib/torch/optim/adadelta.rb +57 -0
- data/lib/torch/optim/adagrad.rb +71 -0
- data/lib/torch/optim/adam.rb +81 -0
- data/lib/torch/optim/adamax.rb +68 -0
- data/lib/torch/optim/adamw.rb +82 -0
- data/lib/torch/optim/asgd.rb +65 -0
- data/lib/torch/optim/lr_scheduler/lr_scheduler.rb +33 -0
- data/lib/torch/optim/lr_scheduler/step_lr.rb +17 -0
- data/lib/torch/optim/optimizer.rb +56 -0
- data/lib/torch/optim/rmsprop.rb +76 -0
- data/lib/torch/optim/rprop.rb +68 -0
- data/lib/torch/optim/sgd.rb +48 -16
- data/lib/torch/tensor.rb +38 -4
- data/lib/torch/utils/data/data_loader.rb +10 -4
- data/lib/torch/utils/data/tensor_dataset.rb +3 -0
- data/lib/torch/version.rb +1 -1
- metadata +21 -3
data/lib/torch.rb
CHANGED
@@ -8,18 +8,40 @@ require "torch/version"
|
|
8
8
|
|
9
9
|
# optim
|
10
10
|
require "torch/optim/optimizer"
|
11
|
+
require "torch/optim/adadelta"
|
12
|
+
require "torch/optim/adagrad"
|
13
|
+
require "torch/optim/adam"
|
14
|
+
require "torch/optim/adamax"
|
15
|
+
require "torch/optim/adamw"
|
16
|
+
require "torch/optim/asgd"
|
17
|
+
require "torch/optim/rmsprop"
|
18
|
+
require "torch/optim/rprop"
|
11
19
|
require "torch/optim/sgd"
|
12
20
|
|
13
|
-
#
|
21
|
+
# optim lr_scheduler
|
22
|
+
require "torch/optim/lr_scheduler/lr_scheduler"
|
23
|
+
require "torch/optim/lr_scheduler/step_lr"
|
24
|
+
|
25
|
+
# nn base classes
|
14
26
|
require "torch/nn/module"
|
15
|
-
require "torch/nn/
|
27
|
+
require "torch/nn/convnd"
|
28
|
+
require "torch/nn/dropoutnd"
|
29
|
+
|
30
|
+
# nn
|
31
|
+
require "torch/nn/alpha_dropout"
|
16
32
|
require "torch/nn/conv2d"
|
33
|
+
require "torch/nn/dropout"
|
34
|
+
require "torch/nn/dropout2d"
|
35
|
+
require "torch/nn/dropout3d"
|
36
|
+
require "torch/nn/embedding"
|
37
|
+
require "torch/nn/feature_alpha_dropout"
|
17
38
|
require "torch/nn/functional"
|
39
|
+
require "torch/nn/init"
|
18
40
|
require "torch/nn/linear"
|
41
|
+
require "torch/nn/mse_loss"
|
19
42
|
require "torch/nn/parameter"
|
20
|
-
require "torch/nn/sequential"
|
21
43
|
require "torch/nn/relu"
|
22
|
-
require "torch/nn/
|
44
|
+
require "torch/nn/sequential"
|
23
45
|
|
24
46
|
# utils
|
25
47
|
require "torch/utils/data/data_loader"
|
@@ -27,6 +49,11 @@ require "torch/utils/data/tensor_dataset"
|
|
27
49
|
|
28
50
|
module Torch
|
29
51
|
class Error < StandardError; end
|
52
|
+
class NotImplementedYet < StandardError
|
53
|
+
def message
|
54
|
+
"This feature has not been implemented yet. Consider submitting a PR."
|
55
|
+
end
|
56
|
+
end
|
30
57
|
|
31
58
|
# keys: https://pytorch.org/docs/stable/tensor_attributes.html#torch.torch.dtype
|
32
59
|
# values: https://github.com/pytorch/pytorch/blob/master/c10/core/ScalarType.h
|
@@ -75,11 +102,18 @@ module Torch
|
|
75
102
|
obj.is_a?(Tensor)
|
76
103
|
end
|
77
104
|
|
78
|
-
# TODO don't copy
|
79
105
|
def from_numo(ndarray)
|
80
106
|
dtype = _dtype_to_numo.find { |k, v| ndarray.is_a?(v) }
|
81
107
|
raise Error, "Cannot convert #{ndarray.class.name} to tensor" unless dtype
|
82
|
-
|
108
|
+
options = tensor_options(device: "cpu", dtype: dtype[0])
|
109
|
+
# TODO pass pointer to array instead of creating string
|
110
|
+
str = ndarray.to_string
|
111
|
+
tensor = _from_blob(str, ndarray.shape, options)
|
112
|
+
# from_blob does not own the data, so we need to keep
|
113
|
+
# a reference to it for duration of tensor
|
114
|
+
# can remove when passing pointer directly
|
115
|
+
tensor.instance_variable_set("@_numo_str", str)
|
116
|
+
tensor
|
83
117
|
end
|
84
118
|
|
85
119
|
# private
|
@@ -197,7 +231,7 @@ module Torch
|
|
197
231
|
high = low
|
198
232
|
low = 0
|
199
233
|
end
|
200
|
-
|
234
|
+
randint(low, high, input.size, like_options(input, options))
|
201
235
|
end
|
202
236
|
|
203
237
|
def randn_like(input, **options)
|
@@ -272,8 +306,13 @@ module Torch
|
|
272
306
|
_min(input)
|
273
307
|
end
|
274
308
|
|
275
|
-
def max(input)
|
276
|
-
|
309
|
+
def max(input, dim = nil, keepdim: false, out: nil)
|
310
|
+
if dim
|
311
|
+
raise NotImplementedYet unless out
|
312
|
+
_max_out(out[0], out[1], input, dim, keepdim)
|
313
|
+
else
|
314
|
+
_max(input)
|
315
|
+
end
|
277
316
|
end
|
278
317
|
|
279
318
|
def exp(input)
|
@@ -284,6 +323,18 @@ module Torch
|
|
284
323
|
_log(input)
|
285
324
|
end
|
286
325
|
|
326
|
+
def sign(input)
|
327
|
+
_sign(input)
|
328
|
+
end
|
329
|
+
|
330
|
+
def gt(input, other)
|
331
|
+
_gt(input, other)
|
332
|
+
end
|
333
|
+
|
334
|
+
def lt(input, other)
|
335
|
+
_lt(input, other)
|
336
|
+
end
|
337
|
+
|
287
338
|
def unsqueeze(input, dim)
|
288
339
|
_unsqueeze(input, dim)
|
289
340
|
end
|
@@ -292,6 +343,10 @@ module Torch
|
|
292
343
|
_dot(input, tensor)
|
293
344
|
end
|
294
345
|
|
346
|
+
def cat(tensors, dim = 0)
|
347
|
+
_cat(tensors, dim)
|
348
|
+
end
|
349
|
+
|
295
350
|
def matmul(input, other)
|
296
351
|
_matmul(input, other)
|
297
352
|
end
|
@@ -300,6 +355,22 @@ module Torch
|
|
300
355
|
_reshape(input, shape)
|
301
356
|
end
|
302
357
|
|
358
|
+
def flatten(input, start_dim: 0, end_dim: -1)
|
359
|
+
_flatten(input, start_dim, end_dim)
|
360
|
+
end
|
361
|
+
|
362
|
+
def sqrt(input)
|
363
|
+
_sqrt(input)
|
364
|
+
end
|
365
|
+
|
366
|
+
def abs(input)
|
367
|
+
_abs(input)
|
368
|
+
end
|
369
|
+
|
370
|
+
def device(str)
|
371
|
+
Device.new(str)
|
372
|
+
end
|
373
|
+
|
303
374
|
private
|
304
375
|
|
305
376
|
def execute_op(op, input, other, out: nil)
|
data/lib/torch/ext.bundle
CHANGED
Binary file
|
data/lib/torch/inspector.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
module Torch
|
2
2
|
module Inspector
|
3
3
|
# TODO make more performance, especially when summarizing
|
4
|
+
# how? only read data that will be displayed
|
4
5
|
def inspect
|
5
6
|
data =
|
6
7
|
if numel == 0
|
7
8
|
"[]"
|
8
9
|
elsif dim == 0
|
9
|
-
|
10
|
+
item
|
10
11
|
else
|
12
|
+
summarize = numel > 1000
|
13
|
+
|
11
14
|
values = to_a.flatten
|
12
15
|
abs = values.select { |v| v != 0 }.map(&:abs)
|
13
16
|
max = abs.max || 1
|
@@ -36,8 +39,6 @@ module Torch
|
|
36
39
|
fmt = "%#{total}d"
|
37
40
|
end
|
38
41
|
|
39
|
-
summarize = numel > 1000
|
40
|
-
|
41
42
|
inspect_level(to_a, fmt, dim - 1, 0, summarize)
|
42
43
|
end
|
43
44
|
|
data/lib/torch/nn/conv2d.rb
CHANGED
@@ -1,36 +1,24 @@
|
|
1
1
|
module Torch
|
2
2
|
module NN
|
3
|
-
class Conv2d <
|
3
|
+
class Conv2d < ConvNd
|
4
4
|
attr_reader :bias, :weight
|
5
5
|
|
6
|
-
def initialize(in_channels, out_channels, kernel_size, stride: 1, padding: 0
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# @dilation = pair(dilation)
|
13
|
-
|
14
|
-
# TODO divide by groups
|
15
|
-
@weight = Parameter.new(Tensor.new(out_channels, in_channels, *@kernel_size))
|
16
|
-
@bias = Parameter.new(Tensor.new(out_channels))
|
17
|
-
|
18
|
-
reset_parameters
|
6
|
+
def initialize(in_channels, out_channels, kernel_size, stride: 1, padding: 0, dilation: 1, groups: 1, bias: true, padding_mode: "zeros")
|
7
|
+
kernel_size = pair(kernel_size)
|
8
|
+
stride = pair(stride)
|
9
|
+
padding = pair(padding)
|
10
|
+
dilation = pair(dilation)
|
11
|
+
super(in_channels, out_channels, kernel_size, stride, padding, dilation, false, pair(0), groups, bias, padding_mode)
|
19
12
|
end
|
20
13
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
fan_in, _ = Init.calculate_fan_in_and_fan_out(@weight)
|
25
|
-
bound = 1 / Math.sqrt(fan_in)
|
26
|
-
Init.uniform_(@bias, -bound, bound)
|
14
|
+
def forward(input)
|
15
|
+
if @padding_mode == "circular"
|
16
|
+
raise NotImplementedError
|
27
17
|
end
|
18
|
+
F.conv2d(input, @weight, @bias, stride: @stride, padding: @padding, dilation: @dilation, groups: @groups)
|
28
19
|
end
|
29
20
|
|
30
|
-
|
31
|
-
F.conv2d(input, @weight, @bias, stride: @stride, padding: @padding) #, @dilation, @groups)
|
32
|
-
end
|
33
|
-
|
21
|
+
# TODO add more parameters
|
34
22
|
def inspect
|
35
23
|
"Conv2d(#{@in_channels}, #{@out_channels}, kernel_size: #{@kernel_size.inspect}, stride: #{@stride.inspect})"
|
36
24
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Torch
|
2
|
+
module NN
|
3
|
+
class ConvNd < Module
|
4
|
+
def initialize(in_channels, out_channels, kernel_size, stride, padding, dilation, transposed, output_padding, groups, bias, padding_mode)
|
5
|
+
super()
|
6
|
+
raise ArgumentError, "in_channels must be divisible by groups" if in_channels % groups != 0
|
7
|
+
raise ArgumentError, "out_channels must be divisible by groups" if out_channels % groups != 0
|
8
|
+
@in_channels = in_channels
|
9
|
+
@out_channels = out_channels
|
10
|
+
@kernel_size = kernel_size
|
11
|
+
@stride = stride
|
12
|
+
@padding = padding
|
13
|
+
@dilation = dilation
|
14
|
+
@transposed = transposed
|
15
|
+
@output_padding = output_padding
|
16
|
+
@groups = groups
|
17
|
+
@padding_mode = padding_mode
|
18
|
+
if transposed
|
19
|
+
@weight = Parameter.new(Tensor.new(in_channels, out_channels / groups, *kernel_size))
|
20
|
+
else
|
21
|
+
@weight = Parameter.new(Tensor.new(out_channels, in_channels / groups, *kernel_size))
|
22
|
+
end
|
23
|
+
if bias
|
24
|
+
@bias = Parameter.new(Tensor.new(out_channels))
|
25
|
+
else
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
reset_parameters
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset_parameters
|
32
|
+
Init.kaiming_uniform!(@weight, Math.sqrt(5))
|
33
|
+
if @bias
|
34
|
+
fan_in, _ = Init.calculate_fan_in_and_fan_out(@weight)
|
35
|
+
bound = 1 / Math.sqrt(fan_in)
|
36
|
+
Init.uniform!(@bias, -bound, bound)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Torch
|
2
|
+
module NN
|
3
|
+
class DropoutNd < Module
|
4
|
+
def initialize(p: 0.5, inplace: false)
|
5
|
+
super()
|
6
|
+
@p = p
|
7
|
+
@inplace = inplace
|
8
|
+
end
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"#{self.class.name.split("::").last}(p: #{@p.inspect}, inplace: #{@inplace.inspect})"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# ported from https://github.com/pytorch/pytorch/blob/master/torch/nn/modules/sparse.py
|
2
|
+
module Torch
|
3
|
+
module NN
|
4
|
+
class Embedding < Module
|
5
|
+
def initialize(num_embeddings, embedding_dim, padding_idx: nil, max_norm: nil,
|
6
|
+
norm_type: 2.0, scale_grad_by_freq: false, sparse: false, _weight: nil)
|
7
|
+
|
8
|
+
super()
|
9
|
+
@num_embeddings = num_embeddings
|
10
|
+
@embedding_dim = embedding_dim
|
11
|
+
|
12
|
+
if padding_idx
|
13
|
+
if padding_idx > 0
|
14
|
+
raise ArgumentError, "Padding_idx must be within num_embeddings" unless padding_idx < @num_embeddings
|
15
|
+
elsif padding_idx < 0
|
16
|
+
raise ArgumentError, "Padding_idx must be within num_embeddings" unless padding_idx >= -@num_embeddings
|
17
|
+
padding_idx = @num_embeddings + padding_idx
|
18
|
+
end
|
19
|
+
end
|
20
|
+
@padding_idx = padding_idx
|
21
|
+
@max_norm = max_norm
|
22
|
+
@norm_type = norm_type
|
23
|
+
@scale_grad_by_freq = scale_grad_by_freq
|
24
|
+
if _weight.nil?
|
25
|
+
@weight = Parameter.new(Tensor.new(num_embeddings, embedding_dim))
|
26
|
+
reset_parameters
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Shape of weight does not match num_embeddings and embedding_dim" unless _weight.shape == [num_embeddings, embedding_dim]
|
29
|
+
@weight = Parameter.new(_weight)
|
30
|
+
end
|
31
|
+
@sparse = sparse
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset_parameters
|
35
|
+
Init.normal!(@weight)
|
36
|
+
if @padding_idx
|
37
|
+
Torch.no_grad do
|
38
|
+
@weight[@padding_idx].fill!(0)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def forward(input)
|
44
|
+
F.embedding(input, @weight, padding_idx: @padding_idx, max_norm: @max_norm, norm_type: @norm_type, scale_grad_by_freq: @scale_grad_by_freq, sparse: @sparse)
|
45
|
+
end
|
46
|
+
|
47
|
+
def inspect
|
48
|
+
"Embedding(#{@num_embeddings}, #{@embedding_dim})"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/torch/nn/functional.rb
CHANGED
@@ -6,17 +6,9 @@ module Torch
|
|
6
6
|
Torch.relu(input)
|
7
7
|
end
|
8
8
|
|
9
|
-
def conv2d(input, weight, bias, stride: 1, padding: 0)
|
9
|
+
def conv2d(input, weight, bias, stride: 1, padding: 0, dilation: 1, groups: 1)
|
10
10
|
# TODO pair stride and padding when needed
|
11
|
-
Torch.conv2d(input, weight, bias, stride, padding)
|
12
|
-
end
|
13
|
-
|
14
|
-
def prelu(input, weight)
|
15
|
-
Torch.prelu(input, weight)
|
16
|
-
end
|
17
|
-
|
18
|
-
def leaky_relu(input, negative_slope = 0.01)
|
19
|
-
Torch.leaky_relu(input, negative_slope)
|
11
|
+
Torch.conv2d(input, weight, bias, stride, padding, dilation, groups)
|
20
12
|
end
|
21
13
|
|
22
14
|
def max_pool2d(input, kernel_size)
|
@@ -41,14 +33,64 @@ module Torch
|
|
41
33
|
nll_loss(log_softmax(input, 1), target)
|
42
34
|
end
|
43
35
|
|
44
|
-
def nll_loss(input, target)
|
36
|
+
def nll_loss(input, target, reduction: "mean")
|
45
37
|
# TODO fix for non-1d
|
46
|
-
Torch.nll_loss(input, target)
|
38
|
+
Torch.nll_loss(input, target, reduction)
|
47
39
|
end
|
48
40
|
|
49
41
|
def log_softmax(input, dim)
|
50
42
|
input.log_softmax(dim)
|
51
43
|
end
|
44
|
+
|
45
|
+
def dropout(input, p: 0.5, training: true, inplace: false)
|
46
|
+
if inplace
|
47
|
+
Torch._dropout!(input, p, training)
|
48
|
+
else
|
49
|
+
Torch._dropout(input, p, training)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def dropout2d(input, p: 0.5, training: true, inplace: false)
|
54
|
+
raise ArgumentError, "dropout probability has to be between 0 and 1, but got #{p}" if p < 0 || p > 1
|
55
|
+
|
56
|
+
if inplace
|
57
|
+
Torch._feature_dropout!(input, p, training)
|
58
|
+
else
|
59
|
+
Torch._feature_dropout(input, p, training)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def dropout3d(input, p: 0.5, training: true, inplace: false)
|
64
|
+
if inplace
|
65
|
+
Torch._feature_dropout!(input, p, training)
|
66
|
+
else
|
67
|
+
Torch._feature_dropout(input, p, training)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def alpha_dropout(input, p: 0.5, training: true, inplace: false)
|
72
|
+
if inplace
|
73
|
+
Torch._alpha_dropout!(input, p, training)
|
74
|
+
else
|
75
|
+
Torch._alpha_dropout(input, p, training)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def feature_alpha_dropout(input, p: 0.5, training: true, inplace: false)
|
80
|
+
if inplace
|
81
|
+
Torch._feature_alpha_dropout!(input, p, training)
|
82
|
+
else
|
83
|
+
Torch._feature_alpha_dropout(input, p, training)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def embedding(input, weight, padding_idx: nil, max_norm: nil, norm_type: 2.0, scale_grad_by_freq: false, sparse: false)
|
88
|
+
# TODO handle max_norm and norm_type
|
89
|
+
raise NotImplementedYet unless max_norm.nil? && norm_type == 2.0
|
90
|
+
|
91
|
+
padding_idx ||= -1
|
92
|
+
Torch._embedding(input, weight, padding_idx, scale_grad_by_freq, sparse)
|
93
|
+
end
|
52
94
|
end
|
53
95
|
end
|
54
96
|
|