Pengkodean Data Sudut untuk Jaringan Saraf Tiruan

20

Saya melatih jaringan saraf (detail tidak penting) di mana data target adalah vektor sudut (antara 0 dan 2 * pi). Saya mencari saran tentang cara menyandikan data ini. Inilah yang sedang saya coba (dengan kesuksesan terbatas):

1) Pengodean 1-of-C: I bin pengaturan kemungkinan sudut menjadi 1000 atau lebih sudut diskrit dan kemudian menunjukkan sudut tertentu dengan menempatkan 1 pada indeks yang relevan. Masalah dengan ini, adalah bahwa jaringan hanya belajar untuk mengeluarkan semua 0 (karena ini hampir persis benar).

2) Penskalaan sederhana: Saya meningkatkan rentang output jaringan ([0,1]) menjadi [0,2 * pi]. Masalahnya di sini adalah bahwa sudut secara alami memiliki topologi melingkar (yaitu 0,0001 dan 2 * pi sebenarnya bersebelahan). Dengan jenis pengkodean ini, informasi itu hilang.

Setiap saran akan sangat dihargai!

Ari Herman
sumber
1
Anda seharusnya tidak memiliki masalah dengan jaringan yang mengeluarkan semua nol, jika Anda menggunakan lapisan output softmax - yang biasanya harus Anda lakukan, jika Anda menggunakan output katagori (yaitu 1-of-C).
Lyndon White
7
Ide penyandian yang murni spekulatif (saya belum pernah melihatnya atau diuji, tapi saya belum melihat) adalah menyandikan sudut Anda ( ) sebagai pasangan: . Saya pikir itu akan menjadi peta berkelanjutan dengan semua nilai seperti , dan dekat satu sama lain. Saya pikir saya mungkin membangun demo ini dan mengujinya. θ ( sin ( θ ) , cos ( θ ) ) 0 2 πθθ(dosa(θ),cos(θ))02π
Lyndon White
Saya sudah memikirkan ini lagi, dan saya pikir itu mungkin sebenarnya hanya semua dalam fungsi kerugian Anda. Saya ingin mencoba banyak hal. Saya membuat demo, tetapi tidak menyelesaikan tes. Harapkan jawaban terinci dengan dukungan eksperimental besok. (Poke saya jika saya tidak)
Lyndon White
Saat ini saya tidak menggunakan lapisan softmax, dan itu mungkin masalahnya. Saya akan menerapkannya hari ini jika saya mendapat kesempatan! Ide (cos, sin) Anda sangat menarik dan saya terutama menyukainya karena secara otomatis memasukkan rentang tersebut ke [-1,1] (bagus jika Anda bekerja dengan fungsi aktivasi tanh). Saya berharap dapat melihat hasil Anda1
Ari Herman
Pembaruan cepat: Saya mencoba menerapkan lapisan softmax, dan saya masih belum beruntung. Masalahnya, saya pikir, adalah bahwa untuk masalah ini sangat penting bahwa "angularitas" data diwakili dalam penyandian. Dengan pengkodean kategoris, topologi data target hilang. Oleh karena itu kesalahan 0,5 * pi dan 0,05 * pi terlihat sama dengan jaringan (ia melihat keduanya sebagai kategorisasi yang salah).
Ari Herman

Jawaban:

18

pengantar

Saya menemukan pertanyaan ini sangat menarik, saya berasumsi seseorang telah meletakkan kertas di atasnya, tapi ini hari libur saya, jadi saya tidak ingin mengejar referensi.

Jadi kita bisa menganggapnya sebagai representasi / pengkodean dari output, yang saya lakukan dalam jawaban ini. Saya tetap berpikir bahwa ada cara yang lebih baik, di mana Anda bisa menggunakan fungsi kerugian yang sedikit berbeda. (Mungkin jumlah perbedaan kuadrat, menggunakan modulo pengurangan 2 ).π

Tetapi selanjutnya dengan jawaban yang sebenarnya.

metode

Saya mengusulkan bahwa sudut direpresentasikan sebagai sepasang nilai, sinus dan cosinus nya.θ

Jadi fungsi encoding adalah: dan fungsi penguraiannya adalah:θ(dosa(θ),cos(θ))
Untukarctan2menjadi garis singgung terbalik, menjaga arah di semua kuadran)(y1,y2)Arktan2(y1,y2)

