red-chainer 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bd5f287aafbc100878391131a0a184c9c6497ddb26e0c5124010166aa455def
4
- data.tar.gz: 6625f1d862ba17db5867b208494419f1e7e7bc1ed5b5276bec785151140a47bd
3
+ metadata.gz: 18e976d36f56e110baeae2d799471b4be2e4932778316ffcb3aafa51563bd3fd
4
+ data.tar.gz: f5429173d5b175738f4358774d9f058e31a86eec1418954cbad72d7875a2a7b8
5
5
  SHA512:
6
- metadata.gz: 659986f00b88051471ca54a88eafb4a6f9ebbdf8f27a9f51c8ff32a27f584d2a78015d47baf20e74c6e9605c09bda0777b4780c4ef79313d194a362e0d3ff013
7
- data.tar.gz: a468488ee913244bcdbc058fe27c93beec897bd4476f1eec50ae2bc3071124701aaf37b9f15cd07848bbb30372e4796c04b24ead672c28e5fcb0dbb1721b7bd6
6
+ metadata.gz: b1a617684703b92491e7876d919c2f6ef9c144039b9e12086d5b2ec7aed8644eca3ea8b2f4b32f2ef98fb6f31db4068b67467f95aa0a5868b3a903e073909b2e
7
+ data.tar.gz: '095870edbd1c68d35da023e9dd9a16096585a264f8e9cedf2c49dc465a62687a46634c58ee8a2d5fca4b2c41872f2f335455e076da66996a47f6c658ca6987e6'
@@ -0,0 +1,90 @@
1
+ module ResNet18
2
+ class Plain < Chainer::Chain
3
+ include Chainer::Functions::Activation
4
+ include Chainer::Initializers
5
+ include Chainer::Links::Connection
6
+ include Chainer::Links::Normalization
7
+
8
+ def initialize(ch, stride, use_conv: false)
9
+ super()
10
+
11
+ @use_conv = use_conv
12
+ w = HeNormal.new
13
+
14
+ init_scope do
15
+ @conv1 = Convolution2D.new(nil, ch, 3, stride: stride, pad: 1, nobias: true, initial_w: w)
16
+ @bn1 = BatchNormalization.new(ch)
17
+ @conv2 = Convolution2D.new(nil, ch, 3, stride: 1, pad: 1, nobias: true, initial_w: w)
18
+ @bn2 = BatchNormalization.new(ch)
19
+ if @use_conv
20
+ @conv3 = Convolution2D.new(nil, ch, 3, stride: stride, pad: 1, nobias: true, initial_w: w)
21
+ @bn3 = BatchNormalization.new(ch)
22
+ end
23
+ end
24
+ end
25
+
26
+ def call(x)
27
+ h = Relu.relu(@bn1.(@conv1.(x)))
28
+ h = @bn2.(@conv2.(h))
29
+ if @use_conv
30
+ h2 = @bn3.(@conv3.(x))
31
+ Relu.relu(h + h2)
32
+ else
33
+ Relu.relu(h + x)
34
+ end
35
+ end
36
+ end
37
+
38
+ class Block < Chainer::ChainList
39
+ def initialize(layer, ch, stride=2)
40
+ super()
41
+ add_link(Plain.new(ch, stride, use_conv: true))
42
+ (layer-1).times do
43
+ add_link(Plain.new(ch, 1))
44
+ end
45
+ end
46
+
47
+ def call(x)
48
+ @children.each do |f|
49
+ x = f.(x)
50
+ end
51
+ x
52
+ end
53
+ end
54
+
55
+ class Model < Chainer::Chain
56
+ include Chainer::Functions::Activation
57
+ include Chainer::Functions::Evaluation
58
+ include Chainer::Functions::Loss
59
+ include Chainer::Functions::Pooling
60
+ include Chainer::Initializers
61
+ include Chainer::Links::Connection
62
+ include Chainer::Links::Normalization
63
+
64
+ def initialize(n_classes: 10)
65
+ super()
66
+ initial_w = HeNormal.new
67
+
68
+ init_scope do
69
+ @conv = Convolution2D.new(3, 64, 7, stride: 2, pad: 3, initial_w: initial_w)
70
+ @bn = BatchNormalization.new(64)
71
+
72
+ @res2 = Block.new(2, 64, 1)
73
+ @res3 = Block.new(2, 128)
74
+ @res4 = Block.new(2, 256)
75
+ @res5 = Block.new(2, 512)
76
+ @fc = Linear.new(nil, out_size: n_classes)
77
+ end
78
+ end
79
+
80
+ def call(x)
81
+ h = Relu.relu(@bn.(@conv.(x)))
82
+ h = @res2.(h)
83
+ h = @res3.(h)
84
+ h = @res4.(h)
85
+ h = @res5.(h)
86
+ h = AveragePooling2D.average_pooling_2d(h, h.shape[2..-1])
87
+ @fc.(h)
88
+ end
89
+ end
90
+ end
@@ -15,7 +15,7 @@ class Block < Chainer::Chain
15
15
  end
