ruby-dnn 0.8.8 → 0.9.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 +4 -4
- data/API-Reference.ja.md +83 -46
- data/examples/cifar10_example.rb +5 -5
- data/examples/mnist_conv2d_example.rb +5 -5
- data/examples/mnist_example.rb +5 -5
- data/examples/mnist_lstm_example.rb +5 -5
- data/examples/xor_example.rb +4 -3
- data/lib/dnn.rb +3 -3
- data/lib/dnn/core/activations.rb +1 -112
- data/lib/dnn/core/cnn_layers.rb +14 -14
- data/lib/dnn/core/dataset.rb +18 -0
- data/lib/dnn/core/initializers.rb +28 -8
- data/lib/dnn/core/layers.rb +62 -90
- data/lib/dnn/core/losses.rb +120 -0
- data/lib/dnn/core/model.rb +124 -66
- data/lib/dnn/core/rnn_layers.rb +17 -13
- data/lib/dnn/core/{util.rb → utils.rb} +10 -6
- data/lib/dnn/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c11d1f0246f81a299edfaa8be69ef8ba6ccdb940a2b185e3b0ab77b56e9ec8ad
|
4
|
+
data.tar.gz: 47441a8cef420dcb120c955cf9e30ef32848763e3301ddbe75abf08a657f5777
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e643a3daaafebedb496d21084db402a5701787cbced23735b224b040556a7835e889d4458018b47351efce991606906bd89f3c878d8ab88fd9a99a98f89441e5
|
7
|
+
data.tar.gz: 9387a6e092ec219e11deb884164fac8364d2a25794791a7a086760dda920910c9157c9207a4c76e4a1cfd74eb3564897b9380654635b211651eee8611499be64
|
data/API-Reference.ja.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
ruby-dnnのAPIリファレンスです。このリファレンスでは、APIを利用するうえで必要となるクラスとメソッドしか記載していません。
|
3
3
|
そのため、プログラムの詳細が必要な場合は、ソースコードを参照してください。
|
4
4
|
|
5
|
-
最終更新バージョン:0.
|
5
|
+
最終更新バージョン:0.9.0
|
6
6
|
|
7
7
|
# module DNN
|
8
8
|
ruby-dnnの名前空間をなすモジュールです。
|
@@ -65,7 +65,7 @@ Model
|
|
65
65
|
なし。
|
66
66
|
|
67
67
|
## def to_json
|
68
|
-
モデルをjson文字列に変換します。
|
68
|
+
モデルをjson文字列に変換します。
|
69
69
|
変換したjson文字列には学習パラメータの情報は含まれません。
|
70
70
|
学習パラメータの情報を取得したい場合は、params_to_jsonを使用してください。
|
71
71
|
### arguments
|
@@ -83,28 +83,39 @@ String
|
|
83
83
|
学習パラメータを変換して生成したjson文字列。
|
84
84
|
|
85
85
|
## def <<(layer)
|
86
|
-
|
86
|
+
モデルにレイヤー追加します。
|
87
87
|
### arguments
|
88
|
-
* Layer
|
89
|
-
|
88
|
+
* Layer
|
89
|
+
追加するレイヤー。
|
90
90
|
### return
|
91
91
|
Model
|
92
92
|
自身のモデルのインスタンス。
|
93
93
|
|
94
94
|
## def optimizer
|
95
95
|
モデルのオプティマイザーを取得します。
|
96
|
-
|
96
|
+
|
97
97
|
### arguments
|
98
98
|
なし。
|
99
99
|
### return
|
100
100
|
Optimizer
|
101
101
|
モデルのオプティマイザー。
|
102
102
|
|
103
|
-
## def
|
103
|
+
## def loss
|
104
|
+
モデルの損失関数を取得します。
|
105
|
+
|
106
|
+
### arguments
|
107
|
+
なし。
|
108
|
+
### return
|
109
|
+
Loss
|
110
|
+
モデルの損失関数。
|
111
|
+
|
112
|
+
## def compile(optimizer, loss)
|
104
113
|
モデルをコンパイルします。
|
105
114
|
### arguments
|
106
115
|
* Optimizer optimizer
|
107
116
|
モデルが学習に使用するオプティマイザー。
|
117
|
+
* Loss loss
|
118
|
+
モデルが学習に使用する損失関数。
|
108
119
|
### return
|
109
120
|
なし。
|
110
121
|
|
@@ -233,11 +244,11 @@ Array
|
|
233
244
|
|
234
245
|
## 【Instance methods】
|
235
246
|
|
236
|
-
## def build(
|
247
|
+
## def build(input_shape)
|
237
248
|
モデルのコンパイル時に、レイヤーをビルドするために使用されます。
|
238
249
|
### arguments
|
239
|
-
*
|
240
|
-
|
250
|
+
* Array input_shape
|
251
|
+
入力されるNArrayの形状。
|
241
252
|
### return
|
242
253
|
なし。
|
243
254
|
|
@@ -550,26 +561,7 @@ N次元のデータを平坦化します。
|
|
550
561
|
データの形状を変更するshapeです。
|
551
562
|
|
552
563
|
|
553
|
-
# class OutputLayer < Layer
|
554
|
-
出力層に該当するレイヤーです。出力層の活性化関数は、全てこのクラスを継承する必要があります。
|
555
|
-
|
556
|
-
## 【Instance methods】
|
557
564
|
|
558
|
-
## abstruct def backward(y)
|
559
|
-
出力層の活性化関数と損失関数を合わせたものを微分した導関数を用いて、教師データの出力データを逆方向に伝搬します。
|
560
|
-
### arguments
|
561
|
-
Numo::SFloat y
|
562
|
-
出力データ。
|
563
|
-
### return
|
564
|
-
出力層の活性化関数と損失関数の微分値。
|
565
|
-
|
566
|
-
## abstruct def loss
|
567
|
-
損失関数の値を取得します。
|
568
|
-
### arguments
|
569
|
-
Numo::SFloat y
|
570
|
-
出力データ。
|
571
|
-
### return
|
572
|
-
損失関数の値。
|
573
565
|
|
574
566
|
|
575
567
|
# class Dropout
|
@@ -668,22 +660,6 @@ Float alpha
|
|
668
660
|
出力値が負のときの傾き。
|
669
661
|
|
670
662
|
|
671
|
-
# class IdentityMSE < OutputLayer
|
672
|
-
恒等関数と二乗誤差関数を合わせた出力層のレイヤーです。
|
673
|
-
|
674
|
-
|
675
|
-
# class IdentityMAE < OutputLayer
|
676
|
-
恒等関数と平均絶対誤差関数を合わせた出力層のレイヤーです。
|
677
|
-
|
678
|
-
|
679
|
-
# class SoftmaxWithLoss < OutputLayer
|
680
|
-
ソフトマックス関数とクロスエントロピー誤差関数を合わせた出力層のレイヤーです。
|
681
|
-
|
682
|
-
|
683
|
-
# class SigmoidWithLoss < OutputLayer
|
684
|
-
シグモイド関数とバイナリクロスエントロピー誤差関数を合わせた出力層のレイヤーです。
|
685
|
-
|
686
|
-
|
687
663
|
# module Initializers
|
688
664
|
全てのInitializerの名前空間をなすモジュールです。
|
689
665
|
|
@@ -894,7 +870,7 @@ Float beta2
|
|
894
870
|
指数平均移動のための係数2。
|
895
871
|
|
896
872
|
|
897
|
-
# module
|
873
|
+
# module Utils
|
898
874
|
ユーティリティ関数を提供します。
|
899
875
|
|
900
876
|
## 【Singleton methods】
|
@@ -924,3 +900,64 @@ Array
|
|
924
900
|
### return
|
925
901
|
NArray
|
926
902
|
カテゴライズされたNArrayのインスタンス。
|
903
|
+
|
904
|
+
## def self.sigmoid(x)
|
905
|
+
xのシグモイド関数の値を返します。
|
906
|
+
### arguments
|
907
|
+
* Numo::SFloat x
|
908
|
+
シグモイド関数の引数の値。
|
909
|
+
### return
|
910
|
+
Numo::SFloat
|
911
|
+
シグモイド関数の値。
|
912
|
+
|
913
|
+
## def self.softmax(x)
|
914
|
+
xのソフトマックス関数の値を返します。
|
915
|
+
### arguments
|
916
|
+
* Numo::SFloat x
|
917
|
+
ソフトマックス関数の引数の値。
|
918
|
+
### return
|
919
|
+
Numo::SFloat
|
920
|
+
ソフトマックス関数の値。
|
921
|
+
|
922
|
+
|
923
|
+
|
924
|
+
# module Losses
|
925
|
+
損失関数のレイヤーの名前空間をなすモジュールです。
|
926
|
+
|
927
|
+
# class Loss
|
928
|
+
出力層に該当するレイヤーです。出力層の活性化関数は、全てこのクラスを継承する必要があります。
|
929
|
+
|
930
|
+
## 【Instance methods】
|
931
|
+
## abstruct def forward(out, y)
|
932
|
+
損失関数の順伝搬を行います。全ての損失関数のクラスは、このメソッドを実装する必要があります。
|
933
|
+
|
934
|
+
### arguments
|
935
|
+
Numo::SFloat out
|
936
|
+
ニューラルネットワークの出力値。
|
937
|
+
Numo::SFloat y
|
938
|
+
教師データの値。
|
939
|
+
### return
|
940
|
+
損失関数の値。
|
941
|
+
|
942
|
+
## abstruct def loss
|
943
|
+
損失関数の値を取得します。
|
944
|
+
### arguments
|
945
|
+
Numo::SFloat y
|
946
|
+
出力データ。
|
947
|
+
### return
|
948
|
+
損失関数の値。
|
949
|
+
|
950
|
+
# class MeanSquaredError < OutputLayer
|
951
|
+
二乗誤差の損失関数です。
|
952
|
+
|
953
|
+
|
954
|
+
# class IdentityMAE < OutputLayer
|
955
|
+
平均絶対誤差の損失関数です。
|
956
|
+
|
957
|
+
|
958
|
+
# class SoftmaxCrossEntropy < OutputLayer
|
959
|
+
ソフトマックス関数とクロスエントロピー誤差を合わせた損失関数です。
|
960
|
+
|
961
|
+
|
962
|
+
# class SigmoidCrossEntropy < OutputLayer
|
963
|
+
シグモイド関数とクロスエントロピー誤差を合わせた損失関数です。
|
data/examples/cifar10_example.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require "dnn"
|
2
2
|
require "dnn/lib/cifar10"
|
3
|
-
#require "numo/linalg/autoloader"
|
3
|
+
# require "numo/linalg/autoloader"
|
4
4
|
|
5
5
|
include DNN::Layers
|
6
6
|
include DNN::Activations
|
7
7
|
include DNN::Optimizers
|
8
|
+
include DNN::Losses
|
8
9
|
Model = DNN::Model
|
9
10
|
CIFAR10 = DNN::CIFAR10
|
10
11
|
|
@@ -17,8 +18,8 @@ x_test = Numo::SFloat.cast(x_test)
|
|
17
18
|
x_train /= 255
|
18
19
|
x_test /= 255
|
19
20
|
|
20
|
-
y_train = DNN::
|
21
|
-
y_test = DNN::
|
21
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
22
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
22
23
|
|
23
24
|
model = Model.new
|
24
25
|
|
@@ -60,8 +61,7 @@ model << ReLU.new
|
|
60
61
|
model << Dropout.new(0.5)
|
61
62
|
|
62
63
|
model << Dense.new(10)
|
63
|
-
model << SoftmaxWithLoss.new
|
64
64
|
|
65
|
-
model.compile(Adam.new)
|
65
|
+
model.compile(Adam.new, SoftmaxCrossEntropy.new)
|
66
66
|
|
67
67
|
model.train(x_train, y_train, 10, batch_size: 100, test: [x_test, y_test])
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require "dnn"
|
2
2
|
require "dnn/lib/mnist"
|
3
|
-
#require "numo/linalg/autoloader"
|
3
|
+
# require "numo/linalg/autoloader"
|
4
4
|
|
5
5
|
include DNN::Layers
|
6
6
|
include DNN::Activations
|
7
7
|
include DNN::Optimizers
|
8
|
+
include DNN::Losses
|
8
9
|
Model = DNN::Model
|
9
10
|
MNIST = DNN::MNIST
|
10
11
|
|
@@ -17,8 +18,8 @@ x_test = Numo::SFloat.cast(x_test).reshape(x_test.shape[0], 28, 28, 1)
|
|
17
18
|
x_train /= 255
|
18
19
|
x_test /= 255
|
19
20
|
|
20
|
-
y_train = DNN::
|
21
|
-
y_test = DNN::
|
21
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
22
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
22
23
|
|
23
24
|
model = Model.new
|
24
25
|
|
@@ -42,8 +43,7 @@ model << ReLU.new
|
|
42
43
|
model << Dropout.new(0.5)
|
43
44
|
|
44
45
|
model << Dense.new(10)
|
45
|
-
model << SoftmaxWithLoss.new
|
46
46
|
|
47
|
-
model.compile(Adam.new)
|
47
|
+
model.compile(Adam.new, SoftmaxCrossEntropy.new)
|
48
48
|
|
49
49
|
model.train(x_train, y_train, 10, batch_size: 100, test: [x_test, y_test])
|
data/examples/mnist_example.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require "dnn"
|
2
2
|
require "dnn/lib/mnist"
|
3
|
-
#require "numo/linalg/autoloader"
|
3
|
+
# require "numo/linalg/autoloader"
|
4
4
|
|
5
5
|
include DNN::Layers
|
6
6
|
include DNN::Activations
|
7
7
|
include DNN::Optimizers
|
8
|
+
include DNN::Losses
|
8
9
|
Model = DNN::Model
|
9
10
|
MNIST = DNN::MNIST
|
10
11
|
|
@@ -17,8 +18,8 @@ x_test = Numo::SFloat.cast(x_test).reshape(x_test.shape[0], 784)
|
|
17
18
|
x_train /= 255
|
18
19
|
x_test /= 255
|
19
20
|
|
20
|
-
y_train = DNN::
|
21
|
-
y_test = DNN::
|
21
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
22
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
22
23
|
|
23
24
|
model = Model.new
|
24
25
|
|
@@ -33,8 +34,7 @@ model << BatchNormalization.new
|
|
33
34
|
model << ReLU.new
|
34
35
|
|
35
36
|
model << Dense.new(10)
|
36
|
-
model << SoftmaxWithLoss.new
|
37
37
|
|
38
|
-
model.compile(RMSProp.new)
|
38
|
+
model.compile(RMSProp.new, SoftmaxCrossEntropy.new)
|
39
39
|
|
40
40
|
model.train(x_train, y_train, 10, batch_size: 100, test: [x_test, y_test])
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require "dnn"
|
2
2
|
require "dnn/lib/mnist"
|
3
|
-
#require "numo/linalg/autoloader"
|
3
|
+
# require "numo/linalg/autoloader"
|
4
4
|
|
5
5
|
include DNN::Layers
|
6
6
|
include DNN::Activations
|
7
7
|
include DNN::Optimizers
|
8
|
+
include DNN::Losses
|
8
9
|
Model = DNN::Model
|
9
10
|
MNIST = DNN::MNIST
|
10
11
|
|
@@ -17,8 +18,8 @@ x_test = Numo::SFloat.cast(x_test).reshape(x_test.shape[0], 28, 28)
|
|
17
18
|
x_train /= 255
|
18
19
|
x_test /= 255
|
19
20
|
|
20
|
-
y_train = DNN::
|
21
|
-
y_test = DNN::
|
21
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
22
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
22
23
|
|
23
24
|
model = Model.new
|
24
25
|
|
@@ -28,8 +29,7 @@ model << LSTM.new(200)
|
|
28
29
|
model << LSTM.new(200, return_sequences: false)
|
29
30
|
|
30
31
|
model << Dense.new(10)
|
31
|
-
model << SoftmaxWithLoss.new
|
32
32
|
|
33
|
-
model.compile(Adam.new)
|
33
|
+
model.compile(Adam.new, SoftmaxCrossEntropy.new)
|
34
34
|
|
35
35
|
model.train(x_train, y_train, 10, batch_size: 100, test: [x_test, y_test])
|
data/examples/xor_example.rb
CHANGED
@@ -3,7 +3,9 @@ require "dnn"
|
|
3
3
|
include DNN::Layers
|
4
4
|
include DNN::Activations
|
5
5
|
include DNN::Optimizers
|
6
|
+
include DNN::Losses
|
6
7
|
Model = DNN::Model
|
8
|
+
Utils = DNN::Utils
|
7
9
|
|
8
10
|
x = Numo::SFloat[[0, 0], [1, 0], [0, 1], [1, 1]]
|
9
11
|
y = Numo::SFloat[[0], [1], [1], [0]]
|
@@ -14,10 +16,9 @@ model << InputLayer.new(2)
|
|
14
16
|
model << Dense.new(16)
|
15
17
|
model << ReLU.new
|
16
18
|
model << Dense.new(1)
|
17
|
-
model << SigmoidWithLoss.new
|
18
19
|
|
19
|
-
model.compile(SGD.new)
|
20
|
+
model.compile(SGD.new, SigmoidCrossEntropy.new)
|
20
21
|
|
21
22
|
model.train(x, y, 20000, batch_size: 4, verbose: false)
|
22
23
|
|
23
|
-
p model.predict(x)
|
24
|
+
p Utils.sigmoid(model.predict(x))
|
data/lib/dnn.rb
CHANGED
@@ -5,18 +5,18 @@ else
|
|
5
5
|
Xumo = Numo
|
6
6
|
end
|
7
7
|
|
8
|
-
Xumo::SFloat.srand(rand(2**64))
|
9
|
-
|
10
8
|
module DNN; end
|
11
9
|
|
12
10
|
require_relative "dnn/version"
|
13
11
|
require_relative "dnn/core/error"
|
14
12
|
require_relative "dnn/core/model"
|
15
13
|
require_relative "dnn/core/param"
|
14
|
+
require_relative "dnn/core/dataset"
|
16
15
|
require_relative "dnn/core/initializers"
|
17
16
|
require_relative "dnn/core/layers"
|
18
17
|
require_relative "dnn/core/activations"
|
18
|
+
require_relative "dnn/core/losses"
|
19
19
|
require_relative "dnn/core/cnn_layers"
|
20
20
|
require_relative "dnn/core/rnn_layers"
|
21
21
|
require_relative "dnn/core/optimizers"
|
22
|
-
require_relative "dnn/core/
|
22
|
+
require_relative "dnn/core/utils"
|
data/lib/dnn/core/activations.rb
CHANGED
@@ -2,10 +2,8 @@ module DNN
|
|
2
2
|
module Activations
|
3
3
|
|
4
4
|
class Sigmoid < Layers::Layer
|
5
|
-
NMath = Xumo::NMath
|
6
|
-
|
7
5
|
def forward(x)
|
8
|
-
@out =
|
6
|
+
@out = Utils.sigmoid(x)
|
9
7
|
end
|
10
8
|
|
11
9
|
def backward(dout)
|
@@ -150,114 +148,5 @@ module DNN
|
|
150
148
|
end
|
151
149
|
end
|
152
150
|
|
153
|
-
|
154
|
-
class IdentityMSE < Layers::OutputLayer
|
155
|
-
def forward(x)
|
156
|
-
@out = x
|
157
|
-
end
|
158
|
-
|
159
|
-
def backward(y)
|
160
|
-
@out - y
|
161
|
-
end
|
162
|
-
|
163
|
-
def loss(y)
|
164
|
-
batch_size = y.shape[0]
|
165
|
-
0.5 * ((@out - y)**2).sum / batch_size + lasso + ridge
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
|
170
|
-
class IdentityMAE < Layers::OutputLayer
|
171
|
-
def forward(x)
|
172
|
-
@out = x
|
173
|
-
end
|
174
|
-
|
175
|
-
def backward(y)
|
176
|
-
dout = @out - y
|
177
|
-
dout[dout >= 0] = 1
|
178
|
-
dout[dout < 0] = -1
|
179
|
-
dout
|
180
|
-
end
|
181
|
-
|
182
|
-
def loss(y)
|
183
|
-
batch_size = y.shape[0]
|
184
|
-
(@out - y).abs.sum / batch_size + lasso + ridge
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
|
189
|
-
class IdentityHuber < Layers::OutputLayer
|
190
|
-
def forward(x)
|
191
|
-
@out = x
|
192
|
-
end
|
193
|
-
|
194
|
-
def loss(y)
|
195
|
-
loss = loss_l1(y)
|
196
|
-
loss = loss > 1 ? loss : loss_l2(y)
|
197
|
-
@loss = loss + lasso + ridge
|
198
|
-
end
|
199
|
-
|
200
|
-
def backward(y)
|
201
|
-
dout = @out - y
|
202
|
-
if @loss > 1
|
203
|
-
dout[dout >= 0] = 1
|
204
|
-
dout[dout < 0] = -1
|
205
|
-
end
|
206
|
-
dout
|
207
|
-
end
|
208
|
-
|
209
|
-
private
|
210
|
-
|
211
|
-
def loss_l1(y)
|
212
|
-
batch_size = y.shape[0]
|
213
|
-
(@out - y).abs.sum / batch_size
|
214
|
-
end
|
215
|
-
|
216
|
-
def loss_l2(y)
|
217
|
-
batch_size = y.shape[0]
|
218
|
-
0.5 * ((@out - y)**2).sum / batch_size
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
|
223
|
-
class SoftmaxWithLoss < Layers::OutputLayer
|
224
|
-
NMath = Xumo::NMath
|
225
|
-
|
226
|
-
def forward(x)
|
227
|
-
@out = NMath.exp(x) / NMath.exp(x).sum(1).reshape(x.shape[0], 1)
|
228
|
-
end
|
229
|
-
|
230
|
-
def backward(y)
|
231
|
-
@out - y
|
232
|
-
end
|
233
|
-
|
234
|
-
def loss(y)
|
235
|
-
batch_size = y.shape[0]
|
236
|
-
-(y * NMath.log(@out + 1e-7)).sum / batch_size + lasso + ridge
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
|
241
|
-
class SigmoidWithLoss < Layers::OutputLayer
|
242
|
-
NMath = Xumo::NMath
|
243
|
-
|
244
|
-
def initialize
|
245
|
-
@sigmoid = Sigmoid.new
|
246
|
-
end
|
247
|
-
|
248
|
-
def forward(x)
|
249
|
-
@out = @sigmoid.forward(x)
|
250
|
-
end
|
251
|
-
|
252
|
-
def backward(y)
|
253
|
-
@out - y
|
254
|
-
end
|
255
|
-
|
256
|
-
def loss(y)
|
257
|
-
batch_size = y.shape[0]
|
258
|
-
-(y * NMath.log(@out + 1e-7) + (1 - y) * NMath.log(1 - @out + 1e-7)).sum / batch_size + lasso + ridge
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
151
|
end
|
263
152
|
end
|