Skip to content
Closed
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
aba84aa
Use Chain to refactor trainer.
reyoung Dec 23, 2016
446fccf
Add network decorator for network defines.
reyoung Dec 26, 2016
2192d23
Merge branch 'feature/mnist_train_api' into feature/python_trainer_api
reyoung Dec 26, 2016
ffefb42
Doing GradientMachine Ops
reyoung Dec 26, 2016
e3d4da2
Add sum cost to Arguments
reyoung Dec 26, 2016
6459d12
Merge branch 'feature/fix_bugs_in_math' into feature/python_trainer_api
reyoung Dec 26, 2016
758856d
Merge branch 'feature/add_sum_cost_in_args' into feature/python_train…
reyoung Dec 26, 2016
3e1bb0f
add Trainer Chain Items
reyoung Dec 26, 2016
9601c2f
Merge branch 'develop' of github.com:baidu/Paddle into feature/add_su…
reyoung Dec 26, 2016
8b833d5
Add load/save method for Parameter
reyoung Dec 26, 2016
22f4ced
Merge branch 'feature/add_sum_cost_in_args' into feature/python_train…
reyoung Dec 26, 2016
20a9caa
Remove MonoChainItem
reyoung Dec 26, 2016
81c238f
init
reyoung Dec 26, 2016
febdc08
Refine dockerfile
Dec 27, 2016
6d62819
Sync Dockerfile => Dockerfile.gpu
reyoung Dec 27, 2016
da5b375
Merge branch 'feature/jupyter_docker' of github.com:reyoung/Paddle in…
reyoung Dec 27, 2016
7701908
Sync Dockerfile => Dockerfile.gpu
reyoung Dec 27, 2016
14fc57c
Merge branch 'develop' into feature/python_trainer_api
reyoung Dec 27, 2016
50434cb
Merge branch 'feature/jupyter_docker' into feature/python_trainer_api
reyoung Dec 27, 2016
9acfc21
Faster DataProvider Converter
reyoung Dec 27, 2016
704ed1e
Add Runner Builder
reyoung Dec 27, 2016
e522266
Move trainer to py_paddle.trainer
reyoung Dec 27, 2016
1f4820d
Extract base.py
reyoung Dec 27, 2016
3e16601
Fix unittest
reyoung Dec 27, 2016
b9f4648
Merge branch 'feature/jupyter_docker' into feature/python_trainer_api
reyoung Dec 27, 2016
3ceee61
Clean & comment code
reyoung Dec 28, 2016
2fdadf5
Add introduction ipynb
reyoung Dec 29, 2016
3242cb6
Support Local Sparse Train.
reyoung Jan 3, 2017
3b1d08b
Add Paddle Trainer API Usage docs
reyoung Jan 5, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions demo/mnist/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ plot.png
train.log
*pyc
.ipynb_checkpoints
*.w0
*.wbias
*.bin
214 changes: 29 additions & 185 deletions demo/mnist/api_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,199 +6,43 @@