16
16
 
17
17
  class VGG < Chainer::Chain
18
- def initialize(class_labels: 10)
18
+ def initialize(n_classes: 10)
19
19
  super()
20
20
  init_scope do
21
21
  @block1_1 = Block.new(64, 3)
@@ -33,7 +33,7 @@ class VGG < Chainer::Chain
33
33
  @block5_3 = Block.new(512, 3)
34
34
  @fc1 = Chainer::Links::Connection::Linear.new(nil, out_size: 512, nobias: true)
35
35
  @bn_fc1 = Chainer::Links::Normalization::BatchNormalization.new(512)
36
- @fc2 = Chainer::Links::Connection::Linear.new(nil, out_size: class_labels, nobias: true)
36
+ @fc2 = Chainer::Links::Connection::Linear.new(nil, out_size: n_classes, nobias: true)
37
37
  end
38
38
  end
39
39
 
@@ -1,5 +1,6 @@
1
1
  require 'chainer'
2
2
  require __dir__ + '/models/vgg'
3
+ require __dir__ + '/models/resnet18'
3
4
  require 'optparse'
4
5
 
5
6
  args = {
@@ -9,7 +10,8 @@ args = {
9
10
  learnrate: 0.05,
10
11
  epoch: 300,
11
12
  out: 'result',
12
- resume: nil
13
+ resume: nil,
14
+ model: 'vgg',
13
15
  }
14
16
 
15
17
 
@@ -21,6 +23,7 @@ opt.on('-l', '--learnrate VALUE', "Learning rate for SGD (default: #{args[:learn
21
23
  opt.on('-e', '--epoch VALUE', "Number of sweeps over the dataset to train (default: #{args[:epoch]})") { |v| args[:epoch] = v.to_i }
22
24
  opt.on('-o', '--out VALUE', "Directory to output the result (default: #{args[:out]})") { |v| args[:out] = v }
23
25
  opt.on('-r', '--resume VALUE', "Resume the training from snapshot") { |v| args[:resume] = v }
26
+ opt.on('-m', '--model VALUE', "Use model") { |v| args[:model] = v }
24
27
  opt.parse!(ARGV)
25
28
 
26
29
  # Set up a neural network to train.
@@ -38,9 +41,15 @@ else
38
41
  raise 'Invalid dataset choice.'
39
42
  end
40
43
 
41
- puts "setup..."
44
+ if args[:model] == 'vgg'
45
+ puts 'Using VGG model'
46
+ model_class = VGG
47
+ elsif args[:model] == 'resnet18'
48
+ puts 'Using ResNet-18 model'
49
+ model_class = ResNet18::Model
50
+ end
42
51
 
43
- model = Chainer::Links::Model::Classifier.new(VGG.new(class_labels: class_labels))
52
+ model = Chainer::Links::Model::Classifier.new(model_class.new(n_classes: class_labels))
44
53
 
45
54
  optimizer = Chainer::Optimizers::MomentumSGD.new(lr: args[:learnrate])
46
55
  optimizer.setup(model)
@@ -58,7 +67,7 @@ trainer.extend(Chainer::Training::Extensions::ExponentialShift.new('lr', 0.5), t
58
67
  frequency = args[:frequency] == -1 ? args[:epoch] : [1, args[:frequency]].max
59
68
  trainer.extend(Chainer::Training::Extensions::Snapshot.new, trigger: [frequency, 'epoch'])
60
69
 
61
- trainer.extend(Chainer::Training::Extensions::LogReport.new)
70
+ trainer.extend(Chainer::Training::Extensions::LogReport.new)
62
71
  trainer.extend(Chainer::Training::Extensions::PrintReport.new(['epoch', 'main/loss', 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy', 'elapsed_time']))
63
72
  trainer.extend(Chainer::Training::Extensions::ProgressBar.new)
64
73
 
data/lib/chainer.rb CHANGED
@@ -43,6 +43,7 @@ require 'chainer/functions/connection/linear'
43
43
  require 'chainer/functions/noise/dropout'
44
44
  require 'chainer/functions/normalization/batch_normalization'
45
45
  require 'chainer/functions/pooling/pooling_2d'
46
+ require 'chainer/functions/pooling/average_pooling_2d'
46
47
  require 'chainer/functions/pooling/max_pooling_2d'
47
48
  require 'chainer/testing/array'
48
49
  require 'chainer/training/extension'
@@ -40,7 +40,7 @@ module Chainer
40
40
  else
41
41
  raise 'invalid ndim for CIFAR dataset'
42
42
  end
43
- images = images.cast_to(Numo::DFloat)
43
+ images = images.cast_to(Numo::SFloat)
44
44
  images *= scale / 255.0
45
45
 
46
46
  if withlabel
@@ -21,7 +21,7 @@ module Chainer
21
21
  end
22
22
  if index.kind_of?(Enumerable)
23
23
  length = batches[0].shape[0]
24
- length.times.map {|i| batches.map { |m| m[i] } }
24
+ length.times.map {|i| batches.map { |m| m.ndim > 1 ? m[i, false] : m[i] } }
25
25
  else
26
26
  batches
27
27
  end
@@ -0,0 +1,45 @@
1
+ module Chainer
2
+ module Functions
3
+ module Pooling
4
+ class AveragePooling2D < Pooling2D
5
+ # Spatial average pooling function.
6
+ #
7
+ # This function acts similarly to :class:`Convolution2D`,
8
+ # but it computes the average of input spatial patch for each channel
9
+ # without any parameter instead of computing the inner products.
10
+ # @param [Chainer::Variable] x Input variable.
11
+ # @param [integer] ksize Size of pooling window. `ksize=k` and `ksize=[k, k]` are equivalent.
12
+ # @param [integer] stride Stride of pooling applications. `stride=s` and `stride=[s, s]` are equivalent.
13
+ # If `nil` is specified, then it uses same stride as the pooling window size.
14
+ # @param [integer] pad Spatial padding width for the input array. `pad=p` and `pad=[p, p]` are equivalent.
15
+ # @return [Chainer::Variable] Output variable
16
+ def self.average_pooling_2d(x, ksize, stride: nil, pad: 0)
17
+ self.new(ksize, stride: stride, pad: pad, cover_all: false).(x)
18
+ end
19
+
20
+ # Average pooling over a set of 2d planes.
21
+ def forward_cpu(x)
22
+ retain_inputs([])
23
+ @in_shape = x[0].shape
24
+ @in_dtype = x[0].class
25
+
26
+ col = Chainer::Utils::Conv.im2col_cpu(x[0], @kh, @kw, @sy, @sx, @ph, @pw)
27
+ y = col.mean(axis: [2, 3])
28
+
29
+ [y]
30
+ end
31
+
32
+ def backward_cpu(x, gy)
33
+ h, w = @in_shape[2..-1]
34
+ shape = gy[0].shape
35
+ shape.insert(2, 1, 1)
36
+ gcol = gy[0].reshape(*shape).tile(1, 1, @kh, @kw, 1, 1)
37
+
38
+ gx = Chainer::Utils::Conv.col2im_cpu(gcol, @sy, @sx, @ph, @pw, h, w)
39
+ gx /= @kh * @kw
40
+ [gx]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -13,8 +13,8 @@ module Chainer
13
13
  return HeNormal.new(scale: 1 / Numo::NMath.sqrt(2)) if initializer.nil?
14
14
  return Constant.new(initializer) if initializer.kind_of?(Numeric)
15
15
  return Constant.new(initializer) if initializer.kind_of?(Numo::NArray)
16
-
17
- unless initializer.method_defined?(:call)
16
+
17
+ unless initializer.respond_to?(:call)
18
18
  raise TypeError, "invalid type of initializer: #{initializer.class}"
19
19
  end
20
20
 
data/lib/chainer/link.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Chainer
2
2
  class Link
3
+ attr_accessor :name
4
+
3
5
  def initialize
4
6
  @params = []
5
7
  @persistent = []
@@ -17,22 +19,28 @@ module Chainer
17
19
 
18
20
  begin
19
21
  yield
20
- set_attr
22
+ self.instance_variables.each do |name|
23
+ set_attr(name, self.instance_variable_get(name))
24
+ end
21
25
  ensure
22
26
  @within_init_scope = old_flag
23
27
  end
24
28
  end
25
29
 
26
- def set_attr
27
- self.instance_variables.each do |name|
28
- value = self.instance_variable_get(name)
29
- if value.instance_of?(Chainer::Parameter)
30
- @params << name
31
- @persistent.delete(name)
32
- end
30
+ def set_attr(name, value)
31
+ if within_init_scope && value.kind_of?(Chainer::Parameter)
32
+ value.name = name
33
+ @params << name
34
+ @persistent.delete(name)
33
35
  end
34
36
  end
35
37
 
38
+ def del_attr(name)
39
+ @params.delete(name)
40
+ @persistent.delete(name)
41
+ self.remove_instance_variable(name)
42
+ end
43
+
36
44
  def cleargrads
37
45
  params do |param|
38
46
  param.cleargrad
@@ -99,16 +107,22 @@ module Chainer
99
107
  @children = []
100
108
  end
101
109
 
102
- def set_attr
103
- self.instance_variables.each do |name|
104
- value = self.instance_variable_get(name)
105
- if value.kind_of?(Chainer::Link)
106
- @children << name
110
+ def set_attr(name, value)
111
+ if within_init_scope && value.kind_of?(Chainer::Link)
112
+ if self.respond_to?(name)
113
+ raise TypeError, "cannot register a new link #{name}: attribute exists"
107
114
  end
115
+ value.name = name
116
+ @children << name
108
117
  end
109
118
  super
110
119
  end
111
120
 
121
+ def del_attr(name)
122
+ @children.delete(name)
123
+ super
124
+ end
125
+
112
126
  def params(include_uninit: true)
113
127
  super(include_uninit: include_uninit) do |param|
114
128
  yield param
@@ -155,4 +169,118 @@ module Chainer
155
169
  end
156
170
  end
157
171
  end
172
+
173
+
174
+ # Composable link with list-like interface.
175
+ #
176
+ # This is another example of compositional link. Unlike :class:`Chainer::Chain`,
177
+ # this class can be used like a list of child links.
178
+ # Each child link is indexed by a non-negative integer,
179
+ # and it maintains the current number of registered child links.
180
+ # The :meth:`add_link` method inserts a new link at the end of the list.
181
+ # It is useful to write a chain with arbitrary number of child links,
182
+ # e.g. an arbitrarily deep multi-layer perceptron.
183
+ class ChainList < Link
184
+ attr_reader :children
185
+
186
+ def initialize(*links)
187
+ super()
188
+ @children = []
189
+
190
+ links.each do |link|
191
+ add_link(link)
192
+ end
193
+ end
194
+
195
+ def set_attr(name, value)
196
+ if within_init_scope && value.kind_of?(Chainer::Link)
197
+ raise TypeError, 'cannot register a new link within a "with chainlist.init_scope:" block.'
198
+ end
199
+ super
200
+ end
201
+
202
+ def [](index)
203
+ @children[index]
204
+ end
205
+
206
+ def each(&block)
207
+ @children.each(&block)
208
+ end
209
+
210
+ def size
211
+ @children.size
212
+ end
213
+
214
+ def <<(link)
215
+ add_link(link)
216
+ end
217
+
218
+ def add_link(link)
219
+ link.name = @children.size.to_s
220
+ @children << link
221
+ end
222
+
223
+ def params(include_uninit: true)
224
+ super(include_uninit: include_uninit) do |param|
225
+ yield param
226
+ end
227
+
228
+ @children.each do |link|
229
+ link.params(include_uninit: include_uninit) do |param|
230
+ yield param
231
+ end
232
+ end
233
+ end
234
+
235
+ def namedparams(include_uninit: true)
236
+ super(include_uninit: include_uninit) do |ret|
237
+ yield ret
238
+ end
239
+ @children.each_with_index do |link, idx|
240
+ prefix = "/#{idx}"
241
+ link.namedparams(include_uninit: include_uninit) do |path, param|
242
+ yield [prefix + path, param]
243
+ end
244
+ end
245
+ end
246
+
247
+ def links(skipself: false)
248
+ unless skipself
249
+ yield self
250
+ end
251
+
252
+ @children.each do |child|
253
+ child.links do |link|
254
+ yield link
255
+ end
256
+ end
257
+ end
258
+
259
+ def namedlinks(skipself: false)
260
+ unless skipself
261
+ yield '/', self
262
+ end
263
+
264
+ @children.each_with_index do |child, idx|
265
+ prefix = "/#{idx}"
266
+ yield prefix, child
267
+ child.namedlinks(skipself: true) do |path, link|
268
+ yield [prefix + path, link]
269
+ end
270
+ end
271
+ end
272
+
273
+ def children
274
+ @children.each do |child|
275
+ yield child
276
+ end
277
+ end
278
+
279
+ def serialize(serializer)
280
+ super
281
+ @children.each_with_index do |child, idx|
282
+ child.serialize(serializer[idx.to_s])
283
+ end
284
+ end
285
+ end
158
286
  end
@@ -23,7 +23,7 @@ module Chainer
23
23
  # @param [Numo::NArray.dtype] dtype Type to use in computing.
24
24
  # @param [boolean] use_gamma If `true`, use scaling parameter. Otherwise, use unit(1) which makes no effect.
25
25
  # @param [boolean] use_beta If `true`, use shifting parameter. Otherwise, use unit(0) which makes no effect.
26
- def initialize(size, decay: 0.9, eps: 2e-5, dtype: Numo::DFloat, use_gamma: true, use_beta: true, initial_gamma: nil, initial_beta: nil)
26
+ def initialize(size, decay: 0.9, eps: 2e-5, dtype: Numo::SFloat, use_gamma: true, use_beta: true, initial_gamma: nil, initial_beta: nil)
27
27
  super()
28
28
  @avg_mean = dtype.zeros(size)
29
29
  register_persistent('avg_mean')
@@ -1,4 +1,4 @@
1
1
  module Chainer
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: red-chainer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusaku Hatanaka
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-19 00:00:00.000000000 Z
11
+ date: 2018-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: numo-narray
@@ -96,6 +96,7 @@ files:
96
96
  - Rakefile
97
97
  - bin/console
98
98
  - bin/setup
99
+ - examples/cifar/models/resnet18.rb
99
100
  - examples/cifar/models/vgg.rb
100
101
  - examples/cifar/train_cifar.rb
101
102
  - examples/iris.rb
@@ -124,6 +125,7 @@ files:
124
125
  - lib/chainer/functions/math/identity.rb
125
126
  - lib/chainer/functions/noise/dropout.rb
126
127
  - lib/chainer/functions/normalization/batch_normalization.rb
128
+ - lib/chainer/functions/pooling/average_pooling_2d.rb
127
129
  - lib/chainer/functions/pooling/max_pooling_2d.rb
128
130
  - lib/chainer/functions/pooling/pooling_2d.rb
129
131
  - lib/chainer/gradient_check.rb