Machine Learning Golf: moltiplicazione


68

Vorrei proporre un diverso tipo di sfida golfistica a questa comunità:

Le reti neurali (artificiali) sono modelli di machine learning molto popolari che possono essere progettati e addestrati per approssimare qualsiasi funzione (di solito sconosciuta). Sono spesso usati per risolvere problemi molto complessi che non sappiamo come risolvere algoritmicamente come il riconoscimento vocale, alcuni tipi di classificazione delle immagini, vari compiti in sistemi di guida autonomi, ... Per un primer sulle reti neurali, considera questo eccellente Articolo di Wikipedia .

Poiché questo è il primo in quella che spero sia una serie di sfide del golf di apprendimento automatico, mi piacerebbe mantenere le cose il più semplice possibile:

Nel linguaggio e nella struttura di tua scelta, progetta e addestra una rete neurale che, data calcola il loro prodotto per tutti i numeri interi tra (e inclusi) e .(x1,x2)x1x2x1,x21010

Obiettivo di prestazione

Per essere idoneo, il tuo modello non può discostarsi di oltre dal risultato corretto su nessuna di queste voci.0.5

Regole

Il tuo modello

  • deve essere una rete neurale "tradizionale" (il valore di un nodo viene calcolato come una combinazione lineare ponderata di alcuni dei nodi in uno strato precedente seguito da una funzione di attivazione),
  • può utilizzare solo le seguenti funzioni di attivazione standard:
    1. linear(x)=x ,
    2. softmax(x)i=exijexj ,
    3. seluα,β(x)={βx, if x>0αβ(ex1), otherwise ,
    4. softplus(x)=ln(ex+1) ,
    5. leaky-reluα(x)={x, if x<0αx, otherwise ,
    6. tanh(x) ,
    7. sigmoid(x)=exex+1 ,
    8. hard-sigmoid(x)={0, if x<2.51, if x>2.50.2x+0.5, otherwise ,
    9. ex
  • deve prendere come tupel / vettore / elenco / ... di numeri interi o float come unico input,(x1,x2)
  • restituisce la risposta come un numero intero, float (o un contenitore adatto, ad esempio un vettore o un elenco, che contiene questa risposta).

La risposta deve includere (o collegarsi a) tutto il codice necessario per verificare i risultati, compresi i pesi addestrati del modello.

punteggio

Vince la rete neurale con il minor numero di pesi (inclusi i pesi di polarizzazione).

Godere!


9
Benvenuti nel sito! Penso che questa sfida potrebbe trarre molti benefici da una definizione più solida di una rete neurale. Ci sono un paio di cose qui 1) Sarebbe molto bello per te dichiararlo in un linguaggio che non implica già la conoscenza di NNs 2) Dovresti davvero elencare le funzioni di attivazione nel tuo post piuttosto che collegarti a una fonte esterna ( i collegamenti esterni possono cambiare o scomparire).
Wheat Wizard

4
Possiamo riutilizzare pesi / usare strati convoluzionali? (Consiglio di rimuovere il bonus, in quanto non aggiunge nulla alla sfida e distrae semplicemente l'obiettivo principale.) I pesi dovrebbero essere reali o possono essere complessi?
Flawr

4
La tua formulazione implica che i nodi del livello 3 non possono usare gli input del livello 1. Costa un peso avere un nodo del livello 2 che fa semplicemente f(x) = xinoltrare il suo input?
Grimmy

4
Dovrebbe esserci un link nella colonna di destra al Sandbox, che è stato creato espressamente per risolvere questo tipo di problemi prima ancora che la domanda venga pubblicata sul sito principale. E la filosofia della rete è che è meglio chiudere una domanda, risolverla e riaprirla piuttosto che ottenere un mucchio di risposte che o non avranno alcun senso dopo che la domanda è stata risolta o vincoleranno strettamente i cambiamenti che possono essere fatti alla domanda .
Peter Taylor,

7
Affatto. Questo tipo di problemi viene rilevato dall'esperienza pluriennale di vedere altre persone fare lo stesso tipo di errori. Alcune ambiguità scivolano oltre la sandbox, ma molte altre vengono catturate lì. E questo sarebbe sicuramente stato colto, perché come indicato nel mio primo commento abbiamo avuto esattamente gli stessi problemi con una domanda di rete neurale due mesi fa.
Peter Taylor,

Risposte:


37

21 13 11 9 pesi

Questo si basa sull'identità di polarizzazione delle forme bilineari che nel caso reale monodimensionale si riduce all'identità polinomiale:

xy=(x+y)2(xy)24

Quindi y1calcola semplicemente [x+y, x-y]usando una trasformazione lineare, ed y3è solo il valore assoluto di y1come un passo di preelaborazione per il prossimo: Quindi la parte "difficile" sta calcolando i quadrati che spiegherò di seguito, e successivamente calcola solo una differenza e un ridimensionamento che è di nuovo un'operazione lineare.

s{0,1,2,,20}0.5

approx_square(x)=i=02wiexp(0.0001ix)

W2=(wi)i0.02

function p = net(x)
% 9 weights
one = 1; 
mone =-1;
zero = 0;
fourth = 0.25;
W1 = [1e-4, 2e-4];
W2  = [-199400468.100687;99700353.6313757];
b2 = 99700114.4299316;
leaky_relu = @(a,x)max(a*x,x); 


% Linear
y0 = [one, one; one, mone] * x;

% Linear + ReLU
y1 = mone * y0;
y2 = [leaky_relu(zero, y0), leaky_relu(zero, y1)];

% Linear
y3 = y2 * [one; one];

% Linear + exp
y4 = exp(y3 * W1); 

% Linear + Bias
y5 =  y4 * W2 + b2;

% Linear
y6 = [one, mone]*y5;
p = y6 * fourth;

end

Provalo online!


Penso che il tuo codice di controllo nel piè di pagina del collegamento TIO non abbia ricevuto un'applicazione abs. Ma va tutto bene comunque.
Christian Sievers,

@ChristianSievers Grazie, ho aggiornato il link TIO!
Flawr

Non sono un esperto di NN, per curiosità, come si fa il conteggio dei pesi? y0ha bisogno di 4, ha y1bisogno di 2, ha y3bisogno di 2, ha y4bisogno di 1, ha y5bisogno di 1 e ha y6bisogno di 2. Sono 12?
Margaret Bloom,

3
@MargaretBloom Sì, questo è in effetti un po 'insolito, ma nei commenti l'OP ha affermato che possiamo riutilizzare i pesi e contarli solo una volta, anche se utilizziamo lo stesso peso più volte. Quindi tutti i pesi che sto usando sono definiti nella prima parte della funzione.
Flawr

31

7 pesi

eps = 1e-6
c = 1 / (2 * eps * eps)

def f(A, B):
	e_s = exp(eps * A + eps * B)  # 2 weights, exp activation
	e_d = exp(eps * A - eps * B)  # 2 weights, exp activation
	return c * e_s + (-c) * e_d + (-1 / eps) * B  # 3 weights, linear activation

Provalo online!

ϵex1+x+x22

ABeϵA+ϵBeϵAϵB2ϵ2Bϵ

ϵepsc


1
Non sono sicuro che questo valga come una "rete neurale tradizionale" (regola n. 1), ma è ovvio che può essere riformattato in uno, quindi non vedo alcun problema. Bella soluzione!
Stefan Mesken,

1
Potresti definire C = -B(1 peso) e quindi avere [e_s, e_d] = conv([A,B,C], [eps, eps])(2 pesi) per risparmiare un peso :) (BTW: approccio molto intelligente!)
flawr

(Ho dimenticato di aggiungere il exp)
flawr

4
Puoi persino abbassarti molto riutilizzando i pesi : non devi contare lo stesso peso più volte.
Flawr

2
@flawr Questo è un bel trucco, ma penso che le indennità per la convoluzione e il riutilizzo dei pesi nei commenti rendano questa sfida così diversa che manterrò questa risposta così com'è.
xnor

22

33 31 pesi

# Activation functions
sub hard { $_[0] < -2.5 ? 0 : $_[0] > 2.5 ? 1 : 0.2 * $_[0] + 0.5 }
sub linear { $_[0] }

# Layer 0
sub inputA() { $a }
sub inputB() { $b }

# Layer 1
sub a15() { hard(5*inputA) }

# Layer 2
sub a8()  { hard(-5*inputA + 75*a15 - 37.5) }

# Layer 3
sub aa()  { linear(-5*inputA + 75*a15 - 40*a8) }

# Layer 4
sub a4()  { hard(aa - 17.5) }

# Layer 5
sub a2()  { hard(aa - 20*a4 - 7.5) }

# Layer 6
sub a1()  { linear(0.2*aa - 4*a4 - 2*a2) }

# Layer 7
sub b15() { hard(0.25*inputB - 5*a15) }
sub b8()  { hard(0.25*inputB - 5*a8) }
sub b4()  { hard(0.25*inputB - 5*a4) }
sub b2()  { hard(0.25*inputB - 5*a2) }
sub b1()  { hard(0.25*inputB - 5*a1) }

# Layer 8
sub output() { linear(-300*b15 + 160*b8 + 80*b4 + 40*b2 + 20*b1 - 10*inputA) }

# Test
for $a (-10..10) {
        for $b (-10..10) {
                die if abs($a * $b - output) >= 0.5;
        }
}

print "All OK";

Provalo online!

Ciò comporta una lunga moltiplicazione in (sorta) binario e quindi restituisce il risultato esatto. Dovrebbe essere possibile sfruttare la finestra di errore 0,5 per giocare ancora a golf, ma non sono sicuro di come.

I livelli da 1 a 6 decompongono il primo input in 5 "bit". Per motivi di golf, non usiamo il binario reale. Il "bit" più significativo ha un peso di -15 invece di 16 e quando l'ingresso è 0, tutti i "bit" sono 0,5 (che funziona ancora bene, poiché conserva l'identità inputA = -15*a15 + 8*a8 + 4*a4 + 2*a2 + 1*a1).


