ndav 0.0.3 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 443c009b1751ab850206b12f6ae175989fef5bb3e9dfd6094d069b338262474a
4
- data.tar.gz: fc5ef147dcbe89690add67f9aca9ed11a71a56ed2d801284936753066da2be2c
3
+ metadata.gz: e27d78e17f22830ab47cba80120c7fa3ad3139690dd276e1267abb8696c6ffe3
4
+ data.tar.gz: 1a3ab5273684a54a5920528663fa5ebcab8ab861213b622b60afe3267ff184e5
5
5
  SHA512:
6
- metadata.gz: 7ce73fa38eba65d0c1933cef3e787a6a770854847f7946098ca4ff7e26ba0e588ee6d5a1d79e469abb27a0c303722f69e9030943a73b5295e7a422c73dee96f5
7
- data.tar.gz: 917725d70d4a3269da345d389b93562d54bec9b0911e88229a469a98d79203026ab37bbe834039aded9b1635c827d6723b5b82f23dcacd3864e9df0908dcab20
6
+ metadata.gz: 6fe639a15fd780e5add9dcf124f3222214f6dd82cef28e4c16589f0f9dae936dda08e378ed28a3fa9bb810933250caf48bad2a18885a6261685451b3faf14bf0
7
+ data.tar.gz: 3b3769ce7d12622bd231d0f4bffeb590b631a4c6be42984e2c998c49b64d2c24499bf922744d11b02c27dd308735c8f29d3385c70d5f3753509ce3bd70d4415f
data/.gitignore CHANGED
@@ -6,3 +6,5 @@ ext/Makefile
6
6
  *.o
7
7
  *.bundle.dSYM
8
8
  pkg/
9
+ doc/
10
+ .yardoc/
data/.gitlab-ci.yml CHANGED
@@ -12,3 +12,15 @@ test:
12
12
  - /root/.local/share/gem/ruby
13
13
  script:
14
14
  - rake test
15
+
16
+ pages:
17
+ stage: deploy
18
+ image: ruby:4.0
19
+ script:
20
+ - bundle exec rake yard
21
+ - mv doc public
22
+ artifacts:
23
+ paths:
24
+ - public
25
+ only:
26
+ - main
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --asset NDAV.png
2
+ -
3
+ LICENSE.txt
data/NDAV.png ADDED
Binary file
data/README.md CHANGED
@@ -1,9 +1,173 @@
1
1
  NDAV - N-Dimensional Array View
2
2
  ===============================
3
3
 
