Если вы не пересматриваете данные, то, вероятно, нет значения при использовании общих переменных.
Следующий код может быть изменен и использован для оценки различных методов получения данных в вашем конкретном вычислении.
Метод «ввода» - тот, который, вероятно, будет лучше, если вам не нужно будет пересматривать данные. Метод «shared_all» может превосходить все остальное, но только если вы можете поместить весь набор данных в память GPU. «Shared_batched» позволяет оценить, может ли иерархическая доработка ваших данных помочь.
В методе «shared_batched» набор данных разделен на множество макросов, и каждая партия макросов делится на множество микропакетов. Для хранения одиночной макроса используется одна общая переменная. Код оценивает все микропакеты в текущей партии макросов. После обработки полной партии макросов следующая партия макросов загружается в общую переменную, и код снова повторяется через микропакеты внутри нее.
В целом можно ожидать, что небольшое количество больших передач памяти будет работать быстрее, чем большее количество меньших передач (где общая передача одинакова для каждого). Но это необходимо проверить (например, с помощью кода ниже), прежде чем он будет известен наверняка; YMMV.
Использование параметра «заимствование» может также оказать существенное влияние на производительность, но имейте в виду the implications перед его использованием.
import math
import timeit
import numpy
import theano
import theano.tensor as tt
def test_input(data, batch_size):
assert data.shape[0] % batch_size == 0
batch_count = data.shape[0]/batch_size
x = tt.tensor4()
f = theano.function([x], outputs=x.sum())
total = 0.
start = timeit.default_timer()
for batch_index in xrange(batch_count):
total += f(data[batch_index * batch_size: (batch_index + 1) * batch_size])
print 'IN\tNA\t%s\t%s\t%s\t%s' % (batch_size, batch_size, timeit.default_timer() - start, total)
def test_shared_all(data, batch_size):
batch_count = data.shape[0]/batch_size
for borrow in (True, False):
start = timeit.default_timer()
all = theano.shared(data, borrow=borrow)
load_time = timeit.default_timer() - start
x = tt.tensor4()
i = tt.lscalar()
f = theano.function([i], outputs=x.sum(), givens={x: all[i * batch_size:(i + 1) * batch_size]})
total = 0.
start = timeit.default_timer()
for batch_index in xrange(batch_count):
total += f(batch_index)
print 'SA\t%s\t%s\t%s\t%s\t%s' % (
borrow, batch_size, batch_size, load_time + timeit.default_timer() - start, total)
def test_shared_batched(data, macro_batch_size, micro_batch_size):
assert data.shape[0] % macro_batch_size == 0
assert macro_batch_size % micro_batch_size == 0
macro_batch_count = data.shape[0]/macro_batch_size
micro_batch_count = macro_batch_size/micro_batch_size
macro_batch = theano.shared(numpy.empty((macro_batch_size,) + data.shape[1:], dtype=theano.config.floatX),
borrow=True)
x = tt.tensor4()
i = tt.lscalar()
f = theano.function([i], outputs=x.sum(), givens={x: macro_batch[i * micro_batch_size:(i + 1) * micro_batch_size]})
for borrow in (True, False):
total = 0.
start = timeit.default_timer()
for macro_batch_index in xrange(macro_batch_count):
macro_batch.set_value(
data[macro_batch_index * macro_batch_size: (macro_batch_index + 1) * macro_batch_size], borrow=borrow)
for micro_batch_index in xrange(micro_batch_count):
total += f(micro_batch_index)
print 'SB\t%s\t%s\t%s\t%s\t%s' % (
borrow, macro_batch_size, micro_batch_size, timeit.default_timer() - start, total)
def main():
numpy.random.seed(1)
shape = (20000, 3, 32, 32)
print 'Creating random data with shape', shape
data = numpy.random.standard_normal(size=shape).astype(theano.config.floatX)
print 'Running tests'
for macro_batch_size in (shape[0]/pow(10, i) for i in xrange(int(math.log(shape[0], 10)))):
test_shared_all(data, macro_batch_size)
test_input(data, macro_batch_size)
for micro_batch_size in (macro_batch_size/pow(10, i) for i in
xrange(int(math.log(macro_batch_size, 10)) + 1)):
test_shared_batched(data, macro_batch_size, micro_batch_size)
main()
Большое вам спасибо :) – Sumido