Implementing machine learning on Arduino (MNIST)

Hello, I'm trying to implement this work on the Arduino mega2560 and using the Arduino IDE 2.3.2 compiler.

So far I haven't been able to make it work, I've tried several changes and haven't gotten any results.
I tried the first approach in the most predictable way, using the serial monitor and sending my vector of 784 elements extracted from the MNIST dataset, I tried with [ ], with { }, with 'space', completing with 3 elements like 0 = 000, changed the line ending CF, CRLF, I tried also with the vector declared directly and nothing.

I then tried switching compilers to VSCode and it didn't improve either.

In the Arduino IDE, 99% of the time I got a printed output "2", regardless of which vector I sent.

Does anyone have any suggestions or know how to solve it?

#include "LogNNet.h"

float Sh[P+1]; 
int i = 1;
byte Y[S+1];

void Hidden_Layer_Calculating(byte Y[S+1]) {
  float W1 = 0;      
  Sh[0] = 1;
  for (int j = 1; j <= P; j++) {
    Sh[j] = 0;
    for (int i = 0; i <= S; i++) {
      W1 = A * sin(i / float(S) * PI / B);
      for (int k = 2; k <= j; k++)
        W1 = 1 - (r * W1 * W1);
      Sh[j] = Sh[j] + Y[i]/255.0 * W1;   
    }
  }
}

void Hidden_Layer_Normalization() {
  Sh[0] = 1;
  for (int j = 1; j <= P; j++) 
    Sh[j] = ((Sh[j] - minH[j-1]/100.0) / 
        (maxH[j-1]/100.0 - minH[j-1]/100.0)) 
            - 0.5 - meanH[j-1]/10000.0;
}

byte Output_Layer() {
  float Sout[M];
  for (int j = 0; j < M; j++) {
    Sout[j] = 0;
    for (int i = 0; i <= P; i++) 
      Sout[j] = Sout[j] + Sh[i] * W2[i][j] / 100.0;
    Sout[j] = 1 / (1 + exp(-1 * Sout[j]));
  }
  byte digit = 0;
  for (int i = 0; i < M; i++) {
    if (Sout[i] > Sout[digit])
      digit = i;
  }
  return digit;
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  if (Serial.available() > 0) {
    Y[i] = Serial.read(); 
    i++;
    if (i == S+1) { 
      Y[0] = 255;
      i = 1;
      Hidden_Layer_Calculating(Y);       
      Hidden_Layer_Normalization();
      byte Digit = Output_Layer(); 
      Serial.print(String(Digit));  
    }
  }
}
//---- LogNNet 784:20:10 ------
#pragma once
#include <Arduino.h>

#define S 784
#define P 20
#define M 10

#define A 0.672304710111946
#define B 1.57740808024101
#define r 1.86376633343066

int maxH[P] = {16458, 13985, 16194, 4846, 9755, 12284, 5592, 5826, 9223, 
            6653, 3504, 11273, 3993, 5204, 7919, 3889, 9294, 6141, 5063, 5334};
int minH[P] = {1043, 944, 900, -2416, -1539, -2423, -2509, -816, -761, -2896, 
            -2205, -125, -2282, -457, -17, -2211, -112, -276, -858, 37};
int meanH[P] = {-2188, -2301, -2094, -595, -1707, -1204, -667, -1419, -1395, 
           -846, -1025, -1562, -451, -1382, -1471, -1016, -1929, -1348, -1137, -1274};
int W2[P+1][M] = {
                {-491, -915, -453, -353, -455, -419, -516, -584, -324, -431},
                {211, -522, 120, -463, -509, -115, 96, -412, 344, 16},
                {17, -1044, 775, -133, -1325, -149, -105, -806, -539, -741},
                {304, 56, -933, -890, 535, -152, 283, 229, 1362, 965},
                {-95, -38, -2354, -4, 965, 219, -1500, 1769, 1154, 1590},
                {-620, 4, -1564, -710, 2701, -1338, 1485, -657, 331, 897},
                {-1012, 1187, 1633, -1741, -1798, -1191, 126, 667, 2425, 46},
                {-644, -242, 391, -1942, -334, -64, 745, -131, 914, 838},
                {-317, -523, -594, -825, -988, 991, 1085, -257, 373, 99},
                {105, 565, -1483, 1147, 614, 1539, -364, -508, -389, -1703},
                {-819, 331, 196, 2209, -900, -340, -471, 118, -781, -684},
                {1250, -2406, -340, 925, -580, 416, -98, -850, -727, -664},
                {-200, -1120, -480, 1527, -516, 245, -685, 68, -1278, -331},
                {137, 542, -203, 464, -111, 323, -479, -399, -237, -77},
                {7, -352, 312, -839, 778, 836, -501, -154, 1087, 220},
                {712, 1207, 1556, -872, 431, 501, -752, -1718, 668, -1003},
                {602, -996, 745, -123, 965, -1148, -1411, 1678, -923, -888},
                {1558, -856, 14, 410, -1222, -1103, 752, -14, -1345, 602},
                {-305, -712, 645, 913, -46, -1199, -969, -469, 86, 727},
                {-588, -72, 655, 733, -20, -930, -197, 501, -1088, -244},
                {-541, -1298, -427, 564, 599, 342, 218, 997, -947, -444}
};

Your sketch doesn't compile. Please show a full code.

1 Like

Done, i add the LogNNet.h

Try define Y[] array in the LogNNet.h file and see what happened.
Does the result change?

I tried with [ ], with { }, with 'space', completing with 3 elements like 0 = 000, changed the line ending CF, CRLF, I tried also with the vector declared directly and nothing.

Have you not carefully studied the code, to figure out what it is doing?

The image is encoded as naked, binary bytes and is read in, byte by byte (785 of them), using the following line:

    Y[i] = Serial.read(); 
1 Like

I think it is extremely difficult, almost impossible, to send such an array manually through the Arduino Monitor. Here we need either an external program on a PC that will send data, or, for example, read from an SD card.
As an option, I suggested to OP to simply insert the array into the .h file, like his other arrays

1 Like

I highly recommend this outstanding Arduino ML tutorial, which demonstrats all aspects of "classical" ML, and the operation of the code is carefully explained.

The Arduino learns to recognize decimal digits from the patterns displayed on a seven segment LED display.

1 Like

ok, I understand what you are saying, but this code is not mine, it was published together with this work, how could the author have achieved the results using the same code?

Please explain more clear, how did you upload the Y[] array to the program?

1 Like

That was obvious.

What do you hope to learn by running the code? It merely demonstrates that this perfectly standard example of classical ML can be made to run on a tiny Arduino.

You should learn a great deal more by going through the tutorial linked above.

The author: "The testing process is performed by transferring images to the board one by one through the serial port. The transferred images have the original scale of 28 × 28 pixels, and are not pre-processed.
The algorithm of the program's operation checks in a loop the presence of data in the input buffer via the Serial.available function and reads all 784 bytes of the Y array."

So like I said, I've already tried send via the monitor serial the Y array like example:

The array of a digit "7" on MNIST is:

Resumo

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 185 159 151 60 36 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 222 254 254 254 254 241 198 198 198 198 198 198 198 198 170 52 0 0 0 0 0 0 0 0 0 0 0 0 67 114 72 114 163 227 254 225 254 254 254 250 229 254 254 140 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 66 14 67 67 67 59 21 236 254 106 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 253 209 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 233 255 83 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 129 254 238 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 249 254 62 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 254 187 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 205 248 58 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 126 254 182 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 251 240 57 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 221 254 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 203 254 219 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 38 254 254 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 31 224 254 115 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 254 254 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 242 254 254 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 254 254 219 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 254 207 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

So, I tried:

0 0 0 ...
0, 0, 0 ...
000 000 000 ...
000, 000, 000...
[0 0 0...]
[0, 0 0...]
{0, 0, 0...}
{0 0 0...}
[000 000 000...]
[000, 000, 000 ...]
{000, 000, 000 ...}
{000 000 000 ...}

Since that clearly doesn't work, you need to do something else.

2 Likes

And how did you trying that? Entering digits by keyboard manually? Upload from the file? Sending by some PC program???