Secara teori, Anda dapat bekerja secara setara dengan sudut jika alat Anda digunakan didukung atan2sebagai fungsi layer (mengambil tepat 2 input dan menghasilkan 1 output). TensorFlow melakukan ini sekarang, dan mendukung penurunan gradien di atasnya , meskipun tidak dimaksudkan untuk penggunaan ini. Saya menyelidiki menggunakan out = atan2(sigmoid(ylogit), sigmoid(xlogit)) dengan fungsi kerugian min((pred - out)^2, (pred - out - 2pi)^2). Saya menemukan bahwa itu dilatih jauh lebih buruk daripada menggunakan outs = tanh(ylogit), outc = tanh(xlogit)) dengan fungsi kehilangan 0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2. Yang saya pikir dapat dikaitkan dengan gradien yang terputus-putusatan2

Pengujian saya di sini menjalankannya sebagai fungsi preprocessing

Untuk mengevaluasi ini saya mendefinisikan tugas:

Diberikan gambar hitam dan putih yang mewakili satu garis pada latar belakang kosong. Output sudut apa garis itu pada "sumbu x positif"

Saya menerapkan fungsi secara acak menghasilkan gambar-gambar ini, dengan garis di sudut acak (NB: versi sebelumnya dari posting ini menggunakan lereng acak, bukan sudut acak. Terima kasih kepada @Ari Herman untuk menunjukkannya. Sekarang sudah diperbaiki). Saya membangun beberapa jaringan saraf untuk mengevaluasi kinerja di sana. Detail lengkap implementasinya ada di notebook Jupyter ini . Semua kode dalam Julia , dan saya menggunakan perpustakaan jaringan saraf Mocha .

Sebagai perbandingan, saya menyajikannya terhadap metode penskalaan alternatif ke 0,1. dan untuk memasukkan ke dalam 500 nampan dan menggunakan softmax soft-label. Saya tidak terlalu senang dengan yang terakhir, dan merasa saya perlu mengubahnya. Itulah sebabnya, tidak seperti yang lain saya hanya mengujinya untuk 1.000 iterasi, vs dua lainnya yang dijalankan untuk 1.000 dan 10.000

Pengaturan eksperimen

101×101

Untuk setiap jejak 1.000 pelatihan, dan 1.000 gambar uji dihasilkan secara acak.

Jaringan evaluasi memiliki satu lapisan tersembunyi dengan lebar 500. Neuron Sigmoid digunakan dalam lapisan tersembunyi.

Itu dilatih oleh Stochastic Gradient Decent, dengan tingkat pembelajaran tetap 0,01, dan momentum tetap 0,9.

Tidak ada regularisasi, atau putus sekolah yang digunakan. Juga tidak ada konvolusi dll. Jaringan sederhana, yang saya harap menyarankan bahwa hasil ini akan digeneralisasi

Sangat mudah untuk mengubah parameter ini dalam kode uji , dan saya mendorong orang untuk melakukannya. (dan cari bug dalam tes).

Hasil

Hasil saya adalah sebagai berikut:

|                        |  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%       |

7π4π4

Saya juga menyajikan akurasi pada berbagai tingkat granularity. Keakuratan menjadi bagian dari kasus uji itu jadi berkarat. Jadi accuracy_to_point01berarti itu dihitung sebagai benar jika output berada dalam 0,01 dari sudut yang sebenarnya. Tak satu pun dari representasi mendapatkan hasil yang sempurna, tapi itu sama sekali tidak mengejutkan mengingat bagaimana matematika floating point bekerja.

Jika Anda melihat sejarah posting ini Anda akan melihat hasilnya memang sedikit berisik, sedikit berbeda setiap kali saya memutarnya kembali. Tetapi urutan umum dan skala nilai tetap sama; sehingga memungkinkan kita untuk menarik beberapa kesimpulan.

Diskusi

π

Pengkodean sin / cos berkinerja jauh lebih baik daripada pengodean 0-1 yang diskalakan. Peningkatannya adalah sejauh pada 1.000 pelatihan iterasi dosa / cos melakukan sekitar 3 kali lebih baik pada kebanyakan metrik daripada skala adalah pada 10.000 iterasi.

Saya pikir, sebagian ini terkait dengan peningkatan generalisasi, karena keduanya mendapatkan kesalahan kuadrat rata-rata yang hampir sama pada set pelatihan, setidaknya sekali 10.000 iterasi dijalankan.

101×101

