#python #machine-learning #pytorch
#python #машинное обучение #pytorch
Вопрос:
Я хотел бы подогнать сеть прямой связи pytorch к созданному набору данных с зависимостью между метками y и двумя объектами из набора данных.
Набор данных генерируется с использованием np.random.random_sample
для распределения между 0 и 1, а метка вычисляется с использованием двух приведенных ниже функций:
sum_bin_label
sum_mod_label
В первой функции я вижу, что потери как при обучении, так и при проверке нейронной сети уменьшаются, и в конечном итоге она способна аппроксимировать функцию с точностью, близкой к 100%, что ожидается, но для второй функции, которая используется sum
, и modulo(num_classes)
она не может добиться какого-либо прогресса. Я пробовал несколько скоростей обучения и сетевых архитектур, но мне не удалось их совместить.
Мне интересно посмотреть, как можно установить эту функцию.
Ниже приведен простой пример, который можно вставить непосредственно в записную книжку jupyter или любой другой python repl, если на то пошло.
Заранее спасибо!
Импорт
import torch
import numpy as np
from sklearn.model_selection import train_test_split
import torch.utils.data as utils
DATASHAPE = (2000, 2)
NUM_CLASSES = 3
Используемые функции и классы
def sum_mod_label(x):
return np.array([x for x in map(
lambda x: x % NUM_CLASSES, map(int, (x[:, 0] x[:, 1]) * 100))])
def sum_bin_label(x):
def binit(x):
if x < 0.807:
return 0
if x < 1.169:
return 1
return 2
return np.array(
[x for x in map(lambda x: binit(x), x[:, 0] x[:, 1])])
class RandomModuloDataset(utils.Dataset):
def __init__(self, shape, label_fn):
self.data = np.random.random_sample(shape)
self.label = label_fn(self.data)
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
return self.data[idx, :], self.label[idx]
class FeedForward(torch.nn.Module):
def __init__(self, input_size, num_classes):
super().__init__()
self.input_size = input_size
self.num_classes = num_classes
self.relu = torch.nn.ReLU()
self.softmax = torch.nn.Softmax(dim=-1)
self.fc1 = torch.nn.Linear(
self.input_size, self.input_size)
self.fc2 = torch.nn.Linear(
self.input_size, self.num_classes)
def forward(self, x, **kwargs):
output = self.fc2(self.relu(self.fc1(x.float())))
return self.softmax(output)
def fitit(trainloader, epochs=10):
neurons = DATASHAPE[1]
net = FeedForward(neurons, NUM_CLASSES)
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for epoch in range(epochs):
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
print('[%d] loss: %.3f' %
(epoch 1, loss.item()))
Итерация с первой функцией (в конечном итоге сходится)
sum_bin_tloader = utils.DataLoader(
RandomModuloDataset(DATASHAPE, sum_bin_label))
fitit(sum_bin_tloader, epochs=50)
[1] loss: 1.111
[2] loss: 1.133
[3] loss: 1.212
[4] loss: 1.264
[5] loss: 1.261
[6] loss: 1.199
[7] loss: 1.094
[8] loss: 1.011
[9] loss: 0.958
[10] loss: 0.922
[11] loss: 0.896
[12] loss: 0.876
[13] loss: 0.858
[14] loss: 0.844
[15] loss: 0.831
[16] loss: 0.820
[17] loss: 0.811
[18] loss: 0.803
[19] loss: 0.795
[20] loss: 0.788
[21] loss: 0.782
[22] loss: 0.776
[23] loss: 0.771
[24] loss: 0.766
[25] loss: 0.761
[26] loss: 0.757
[27] loss: 0.753
[28] loss: 0.749
[29] loss: 0.745
[30] loss: 0.741
[31] loss: 0.738
[32] loss: 0.734
[33] loss: 0.731
[34] loss: 0.728
[35] loss: 0.725
[36] loss: 0.722
[37] loss: 0.719
[38] loss: 0.717
[39] loss: 0.714
[40] loss: 0.712
[41] loss: 0.709
[42] loss: 0.707
[43] loss: 0.705
[44] loss: 0.703
[45] loss: 0.701
[46] loss: 0.699
[47] loss: 0.697
[48] loss: 0.695
[49] loss: 0.693
[50] loss: 0.691
Итерация со второй функцией (не сходится)
sum_mod_tloader = utils.DataLoader(
RandomModuloDataset(DATASHAPE, sum_mod_label))
fitit(sum_mod_tloader, epochs=50)
[1] loss: 1.059
[2] loss: 1.065
[3] loss: 1.079
[4] loss: 1.087
[5] loss: 1.091
[6] loss: 1.092
[7] loss: 1.092
[8] loss: 1.092
[9] loss: 1.092
[10] loss: 1.091
[11] loss: 1.091
[12] loss: 1.091
[13] loss: 1.091
[14] loss: 1.091
[15] loss: 1.090
[16] loss: 1.090
[17] loss: 1.090
[18] loss: 1.090
[19] loss: 1.090
[20] loss: 1.090
[21] loss: 1.090
[22] loss: 1.089
[23] loss: 1.089
[24] loss: 1.089
[25] loss: 1.089
[26] loss: 1.089
[27] loss: 1.089
[28] loss: 1.089
[29] loss: 1.089
[30] loss: 1.089
[31] loss: 1.089
[32] loss: 1.089
[33] loss: 1.089
[34] loss: 1.089
[35] loss: 1.089
[36] loss: 1.089
[37] loss: 1.089
[38] loss: 1.089
[39] loss: 1.089
[40] loss: 1.089
[41] loss: 1.089
[42] loss: 1.089
[43] loss: 1.089
[44] loss: 1.089
[45] loss: 1.089
[46] loss: 1.089
[47] loss: 1.089
[48] loss: 1.089
[49] loss: 1.089
[50] loss: 1.089
Я ожидаю, что смогу совместить обе функции, поскольку NN должен иметь возможность находить любую функцию y = f (x), описывающую зависимую переменную, но обучение не продвигается для sum_mod_label .
Используя catboost, я смог получить разумную точность (~ 75% для sum_mod_label)
Ответ №1:
Просто попробуйте отобразить свои данные, и вы увидите, что функции создают наборы данных разной сложности. Во втором случае классы почти неразделимы, поэтому вам нужно увеличить сложность вашей модели.
Как увеличить сложность вашей модели:
- Больше слоев
- Больше скрытых единиц
- Настройка размера пакета
- Настройте lr, попробуйте использовать lr-scheduler
- Попробуйте другой оптимизатор, например, Adam
- Чтобы избежать переобучения в очень глубоких сетях, добавьте слои отсева
- Взгляните на очень многообещающие самонормализующиеся нейронные сети
Код:
import numpy as np
import matplotlib.pyplot as p
DATASHAPE = (2000, 2)
NUM_CLASSES = 3
def sum_mod_label(x):
return np.array([x for x in map(lambda x: x % NUM_CLASSES, map(int, (x[:, 0] x[:, 1]) * 100))])
def sum_bin_label(x):
def binit(x):
if x < 0.807:
return 0
if x < 1.169:
return 1
return 2
return np.array([x for x in map(lambda x: binit(x), x[:, 0] x[:, 1])])
data = np.random.random_sample(DATASHAPE)
bin_label = sum_bin_label(data)
mod_label = sum_mod_label(data)
def plot_data(data, label, title):
plt.figure(figsize=(9, 9))
plt.title(title)
plt.scatter(data[..., 0], data[..., 1], c=label)
plt.show()
plot_data(data, bin_label, 'sum_bin_label')
plot_data(data, mod_label, 'sum_mod_label')
Вывод:
Комментарии:
1. @tsavcyn, согласно теореме об универсальности, существует нейронная сеть, которая может аппроксимировать каждую отдельную функцию. Более подробную информацию можно найти в следующем тексте: neuralnetworksanddeeplearning.com/chap4.html Тем не менее, графики очень интересны, но я не верю, что они доказывают, что NN не может аппроксимировать функцию. Вероятно, если вы попробуете методы кластеризации, они потерпят неудачу во втором примере. Мне интересно, что скажут эксперты по этому вопросу. Спасибо
2. да, вы правы, согласно теории, вам просто нужен один скрытый слой. Но «… на практике для более быстрого и эффективного решения проблемы следует использовать более одного скрытого слоя …» и «.. сеть с двумя скрытыми слоями и гораздо меньшим количеством узлов в целом должна быть способна решать ту же проблему более эффективно».. В вашем случае у вас есть только 2 слоя с 2 скрытыми единицами, чего недостаточно для точного приближения ко 2-й задаче. Подробнее: pdfs.semanticscholar.org/20df /…
3. И я не говорю, что NN не может ее аппроксимировать. График просто показывает, что вам нужна более сложная модель. Больше слоев, скрытых единиц, поскольку классы не являются линейно разделяемыми
4. Итак, ответьте на ваш вопрос «Как сопоставить математическую формулу с нейронной сетью?» будет — Увеличьте сложность вашей модели 🙂
5. Спасибо за pdf 🙂 Я пробовал использовать до 10 скрытых слоев и 20 нейронов, но все еще не смог сойтись, теперь эта сеть тоже не может соответствовать более простой функции. Есть ли у вас какие-либо предложения по глубине / количеству нейронов и скорости обучения (есть ли что-нибудь еще для настройки?) Обновит вопрос.