Кодування даних кутових даних для нейронної мережі


20

Я треную нейронну мережу (деталі не важливі), де цільові дані - вектор кутів (між 0 і 2 * пі). Я шукаю поради щодо кодування цих даних. Ось що я зараз намагаюся (з обмеженим успіхом):

1) Кодування 1-С: Я розбиваю задані можливі кути на 1000 або близько дискретних кутів, а потім вказую конкретний кут, ставлячи 1 на відповідний показник. Проблема в цьому полягає в тому, що мережа просто вчиться виводити всі 0 (оскільки це майже точно).

2) Просте масштабування: я масштабував діапазон виходу мереж ([0,1]) до [0,2 * пі]. Проблема тут полягає в тому, що кути, природно, мають кругову топологію (тобто 0,0001 і 2 * pi є насправді прямо один біля одного). При такому типі кодування ця інформація втрачається.

Будь-які пропозиції будуть вдячні!


1
У вас не повинно виникнути проблем з мережевим виведенням усіх нулів, якщо ви використовуєте вихідний шар softmax - що, як правило, слід робити, якщо ви використовуєте катагоричний (тобто 1-з-С) вихід.
Ліндон Уайт

7
Суто спекулятивна ідея кодування (я не бачив, щоб це було зроблено чи протестовано, але я не дивився) - це кодувати ваш кут ( ) у вигляді пари: . Я думаю, тоді це була б неперервна карта з усіма значеннями, такими як , і близькі один до одного. Я думаю, що я можу створити демонстрацію цього і перевірити його. θθ(гріх(θ),cos(θ))02π
Ліндон Уайт

я ще раз про це думав, і я думаю, що це насправді може бути все у вашій функції втрат. Я хочу спробувати купу речей. Я зробив демонстрацію, але не закінчив тести на ній. Очікуйте детальної відповіді з експериментальною підтримкою завтра колись. (Тикай мені, якщо я цього не роблю)
Ліндон Уайт

Наразі я не використовую шар softmax, і це, мабуть, проблема. Я реалізую це сьогодні, якщо отримаю шанс! Ваша ідея (cos, sin) дуже цікава, і мені особливо подобається, що вона автоматично ставить цей діапазон у [-1,1] (добре, якщо ви працюєте з функцією активації tanh). Я з нетерпінням чекаю Ваших результатів1
Арі Герман

Швидке оновлення: я спробував реалізувати шар softmax, і мені все ще не пощастило. Думаю, питання полягає в тому, що для цієї проблеми важливо, щоб "кутовість" даних була якось представлена ​​в кодуванні. При категоричному кодуванні топологія цільових даних втрачається. Отже, помилка 0,5 * пі та 0,05 * пі виглядає однаково в мережі (вона бачить як неправильну категоризацію).
Арі Герман

Відповіді:


18

Вступ

Я вважаю це питання дійсно цікавим, я припускаю, що хтось виклав на ньому документ, але це мій вихідний день, тому я не хочу переслідувати посилання.

Таким чином, ми могли б розглядати це як подання / кодування результатів, що я роблю в цій відповіді. Я все ще думаю, що є кращий спосіб, де можна просто використовувати дещо іншу функцію втрат. (Можливо, сума квадратичних різниць із використанням модуля віднімання 2 ).π

Але далі з фактичною відповіддю.

Метод

Я пропоную представити кут як пару значень, його синус та косинус.θ

Отже функцією кодування є: а функцією декодування є: Для arctan2 є зворотними дотичними, зберігаючи напрямок у всіх квадрантах)θ(гріх(θ),cos(θ))
(у1,у2)арктан2(у1,у2)

Теоретично ви могли б еквівалентно працювати безпосередньо з кутами, якщо ваш інструмент використовує підтримку atan2як функцію шару (беручи рівно 2 входи та виробляючи 1 вихід). TensorFlow робить це зараз і підтримує градієнтний спуск по ньому , хоча і не призначений для цього використання. Я досліджував за out = atan2(sigmoid(ylogit), sigmoid(xlogit)) допомогою функції втрат min((pred - out)^2, (pred - out - 2pi)^2). Я виявив, що це тренувалося набагато гірше, ніж використання outs = tanh(ylogit), outc = tanh(xlogit)) з функцією втрат 0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2. Я думаю, що це можна віднести до того, що градієнт припиняєтьсяatan2

