lib/dnn/core/models.rb in ruby-dnn-1.1.1 vs lib/dnn/core/models.rb in ruby-dnn-1.1.2
- old
+ new
@@ -107,10 +107,11 @@
end
# This class deals with the model of the network.
class Model < Chain
attr_accessor :optimizer
+ attr_accessor :loss_weights
attr_reader :last_log
# Load marshal model.
# @param [String] file_name File name of marshal model to load.
# @return [DNN::Models::Model] Return the loaded model.
@@ -124,10 +125,11 @@
def initialize
super
@optimizer = nil
@loss_func = nil
@built = false
+ @loss_weights = nil
@callbacks = []
@last_log = {}
end
def call(input_tensors)
@@ -137,19 +139,21 @@
end
# Set optimizer and loss_func to model.
# @param [DNN::Optimizers::Optimizer] optimizer Optimizer to use for learning.
# @param [DNN::Losses::Loss] loss_func Loss function to use for learning.
- def setup(optimizer, loss_func)
+ # @param [Array | NilClass] loss_weights Setting loss weights contribution.
+ def setup(optimizer, loss_func, loss_weights: nil)
unless optimizer.is_a?(Optimizers::Optimizer)
raise TypeError, "optimizer:#{optimizer.class} is not an instance of DNN::Optimizers::Optimizer class."
end
unless loss_func.is_a?(Losses::Loss) || loss_func.is_a?(Array)
raise TypeError, "loss_func:#{loss_func.class} is not an instance of DNN::Losses::Loss or Array class."
end
@optimizer = optimizer
self.loss_func = loss_func
+ @loss_weights = loss_weights
end
def loss_func
@loss_func
end
@@ -176,22 +180,25 @@
# @param [Integer] batch_size Batch size used for one training.
# @param [Integer] initial_epoch Initial epoch.
# @param [Array | NilClass] test If you to test the model for every 1 epoch,
# specify [x_test, y_test]. Don't test to the model, specify nil.
# @param [Boolean] verbose Set true to display the log. If false is set, the log is not displayed.
+ # @param [Boolean] accuracy Set true to compute the accuracy.
def train(x, y, epochs,
batch_size: 1,
initial_epoch: 1,
test: nil,
- verbose: true)
+ verbose: true,
+ accuracy: true)
check_xy_type(x, y)
train_iterator = Iterator.new(x, y)
train_by_iterator(train_iterator, epochs,
batch_size: batch_size,
initial_epoch: initial_epoch,
test: test,
- verbose: verbose)
+ verbose: verbose,
+ accuracy: accuracy)
end
alias fit train
# Start training by iterator.
@@ -201,15 +208,17 @@
# @param [Integer] batch_size Batch size used for one training.
# @param [Integer] initial_epoch Initial epoch.
# @param [Array | NilClass] test If you to test the model for every 1 epoch,
# specify [x_test, y_test]. Don't test to the model, specify nil.
# @param [Boolean] verbose Set true to display the log. If false is set, the log is not displayed.
+ # @param [Boolean] accuracy Set true to compute the accuracy.
def train_by_iterator(train_iterator, epochs,
batch_size: 1,
initial_epoch: 1,
test: nil,
- verbose: true)
+ verbose: true,
+ accuracy: true)
raise DNNError, "The model is not optimizer setup complete." unless @optimizer
raise DNNError, "The model is not loss_func setup complete." unless @loss_func
num_train_datas = train_iterator.num_datas
num_train_datas = num_train_datas / batch_size * batch_size if train_iterator.last_round_down
@@ -240,15 +249,22 @@
print log if verbose
end
if test
acc, loss = if test.is_a?(Array)
- evaluate(test[0], test[1], batch_size: batch_size)
+ evaluate(test[0], test[1], batch_size: batch_size, accuracy: accuracy)
else
- evaluate_by_iterator(test, batch_size: batch_size)
+ evaluate_by_iterator(test, batch_size: batch_size, accuracy: accuracy)
end
- print " " + metrics_to_str({ accuracy: acc, test_loss: loss }) if verbose
+ if verbose
+ metrics = if accuracy
+ { accuracy: acc, test_loss: loss }
+ else
+ { test_loss: loss }
+ end
+ print " " + metrics_to_str(metrics)
+ end
end
puts "" if verbose
call_callbacks(:after_epoch)
end
nil
@@ -283,21 +299,20 @@
DNN.learning_phase = true
output_tensors = call(Tensor.convert(x))
if output_tensors.is_a?(Array)
loss_data = []
output_tensors.each.with_index do |out, i|
- loss = if i == 0
- @loss_func[i].loss(out, Tensor.convert(y[i]), layers)
- else
- @loss_func[i].loss(out, Tensor.convert(y[i]))
- end
+ loss_opt = {}
+ loss_opt[:layers] = layers if i == 0
+ loss_opt[:loss_weight] = @loss_weights[i] if @loss_weights
+ loss = @loss_func[i].loss(out, Tensor.convert(y[i]), **loss_opt)
loss_data << loss.data.to_f
loss.link.backward(Xumo::SFloat.ones(y[i][0...1, false].shape[0], 1))
end
else
out = output_tensors
- loss = @loss_func.loss(out, Tensor.convert(y), layers)
+ loss = @loss_func.loss(out, Tensor.convert(y), layers: layers)
loss_data = loss.data.to_f
loss.link.backward(Xumo::SFloat.ones(y[0...1, false].shape[0], 1))
end
@optimizer.update(get_all_trainable_params)
@last_log[:train_loss] = loss_data
@@ -308,20 +323,22 @@
# Evaluate model and get accuracy and loss of test data.
# @param [Numo::SFloat] x Input test data.
# @param [Numo::SFloat] y Output test data.
# @param [Integer] batch_size Batch size used for one test.
# @return [Array] Returns the test data accuracy and mean loss in the form [accuracy, mean_loss].
- def evaluate(x, y, batch_size: 100)
+ # If accuracy is not needed returns in the form [nil, mean_loss].
+ def evaluate(x, y, batch_size: 100, accuracy: true)
check_xy_type(x, y)
- evaluate_by_iterator(Iterator.new(x, y, random: false), batch_size: batch_size)
+ evaluate_by_iterator(Iterator.new(x, y, random: false), batch_size: batch_size, accuracy: accuracy)
end
# Evaluate model by iterator.
# @param [DNN::Iterator] test_iterator Iterator used for testing.
# @param [Integer] batch_size Batch size used for one test.
# @return [Array] Returns the test data accuracy and mean loss in the form [accuracy, mean_loss].
- def evaluate_by_iterator(test_iterator, batch_size: 100)
+ # If accuracy is not needed returns in the form [nil, mean_loss].
+ def evaluate_by_iterator(test_iterator, batch_size: 100, accuracy: true)
num_test_datas = test_iterator.num_datas
batch_size = batch_size >= num_test_datas ? num_test_datas : batch_size
if @loss_func.is_a?(Array)
total_correct = Array.new(@loss_func.length, 0)
sum_loss = Array.new(@loss_func.length, 0)
@@ -329,55 +346,58 @@
total_correct = 0
sum_loss = 0
end
max_steps = (num_test_datas.to_f / batch_size).ceil
test_iterator.foreach(batch_size) do |x_batch, y_batch|
- correct, loss_value = test_on_batch(x_batch, y_batch)
+ correct, loss_value = test_on_batch(x_batch, y_batch, accuracy: accuracy)
if @loss_func.is_a?(Array)
@loss_func.each_index do |i|
- total_correct[i] += correct[i]
+ total_correct[i] += correct[i] if accuracy
sum_loss[i] += loss_value[i]
end
else
- total_correct += correct
+ total_correct += correct if accuracy
sum_loss += loss_value
end
end
+ acc = nil
if @loss_func.is_a?(Array)
mean_loss = Array.new(@loss_func.length, 0)
- acc = Array.new(@loss_func.length, 0)
+ acc = Array.new(@loss_func.length, 0) if accuracy
@loss_func.each_index do |i|
mean_loss[i] += sum_loss[i] / max_steps
- acc[i] += total_correct[i].to_f / num_test_datas
+ acc[i] += total_correct[i].to_f / num_test_datas if accuracy
end
else
mean_loss = sum_loss / max_steps
- acc = total_correct.to_f / num_test_datas
+ acc = total_correct.to_f / num_test_datas if accuracy
end
@last_log[:test_loss] = mean_loss
@last_log[:test_accuracy] = acc
[acc, mean_loss]
end
# Evaluate once.
# @param [Numo::SFloat | Array] x Input test data.
# @param [Numo::SFloat | Array] y Output test data.
- # @return [Array] Returns the test data accuracy and mean loss in the form [accuracy, mean_loss].
- def test_on_batch(x, y)
+ # @return [Array] Returns the test data accuracy and mean loss in the form [accuracy, loss].
+ # If accuracy is not needed returns in the form [nil, loss].
+ def test_on_batch(x, y, accuracy: true)
call_callbacks(:before_test_on_batch)
DNN.learning_phase = false
output_tensors = call(Tensor.convert(x))
+ correct = nil
if output_tensors.is_a?(Array)
- correct = []
+ correct = [] if accuracy
loss_data = []
output_tensors.each.with_index do |out, i|
- correct << accuracy(out.data, y[i])
+ correct << accuracy(out.data, y[i]) if accuracy
loss = @loss_func[i].(out, Tensor.convert(y[i]))
loss_data << loss.data.to_f
end
else
out = output_tensors
- correct = accuracy(out.data, y)
+ correct = accuracy(out.data, y) if accuracy
loss = @loss_func.(out, Tensor.convert(y))
loss_data = loss.data.to_f
end
call_callbacks(:after_test_on_batch)
[correct, loss_data]