Tampaknya juga bahwa pada skala absolut untuk bergerak melampaui kinerja ini, jaringan saraf yang lebih baik diperlukan. Daripada yang sangat sederhana yang diuraikan di atas dalam pengaturan eksperimental.

Kesimpulan.

Tampaknya representasi dosa / cos sejauh ini adalah yang terbaik, dari representasi yang saya selidiki di sini. Ini masuk akal, karena memang memiliki nilai yang halus saat Anda bergerak di sekitar lingkaran. Saya juga suka bahwa kebalikannya dapat dilakukan dengan arctan2 , yang elegan.

f(x)=y1y2x

Lyndon White
sumber
Ini tentu saja merupakan respon paling menyeluruh yang pernah saya terima pada pertukaran stack Karena saya tidak terbiasa dengan Julia, sulit bagi saya untuk memeriksa kode Anda ... jadi, alih-alih saya akan mencoba mereplikasi hasil Anda menggunakan Python. Saya akan mengirimi saya temuan hari ini atau besok.
Ari Herman
Sementara saya tidak terkejut bahwa binning berkinerja buruk, saya terkejut pada sejauh mana penskalaan (0,1) lebih baik dari metode (cos, sin). Saya perhatikan bahwa Anda membuat contoh dengan memilih secara acak naik turunnya garis. Saya pikir, ini akan menghasilkan garis yang sudutnya tidak terdistribusi secara seragam, tetapi memiliki kemiringan yang berbeda. Mungkinkah ini sebabnya metode (cos, sin) dilakukan jauh lebih baik? Apa yang akan terjadi jika Anda membuat target tan (sudut) ...?
Ari Herman
tan(angle)π/4
Harus ada peta dekat ke satu antara julia dan numpy, dan antara Mocha dan Caffe, jika Anda benar-benar ingin mengimplementasikannya kembali. Apakah ada bagian tertentu dari kode yang menurut Anda sulit dibaca? Julia harus menjadi bahasa yang mudah dimengerti. Jadi mungkin saya telah melakukan sesuatu yang aneh.
Lyndon White
Saya akhirnya membaca kode Anda, dan semuanya tampak benar. Tetap saja, saya ingin menulis versi saya sendiri, karena hal itu biasanya bersifat instruktif. Implementasi saya sedikit berbeda dari Anda, jadi akan menarik untuk membandingkan hasilnya. Saya akan mempostingnya dalam beberapa jam ke depan.
Ari Herman
5

Berikut ini adalah implementasi Python lain yang membandingkan pengodean yang diusulkan Lyndon White dengan pendekatan binned. Kode di bawah ini menghasilkan output berikut:

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