Моє тестування тут працює як функція попередньої обробки

Для цього я визначив завдання:

Дано чорно-біле зображення, що представляє одну лінію на порожньому тлі. Виведіть, під яким кутом знаходиться ця лінія до «позитивної осі x»

Я реалізував функцію випадковим чином генерувати ці зображення із лініями під випадковими кутами (Примітка: в попередніх версіях цієї публікації використовувались випадкові нахили, а не випадкові кути. Завдяки @Ari Herman за її вказівку. Це тепер виправлено). Я побудував кілька нейронних мереж, щоб оцінити ефективність цього завдання. Повна інформація про реалізацію міститься в цьому ноутбуці Юпітера . Цей код у Julia , і я використовую бібліотеку нейронних мереж Mocha .

Для порівняння, я подаю це проти альтернативних методів масштабування до 0,1. і складати в 500 бункерів і використовувати softmax з м'якою міткою. Я не особливо задоволений останнім, і відчуваю, що мені потрібно підправити це. Ось чому, на відміну від інших, я пробую лише 1000 ітерацій, проти двох інших, які були виконані на 1000 і на 10 000

Експериментальне встановлення

Зображення становили піксель, лінія починається в центрі і йде до краю. На зображенні не було шуму тощо, лише "чорна" лінія на білому тлі.101×101

Для кожного треку було створено 1000 тренувань та 1000 тестових зображень випадковим чином.

Мережа оцінювання мала єдиний прихований шар шириною 500. У прихованому шарі використовувались сигмоїдні нейрони.

Його готували за стохастичним градієнтним порядком, із фіксованою швидкістю навчання 0,01 та фіксованим імпульсом 0,9.

Ні регуляризація, ні випадання не використовувались. Не було ніякої згортки тощо. Проста мережа, яка, сподіваюсь, дозволяє припустити, що ці результати узагальниться

Налаштувати ці параметри в тестовому коді дуже просто , і я закликаю людей до цього. (і шукайте помилок у тесті).

Результати

Мої результати такі:

|                        |  500 bins    |  scaled to 0-1 |  Sin/Cos     |  scaled to 0-1 |  Sin/Cos     |
|                        | 1,000 Iter   | 1,000 Iter     | 1,000 iter   | 10,000 Iter    | 10,000 iter  |
|------------------------|--------------|----------------|--------------|----------------|--------------|
| mean_error             | 0.4711263342 | 0.2225284486   | 2.099914718  | 0.1085846429   | 2.1036656318 |
| std(errors)            | 1.1881991421 | 0.4878383767   | 1.485967909  | 0.2807570442   | 1.4891605068 |
| minimum(errors)        | 1.83E-006    | 1.82E-005      | 9.66E-007    | 1.92E-006      | 5.82E-006    |
| median(errors)         | 0.0512168533 | 0.1291033982   | 1.8440767072 | 0.0562908143   | 1.8491085947 |
| maximum(errors)        | 6.0749693965 | 4.9283551248   | 6.2593307366 | 3.735884823    | 6.2704853962 |
| accurancy              | 0.00%        | 0.00%          | 0.00%        | 0.00%          | 0.00%        |
| accurancy_to_point001  | 2.10%        | 0.30%          | 3.70%        | 0.80%          | 12.80%       |
| accurancy_to_point01   | 21.90%       | 4.20%          | 37.10%       | 8.20%          | 74.60%       |
| accurancy_to_point1    | 59.60%       | 35.90%         | 98.90%       | 72.50%         | 99.90%       |

Де я посилаюсь на помилку, це абсолютне значення різниці між кутом виходу нейронної мережі та справжнім кутом. Отже, середня помилка (наприклад) - це середня величина за 1000 тестових випадків такої різниці тощо. Я не впевнений, що мені не слід її змінити, зробивши помилку, скажімо, бути рівним до помилки ).7π4π4

Я також представляю точність на різних рівнях деталізації. Точність, що є частиною тестових випадків, яку вона отримала. Значить accuracy_to_point01, це вважалося правильним, якщо вихід був у межах 0,01 від істинного кута. Жодне з представлень не дало ідеальних результатів, але це зовсім не дивно, враховуючи, як працює математика з плаваючою комою.

Якщо ви подивитесь на історію цього допису, ви побачите, що результати мають трохи шуму до них, трохи відрізняючись кожного разу, коли я його повторюю. Але загальний порядок і масштаб значень залишаються однаковими; тим самим дозволяючи зробити деякі висновки.

Обговорення

Спілка з softmax є найгіршою, тому що я сказав, що не впевнений, що я щось не накрутив у виконанні. Хоча це і працює незначно вище показника здогаду. якби тільки здогадувалися, ми отримаємо середню помилкуπ

Кодування sin / cos працює значно краще, ніж масштабування 0-1. Поліпшення полягає в тій мірі, коли на 1000 тренувань тренувань sin / cos виконує приблизно в 3 рази краще на більшості метрик, ніж масштабування становить 10 000 ітерацій.

Я думаю, частково це пов’язано з вдосконаленням узагальнення, оскільки обидва отримували досить схожу середню квадратичну помилку на тренувальному наборі, принаймні один раз виконувались 10 000 ітерацій.

Звичайно, існує верхня межа щодо найкращого виконання цього завдання, враховуючи, що кут може бути більш-менш будь-яким реальним числом, але не всі такі ангели створюють різні лінії з роздільною здатністю пікселів. Так як, наприклад, кути 45.0 і 45.0000001 обидва прив’язані до одного зображення при цій роздільній здатності, жоден метод ніколи не отримає обидва цілком правильні.101×101

Також здається ймовірним, що в абсолютних масштабах, щоб вийти за рамки цієї продуктивності, потрібна краща нейронна мережа. Замість простого, описаного вище в експериментальних установках.

Висновок.

Здається, що представлення гріх / союз є найкращим з представлень, які я тут досліджував. Це має сенс, оскільки воно має плавне значення під час переміщення по колу. Мені також подобається, що обернення можна зробити за допомогою arctan2 , який є елегантним.

Я вважаю, що поставлене завдання є достатнім для його здатності представляти розумну проблему для мережі. Хоча я гадаю, що насправді це просто навчитися робити криву, що підходить до тому, можливо, це занадто просто. І, можливо, гірше, що це може сприяти парному представництву. Я не думаю, що це так, але тут вже запізно, тому я, можливо, щось пропустив, я запрошую вас ще раз переглянути мій код . Запропонуйте вдосконалення чи альтернативні завдання.f(х)=у1у2х


Це, безумовно, найбільш ретельна відповідь, яку я коли-небудь отримував при обміні стеками. Оскільки я не знайомий з Джулією, мені важко вивчити ваш код ... тому я замість цього намагаюся повторити ваші результати за допомогою Python. Я опублікую висновки пізніше сьогодні або завтра.
Арі Герман

Хоча я не був здивований тим, що бінінг пройшов погано, я був здивований тим, наскільки (0,1) масштабування перевершило метод (cos, sin) методом. Я помітив, що ви генерували ваші приклади, випадковим чином вибираючи підйом і пробіг рядків. Це, на мій погляд, породжувало б лінії, кути яких не рівномірно розподілені, але нахили яких є. Чи можливо, саме тому метод (cos, sin) виконується настільки краще? Що буде, якби ви зробили цілі засмаги (кут) ...?
Арі Герман

tan(angle)π/4

Між Джулією та Нумію та між Моккою та Кафе має бути близько одна до однієї карти, якщо ви дійсно хочете її повторно реалізувати. Чи є певна частина коду, яку вам важко прочитати? Юлія повинна бути легкою для розуміння мовою. Тож, можливо, я зробив щось дивне.
Ліндон Уайт

Я прочитав ваш код, і все здається правильним. Все-таки я хотів написати свою власну версію, оскільки це, як правило, повчально. Моя реалізація трохи відрізняється від вашої, тому буде цікаво порівняти результати. Я буду публікувати їх протягом наступних двох годин.
Арі Герман

5

Ось ще одна реалізація Python, яка порівнює запропоноване Lyndon White кодування з розробленим підходом. Код нижче дав такий вихід:

Training Size: 100
Training Epochs: 100
Encoding: cos_sin
Test Error: 0.017772154610047136
Encoding: binned
Test Error: 0.043398792553251526

Training Size: 100
Training Epochs: 500
Encoding: cos_sin
Test Error: 0.015376604917819397
Encoding: binned
Test Error: 0.032942592915322394

Training Size: 1000
Training Epochs: 100
Encoding: cos_sin
Test Error: 0.007544091937411164
Encoding: binned
Test Error: 0.012796594492198667

Training Size: 1000
Training Epochs: 500
Encoding: cos_sin
Test Error: 0.0038051515079569097
Encoding: binned
Test Error: 0.006180633805557207

(гріх(θ),cos(θ))(гріх(θ),cos(θ))

import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.utils.data

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")


class Net(nn.Module):
    def __init__(self, input_size, hidden_size, num_out):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.sigmoid = nn.Sigmoid()
        self.fc2 = nn.Linear(hidden_size, num_out)

    def forward(self, x):
        out = self.fc1(x)
        out = self.sigmoid(out)
        out = self.fc2(out)
        return out


def gen_train_image(angle, side, thickness):
    image = np.zeros((side, side))
    (x_0, y_0) = (side / 2, side / 2)
    (c, s) = (np.cos(angle), np.sin(angle))
    for y in range(side):
        for x in range(side):
            if (abs((x - x_0) * c + (y - y_0) * s) < thickness / 2) and (
                    -(x - x_0) * s + (y - y_0) * c > 0):
                image[x, y] = 1

    return image.flatten()


def gen_data(num_samples, side, num_bins, thickness):
    angles = 2 * np.pi * np.random.uniform(size=num_samples)
    X = [gen_train_image(angle, side, thickness) for angle in angles]
    X = np.stack(X)

    y = {"cos_sin": [], "binned": []}
    bin_size = 2 * np.pi / num_bins
    for angle in angles:
        idx = int(angle / bin_size)
        y["binned"].append(idx)
        y["cos_sin"].append(np.array([np.cos(angle), np.sin(angle)]))

    for enc in y:
        y[enc] = np.stack(y[enc])

    return (X, y, angles)


def get_model_stuff(train_y, input_size, hidden_size, output_sizes,
                    learning_rate, momentum):
    nets = {}
    optimizers = {}

    for enc in train_y:
        net = Net(input_size, hidden_size, output_sizes[enc])
        nets[enc] = net.to(device)
        optimizers[enc] = torch.optim.SGD(net.parameters(), lr=learning_rate,
                                          momentum=momentum)

    criterions = {"binned": nn.CrossEntropyLoss(), "cos_sin": nn.MSELoss()}
    return (nets, optimizers, criterions)


def get_train_loaders(train_X, train_y, batch_size):
    train_X_tensor = torch.Tensor(train_X)

    train_loaders = {}

    for enc in train_y:
        if enc == "binned":
            train_y_tensor = torch.tensor(train_y[enc], dtype=torch.long)
        else:
            train_y_tensor = torch.tensor(train_y[enc], dtype=torch.float)

        dataset = torch.utils.data.TensorDataset(train_X_tensor, train_y_tensor)
        train_loader = torch.utils.data.DataLoader(dataset=dataset,
                                                   batch_size=batch_size,
                                                   shuffle=True)
        train_loaders[enc] = train_loader

    return train_loaders


def show_image(image, side):
    img = plt.imshow(np.reshape(image, (side, side)), interpolation="nearest",
                     cmap="Greys")
    plt.show()


def main():
    side = 101
    input_size = side ** 2
    thickness = 5.0
    hidden_size = 500
    learning_rate = 0.01
    momentum = 0.9
    num_bins = 500
    bin_size = 2 * np.pi / num_bins
    half_bin_size = bin_size / 2
    batch_size = 50
    output_sizes = {"binned": num_bins, "cos_sin": 2}
    num_test = 1000

    (test_X, test_y, test_angles) = gen_data(num_test, side, num_bins,
                                             thickness)

    for num_train in [100, 1000]:

        (train_X, train_y, train_angles) = gen_data(num_train, side, num_bins,
                                                    thickness)
        train_loaders = get_train_loaders(train_X, train_y, batch_size)

        for epochs in [100, 500]:

            (nets, optimizers, criterions) = get_model_stuff(train_y, input_size,
                                                             hidden_size, output_sizes,
                                                             learning_rate, momentum)

            for enc in train_y:
                optimizer = optimizers[enc]
                net = nets[enc]
                criterion = criterions[enc]

                for epoch in range(epochs):
                    for (i, (images, ys)) in enumerate(train_loaders[enc]):
                        optimizer.zero_grad()

                        outputs = net(images.to(device))
                        loss = criterion(outputs, ys.to(device))
                        loss.backward()
                        optimizer.step()


            print("Training Size: {0}".format(num_train))
            print("Training Epochs: {0}".format(epochs))
            for enc in train_y:
                net = nets[enc]
                preds = net(torch.tensor(test_X, dtype=torch.float).to(device))
                if enc == "binned":
                    pred_bins = np.array(preds.argmax(dim=1).detach().cpu().numpy(),
                                         dtype=np.float)
                    pred_angles = bin_size * pred_bins + half_bin_size
                else:
                    pred_angles = torch.atan2(preds[:, 1], preds[:, 0]).detach().cpu().numpy()
                    pred_angles[pred_angles < 0] = pred_angles[pred_angles < 0] + 2 * np.pi

                print("Encoding: {0}".format(enc))
                print("Test Error: {0}".format(np.abs(pred_angles - test_angles).mean()))

            print()


if __name__ == "__main__":
    main()

3

Ось моя версія Python вашого експерименту. Я зберігав багато деталей вашої реалізації однаковими, зокрема я використовую однаковий розмір зображення, розміри мережевого шару, показники швидкості навчання, імпульсу та успішності.

Кожна перевірена мережа має один прихований шар (розмір = 500) з логістичними нейронами. Вихідні нейрони є лінійними або софтмакс, як зазначалося. Я використовував 1000 навчальних зображень та 1000 тестових зображень, які були незалежно, генеровані випадковим чином (тому можуть бути повтори). Тренінг складався з 50 ітерацій через навчальний набір.

Мені вдалося отримати досить гарну точність за допомогою бінінгу та "гауссового" кодування (ім'я, яке я склав; подібне до бінінгу, за винятком того, що цільовий вихідний вектор має вигляд exp (-pi * ([1,2,3, ... , 500] - idx) ** 2) де idx - індекс, відповідний правильному куту). Код внизу; ось мої результати:

Помилка тесту кодування (cos, sin):

1000 навчальних зображень, 1000 тестових зображень, 50 ітерацій, лінійний вихід

  • Середнє значення: 0,0911558142071

  • Медіана: 0,0429723541743

  • Мінімум: 2.77769843793e-06

  • Максимум: 6.2608513539

  • Точність до 0,1: 85,2%

  • Точність до 0,01: 11,6%

  • Точність до 0,001: 1,0%

Помилка тесту кодування [-1,1]:

1000 навчальних зображень, 1000 тестових зображень, 50 ітерацій, лінійний вихід

  • Середнє значення: 0,234181700523

  • Медіана: 0,17460197307

  • Мінімум: 0.000473665840258

  • Максимум: 6.00637777237

  • Точність до 0,1: 29,9%

  • Точність до 0,01: 3,3%

  • Точність до 0,001: 0,1%

Помилка тесту для кодування 1 із 500:

1000 навчальних зображень, 1000 тестових зображень, 50 ітерацій, вихід softmax

  • Середнє значення: 0,0298767021922

  • Медіана: 0,00388858079174

  • Мінімум: 4.08712407829e-06

  • Максимум: 6.2784479965

  • Точність до 0,1: 99,6%

  • Точність до 0,01: 88,9%

  • Точність до 0,001: 13,5%

Помилка тесту для кодування Гаусса:

1000 навчальних зображень, 1000 тестових зображень, 50 ітерацій, вихід softmax

  • Середнє значення: 0,0296905377463
  • Медіана: 0,00365867335107
  • Мінімум: 4.08712407829e-06
  • Максимум: 6.2784479965
  • Точність до 0,1: 99,6%
  • Точність до 0,01: 90,8%
  • Точність до 0,001: 14,3%

Я не можу зрозуміти, чому наші результати, здається, суперечать один одному, але, здається, варто додаткового дослідження.

# -*- coding: utf-8 -*-
"""
Created on Mon Jun 13 16:59:53 2016

@author: Ari
"""

from numpy import savetxt, loadtxt, round, zeros, sin, cos, arctan2, clip, pi, tanh, exp, arange, dot, outer, array, shape, zeros_like, reshape, mean, median, max, min
from numpy.random import rand, shuffle
import matplotlib.pyplot as plt

###########
# Functions
###########

# Returns a B&W image of a line represented as a binary vector of length width*height
def gen_train_image(angle, width, height, thickness):
    image = zeros((height,width))
    x_0,y_0 = width/2, height/2
    c,s = cos(angle),sin(angle)
    for y in range(height):
        for x in range(width):
            if abs((x-x_0)*c + (y-y_0)*s) < thickness/2 and -(x-x_0)*s + (y-y_0)*c > 0:
                image[x,y] = 1
    return image.flatten()

# Display training image    
def display_image(image,height, width):    
    img = plt.imshow(reshape(image,(height,width)), interpolation = 'nearest', cmap = "Greys")
    plt.show()    

# Activation function
def sigmoid(X):
    return 1.0/(1+exp(-clip(X,-50,100)))

# Returns encoded angle using specified method ("binned","scaled","cossin","gaussian")
def encode_angle(angle, method):
    if method == "binned": # 1-of-500 encoding
        X = zeros(500)
        X[int(round(250*(angle/pi + 1)))%500] = 1
    elif method == "gaussian": # Leaky binned encoding
        X = array([i for i in range(500)])
        idx = 250*(angle/pi + 1)
        X = exp(-pi*(X-idx)**2)
    elif method == "scaled": # Scaled to [-1,1] encoding
        X = array([angle/pi])
    elif method == "cossin": # Oxinabox's (cos,sin) encoding
        X = array([cos(angle),sin(angle)])
    else:
        pass
    return X

# Returns decoded angle using specified method
def decode_angle(X, method):
    if method == "binned" or method == "gaussian": # 1-of-500 or gaussian encoding
        M = max(X)
        for i in range(len(X)):
            if abs(X[i]-M) < 1e-5:
                angle = pi*i/250 - pi
                break
#        angle = pi*dot(array([i for i in range(500)]),X)/500  # Averaging
    elif method == "scaled": # Scaled to [-1,1] encoding
        angle = pi*X[0]
    elif method == "cossin": # Oxinabox's (cos,sin) encoding
        angle = arctan2(X[1],X[0])
    else:
        pass
    return angle

# Train and test neural network with specified angle encoding method
def test_encoding_method(train_images,train_angles,test_images, test_angles, method, num_iters, alpha = 0.01, alpha_bias = 0.0001, momentum = 0.9, hid_layer_size = 500):
    num_train,in_layer_size = shape(train_images)
    num_test = len(test_angles)

    if method == "binned":
        out_layer_size = 500
    elif method == "gaussian":
        out_layer_size = 500
    elif method == "scaled":
        out_layer_size = 1
    elif method == "cossin":
        out_layer_size = 2
    else:
        pass

    # Initial weights and biases
    IN_HID = rand(in_layer_size,hid_layer_size) - 0.5 # IN --> HID weights
    HID_OUT = rand(hid_layer_size,out_layer_size) - 0.5 # HID --> OUT weights
    BIAS1 = rand(hid_layer_size) - 0.5 # Bias for hidden layer
    BIAS2 = rand(out_layer_size) - 0.5 # Bias for output layer

    # Initial weight and bias updates
    IN_HID_del = zeros_like(IN_HID)
    HID_OUT_del = zeros_like(HID_OUT)
    BIAS1_del = zeros_like(BIAS1)
    BIAS2_del = zeros_like(BIAS2)

    # Train
    for j in range(num_iters):
        for i in range(num_train):
            # Get training example
            IN = train_images[i]
            TARGET = encode_angle(train_angles[i],method) 

            # Feed forward and compute error derivatives
            HID = sigmoid(dot(IN,IN_HID)+BIAS1)

            if method == "binned" or method == "gaussian": # Use softmax
                OUT = exp(clip(dot(HID,HID_OUT)+BIAS2,-100,100))
                OUT = OUT/sum(OUT)
                dACT2 = OUT - TARGET
            elif method == "cossin" or method == "scaled": # Linear
                OUT = dot(HID,HID_OUT)+BIAS2 
                dACT2 = OUT-TARGET 
            else:
                print("Invalid encoding method")

            dHID_OUT = outer(HID,dACT2)
            dACT1 = dot(dACT2,HID_OUT.T)*HID*(1-HID)
            dIN_HID = outer(IN,dACT1)
            dBIAS1 = dACT1
            dBIAS2 = dACT2

            # Update the weight updates 
            IN_HID_del = momentum*IN_HID_del + (1-momentum)*dIN_HID
            HID_OUT_del = momentum*HID_OUT_del + (1-momentum)*dHID_OUT
            BIAS1_del = momentum*BIAS1_del + (1-momentum)*dBIAS1
            BIAS2_del = momentum*BIAS2_del + (1-momentum)*dBIAS2

            # Update the weights
            HID_OUT -= alpha*dHID_OUT
            IN_HID -= alpha*dIN_HID
            BIAS1 -= alpha_bias*dBIAS1
            BIAS2 -= alpha_bias*dBIAS2

    # Test
    test_errors = zeros(num_test)
    angles = zeros(num_test)
    target_angles = zeros(num_test)
    accuracy_to_point001 = 0
    accuracy_to_point01 = 0
    accuracy_to_point1 = 0

    for i in range(num_test):

        # Get training example
        IN = test_images[i]
        target_angle = test_angles[i]

        # Feed forward
        HID = sigmoid(dot(IN,IN_HID)+BIAS1)

        if method == "binned" or method == "gaussian":
            OUT = exp(clip(dot(HID,HID_OUT)+BIAS2,-100,100))
            OUT = OUT/sum(OUT)
        elif method == "cossin" or method == "scaled":
            OUT = dot(HID,HID_OUT)+BIAS2 

        # Decode output 
        angle = decode_angle(OUT,method)

        # Compute errors
        error = abs(angle-target_angle)
        test_errors[i] = error
        angles[i] = angle

        target_angles[i] = target_angle
        if error < 0.1:
            accuracy_to_point1 += 1
        if error < 0.01: 
            accuracy_to_point01 += 1
        if error < 0.001:
            accuracy_to_point001 += 1

    # Compute and return results
    accuracy_to_point1 = 100.0*accuracy_to_point1/num_test
    accuracy_to_point01 = 100.0*accuracy_to_point01/num_test
    accuracy_to_point001 = 100.0*accuracy_to_point001/num_test

    return mean(test_errors),median(test_errors),min(test_errors),max(test_errors),accuracy_to_point1,accuracy_to_point01,accuracy_to_point001

# Dispaly results
def display_results(results,method):
    MEAN,MEDIAN,MIN,MAX,ACC1,ACC01,ACC001 = results
    if method == "binned":
        print("Test error for 1-of-500 encoding:")
    elif method == "gaussian":
        print("Test error for gaussian encoding: ")
    elif method == "scaled":
        print("Test error for [-1,1] encoding:")
    elif method == "cossin":
        print("Test error for (cos,sin) encoding:")
    else:
        pass
    print("-----------")
    print("Mean: "+str(MEAN))
    print("Median: "+str(MEDIAN))
    print("Minimum: "+str(MIN))
    print("Maximum: "+str(MAX))
    print("Accuracy to 0.1: "+str(ACC1)+"%")
    print("Accuracy to 0.01: "+str(ACC01)+"%")
    print("Accuracy to 0.001: "+str(ACC001)+"%")
    print("\n\n")


##################
# Image parameters
##################
width = 100 # Image width
height = 100 # Image heigth
thickness = 5.0 # Line thickness

#################################
# Generate training and test data
#################################
num_train = 1000
num_test = 1000
test_images = []
test_angles = []
train_images = []
train_angles = []
for i in range(num_train):
    angle = pi*(2*rand() - 1)
    train_angles.append(angle)
    image = gen_train_image(angle,width,height,thickness)
    train_images.append(image)
for i in range(num_test):
    angle = pi*(2*rand() - 1)
    test_angles.append(angle)
    image = gen_train_image(angle,width,height,thickness)
    test_images.append(image)
train_angles,train_images,test_angles,test_images = array(train_angles),array(train_images),array(test_angles),array(test_images)



###########################
# Evaluate encoding schemes
###########################
num_iters = 50

# Train with cos,sin encoding
method = "cossin"
results1 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results1,method)

# Train with scaled encoding
method = "scaled"
results3 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results3,method)

# Train with binned encoding
method = "binned"
results2 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results2,method)

# Train with gaussian encoding
method = "gaussian"
results4 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results4,method)

Класно, На клавіші різні. Ви тренуєтесь на кожному зображенні лише один раз. Я тренуюсь на кожному зображенні 1000 разів, або 10000 разів. Багаторазові повторення, хоча дані про навчання є нормальними, особливо, коли навчаються на порівняно невеликих обсягах даних (і мені знадобилося лише одну неопубліковану недооцінену дисертацію, щоб дізнатися це, але це вже інша історія). З урахуванням сказаного, я повинен додати стовпчик 1 ітер до своєї таблиці. це було б інформативно
Ліндон Уайт

Я думаю, що навчання подібним (але не однаковим) зображенням із подібними цілями вплине на цю мережу аналогічно. Якщо це правда, слід добре працювати, щоб просто збільшити кількість випадкових зображень, на яких тренуються, а не повторювати багато разів через менший навчальний набір. Ти кажеш, це не так?
Арі Герман

Це аналогічно, але для цього прикладу завдання не має проблеми, що в кінцевому підсумку ви покажете всі можливі зображення, тому ваш тест буде збігатися з вашим поїздом, тому тестування генералізації не буде працювати. Більш істотно, хоча ви робите 100 000 навчальних зображень, що <1000 * 1000 навчальних зображень * Ітерацій.
Ліндон Уайт

Ви праві, я вирішу це питання. У моєму коді є ще більш значна проблема: я використовую логістичні нейрони, які не здатні виробляти негативні значення, необхідні для представлення (cos, sin). D'oh! Я буду переглядати свій код і якнайшвидше повторно публікувати його.
Арі Герман

Ви можете (якщо ви ще цього не зробили) зацікавлені в тому, щоб зробити перевірку Graident , що варто, коли впроваджувати нейронні мережі з нуля, оскільки дуже легко зробити незначну помилку, і ваша мережа все ще працює в основному. Re: Нейрон: так, у мене лінійний вихідний шар, на прихований шар
сигмоїди

1

Ще один спосіб кодування кута - це набір двох значень:

y1 = max (0, тета)

y2 = max (0, -тета)

theta_out = y1 - y2

Це матиме аналогічну проблему з arctan2 тим, що градієнт не визначений у theta = 0. У мене немає часу для тренування мережі та порівняння з іншими кодуваннями, але в цій роботі ця техніка видалася досить успішною.


1
Це схоже на відповідь, змішану з іншим запитанням в одному дописі. Цей сайт працює дещо інакше, ніж на форумі. Тут відповіді слід зосередити на відповіді на початкове запитання. А якщо у вас є інше питання чи коментар - його слід розмістити як таке.
Кароліс Концевічус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.