4
- Wrapper for MemoryView and pointer.
4
+ [![Gem Version](https://badge.fury.io/rb/ndav.svg)](https://badge.fury.io/rb/ndav)
5
+
6
+ A thin wrapper around [MemoryView][] ("buffer protocol" for Ruby).
7
+
8
+ It provides an interoperability layer for multi-dimensional arrays which can be shared between libraries.
9
+
10
+ ![NDAV converts library data each other](./NDAV.png)
11
+
12
+ SYNOPSIS
13
+ --------
14
+
15
+ waveform, sample_rate = TorchAudio.load("path/to/audio.wav")
16
+
17
+ # Convert Torch::Tensor to NDAV
18
+ # so that you can convert it to OrtValue,
19
+ # a data format for ONNX Runtime
20
+ input = waveform
21
+ .to_ndav
22
+ .to_ort_value
23
+
24
+ # Make ONNX Runtime return result as OrtValue
25
+ outputs = OnnxRuntime::Session.new("path/to/model.onnx")
26
+ .run(
27
+ [:output_name],
28
+ {input_name: input},
29
+ output_type: :ort_value
30
+ )
31
+
32
+ # You may convert OrtValue to Torch::Tensor via NDAV
33
+ output_tensor = outputs[0]
34
+ .to_ndav
35
+ .to_torch_tensor # converts back to Torch::Tensor
36
+
37
+ TorchAudio.save("path/to/output.wav", output_tensor, sample_rate)
38
+
39
+ ABSTRACT
40
+ --------
41
+
42
+ NDAV acts as an interoperability layer between multi-dimensional arrays including images, audio and tensors such as [Numo::NArray][], [Torch.rb][]'s `Torch::Tensor`, [ONNX Runtime Ruby][]'s `OnnxRuntime::OrtValue`, [Red Arrow][]'s `Arrow::Array` and so on.
43
+
44
+ It allows data to be shared without copying.
45
+
46
+ BACKGROUND
47
+ ----------
48
+
49
+ In the modern Ruby community, [Numo::NArray][] is often used for data conversion. But, data are copied when converting to and from Numo::NArray. In addition, Numo::NArray neither exports nor accepts MemoryView.
50
+
51
+ [Red Arrow][] is also used and it can export MemoryView from `Arrow::Array` (not from `Arrow::Tensor`, though). It also can be converted to and from Numo::NArray using [Red Arrow Numo::NArray][]. But, in real-world usage, we need, for example, to convert data with many hops:
52
+
53
+ Torch::Tensor -> Numo::NArray -> Red Arrow -> MemoryView -> some process...
54
+
55
+ It might not be difficult, but a little bit cumbersome. Additionally, Red Arrow doesn't accept MemoryView.
56
+
57
+ USAGE
58
+ -----
59
+
60
+ `ndav` gem is just a base library. You need to install bridges as well. Say, assume you want to make conversions between Numo::NArray each other.
61
+
62
+ require "numo/narray"
63
+ require "ndav"
64
+ require "ndav/numo/narray"
65
+
66
+ numo = Numo::SFloat.new(3, 5).seq # => Numo::SFloat
67
+ ndav = numo.to_ndav # => NDAV
68
+
69
+ numo = Numo::SFloat.from_ndav(ndav) # => Numo::SFloat
70
+ ndav = NDAV.from_numo_narray(numo) # => NDAV
71
+
72
+ include NDAV::Converter
73
+ numo = NumoNArray(ndav) #=> Numo::SFloat
74
+ ndav = NDAV(numo) # => NDAV
75
+
76
+ For `Torch::Tensor` and `OnnxRuntime::OrtValue`, you can do the same operation, therefore you may convert them to each other, like this:
77
+
78
+ numo
79
+ .to_ndav
80
+ .to_torch_tensor
81
+ .then {|torch_tensor| some_process(torch_tensor)}
82
+ .to_ndav
83
+ .to_ort_value
84
+ .then {|ort_value|
85
+ OnnxRuntime::Session.new("model.onnx")
86
+ .run(
87
+ [:output],
88
+ {input: ort_value},
89
+ output_type: :ort_value
90
+ )[0]
91
+ }
92
+ .to_ndav
93
+ .to_torch_tensor
94
+ .then {|torch_tensor| TorchAudio.save(torch_tensor, sample_rate)}
95
+
96
+ ### Working With MemoryView ###
97
+
98
+ NDAV can be initialized *directly* from libraries which export [MemoryView][] such as [Red Arrow][], without any bridge library:
99
+
100
+ arrow = Arrow::Int16Array.new([1, 2, 3])
101
+ ndav = NDAV.new(arrow)
102
+
103
+ On the other hand, it also exports MemoryView. You can pass NDAV arrays *directly* to methods which accept MemoryView such as whispercpp without bridge libraries:
104
+
105
+ waveform, sample_rate = TorchAudio.load("path/to/audio.wav")
106
+ samples = waveform.to_ndav
107
+ whisper.full(params, samples)
108
+
109
+ ### Notice On Memory Sharing ###
110
+
111
+ Notice that NDAV is just a memory view and libraries share a memory address. If you change source data destructively, it affects converted data.
112
+
113
+ Additionally, you potentially encounter odd data corruption or segmentation fault. These might be bugs in bridge libraries such as [ndav-numo-narray][]. As a user, you don't need to worry about this kind of memory management, but it's worth knowing such situations may occur.
114
+
115
+ INSTALLATION
116
+ ------------
117
+
118
+ % gem install ndav
119
+
120
+ or,
121
+
122
+ % bundle add ndav
123
+
124
+ But, you need bridges for real-world use. See each bridge's documentation for individual requirements.
125
+
126
+ BRIDGES
127
+ -------
128
+
129
+ There are some bridges using NDAV:
130
+
131
+ * [ndav/ffi][]: [`FFI::MemoryPointer`][FFI Pointer], [`FFI::Pointer`][FFI Pointer] <-> `NDAV`
132
+ * [ndav-numo-narray][]: [`Numo::NArray`][Numo::NArray] <-> `NDAV`
133
+ * [ndav-ort_value][]: [`OnnxRuntime::OrtValue`][ONNX Runtime Ruby] <-> `NDAV`
134
+ * [ndav-torch-tensor][]: [`Torch::Tensor`][Torch.rb] <-> `NDAV`
135
+ * [onnxruntime-torch-tensor][]: [`Torch::Tensor`][Torch.rb] <-> [`OnnxRuntime::OrtValue`][ONNX Runtime Ruby] via `NDAV`
136
+
137
+ CREATING BRIDGES
138
+ ----------------
139
+
140
+ Refer to existing bridge implementations listed above to create your bridge.
141
+
142
+ The points are:
143
+
144
+ * Implement `FromNDAV#from_ndav`, `ToNDAV#to_ndav` and `NDAV.register` them, and `NDAV.from_your_data` and `NDAV#to_your_data` are automatically derived
145
+ * When initializing NDAV object from your object, use `lifetime` keyword argument for `NDAV.new` effectively to prevent Ruby from GCing your object, which would lead to a dangling pointer
146
+ * When initializing your object from NDAV object, keep NDAV object alive to prevent Ruby from GCing NDAV object, which would lead to a dangling pointer, [ndav-numo-narray][], for instance, embeds the NDAV object in an instance variable
147
+
148
+ An advantage of NDAV over raw MemoryView is that you can write bridges in pure Ruby in most cases. It helps prototyping and experimentation. As an exception, I had to write C code for ndav-numo-narray because Numo::NArray only provides methods that access data by copying and does not directly expose its raw data pointer to Ruby API. However, in even such case, pure Ruby bridge remains a viable option for prototyping and experiments where a single initial copy is acceptable.
149
+
150
+ If you are a library author, I want you to consider making your library work with [MemoryView][] instead of creating an NDAV bridge.
151
+
152
+ FUTURE
153
+ ------
154
+
155
+ If [MemoryView][] gets popular enough in the Ruby ecosystem, this library will end its role and will no longer be needed. I hope such future.
5
156
 
6
157
  LICENSE
7
158
  -------
8
159
 
9
160
  BSD-2-Clause license. See LICENSE.txt file.
161
+
162
+ [MemoryView]: https://docs.ruby-lang.org/en/master/contributing/memory_view_md.html
163
+ [Numo::NArray]: https://ruby-numo.github.io/narray/
164
+ [Torch.rb]: https://github.com/ankane/torch.rb
165
+ [ONNX Runtime Ruby]: https://github.com/ankane/onnxruntime-ruby
166
+ [Red Arrow]: https://github.com/apache/arrow/tree/main/ruby
167
+ [Red Arrow Numo::NArray]: https://github.com/red-data-tools/red-arrow-numo-narray
168
+ [ndav/ffi]: https://gitlab.com/KitaitiMakoto/ndav/-/blob/main/lib/ndav/ffi.rb?ref_type=heads
169
+ [FFI Pointer]: https://github.com/ffi/ffi/wiki/Pointers
170
+ [ndav-numo-narray]: https://gitlab.com/KitaitiMakoto/ndav-numo-narray
171
+ [ndav-ort_value]: https://gitlab.com/KitaitiMakoto/ndav-ort_value
172
+ [ndav-torch-tensor]: https://gitlab.com/KitaitiMakoto/ndav-torch-tensor
173
+ [onnxruntime-torch-tensor]: https://gitlab.com/KitaitiMakoto/onnxruntime-torch-tensor
data/Rakefile CHANGED
@@ -1,18 +1,20 @@
1
1
  require "rake/clean"
2
2
  require "rake/testtask"
3
3
  require "rubygems/tasks"
4
+ require "yard"
4
5
 
5
6
  DL_NAME = "ndav".ext(RbConfig::CONFIG["DLEXT"])
6
7
  DL_BUILD_PATH = File.join("ext", DL_NAME)
7
8
  DL_PATH = File.join("lib", DL_NAME)
8
9
 
9
10
  SRC = FileList["ext/**.{h,c,rb}"]
11
+ CLEAN.include SRC.select {|src| src.end_with?(".o", ".so", ".bundle", ".dll") }
10
12
 
11
13
  task default: :test
12
14
 
13
15
  Rake::TestTask.new test: DL_PATH
14
- tasks = Gem::Tasks.new
15
- gemspec = tasks.build.gem.project.gemspec
16
+ Gem::Tasks.new
17
+ YARD::Rake::YardocTask.new
16
18
 
17
19
  file DL_PATH => DL_BUILD_PATH do |t|
18
20
  copy t.source, t.name
@@ -4,6 +4,10 @@ class NDAV
4
4
  alias from_fiddle_memory_view new
5
5
  alias from_fiddle_pointer new
6
6
 
7
+ def from_string(str, *, **)
8
+ new(Fiddle::Pointer[str], *, **)
9
+ end
10
+
7
11
  def register(cls, mdl, name:)
8
12
  if mdl.const_defined?(:FromNDAV)
9
13
  cls.extend mdl::FromNDAV
data/ndav.gemspec CHANGED
@@ -1,10 +1,11 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ndav"
3
- s.version = "0.0.3"
3
+ s.version = "0.0.4"
4
4
  s.summary = "N-Dimensional Array View"
5
5
  s.authors = ["Kitaiti Makoto"]
6
6
  s.licenses = ["BSD-2-Clause"]
7
- s.homepage = "https://gitlab.com/KitaitiMakoto/ndav"
7
+ s.homepage = "https://kitaitimakoto.gitlab.io/ndav"
8
+ s.metadata["source_code_uri"] = "https://gitlab.com/KitaitiMakoto/ndav"
8
9
 
9
10
  s.files = Dir.chdir(__dir__) {`git ls-files -z`.split("\x0")}
10
11
  s.extensions = ["ext/extconf.rb"]
@@ -20,4 +21,5 @@ Gem::Specification.new do |s|
20
21
  s.add_development_dependency "rubygems-requirements-system"
21
22
  s.add_development_dependency "red-arrow"
22
23
  s.add_development_dependency "ffi"
24
+ s.add_development_dependency "yard"
23
25
  end
data/test/test_ndav.rb CHANGED
@@ -28,4 +28,11 @@ class TestNDAV < TestBase
28
28
  assert_equal ptr, ndav.to_fiddle_pointer
29
29
  assert_int_array ndav
30
30
  end
31
+
32
+ def test_string
33
+ str = [1, 2, 3].pack("s*")
34
+ ndav = NDAV.from_string(str, format: "s")
35
+
36
+ assert_int_array ndav
37
+ end
31
38
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ndav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kitaiti Makoto
@@ -149,6 +149,20 @@ dependencies:
149
149
  - - ">="
150
150
  - !ruby/object:Gem::Version
151
151
  version: '0'
152
+ - !ruby/object:Gem::Dependency
153
+ name: yard
154
+ requirement: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ type: :development
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
152
166
  executables: []
153
167
  extensions:
154
168
  - ext/extconf.rb
@@ -156,8 +170,10 @@ extra_rdoc_files: []
156
170
  files:
157
171
  - ".gitignore"
158
172
  - ".gitlab-ci.yml"
173
+ - ".yardopts"
159
174
  - Gemfile
160
175
  - LICENSE.txt
176
+ - NDAV.png
161
177
  - README.md
162
178
  - Rakefile
163
179
  - ext/extconf.rb
@@ -173,10 +189,11 @@ files:
173
189
  - test/test_ffi.rb
174
190
  - test/test_ndav.rb
175
191
  - test/test_package.rb
176
- homepage: https://gitlab.com/KitaitiMakoto/ndav
192
+ homepage: https://kitaitimakoto.gitlab.io/ndav
177
193
  licenses:
178
194
  - BSD-2-Clause
179
- metadata: {}
195
+ metadata:
196
+ source_code_uri: https://gitlab.com/KitaitiMakoto/ndav
180
197
  rdoc_options: []
181
198
  require_paths:
182
199
  - lib