(dosa(θ),cos(θ))(dosa(θ),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
sumber
3

Ini versi percobaan Python saya. Saya menyimpan banyak detail implementasi Anda yang sama, khususnya saya menggunakan ukuran gambar yang sama, ukuran lapisan jaringan, tingkat pembelajaran, momentum, dan metrik kesuksesan.

Setiap jaringan yang diuji memiliki satu lapisan tersembunyi (ukuran = 500) dengan neuron logistik. Neuron output berupa linear atau softmax seperti disebutkan. Saya menggunakan 1.000 gambar latihan dan 1.000 gambar uji yang dibuat secara independen, secara acak (jadi mungkin ada pengulangan). Pelatihan terdiri dari 50 iterasi melalui set pelatihan.

Saya bisa mendapatkan akurasi yang cukup baik menggunakan pengkodean binning dan "gaussian" (nama saya dibuat; mirip dengan binning kecuali bahwa vektor output target memiliki bentuk exp (-pi * ([1,2,3, ... , 500] - idx) ** 2) di mana idx adalah indeks yang sesuai dengan sudut yang benar). Kode di bawah ini; inilah hasil saya:

Kesalahan tes untuk penyandian (cos, sin):

1.000 gambar pelatihan, 1.000 gambar uji, 50 iterasi, output linier

  • Berarti: 0,0911558142071

  • Median: 0,0429723541743

  • Minimum: 2.77769843793e-06

  • Maksimal: 6.2608513539

  • Akurasi menjadi 0,1: 85,2%

  • Akurasi hingga 0,01: 11,6%

  • Akurasi hingga 0,001: 1,0%

Kesalahan tes untuk penyandian [-1,1]:

1.000 gambar pelatihan, 1.000 gambar uji, 50 iterasi, output linier

  • Berarti: 0,234181700523

  • Median: 0.17460197307

  • Minimal: 0,000473665840258

  • Maksimal: 6.00637777237

  • Akurasi menjadi 0,1: 29,9%

  • Akurasi hingga 0,01: 3,3%

  • Akurasi hingga 0,001: 0,1%

Kesalahan tes untuk penyandian 1-of-500:

1.000 gambar pelatihan, 1.000 gambar uji, 50 iterasi, output softmax

  • Berarti: 0,0298767021922

  • Median: 0,00388858079174

  • Minimum: 4.08712407829e-06

  • Maksimal: 6.2784479965

  • Akurasi menjadi 0,1: 99,6%

  • Akurasi hingga 0,01: 88,9%

  • Akurasi hingga 0,001: 13,5%

Kesalahan tes untuk penyandian gaussian:

1.000 gambar pelatihan, 1.000 gambar uji, 50 iterasi, output softmax

  • Berarti: 0,0296905377463
  • Median: 0,00365867335107
  • Minimum: 4.08712407829e-06
  • Maksimal: 6.2784479965
  • Akurasi menjadi 0,1: 99,6%
  • Akurasi hingga 0,01: 90,8%
  • Akurasi hingga 0,001: 14,3%

Saya tidak tahu mengapa hasil kami tampaknya bertentangan satu sama lain, tetapi tampaknya perlu diselidiki lebih lanjut.

# -*- 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)
Ari Herman
sumber
Keren, tombol berbeda. Anda hanya berlatih pada setiap gambar satu kali. Saya berlatih pada setiap gambar 1.000 kali, atau 10.000 kali. Berulang kali meskipun data pelatihan normal, terutama ketika pelatihan pada jumlah data yang relatif kecil (dan saya hanya perlu satu tesis sarjana yang tidak dapat diterbitkan untuk mempelajari ini, tetapi itu adalah cerita lain). Dengan itu, saya harus menambahkan kolom 1 iter ke meja saya. itu akan informatif
Lyndon White
Saya akan berpikir bahwa pelatihan pada gambar yang serupa (tetapi tidak identik) dengan target yang sama akan mempengaruhi jaringan yang sama. Jika itu benar, itu akan berfungsi dengan baik untuk hanya meningkatkan jumlah gambar acak yang dilatih, bukan berulang kali melalui pelatihan yang lebih kecil. Apakah Anda mengatakan ini bukan masalahnya?
Ari Herman
Ini mirip, tetapi untuk tugas contoh ini tidak memiliki masalah yang pada akhirnya Anda akan menampilkan semua gambar yang mungkin sehingga tes Anda akan tumpang tindih dengan kereta Anda, sehingga pengujian generalision tidak akan berfungsi. Lebih penting lagi, Anda melakukan 100.000 gambar latihan, yaitu <1000 * 1000 gambar latihan * Iterasi.
Lyndon White
Anda benar, saya akan memperbaiki masalah itu. Ada masalah yang lebih signifikan dengan kode saya: Saya menggunakan neuron logistik yang tidak mampu menghasilkan nilai-nilai negatif yang diperlukan oleh representasi (cos, sin). Doh! Saya akan merevisi kode saya dan memposting ulang sesegera mungkin.
Ari Herman
Anda mungkin (jika Anda belum melakukannya) tertarik untuk melakukan Graident Check , yang bermanfaat ketika mengimplementasikan jaringan saraf dari awal, karena sangat mudah untuk membuat kesalahan kecil dan sebagian besar jaringan Anda masih berfungsi. Neuron: yeah, saya memiliki lapisan keluaran linier, ke lapisan tersembunyi sigmoid
Lyndon White
1

Cara lain untuk menyandikan sudut adalah sebagai satu set dari dua nilai:

y1 = maks (0, theta)

y2 = maks (0, -teta)

theta_out = y1 - y2

Ini akan memiliki masalah yang mirip dengan arctan2 dalam hal gradien tidak terdefinisi pada theta = 0. Saya tidak punya waktu untuk melatih jaringan dan membandingkan dengan pengkodean lainnya tetapi dalam makalah ini teknik ini kelihatannya cukup berhasil.

DerekG
sumber
1
Ini sepertinya jawaban yang dicampur dengan pertanyaan lain dalam satu posting. Situs ini beroperasi sedikit berbeda dari cara forum. Di sini jawaban harus berkonsentrasi pada menjawab pertanyaan awal. Dan jika Anda memiliki pertanyaan atau komentar lain - itu harus diposting seperti itu.
Karolis Koncevičius