1
Mi aspettavo che qualcuno venisse fuori con un algoritmo di moltiplicazione codificato in ANN. Ma non pensavo che sarebbe stata la prima risposta. Molto bene! (Sono anche ansioso di vedere se sarai in grado di realizzare qualcosa del genere con il set di dati MNIST o qualche altro problema ML più relastico: D.)
Stefan Mesken

14

43 pesi

Le due soluzioni pubblicate finora sono state molto intelligenti, ma i loro approcci probabilmente non funzioneranno per compiti più tradizionali nell'apprendimento automatico (come l'OCR). Quindi mi piacerebbe presentare una soluzione "generica" ​​(senza trucchi intelligenti) per questo compito che si spera ispiri altre persone a migliorarlo e ad essere risucchiato nel mondo dell'apprendimento automatico:

Il mio modello è una rete neurale molto semplice con 2 livelli nascosti integrati in TensorFlow 2.0 (ma funzionerebbe anche qualsiasi altro framework):

model = tf.keras.models.Sequential([
tf.keras.layers.Dense(6, activation='tanh', input_shape=(2,)),
tf.keras.layers.Dense(3, activation='tanh'),
tf.keras.layers.Dense(1, activation='linear')
])

Come puoi vedere, tutti i livelli sono densi (che sicuramente non è ottimale), la funzione di attivazione è tanh (che potrebbe effettivamente andare bene per questa attività), ad eccezione del livello di output che, a causa della natura di questa attività, ha una funzione di attivazione lineare.