The user api could be simpler and carefully designed.
"""
import py_paddle.swig_paddle as api
from py_paddle import DataProviderConverter

import paddle.trainer.PyDataProvider2 as dp
import numpy as np
import random
from mnist_util import read_from_mnist
from paddle.trainer_config_helpers import *


def optimizer_config():
settings(
learning_rate=1e-4,
learning_method=AdamOptimizer(),
batch_size=1000,
model_average=ModelAverage(average_window=0.5),
regularization=L2Regularization(rate=0.5))


def network_config():
imgs = data_layer(name='pixel', size=784)
hidden1 = fc_layer(input=imgs, size=200)
import mnist_provider
from py_paddle.trainer import *


@network(
inputs={
'pixel': dp.dense_vector(784),
'label': dp.integer_value(10),
},
learning_rate=1e-4,
learning_method=AdamOptimizer(),
batch_size=1000,
model_average=ModelAverage(average_window=0.5),
regularization=L2Regularization(rate=0.5))
def mnist_network(pixel, label):
hidden1 = fc_layer(input=pixel, size=200)
hidden2 = fc_layer(input=hidden1, size=200)
inference = fc_layer(input=hidden2, size=10, act=SoftmaxActivation())
cost = classification_cost(
input=inference, label=data_layer(
name='label', size=10))
outputs(cost)


def init_parameter(network):
assert isinstance(network, api.GradientMachine)
for each_param in network.getParameters():
assert isinstance(each_param, api.Parameter)
array_size = len(each_param)
array = np.random.uniform(-1.0, 1.0, array_size).astype('float32')
each_param.getBuf(api.PARAMETER_VALUE).copyFromNumpyArray(array)


def generator_to_batch(generator, batch_size):
ret_val = list()
for each_item in generator:
ret_val.append(each_item)
if len(ret_val) == batch_size:
yield ret_val
ret_val = list()
if len(ret_val) != 0:
yield ret_val


class BatchPool(object):
def __init__(self, generator, batch_size):
self.data = list(generator)
self.batch_size = batch_size

def __call__(self):
random.shuffle(self.data)
for offset in xrange(0, len(self.data), self.batch_size):
limit = min(offset + self.batch_size, len(self.data))
yield self.data[offset:limit]


def input_order_converter(generator):
for each_item in generator:
yield each_item['pixel'], each_item['label']
cost = classification_cost(input=inference, label=label)
return cost


def main():
api.initPaddle("-use_gpu=false", "-trainer_count=4") # use 4 cpu cores

# get enable_types for each optimizer.
# enable_types = [value, gradient, momentum, etc]
# For each optimizer(SGD, Adam), GradientMachine should enable different
# buffers.
opt_config_proto = parse_optimizer_config(optimizer_config)
opt_config = api.OptimizationConfig.createFromProto(opt_config_proto)
_temp_optimizer_ = api.ParameterOptimizer.create(opt_config)
enable_types = _temp_optimizer_.getParameterTypes()

# Create Simple Gradient Machine.
model_config = parse_network_config(network_config)
m = api.GradientMachine.createFromConfigProto(
model_config, api.CREATE_MODE_NORMAL, enable_types)

# This type check is not useful. Only enable type hint in IDE.
# Such as PyCharm
assert isinstance(m, api.GradientMachine)

# Initialize Parameter by numpy.
init_parameter(network=m)

# Create Local Updater. Local means not run in cluster.
# For a cluster training, here we can change to createRemoteUpdater
# in future.
updater = api.ParameterUpdater.createLocalUpdater(opt_config)
assert isinstance(updater, api.ParameterUpdater)

# Initialize ParameterUpdater.
updater.init(m)

# DataProvider Converter is a utility convert Python Object to Paddle C++
# Input. The input format is as same as Paddle's DataProvider.
converter = DataProviderConverter(
input_types=[dp.dense_vector(784), dp.integer_value(10)])

train_file = './data/raw_data/train'
test_file = './data/raw_data/t10k'

# start gradient machine.
# the gradient machine must be started before invoke forward/backward.
# not just for training, but also for inference.
m.start()

# evaluator can print error rate, etc. It is a C++ class.
batch_evaluator = m.makeEvaluator()
test_evaluator = m.makeEvaluator()

# Get Train Data.
# TrainData will stored in a data pool. Currently implementation is not care
# about memory, speed. Just a very naive implementation.
train_data_generator = input_order_converter(read_from_mnist(train_file))
train_data = BatchPool(train_data_generator, 512)

# outArgs is Neural Network forward result. Here is not useful, just passed
# to gradient_machine.forward
outArgs = api.Arguments.createArguments(0)

for pass_id in xrange(2): # we train 2 passes.
updater.startPass()

for batch_id, data_batch in enumerate(train_data()):
# data_batch is input images.
# here, for online learning, we could get data_batch from network.

# Start update one batch.
pass_type = updater.startBatch(len(data_batch))

# Start BatchEvaluator.
# batch_evaluator can be used between start/finish.
batch_evaluator.start()

# forwardBackward is a shortcut for forward and backward.
# It is sometimes faster than invoke forward/backward separately,
# because in GradientMachine, it may be async.
m.forwardBackward(converter(data_batch), outArgs, pass_type)

for each_param in m.getParameters():
updater.update(each_param)

# Get cost. We use numpy to calculate total cost for this batch.
cost_vec = outArgs.getSlotValue(0)
cost_vec = cost_vec.copyToNumpyMat()
cost = cost_vec.sum() / len(data_batch)

# Make evaluator works.
m.eval(batch_evaluator)

# Print logs.
print 'Pass id', pass_id, 'Batch id', batch_id, 'with cost=', \
cost, batch_evaluator

batch_evaluator.finish()
# Finish batch.
# * will clear gradient.
# * ensure all values should be updated.
updater.finishBatch(cost)

# testing stage. use test data set to test current network.
updater.apply()
test_evaluator.start()
test_data_generator = input_order_converter(read_from_mnist(test_file))
for data_batch in generator_to_batch(test_data_generator, 512):
# in testing stage, only forward is needed.
m.forward(converter(data_batch), outArgs, api.PASS_TEST)
m.eval(test_evaluator)

# print error rate for test data set
print 'Pass', pass_id, ' test evaluator: ', test_evaluator
test_evaluator.finish()
updater.restore()

updater.catchUpWith()
params = m.getParameters()
for each_param in params:
assert isinstance(each_param, api.Parameter)
value = each_param.getBuf(api.PARAMETER_VALUE)
value = value.copyToNumpyArray()

# Here, we could save parameter to every where you want
print each_param.getName(), value

updater.finishPass()

m.finish()
mnist = mnist_network()
runner = RunnerBuilder(
network=mnist, device_count=2).with_std_local_trainer(
method=mnist_provider.process,
file_list=['./data/raw_data/train']).with_std_tester(
method=mnist_provider.process,
file_list=['./data/raw_data/t10k']).build()
with runner:
for _ in xrange(2):
runner.run_one_pass()


if __name__ == '__main__':
Expand Down
28 changes: 25 additions & 3 deletions demo/mnist/mnist_provider.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from paddle.trainer.PyDataProvider2 import *
from mnist_util import read_from_mnist
import numpy


# Define a py data provider
Expand All @@ -8,5 +8,27 @@
'label': integer_value(10)},
cache=CacheType.CACHE_PASS_IN_MEM)
def process(settings, filename): # settings is not used currently.
for each in read_from_mnist(filename):
yield each
imgf = filename + "-images-idx3-ubyte"
labelf = filename + "-labels-idx1-ubyte"
f = open(imgf, "rb")
l = open(labelf, "rb")

f.read(16)
l.read(8)

# Define number of samples for train/test
if "train" in filename:
n = 60000
else:
n = 10000

images = numpy.fromfile(
f, 'ubyte', count=n * 28 * 28).reshape((n, 28 * 28)).astype('float32')
images = images / 255.0 * 2.0 - 1.0
labels = numpy.fromfile(l, 'ubyte', count=n).astype("int")

for i in xrange(n):
yield {"pixel": images[i, :], 'label': labels[i]}

f.close()
l.close()
30 changes: 0 additions & 30 deletions demo/mnist/mnist_util.py

This file was deleted.

4 changes: 4 additions & 0 deletions paddle/api/Arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ void Arguments::setSlotSequenceDim(size_t idx, IVector* vec) throw(RangeError) {
a.cpuSequenceDims = m->cast<paddle::IVector>(vec->getSharedPtr());
}

float Arguments::sumCosts() const {
return paddle::Argument::sumCosts(m->outputs);
}

int64_t Arguments::getBatchSize(size_t idx) const throw(RangeError) {
auto& a = m->getArg(idx);
return a.getBatchSize();
Expand Down
6 changes: 6 additions & 0 deletions paddle/api/PaddleAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ class Arguments {
IVector* vec) throw(RangeError);
void setSlotSequenceDim(size_t idx, IVector* vec) throw(RangeError);

float sumCosts() const;

private:
static Arguments* createByPaddleArgumentVector(void* ptr);
void* getInternalArgumentsPtr() const;
Expand Down Expand Up @@ -548,6 +550,10 @@ class Parameter {

size_t getSize() const;

bool save(const std::string& filename) const;

bool load(const std::string& filename) const;

private:
static Parameter* createFromRawPtr(void* ptr);
static Parameter* createFromSharedPtr(void* ptr);
Expand Down
8 changes: 8 additions & 0 deletions paddle/api/Parameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ size_t Parameter::getID() const { return m->getPtr()->getID(); }
void Parameter::setValueUpdated() { m->getPtr()->setValueUpdated(); }

size_t Parameter::getSize() const { return m->getPtr()->getSize(); }

bool Parameter::save(const std::string& filename) const {
return m->getPtr()->save(filename);
}

bool Parameter::load(const std::string& filename) const {
return m->getPtr()->load(filename);
}
6 changes: 6 additions & 0 deletions paddle/api/test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
___fc_layer_0__.w0
___fc_layer_0__.wbias
_hidden1.w0
_hidden1.wbias
_hidden2.w0
_hidden2.wbias
2 changes: 2 additions & 0 deletions paddle/api/test/testArguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ def test_load_arguments(self):
args = swig_paddle.Arguments.createArguments(1)
args.setSlotValue(0, m)

self.assertAlmostEqual(27.0, args.sumCosts())

mat = args.getSlotValue(0)
assert isinstance(mat, swig_paddle.Matrix)
np_mat = mat.toNumpyMatInplace()
Expand Down
4 changes: 4 additions & 0 deletions paddle/api/test/testGradientMachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def test_create_gradient_machine(self):
assert isinstance(val, swig_paddle.Vector)
arr = numpy.full((len(val), ), 0.1, dtype="float32")
val.copyFromNumpyArray(arr)
self.assertTrue(param.save(param.getName()))
param_config = param.getConfig().toProto()
assert isinstance(param_config,
paddle.proto.ParameterConfig_pb2.ParameterConfig)
Expand Down Expand Up @@ -92,6 +93,9 @@ def backward_callback(param_):

self.assertTrue(self.isCalled)

for param in machine.getParameters():
self.assertTrue(param.load(param.getName()))

def test_train_one_pass(self):
conf_file_path = './testTrainConfig.py'
trainer_config = swig_paddle.TrainerConfig.createFromTrainerConfigFile(
Expand Down
3 changes: 2 additions & 1 deletion paddle/py_paddle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
'paddle',
'DataProviderConverter',
'DataProviderWrapperConverter', # for deprecated usage.
'loadParameterFile'
'loadParameterFile',
'trainer'
]
util.monkeypatches()
Loading