Проблемът

OpenAI наскоро публикува някои отворени изследователски въпроси. Като начинаещ в AI реших да се справя с „Warmups“ за начинаещи, които те предлагат. Можете да видите техния блог пост тук: https://blog.openai.com/requests-for-research-2/:

Обучете LSTM за решаване на проблема с XOR: тоест, дадена последователност от битове, определете нейния паритет. LSTM трябва да използва последователността, един бит наведнъж, и след това да изведе правилния отговор в края на последователността. Тествайте двата подхода по-долу:

  • Генерирайте набор от данни от произволни 100 000 двоични низа с дължина 50. Обучете LSTM; какво представяне получаваш?
  • Генерирайте набор от данни от произволни 100 000 двоични низа, където дължината на всеки низ е независимо и произволно избрана между 1 и 50. Обучете LSTM. Успява ли? Какво обяснява разликата?

Функцията XOR

| Вход | Вход 2 | Изход |
| — — — — — — — |: — — — — — — -:| — — -:|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |

Проблем 1: 100 000 двоични низа с дължина 50

Кодът за решаване на този проблем е благодарение на [christopher5106](https://github.com/christopher5106/grid-1D-LSTM-theano/blob/master/main.py)

Настройвам

python
‘’’
Trains a 1D Grid LSTM network to learn XOR answers.
‘’’
from __future__ import print_function
import numpy as np
import theano
import theano.tensor as T
import lasagne
#Lasagne Seed for Reproducibility
lasagne.random.set_rng(np.random.RandomState(1))
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(‘ — iterations’, type=int, default=100000, help=’Number of iterations’)
parser.add_argument(‘ — bits’, type=int, default=50, help=’Number of bits in the input strings’)
parser.add_argument(‘ — hidden’, type=int, default=2, help=’Number of units in the two hidden (LSTM) layers’)
parser.add_argument(‘ — learning_rate’, type=float, default=0.5, help=’Optimization learning rate’)
#parser.add_argument(‘ — grad_clip’, type=int, default=100, help=’All gradients above this will be clipped’)
parser.add_argument(‘ — print_freq’, type=int, default=500, help=’How often should we check the output?’)
parser.add_argument(‘ — batch_size’, type=int, default=1, help=’Batch size’)
parser.add_argument(‘ — layers’, type=int, default=2, help=’Number of layers’)
args = parser.parse_args()
print(“Parameters:”)
print(args)
args.print_batch_freq = args.print_freq / args.batch_size + 1

Генератор на произволни низове

python
def gen_data(bits=args.bits, batch_size = args.batch_size):
 x = np.random.randint(2, size=(batch_size,bits))
 y = x.sum(axis=1) % 2
 return x, y
```
# Network
```python
print(“Building network …”)
l_in = lasagne.layers.InputLayer(shape=(None,1))
l_in_zero = lasagne.layers.InputLayer(shape=(None, args.layers, 1))
l_lin = lasagne.layers.DenseLayer(l_in, num_units = args.hidden, nonlinearity = None)
l_forward = lasagne.layers.LSTMLayer(
 l_in_zero, args.hidden,
 nonlinearity=lasagne.nonlinearities.tanh, hid_init = l_lin, only_return_final=True)
l_lin_out = lasagne.layers.DenseLayer(l_forward, num_units = 2, nonlinearity = None)
l_out = lasagne.layers.DenseLayer(l_lin_out, num_units=2, nonlinearity=lasagne.nonlinearities.softmax)
target_values = T.ivector(‘target_output’)
network_output = lasagne.layers.get_output(l_out)
cost = T.nnet.categorical_crossentropy(network_output,target_values).mean()
accuracy = lasagne.objectives.categorical_accuracy(network_output,target_values).mean()
all_params = lasagne.layers.get_all_params(l_out,trainable=True)
all_params2 = lasagne.layers.get_all_params(l_out,trainable=False)

Теано функции

python
print(“Computing updates …”)
updates = lasagne.updates.adadelta(cost, all_params, args.learning_rate)
updates2 = lasagne.updates.adagrad(cost, all_params2, args.learning_rate)
print(“Compiling functions …”)
train = theano.function([l_in.input_var, l_in_zero.input_var, target_values], cost, updates=updates, allow_input_downcast=True)
train2 = theano.function([l_in.input_var, l_in_zero.input_var, target_values], cost, updates=updates2, allow_input_downcast=True)
compute_cost = theano.function([l_in.input_var, l_in_zero.input_var, target_values], cost, allow_input_downcast=True)
compute_accuracy = theano.function([l_in.input_var, l_in_zero.input_var, target_values],
 accuracy, allow_input_downcast=True)
probs = theano.function([l_in.input_var, l_in_zero.input_var],network_output,allow_input_downcast=True)

обучение

python
print(“Training …”)
print(“The average loss and accuracy will be printed every {} iterations”.format(args.print_batch_freq*args.batch_size))
num_batch_print_iter = args.iterations / args.batch_size / args.print_batch_freq + 1
act_num_batches = int(num_batch_print_iter * args.print_batch_freq)
all_cost = np.zeros((act_num_batches))
all_accuracy = np.zeros((act_num_batches))
for it_out in range(int(num_batch_print_iter)):
 for it_in in range(int(args.print_batch_freq)):
 x,y = gen_data()
 stoplen = (len(x[0])-1)
 for i in range(0,stoplen):
 x_zero = np.zeros((args.batch_size,args.layers,1),dtype=’int32')
 batch_cost = train2(np.reshape(x[0][i], newshape=(1,1)), x_zero, y)
 x_zero = np.zeros((args.batch_size, args.layers, 1), dtype=’int32')
 batch_iter = int(it_out * args.print_batch_freq + it_in + 1)
 batch_cost = train(np.reshape(x[0][len(x[0])-1], newshape=(1,1)), x_zero, y)
 batch_accuracy = compute_accuracy(np.reshape(x[0][len(x[0])-1], newshape=(1,1)), x_zero, y)
all_cost[batch_iter — 1] = batch_cost
 all_accuracy[batch_iter — 1] = batch_accuracy
 start_index = int(it_out * args.print_batch_freq)
 end_index = int((it_out + 1) * args.print_batch_freq)
 av_cost = all_cost[start_index:end_index].mean()
 av_accuracy = all_accuracy[start_index:end_index].mean()
 np.savetxt(‘cost.txt’, all_cost[:end_index], delimiter=’,’) #average in batch
 np.savetxt(‘accuracy.txt’, all_accuracy[:end_index], delimiter=’,’)
print(“Iteration {} average loss = {} average accuracy = {}”.format(batch_iter*args.batch_size,
av_cost,av_accuracy))

Проблем 2: 100 000 двоични низа с произволна дължина 1:50

Кодови разлики

```python
parser.add_argument(‘ — hidden’, type=int, default=100, help=’Number of units in the two hidden (LSTM) layers’)
parser.add_argument(‘ — layers’, type=int, default=2, help=’Number of layers’)
args = parser.parse_args()
```
```python
def gen_data(bits=args.bits, batch_size = args.batch_size):
 bitsran = np.random.randint(1, bits)
 x = np.random.randint(2, size=(batch_size,bitsran))
 y = x.sum(axis=1) % 2
 return x, y
```

Заключение