Ci sono 43 pesi:

  • (2+1)6=18
  • (6+1)3=21
  • (3+1)1=4

1010

Successivamente, li ho perfezionati - ottimizzando per la massima deviazione su qualsiasi attività di moltiplicazione dei numeri interi. Sfortunatamente, i miei appunti non mostrano molto bene l'accordatura che ho finito per fare, ma era molto minore. Nelle vicinanze di 100 epoche su quei 441 campioni di addestramento, con una dimensione del lotto di 441.

Questi sono i pesi con cui sono finito:

[<tf.Variable 'dense/kernel:0' shape=(2, 6) dtype=float32, numpy=
 array([[ 0.10697944,  0.05394982,  0.05479664, -0.04538541,  0.05369904,
         -0.0728976 ],
        [ 0.10571832,  0.05576797, -0.04670485, -0.04466859, -0.05855528,
         -0.07390639]], dtype=float32)>,
 <tf.Variable 'dense/bias:0' shape=(6,) dtype=float32, numpy=
 array([-3.4242163, -0.8875816, -1.7694025, -1.9409281,  1.7825342,
         1.1364107], dtype=float32)>,
 <tf.Variable 'dense_1/kernel:0' shape=(6, 3) dtype=float32, numpy=
 array([[-3.0665843 ,  0.64912266,  3.7107112 ],
        [ 0.4914808 ,  2.1569328 ,  0.65417236],
        [ 3.461693  ,  1.2072319 , -4.181983  ],
        [-2.8746269 , -4.9959164 ,  4.505049  ],
        [-2.920127  , -0.0665407 ,  4.1409926 ],
        [ 1.3777553 , -3.3750365 , -0.10507642]], dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(3,) dtype=float32, numpy=array([-1.376577  ,  2.8885336 ,  0.19852689], dtype=float32)>,
 <tf.Variable 'dense_2/kernel:0' shape=(3, 1) dtype=float32, numpy=
 array([[-78.7569  ],
        [-23.602606],
        [ 84.29587 ]], dtype=float32)>,
 <tf.Variable 'dense_2/bias:0' shape=(1,) dtype=float32, numpy=array([8.521169], dtype=float32)>]

0.44350433910=90.443504

Il mio modello può essere trovato qui e puoi anche provarlo online! in un ambiente Google Colab.


6

2 pesi

ϵ>0

xyeϵx+ϵy+eϵxϵyeϵxϵyeϵx+ϵy4ϵ2.

ϵ=0.01

{±ϵ,±(4ϵ2)1}{±ϵ,(4ϵ3)1}±(4ϵ2)1=±ϵ(4ϵ3)1. Come ho già detto in un commento sopra, ogni rete neurale con pesi nella precisione della macchina può essere giocata su una rete (enorme!) Neurale con solo due pesi distinti. Ho applicato questa procedura per scrivere il seguente codice MATLAB:

function z=approxmultgolfed(x,y)

w1 = 0.1;   % first weight
w2 = -w1;   % second weight

k  = 250000;
v1 = w1*ones(k,1);
v2 = w2*ones(k,1);

L1 = w1*eye(2);
L2 = [ w1 w1; w2 w2; w1 w2; w2 w1 ];
L3 = [ v1 v1 v2 v2 ];
L4 = v1';

z = L4 * L3 * exp( L2 * L1 * [ x; y ] );

{±0.1}

Come cavarsela con solo 1 peso (!)

{±0.1}0.10.1

0.1x=wwx,

w100.110.5

{±10k}10k

(Forse dovremmo modificare il modo in cui i pesi riutilizzati vengono assegnati nelle future sfide del golf della rete neurale.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.