blob: 6c2bcb3955cc81fe5fc8b5edda37be8c39993194 [file]
#-------------------------------------------------------------
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#-------------------------------------------------------------
# Imports
source("nn/layers/affine.dml") as affine
source("nn/layers/cross_entropy_loss.dml") as cross_entropy_loss
source("nn/layers/relu.dml") as relu
source("nn/layers/sigmoid.dml") as sigmoid
source("nn/layers/softmax.dml") as softmax
source("nn/optim/sgd.dml") as sgd
init_model = function(Integer inputDimension, Integer outputDimension, int seed = -1)
return(list[unknown] model){
[W1, b1] = affine::init(inputDimension, 200, seed = seed)
l_seed = ifelse(seed==-1, -1, seed + 1);
[W2, b2] = affine::init(200, 200, seed = l_seed)
l_seed = ifelse(seed==-1, -1, seed + 2);
[W3, b3] = affine::init(200, outputDimension, seed = l_seed)
model = list(W1, W2, W3, b1, b2, b3)
}
predict = function(matrix[double] X,
list[unknown] model)
return (matrix[double] probs) {
W1 = as.matrix(model[1]); b1 = as.matrix(model[4])
W2 = as.matrix(model[2]); b2 = as.matrix(model[5])
W3 = as.matrix(model[3]); b3 = as.matrix(model[6])
out1a = sigmoid::forward(affine::forward(X, W1, b1))
out2a = relu::forward(affine::forward(out1a, W2, b2))
probs = softmax::forward(affine::forward(out2a, W3, b3))
}
eval = function(matrix[double] probs, matrix[double] y)
return (double accuracy) {
correct_pred = rowIndexMax(probs) == rowIndexMax(y)
accuracy = mean(correct_pred)
}
gradients = function(list[unknown] model,
list[unknown] hyperparams,
matrix[double] features,
matrix[double] labels)
return (list[unknown] gradients) {
W1 = as.matrix(model[1]); b1 = as.matrix(model[4])
W2 = as.matrix(model[2]); b2 = as.matrix(model[5])
W3 = as.matrix(model[3]); b3 = as.matrix(model[6])
# Compute forward pass
out1 = affine::forward(features, W1, b1)
out1a = sigmoid::forward(out1)
out2 = affine::forward(out1a, W2, b2)
out2a = relu::forward(out2)
out3 = affine::forward(out2a, W3, b3)
probs = softmax::forward(out3)
# Compute loss & accuracy for training data
# loss = cross_entropy_loss::forward(probs, labels)
# print("Batch loss: " + loss)
# Compute data backward pass
# Note it is same arguments as forward with one extra argument in front
dloss = cross_entropy_loss::backward(probs, labels)
dout3 = softmax::backward(dloss, out3)
[dout2a, dW3, db3] = affine::backward(dout3, out2a, W3, b3)
dout2 = relu::backward(dout2a, out2)
[dout1a, dW2, db2] = affine::backward(dout2, out1a, W2, b2)
dout1 = sigmoid::backward(dout1a, out1)
[a, dW1, db1] = affine::backward(dout1, features, W1, b1)
gradients = list(dW1, dW2, dW3, db1, db2, db3)
}
aggregation = function(list[unknown] model,
list[unknown] hyperparams,
list[unknown] gradients)
return (list[unknown] model_result) {
W1 = as.matrix(model[1]); dW1 = as.matrix(gradients[1])
W2 = as.matrix(model[2]); dW2 = as.matrix(gradients[2])
W3 = as.matrix(model[3]); dW3 = as.matrix(gradients[3])
b1 = as.matrix(model[4]); db1 = as.matrix(gradients[4])
b2 = as.matrix(model[5]); db2 = as.matrix(gradients[5])
b3 = as.matrix(model[6]); db3 = as.matrix(gradients[6])
learning_rate = as.double(as.scalar(hyperparams["learning_rate"]))
# Optimize with SGD
W3 = sgd::update(W3, dW3, learning_rate)
b3 = sgd::update(b3, db3, learning_rate)
W2 = sgd::update(W2, dW2, learning_rate)
b2 = sgd::update(b2, db2, learning_rate)
W1 = sgd::update(W1, dW1, learning_rate)
b1 = sgd::update(b1, db1, learning_rate)
model_result = list(W1, W2, W3, b1, b2, b3)
}
train = function(matrix[double] X, matrix[double] y,
int epochs, int batch_size, double learning_rate,
int seed = -1)
return (list[unknown] model_trained) {
N = nrow(X) # num examples
D = ncol(X) # num features
K = ncol(y) # num classes
model = init_model(D, K, seed)
W1 = as.matrix(model[1]); b1 = as.matrix(model[4])
W2 = as.matrix(model[2]); b2 = as.matrix(model[5])
W3 = as.matrix(model[3]); b3 = as.matrix(model[6])
# Create the hyper parameter list
hyperparams = list(learning_rate=learning_rate)
# Calculate iterations
iters = ceil(N / batch_size)
for (e in 1:epochs) {
for(i in 1:iters) {
# Create the model list
model_list = list(W1, W2, W3, b1, b2, b3)
# Get next batch
beg = ((i-1) * batch_size) %% N + 1
end = min(N, beg + batch_size - 1)
X_batch = X[beg:end,]
y_batch = y[beg:end,]
gradients_list = gradients(model_list, hyperparams, X_batch, y_batch)
model_updated = aggregation(model_list, hyperparams, gradients_list)
W1 = as.matrix(model_updated[1]); b1 = as.matrix(model_updated[4])
W2 = as.matrix(model_updated[2]); b2 = as.matrix(model_updated[5])
W3 = as.matrix(model_updated[3]); b3 = as.matrix(model_updated[6])
}
}
model_trained = list(W1, W2, W3, b1, b2, b3)
}
train_paramserv = function(matrix[Double] X, matrix[Double] y,
Integer epochs, Integer batch_size, Double learning_rate, Integer workers,
Integer seed)
return (list[unknown] model_trained) {
utype = "BSP"
freq = "BATCH"
mode = "LOCAL"
N = nrow(X) # num examples
D = ncol(X) # num features
K = ncol(y) # num classes
# Create the model list
model_list = init_model(D, K, seed)
# Create the hyper parameter list
params = list(learning_rate=learning_rate)
# Use paramserv function
model_trained = paramserv(model=model_list, features=X, labels=y,
val_features=matrix(0, rows=0, cols=0), val_labels=matrix(0, rows=0, cols=0),
upd="./tests/examples/tutorials/neural_net_source.dml::gradients",
agg="./tests/examples/tutorials/neural_net_source.dml::aggregation",
mode=mode, utype=utype, freq=freq, epochs=epochs, batchsize=batch_size,
k=workers, hyperparams=params, checkpointing="NONE")
}