In [ ]:
!pip install install Theano==0.8.2
!pip install https://github.com/Lasagne/Lasagne/archive/master.zip
In [1]:
import numpy as np
def sum_squares(N):
return сумма квадратов чисел от 0 до N
In [2]:
%%time
sum_squares(10**8)
Out[2]:
In [3]:
import theano
import theano.tensor as T
In [4]:
#будущий параметр функции
N = T.scalar("a dimension",dtype='int32')
#рецепт получения суммы квадратов
result = (T.arange(N)**2).sum()
#компиляция функции "сумма квадратов" чисел от 0 до N
sum_function = theano.function(inputs = [N],outputs=result)
In [5]:
%%time
sum_function(10**8)
Out[5]:
Ничего не понятно? Сейчас исправим.
In [6]:
#входы
example_input_integer = T.scalar("вход - одно число(пример)",dtype='float32')
example_input_tensor = T.tensor4("вход - четырёхмерный тензор(пример)")
#не бойся, тензор нам не пригодится
input_vector = T.vector("вход - вектор целых чисел", dtype='int32')
In [7]:
#преобразования
#поэлементное умножение
double_the_vector = input_vector*2
#поэлементный косинус
elementwise_cosine = T.cos(input_vector)
#разность квадрата каждого элемента и самого элемента
vector_squares = input_vector**2 - input_vector
In [8]:
double_the_vector
Out[8]:
In [ ]:
#теперь сам:
#создай 2 вектора из чисел float32
my_vector = <вектор из float32>
my_vector2 = <ещё один такой же>
In [ ]:
#напиши преобразование, которое считает
#(вектор 1)*(вектор 2) / (sin(вектор 1) +1)
my_transformation = <преобразование>
In [ ]:
print (my_transformation)
#то, что получилась не чиселка - это нормально
In [ ]:
inputs = [<от чего завсит функция>]
outputs = [<что вычисляет функция (можно сразу несколько - списком, либо 1 преобразование)>]
# можно скомпилировать написанные нами преобразования как функцию
my_function = theano.function(
inputs,outputs,
allow_input_downcast=True #автоматически прводить типы (необязательно)
)
In [ ]:
#можно вызвать вот-так:
print ("using python lists:")
print (my_function([1,2,3],[4,5,6]))
print()
#а можно так.
#К слову, ту тип float приводится к типу второго вектора
print ("using numpy arrays:")
print (my_function(np.arange(10),
np.linspace(5,6,10,dtype='float')))
In [ ]:
#словарик значений для входов
my_function_inputs = {
my_vector:[1,2,3],
my_vector2:[4,5,6]
}
#вычислить без компиляции
#если мы ничего не перепутали,
#должно получиться точно то же, что и раньше
print my_transformation.eval(my_function_inputs)
#можно вычислять преобразования на ходу
print ("сумма 2 векторов", (my_vector + my_vector2).eval(my_function_inputs))
#!ВАЖНО! если преобразование зависит только от части переменных,
#остальные давать не надо
print ("форма первого вектора", my_vector.shape.eval({
my_vector:[1,2,3]
}))
In [ ]:
# Задание 1 - напиши и скомпилируй theano-функцию, которая считает среднеквадратичную ошибку двух векторов-входов
# Вернуть нужно одно число - собственно, ошибку. Обновлять ничего не нужно
<твой код - входы и преобразования>
compute_mse =<твой код - компиляция функции>
In [ ]:
#тесты
from sklearn.metrics import mean_squared_error
for n in [1,5,10,10**3]:
elems = [np.arange(n),np.arange(n,0,-1), np.zeros(n),
np.ones(n),np.random.random(n),np.random.randint(100,size=n)]
for el in elems:
for el_2 in elems:
true_mse = np.array(mean_squared_error(el,el_2))
my_mse = compute_mse(el,el_2)
if not np.allclose(true_mse,my_mse):
print ('Wrong result:')
print ('mse(%s,%s)'%(el,el_2))
print ("should be: %f, but your function returned %f"%(true_mse,my_mse))
raise ValueError("Что-то не так")
print ("All tests passed")
In [9]:
#cоздадим расшаренную перменную
shared_vector_1 = theano.shared(np.ones(10,dtype='float64'))
In [10]:
#получить (численное) значение переменной
print ("initial value",shared_vector_1.get_value())
In [11]:
#задать новое значение
shared_vector_1.set_value( np.arange(5) )
#проверим значение
print ("new value", shared_vector_1.get_value())
#Заметь, что раньше это был вектор из 10 элементов, а сейчас - из 5.
#Если граф при этом остался выполним, это сработает.
In [ ]:
#напиши рецепт (преобразование), которое считает произведение(поэллементное) shared_vector на input_scalar
#скомпилируй это в функцию от input_scalar
input_scalar = T.scalar('coefficient',dtype='float32')
scalar_times_shared = <рецепт тут>
shared_times_n = <твой код, который компилирует функцию>
In [ ]:
print ("shared:", shared_vector_1.get_value())
print ("shared_times_n(5)",shared_times_n(5))
print ("shared_times_n(-0.5)",shared_times_n(-0.5))
In [ ]:
#поменяем значение shared_vector_1
shared_vector_1.set_value([-1,0,1])
print ("shared:", shared_vector_1.get_value())
print ("shared_times_n(5)",shared_times_n(5))
print ("shared_times_n(-0.5)",shared_times_n(-0.5))
Ограничения
In [12]:
my_scalar = T.scalar(name='input',dtype='float64')
scalar_squared = T.sum(my_scalar**2)
#производная v_squared по my_vector
derivative = T.grad(scalar_squared,my_scalar)
fun = theano.function([my_scalar],scalar_squared)
grad = theano.function([my_scalar],derivative)
In [13]:
import matplotlib.pyplot as plt
%matplotlib inline
x = np.linspace(-3,3)
x_squared = list(map(fun,x))
x_squared_der = list(map(grad,x))
plt.plot(x, x_squared,label="x^2")
plt.plot(x, x_squared_der, label="derivative")
plt.legend()
Out[13]:
In [14]:
my_vector = T.vector('float64')
#посчитай производные этой функции по my_scalar и my_vector
#warning! Не пытайся понять физический смысл этой функции
weird_psychotic_function = ((my_vector+my_scalar)**(1+T.var(my_vector)) +1./T.arcsinh(my_scalar)).mean()/(my_scalar**2 +1) + 0.01*T.sin(2*my_scalar**1.5)*(T.sum(my_vector)* my_scalar**2)*T.exp((my_scalar-4)**2)/(1+T.exp((my_scalar-4)**2))*(1.-(T.exp(-(my_scalar-4)**2))/(1+T.exp(-(my_scalar-4)**2)))**2
der_by_scalar,der_by_vector = градиент функции сверху по скаляру и вектору (можно дать списком)
compute_weird_function = theano.function([my_scalar,my_vector],weird_psychotic_function)
compute_der_by_scalar = theano.function([my_scalar,my_vector],der_by_scalar)
In [15]:
#график функции и твоей производной
vector_0 = [1,2,3]
scalar_space = np.linspace(0,7)
y = [compute_weird_function(x,vector_0) for x in scalar_space]
plt.plot(scalar_space,y,label='function')
y_der_by_scalar = [compute_der_by_scalar(x,vector_0) for x in scalar_space]
plt.plot(scalar_space,y_der_by_scalar,label='derivative')
plt.grid();plt.legend()
Out[15]:
In [ ]:
#умножим shared вектор на число и сохраним новое значение обратно в этот shared вектор
inputs = [input_scalar]
outputs = [scalar_times_shared] #вернём вектор, умноженный на число
my_updates = {
shared_vector_1:scalar_times_shared #и этот же результат запишем в shared_vector_1
}
compute_and_save = theano.function(inputs, outputs, updates=my_updates)
In [ ]:
shared_vector_1.set_value(np.arange(5))
#изначальное значение shared_vector_1
print ("initial shared value:" ,shared_vector_1.get_value())
# теперь вычислим функцию (значение shared_vector_1 при этом поменяется)
print ("compute_and_save(2) returns",compute_and_save(2))
#проверим, что в shared_vector_1
print ("new shared value:" ,shared_vector_1.get_value())
In [ ]:
from sklearn.datasets import load_digits
mnist = load_digits(2)
X,y = mnist.data, mnist.target
print ("y [форма - %s]:"%(str(y.shape)),y[:10])
print ("X [форма - %s]:"%(str(X.shape)))
print (X[:3])
In [ ]:
# переменные и входы
shared_weights = <твой код>
input_X = <твой код>
input_y = <твой код>
In [ ]:
predicted_y = <предсказание логрегрессии на input_X (вероятность класса)>
loss = <логистическая ошибка (число - среднее по выборке)>
grad = <градиент loss по весам модели>
updates = {
shared_weights: <новое значение весов после шага градиентного спуска>
}
In [ ]:
train_function = <функция, которая по X и Y возвращает ошибку и обновляет веса>
predict_function = <функция, которая по X считает предсказание для y>
In [ ]:
from sklearn.cross_validation import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y)
In [ ]:
from sklearn.metrics import roc_auc_score
for i in range(5):
loss_i = train_function(X_train,y_train)
print ("loss at iter %i:%.4f"%(i,loss_i))
print ("train auc:",roc_auc_score(y_train,predict_function(X_train)))
print ("test auc:",roc_auc_score(y_test,predict_function(X_test)))
print ("resulting weights:")
plt.imshow(shared_weights.get_value().reshape(8,-1))
plt.colorbar()
In [17]:
from mnist import load_dataset
X_train,y_train,X_val,y_val,X_test,y_test = load_dataset()
print (X_train.shape,y_train.shape)
In [18]:
plt.imshow(X_train[0,0])
Out[18]:
In [19]:
import lasagne
input_X = T.tensor4("X")
#размерность входа (None означает "может изменяться")
input_shape = [None,1,28,28]
target_y = T.vector("target Y integer",dtype='int32')
Так задаётся архитектура нейронки
In [20]:
#входной слой (вспомогательный)
input_layer = lasagne.layers.InputLayer(shape = input_shape,input_var=input_X)
#полносвязный слой, который принимает на вход input layer и имеет 100 нейронов.
# нелинейная функция - сигмоида как в логистической регрессии
# слоям тоже можно давать имена, но это необязательно
dense_1 = lasagne.layers.DenseLayer(input_layer,num_units=50,
nonlinearity = lasagne.nonlinearities.sigmoid,
name = "hidden_dense_layer")
#ВЫХОДНОЙ полносвязный слой, который принимает на вход dense_1 и имеет 10 нейронов -по нейрону на цифру
#нелинейность - softmax - чтобы вероятности всех цифр давали в сумме 1
dense_output = lasagne.layers.DenseLayer(dense_1,num_units = 10,
nonlinearity = lasagne.nonlinearities.softmax,
name='output')
In [21]:
#предсказание нейронки (theano-преобразование)
y_predicted = lasagne.layers.get_output(dense_output)
In [25]:
#все веса нейронки (shared-переменные)
all_weights = lasagne.layers.get_all_params(dense_output)
print (all_weights)
In [ ]:
In [30]:
#функция ошибки - средняя кроссэнтропия
loss = lasagne.objectives.categorical_crossentropy(y_predicted,target_y).mean()
accuracy = lasagne.objectives.categorical_accuracy(y_predicted,target_y).mean()
#сразу посчитать словарь обновлённых значений с шагом по градиенту, как раньше
updates_sgd = lasagne.updates.rmsprop(loss, all_weights,learning_rate=0.01)
In [31]:
#функция, которая обучает сеть на 1 шаг и возвращащет значение функции потерь и точности
train_fun = theano.function([input_X,target_y],[loss,accuracy],updates= updates_sgd)
#функция, которая считает точность
accuracy_fun = theano.function([input_X,target_y],accuracy)
In [39]:
# вспомогательная функция, которая возвращает список мини-батчей для обучения нейронки
#на вход
# X - тензор из картинок размером (много, 1, 28, 28), например - X_train
# y - вектор из чиселок - ответов для каждой картинки из X; например - Y_train
#batch_size - одно число - желаемый размер группы
#что нужно сделать
# 1) перемешать данные
# - важно перемешать X и y одним и тем же образом, чтобы сохранить соответствие картинки ответу на неё
# 3) побить данные на подгруппы так, чтобы в каждой подгруппе было batch_size картинок и ответов
# - если число картинок не делится на batch_size, одну подгруппу можно вернуть другого размера
# 4) вернуть список (или итератор) пар:
# - (подгруппа картинок, ответы из y на эту подгруппу)
def iterate_minibatches(X, y, batchsize):
return X_minibatches, Y_minibatches # можно сделать списки, а ещё лучше - генератором через yield
#
#
#
#
#
#
#
# Всё плохо и ты не понимаешь, что от тебя хотят?
# можешь поискать похожую функцию в примере
# https://github.com/Lasagne/Lasagne/blob/master/examples/mnist.py
In [40]:
import time
num_epochs = 100 #количество проходов по данным
batch_size = 50 #размер мини-батча
for epoch in range(num_epochs):
# In each epoch, we do a full pass over the training data:
train_err = 0
train_acc = 0
train_batches = 0
start_time = time.time()
for batch in iterate_minibatches(X_train, y_train,batch_size):
inputs, targets = batch
train_err_batch, train_acc_batch= train_fun(inputs, targets)
train_err += train_err_batch
train_acc += train_acc_batch
train_batches += 1
# And a full pass over the validation data:
val_acc = 0
val_batches = 0
for batch in iterate_minibatches(X_val, y_val, batch_size):
inputs, targets = batch
val_acc += accuracy_fun(inputs, targets)
val_batches += 1
# Then we print the results for this epoch:
print("Epoch {} of {} took {:.3f}s".format(
epoch + 1, num_epochs, time.time() - start_time))
print(" training loss (in-iteration):\t\t{:.6f}".format(train_err / train_batches))
print(" train accuracy:\t\t{:.2f} %".format(
train_acc / train_batches * 100))
print(" validation accuracy:\t\t{:.2f} %".format(
val_acc / val_batches * 100))
In [41]:
test_acc = 0
test_batches = 0
for batch in iterate_minibatches(X_test, y_test, 500):
inputs, targets = batch
acc = accuracy_fun(inputs, targets)
test_acc += acc
test_batches += 1
print("Final results:")
print(" test accuracy:\t\t{:.2f} %".format(
test_acc / test_batches * 100))
if test_acc / test_batches * 100 > 99:
print ("Achievement unlocked: колдун 80 уровня")
else:
print ("Нужно больше магии!")
В конце есть мини-отчётик, который имеет смысл прочитать вначале и заполнять по ходу работы.
lasagne.layers.DropoutLayer(предыдущий_слой, p=вероятность_занулить)
Свёрточные слои
network = lasagne.layers.Conv2DLayer(предыдущий_слой,
num_filters = число нейронов,
filter_size = (ширина_квадрата, высота_квадрата),
nonlinearity = нелинейная_функция)
Любые другие слои и архитектуры
Для удобства, ниже есть заготовка решения, которое можно заполнять, а можно выкинуть и написать своё
In [ ]:
from mnist import load_dataset
X_train,y_train,X_val,y_val,X_test,y_test = load_dataset()
print (X_train.shape,y_train.shape)
In [ ]:
import lasagne
input_X = T.tensor4("X")
#размерность входа (None означает "может изменяться")
input_shape = [None,1,28,28]
target_y = T.vector("target Y integer",dtype='int32')
In [ ]:
#входной слой (вспомогательный)
input_layer = lasagne.layers.InputLayer(shape = input_shape,input_var=input_X)
<моя архитектура>
#ВЫХОДНОЙ полносвязный слой, который принимает на вход dense_1 и имеет 10 нейронов -по нейрону на цифру
#нелинейность - softmax - чтобы вероятности всех цифр давали в сумме 1
dense_output = lasagne.layers.DenseLayer(<предвыходной_слой>,num_units = 10,
nonlinearity = lasagne.nonlinearities.softmax,
name='output')
In [ ]:
#предсказание нейронки (theano-преобразование)
y_predicted = lasagne.layers.get_output(dense_output)
In [ ]:
#все веса нейронки (shared-переменные)
all_weights = lasagne.layers.get_all_params(dense_output)
print (all_weights)
In [ ]:
#функция ошибки - средняя кроссэнтропия
loss = lasagne.objectives.categorical_crossentropy(y_predicted,target_y).mean()
#<возможно добавить регуляризатор>
accuracy = lasagne.objectives.categorical_accuracy(y_predicted,target_y).mean()
#сразу посчитать словарь обновлённых значений с шагом по градиенту, как раньше
updates_sgd = <поиграться с методами>
In [ ]:
#функция, которая обучает сеть на 1 шаг и возвращащет значение функции потерь и точности
train_fun = theano.function([input_X,target_y],[loss,accuracy],updates= updates_sgd)
#функция, которая считает точность
accuracy_fun = theano.function([input_X,target_y],accuracy)
In [ ]:
#итерации обучения
num_epochs = сколько_эпох #количество проходов по данным
batch_size = сколько_картинок_в_минибатче #размер мини-батча
for epoch in range(num_epochs):
# In each epoch, we do a full pass over the training data:
train_err = 0
train_acc = 0
train_batches = 0
start_time = time.time()
for batch in iterate_minibatches(X_train, y_train,batch_size):
inputs, targets = batch
train_err_batch, train_acc_batch= train_fun(inputs, targets)
train_err += train_err_batch
train_acc += train_acc_batch
train_batches += 1
# And a full pass over the validation data:
val_acc = 0
val_batches = 0
for batch in iterate_minibatches(X_val, y_val, batch_size):
inputs, targets = batch
val_acc += accuracy_fun(inputs, targets)
val_batches += 1
# Then we print the results for this epoch:
print("Epoch {} of {} took {:.3f}s".format(
epoch + 1, num_epochs, time.time() - start_time))
print(" training loss (in-iteration):\t\t{:.6f}".format(train_err / train_batches))
print(" train accuracy:\t\t{:.2f} %".format(
train_acc / train_batches * 100))
print(" validation accuracy:\t\t{:.2f} %".format(
val_acc / val_batches * 100))
In [ ]:
test_acc = 0
test_batches = 0
for batch in iterate_minibatches(X_test, y_test, 500):
inputs, targets = batch
acc = accuracy_fun(inputs, targets)
test_acc += acc
test_batches += 1
print("Final results:")
print(" test accuracy:\t\t{:.2f} %".format(
test_acc / test_batches * 100))
Отчётик, примерный его вид.
Творческий подход приветствуется, но хотелось бы узнать про следующие вещи:
Строгих математических выводов от вас никто не ждёт, вариант
___ ___
, и вот моя историяКогда-то давно, когда трава была зеленее, а до дедлайна ещё оставалось больше часа, мне в голову пришла идея:
Так мне казалось.
Эта злыдня, наконец, доучилась, как вдруг
Которая, после стольких мук, __ [минут, часов или дней - по вкусу] обучения дала-таки точность
[опциональное послесловие и пожелания автору задания сдохнуть в страшных муках]
In [ ]: