Данные об угле кодирования для нейронной сети

20

Я тренирую нейронную сеть (детали не важны), где целевые данные - это вектор углов (между 0 и 2 * пи). Я ищу совет о том, как кодировать эти данные. Вот что я сейчас пытаюсь (с ограниченным успехом):

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

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

Мы ценим любые предложения!

Ари Герман
источник
1
У вас не должно быть проблем с сетью, выводящей все нули, если вы используете выходной слой softmax - что вам обычно следует делать, если вы используете катагорический (т.е. 1-из-C) выход.
Линдон Уайт
7
Идея чисто умозрительного кодирования (я не видел, чтобы это делалось или проверялось, но я не смотрел) заключается в кодировании вашего угла ( ) в виде пары: . Я думаю, что тогда это будет непрерывная карта со всеми значениями, такими как и близкими друг к другу. Я думаю, что я мог бы построить демо этого и проверить его. θ ( sin ( θ ) , cos ( θ ) ) 0 2 πθθ(грех(θ),соз(θ))02π
Линдон Уайт
Я думал об этом еще немного, и я думаю, что это может быть только в вашей функции потери. Я хочу попробовать кучу вещей. Я сделал демо, но не закончил тесты на нем. Ожидайте подробный ответ с экспериментальной поддержкой завтра когда-нибудь. (Ткните меня, если я не буду)
Линдон Уайт
В настоящее время я не использую слой softmax, и это, вероятно, проблема. Я осуществлю это сегодня, если у меня будет шанс! Ваша (потому что, грех) идея очень интересна, и мне особенно нравится, что она автоматически переводит этот диапазон в [-1,1] (хорошо, если вы работаете с функцией активации tanh). Я с нетерпением жду ваших результатов1
Ари Херман
Быстрое обновление: я попытался реализовать слой softmax, и мне все еще не повезло. Проблема, я думаю, заключается в том, что для этой проблемы важно, чтобы «угловатость» данных была как-то представлена ​​в кодировке. При категориальном кодировании топология целевых данных теряется. Следовательно, ошибки 0,5 * пи и 0,05 * пи выглядят одинаково для сети (она видит обе категории как неправильные классификации).
Ари Херман

Ответы:

18

Вступление

Я нахожу этот вопрос действительно интересным, я полагаю, что кто-то выпустил статью по нему, но это мой выходной, поэтому я не хочу гоняться за ссылками.

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

Но далее с фактическим ответом.

метод

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

Таким образом, функция кодирования: а функция декодирования: Для arctan2, являющегося обратными касательными, сохраняя направление во всех квадрантах)θ(грех(θ),соз(θ))
(Y1,Y2)агс2(Y1,Y2)

Теоретически, вы можете эквивалентно работать напрямую с углами, если ваш инструмент поддерживает 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 за указание на это. Теперь это исправлено). Я построил несколько нейронных сетей, чтобы оценить эффективность выполнения задачи. Полная информация о реализации находится в этой записной книжке Jupyter . Код целиком на Юлии , и я использую библиотеку нейронных сетей Mocha .

Для сравнения я представляю его против альтернативных методов масштабирования до 0,1. и положить в 500 бункеров и использовать softmax. Я не особенно доволен последним, и чувствую, что мне нужно его настроить. Вот почему, в отличие от других, я тестирую его только на 1000 итераций, в отличие от двух других, которые были запущены на 1000 и на 10000

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

Изображения были пикселей, с линией, начинающейся в центре и идущей к краю. На изображении не было никаких шумов и т. Д., Только «черная» линия на белом фоне.101×101

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

Оценочная сеть имела один скрытый слой шириной 500. В скрытом слое использовались сигмовидные нейроны.

Он обучался Stochastic Gradient Decent с фиксированной скоростью обучения 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 раза лучше по большинству показателей, чем масштабирование при 10000 итераций.

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

Безусловно, существует верхний предел наилучшей возможной производительности в этой задаче, учитывая, что Угол может быть больше или меньше любого действительного числа, но не все такие ангелы выдают разные линии с разрешением пикселей. Так как, например, углы 45.0 и 45.0000001 оба связаны с одним и тем же изображением с таким разрешением, ни один метод никогда не получит оба совершенно правильных.101×101

Также представляется вероятным, что в абсолютном масштабе, чтобы выйти за рамки этой производительности, необходима лучшая нейронная сеть. Вместо очень простого, описанного выше в экспериментальной установке.

Вывод.

Кажется, что представление sin / cos является безусловно лучшим из представлений, которые я исследовал здесь. Это имеет смысл, поскольку оно имеет плавное значение при перемещении по кругу. Мне также нравится, что обратное можно сделать с помощью arctan2 , что элегантно.

Я полагаю, что поставленная задача достаточна в ее способности представить разумную проблему для сети. Хотя я полагаю, что на самом деле это просто обучение подгонке кривой к так что, возможно, это слишком просто. И, возможно, хуже, это может быть в пользу парного представления. Я не думаю, что это так, но здесь уже поздно, поэтому я мог что-то упустить, и я приглашаю вас снова просмотреть мой код . Предлагайте улучшения или альтернативные задачи.е(Икс)знак равноY1Y2Икс

Линдон Уайт
источник
Это, безусловно, самый полный ответ, который я когда-либо получал при обмене стека. Поскольку я не знаком с Джулией, мне сложно изучить ваш код ... поэтому вместо этого я попытаюсь повторить ваши результаты, используя Python. Я опубликую свои выводы позже сегодня или завтра.
Ари Герман
Хотя я не был удивлен, что биннинг работал плохо, я был удивлен тем, в какой степени (0,1) масштабирование превзошло метод (cos, sin). Я заметил, что вы сгенерировали свои примеры, случайным образом выбирая рост и ход линий. Я думаю, что это приведет к появлению линий, углы которых распределены неравномерно, но имеют наклоны. Возможно ли, что именно поэтому (cos, sin) метод работает намного лучше? Что произойдет, если вы сделаете цели загар (угол) ...?
Ари Герман
вы правы насчет случайного наклона против случайного угла. но я не думаю, что нацеливание tan(angle)пойдет так хорошо, учитывая, что tan не определен для всех углов (например, ). Я перезапущу его со случайно сгенерированными углами и отредактирую посты. π/4
Линдон Уайт
Между Джулией и Нумпи и между Мокко и Кафе должна быть близкая к одному карта, если вы действительно хотите переопределить ее. Есть ли какая-то конкретная часть кода, которую вам трудно прочитать? Юлия должна быть легким для понимания языком. Так что, возможно, я сделал что-то странное.
Линдон Уайт
Я прочитал твой код, и все кажется правильным. Тем не менее, я хотел написать свою собственную версию, так как обычно это поучительно. Моя реализация немного отличается от вашей, поэтому будет интересно сравнить результаты. Я буду публиковать их в течение следующих нескольких часов.
Ари Херман
5

Вот еще одна реализация Python, сравнивающая предложенную Линдоном Уайтом кодировку с бинн-подходом. Код ниже выдает следующий вывод:

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

(грех(θ),соз(θ))(sin(θ),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()
airalcorn2
источник
3

Вот моя Python-версия вашего эксперимента. Я сохранил многие детали вашей реализации, в частности, я использую одинаковый размер изображения, размеры сетевого уровня, скорость обучения, импульс и метрики успеха.

Каждая протестированная сеть имеет один скрытый слой (размер = 500) с логистическими нейронами. Выходные нейроны являются либо линейными, либо softmax, как отмечено. Я использовал 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 iter к моей таблице. это было бы информативно
Линдон Уайт
Я думаю, что обучение на похожих (но не идентичных) изображениях с одинаковыми целями будет влиять на эту сеть аналогичным образом. Если это правда, он должен работать нормально, просто увеличивая количество случайных изображений, на которых обучаются, а не раз многократно повторяясь через меньший обучающий набор. Вы говорите, что это не так?
Ари Херман
Это похоже, но для этого примера задачи не имеет проблемы, что в конечном итоге вы покажете все возможные изображения, так что ваш тест будет совпадать с вашим поездом, поэтому обобщение тестирования не будет работать. Еще важнее то, что вы делаете 100 000 тренировочных образов, что составляет <1000 * 1000 тренировочных образов * Итерации.
Линдон Уайт
Вы правы, я исправлю эту проблему. Есть еще более существенная проблема с моим кодом: я использую логистические нейроны, которые не способны генерировать отрицательные значения, требуемые представлением (cos, sin). D'о! Я буду пересматривать свой код и переиздавать как можно скорее.
Ари Герман
Вы можете (если вы еще этого не сделали) заинтересоваться выполнением Graident Check , что полезно при внедрении нейронных сетей с нуля, поскольку очень легко сделать небольшую ошибку и ваша сеть по-прежнему в основном работает. Re: Нейрон: да, у меня есть линейный выходной слой на сигмовидный скрытый слой
Линдон Уайт
1

Другой способ кодирования угла - это набор из двух значений:

у1 = макс (0, тета)

у2 = макс (0, -тета)

theta_out = y1 - y2

Это будет иметь ту же проблему, что и arctan2, в том, что градиент не определен при тета = 0. У меня нет времени, чтобы обучить сеть и сравнить с другими кодировками, но в этой статье техника показалась достаточно успешной.

DerekG
источник
1
Это похоже на ответ, смешанный с другим вопросом в одном посте. Этот сайт работает немного иначе, чем форум. Здесь ответы должны быть сосредоточены на ответе на оригинальный вопрос. А если у вас есть другой вопрос или комментарий - его следует опубликовать как таковой.
Каролис Концевичюс