Scraping DDG dengan python

from duckduckgo_search import DDGS
from pathlib import Path
from fastprogress.fastprogress import progress_bar
import requests
import uuid
from PIL import Image as PImage

root = Path().cwd()/"jilbabcantik"  #isikan nama folder
keywords = 'jilbab cantik'          #isikan kata kunci
max_results=20

links=[]
with DDGS(proxies="socks5://localhost:9150", timeout=20) as ddgs:
    ddgs_images_gen = ddgs.images(
      keywords,
      safesearch="off",
    )
    for r in ddgs_images_gen:    
        #print(r["image"])
        links.append(r["image"])
        if len(links) >= max_results:
            break


if(len(links) == 0):
    print("Tidak ada yang bisa diunduh!");

uuid_names=True
path = Path(root)
path.mkdir(parents=True, exist_ok=True)

print("Mengunduh hasil ke dalam", path)
pbar = progress_bar(links)
pbar.comment = 'Gambar yang diunduh'

i = 1
mk_uniq = lambda : '_' + str(uuid.uuid4())[:8] if uuid_names else ''
mk_fp = lambda x: path/(str(x).zfill(3) + mk_uniq() + ".jpg")
is_file = lambda x: len(list(path.glob(str(x).zfill(3) + '*.jpg'))) > 0

while is_file(i): i += 1 

results = []

for link in pbar:
      try:
        resp = requests.get(link)
        fp = mk_fp(i)
        fp.write_bytes(resp.content)

        try:
          img = PImage.open(fp)
          img.verify()
          img.close()
          results.append(Path(fp))
        except Exception as e:
          print(e)
          print(fp, " tidak valid")
          fp.unlink()
      except Exception as e:
         print(e)
         print("Terjadi pengecualian saat mengambil ", link)

      i += 1


Download MP3 dari YouTube dan situs lain degan JDownloader 2

//Add your script here. Feel free to use the available api properties and methods
if (link.finished) {
    var input = link.downloadPath;
    var output = input.replace(/(aac|m4a|ogg)$/, "mp3");

    if (input != output) {
        try {
            var ffmpeg = callAPI("config", "get", "org.jdownloader.controlling.ffmpeg.FFmpegSetup", null, "binarypath");
            var bitrate = callSync(ffmpeg, "-i", input).match(/bitrate: (\d+) kb/)[1];

            callAsync(function(error) {
                !error && getPath(input).delete();
            }, ffmpeg, "-y", "-i", input, "-b:a", bitrate + "k", output);
        } catch (e) {};
    }
}

Fix ampersamp in syntaxhighlighter

This can be done directly from the webinterface. Just go to Plugins -> Plugin Editor -> select the Plugin SyntaxHighlighter Evolved -> add the snippet to the end

/**
 * Filter to fix issue with & in SyntaxHighlighter Evolved plugin.
 *
 * @param string $code Code to format.
 * @param array $atts Attributes.
 * @param string $tag Tag.
 *
 * @return string
 */
function kagg_syntaxhighlighter_precode( $code, $atts, $tag ) {
    if ( 'code' === $tag ) {
        $code = wp_specialchars_decode( $code );
    }
    return $code;
}
add_filter( 'syntaxhighlighter_precode', 'kagg_syntaxhighlighter_precode', 10, 3 );

Sumber: https://nocin.eu/wordpress-syntaxhighlighter-ampersand-character/

Antarmuka Port Serial dengan C++

Gunakan Class Serial berikut:

//File: Serial.h
#ifndef SERIALCLASS_H_INCLUDED
#define SERIALCLASS_H_INCLUDED

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

class Serial
{
    private:
        //Serial comm handler
        HANDLE hSerial;
        //Connection status
        bool connected;
        //Get various information about the connection
        COMSTAT status;
        //Keep track of last error
        DWORD errors;

    public:
        //Initialize Serial communication with the given COM port
        Serial(char *portName);
        //Close the connection
        ~Serial();
        //Read data in a buffer, if nbChar is greater than the
        //maximum number of bytes available, it will return only the
        //bytes available. The function return -1 when nothing could
        //be read, the number of bytes actually read.
        int ReadData(char *buffer, unsigned int nbChar);
        //Writes data from a buffer through the Serial connection
        //return true on success.
        bool WriteData(char *buffer, unsigned int nbChar);
        //Check if we are actually connected
        bool IsConnected();


};

#endif // SERIALCLASS_H_INCLUDED

//File: Serial.cpp
#include "Serial.h"

Serial::Serial(char *portName)
{
    //We're not yet connected
    this->connected = false;

    //Try to connect to the given port throuh CreateFile
 #if _MSC_VER && !__INTEL_COMPILER
    const size_t cSize = strlen(portName) + 1;
    wchar_t* wc = new wchar_t[cSize];
    mbstowcs_s(NULL, wc, cSize, portName, cSize);
    this->hSerial = CreateFile(wc,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
#else
    //Try to connect to the given port throuh CreateFile
    this->hSerial = CreateFile(portName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
#endif

    //Check if the connection was successfull
    if(this->hSerial==INVALID_HANDLE_VALUE)
    {
        //If not success full display an Error
        if(GetLastError()==ERROR_FILE_NOT_FOUND){

            //Print Error if neccessary
            printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName);

        }
        else
        {
            printf("ERROR!!!");
        }
    }
    else
    {
        //If connected we try to set the comm parameters
        DCB dcbSerialParams = {0};

        //Try to get the current
        if (!GetCommState(this->hSerial, &dcbSerialParams))
        {
            //If impossible, show an error
            printf("failed to get current serial parameters!");
        }
        else
        {
            //Define serial connection parameters for the arduino board
            dcbSerialParams.BaudRate=CBR_9600;
            dcbSerialParams.ByteSize=8;
            dcbSerialParams.StopBits=ONESTOPBIT;
            dcbSerialParams.Parity=NOPARITY;
            //Setting the DTR to Control_Enable ensures that the Arduino is properly
            //reset upon establishing a connection
            dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;

             //Set the parameters and check for their proper application
             if(!SetCommState(hSerial, &dcbSerialParams))
             {
                printf("ALERT: Could not set Serial Port parameters");
             }
             else
             {
                 //If everything went fine we're connected
                 this->connected = true;
                 //Flush any remaining characters in the buffers
                 PurgeComm(this->hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR);
                 //We wait 2s as the arduino board will be reseting
                 Sleep(2000);
             }
        }
    }

}

Serial::~Serial()
{
    //Check if we are connected before trying to disconnect
    if(this->connected)
    {
        //We're no longer connected
        this->connected = false;
        //Close the serial handler
        CloseHandle(this->hSerial);
    }
}

int Serial::ReadData(char *buffer, unsigned int nbChar)
{
    //Number of bytes we'll have read
    DWORD bytesRead;
    //Number of bytes we'll really ask to read
    unsigned int toRead;

    //Use the ClearCommError function to get status info on the Serial port
    ClearCommError(this->hSerial, &this->errors, &this->status);

    //Check if there is something to read
    if(this->status.cbInQue>0)
    {
        //If there is we check if there is enough data to read the required number
        //of characters, if not we'll read only the available characters to prevent
        //locking of the application.
        if(this->status.cbInQue>nbChar)
        {
            toRead = nbChar;
        }
        else
        {
            toRead = this->status.cbInQue;
        }

        //Try to read the require number of chars, and return the number of read bytes on success
        if(ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL) && bytesRead != 0)
        {
            return bytesRead;
        }

    }

    //If nothing has been read, or that an error was detected return -1
    return -1;

}


bool Serial::WriteData(char *buffer, unsigned int nbChar)
{
    DWORD bytesSend;

    //Try to write the buffer on the Serial port
    if(!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0))
    {
        //In case it don't work get comm error and return false
        ClearCommError(this->hSerial, &this->errors, &this->status);

        return false;
    }
    else
        return true;
}

bool Serial::IsConnected()
{
    //Simply return the connection status
    return this->connected;
}


Berikut contoh koneksi pengiriman data

#include <iostream>
#include "windows.h"
#include "Serial.h"

#include <thread>
#include <chrono>

using namespace std;

void delay(int ms){
    std::this_thread::sleep_for (std::chrono::milliseconds(ms));
}

int main(int argc, char** argv) {

    char alamatPort[] = "\\\\.\\COM7";
    Serial* s = new Serial(alamatPort);

	char dataOn[256] = "on1\n"; //"Nyala!";
	char dataOff[256] = "off0\n"; //"mati!";

	cout<<"isikan angka 1 untuk menyalakan, atau 0 untuk mematikan"<<endl;


	int jawab;
	do{
        cin>>jawab;;

        if(jawab==0)
            s->WriteData(dataOff, sizeof(dataOff));
        if(jawab==1)
            s->WriteData(dataOn, sizeof(dataOn));
        if(jawab==2)
            for(int a=0;a<5;a++){
                s->WriteData(dataOn, sizeof(dataOn));
                delay(500);
                s->WriteData(dataOff, sizeof(dataOff));
                delay(500);
            }
	}while(jawab<3);

	return 0;
}

Berikut contoh untuk mengirim dan menerima data

#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include "Serial.h" // Library described above
#include <string>


/* run this program using the console pauser or add your own getch, system("pause") or input loop */
char alamatPort[] = "\\\\.\\COM7";
Serial* SP = new Serial(alamatPort);    // adjust as needed

void* baca(void* data)
{

    char incomingData[256] = "";            // don't forget to pre-allocate memory
    //printf("%s\n",incomingData);
    int dataLength = 256;
    int readResult = 0;


    while (SP->IsConnected())
    {
        readResult = SP->ReadData(incomingData, dataLength);
        if (readResult > 0) {
            printf("%s\n", incomingData);
        }
        //printf("Bytes read: (-1 means no data available) %i\n",readResult);

        //std::string test(incomingData);

        //printf("%s",incomingData);
        //test = "";

        Sleep(500);
    }
    return NULL;
}

void* tulis(void* data)
{
    while (SP->IsConnected())
    {
        char outgoingData[256] = "";
        char keluar[256] = "keluar";
        int dataLength = sizeof(outgoingData);        // don't forget to pre-allocate memory
        scanf_s("%255s", outgoingData, dataLength);

        if (outgoingData != "")
        {
            if (strcmp(outgoingData, "OK") == 0) {
                printf("Pengiriman selesai\n");
                return NULL;

            }
            if (SP->WriteData(outgoingData, dataLength))
            {
                printf("Data send:%s\n", outgoingData);
            }
        }

        Sleep(500);
    }
    // do stuff...
    return NULL;
}

#if _MSC_VER && !__INTEL_COMPILER
#include <thread>

int main(int argc, char** argv) {
    printf("Welcome to the serial test app!\n\n");
    if (SP->IsConnected())
        printf("Serial sudah terhubung\n");
    int status;
    std::thread thrd_1(baca,(void*)0);
    std::thread thrd_2(tulis, (void*)0);

    thrd_1.join();
    thrd_2.join();

}
#else
// thread example
#include <pthread.h>

int main(int argc, char** argv) {
    printf("Welcome to the serial test app!\n\n");
    if (SP->IsConnected())
        printf("Serial sudah terhubung\n");

    pthread_t thrd_1;
    pthread_t thrd_2;
    int status;

    pthread_create(&thrd_1, NULL, baca, (void*)0);
    pthread_create(&thrd_2, NULL, tulis, (void*)0);

    pthread_join(thrd_1, (void**)&status);
    pthread_join(thrd_2, (void**)&status);

    printf("Terima kasih");

    return 0;
}
#endif

String dan Pointer C++

typedef struct
{
  int x, y;
  short life;
  char *nama;
} Man;

void setup() {
  Serial.begin(9600);

  //menggunakan 4 memori untuk string
  String hi = "Hello";
  String names = "World";
  String hello = hi + " " + names;

  //menggunakan 1 memori
  String greeting = hi;
  greeting.concat(" ");
  greeting.concat(names);



  String tempname = "Temperature";
  String temp = "23C";
  PrintVal1(tempname, temp); //membuat string redundan. Lihat fungsi
  PrintVal2(tempname, temp); //pass by reference, tidak redundan. Lihat fungsi

  char thestring[30] = "This is a string";
  //thestring = "New content"; //cara yang salah, panjang string harus sama!
  strcpy(thestring, "New content"); //good method

  char isgood[8] = "is good";
  //char allbad[38] = thestring + isgood; //cara yang salah, ini adalah operasi biner. gunakan strcat
  char allgood[38];
  strcat(allgood, thestring); strcat(allgood, isgood);



  char a[2] = "A"; char b[2] = "A";
  if (a == b) {}//cara yang salah, akan selalu bernilai false
  if (strcmp(a, b) == 0 ) {} //car yang benar, atau gunakan strcasecmp()


  //pointer
  int var = 0;
  int arr[] = {1, 2, 3};
  int *ptr;           //init, don't set to NULL (destroy), *ptr = 0, first address? no!
  ptr = &var;         //to address of var, not the value of var
  *ptr = 50;;         //pointer content is 50
  //ptr = 50;         //pointer (address) is 50
  //ptr++;            //pointer address + 1

  ptr = arr;         //to array
  ptr[0] = 50;      //array number 0, is 50
  ptr = &arr[0];     //equal to above, array number 0 is 50

  Man *ptrMan;
  Man manusia = {0, 0, 0, NULL};
  manusia.life = 9;       //kucing :D
  manusia.nama = "Todol"; //pointer in struct
  ptrMan = &manusia;
  ptrMan-> life = 0;         //mati
  
  char *pString = "This is text"; //not safe to change content! don't do!
  const char *pStringSafe = "This is text"; //display warning when change content

  char temperature[] = "23C"; //constant
  //Following syntax is not compiler friendly, it will be unhappy
  PrintValP("Temperature", temperature);
  //The following will make compiler happier (look at the fuction!)
  PrintValPC("Temperature", temperature);

  PrintString(temperature);
}


//make 2 new strings, redundant string
void PrintVal1(String tag, String value) {
  Serial.print(tag);
  Serial.print(" = ");
  Serial.println(value);
}

//pass by reference
void PrintVal2(String &tag, String &value) {
  Serial.print(tag);
  Serial.print(" = ");
  Serial.println(value);
}

//pass by pointer
void PrintValP(char *tag, char *value) {
  Serial.print(tag);
  Serial.print(" = ");
  Serial.println(value);
}
void PrintValPC(const char *tag, const char *value) {
  Serial.print(tag);
  Serial.print(" = ");
  Serial.println(value);
}
void PrintString(const char *str) {
  const char *p;
  p = str;
  while (*p) {
    Serial.print(*p);
    p++;
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

Raspberry Bluetooth Printer

You have to perform several steps in order to establish communication.

You have to pair your desired bluetooth device using bluetoothctl

sudo bluetoothctl -a

scan on

devices

pair XX:XX:XX:XX:XX:XX

trust XX:XX:XX:XX:XX:XX

quit

Where XX:XX:XX:XX:XX:XX is the MAC address of your bluetooth device.

You have to create the serial device that binds to your paired bluetooth device.

sudo rfcomm bind /dev/rfcomm0 XX:XX:XX:XX:XX:XX 1

The last number is the communication channel. It has to bee unique for all your connections.

Then you should be able to open a connection. (Assuming your bluetooth device actually supports the required SPP protocol.)

echo “test” > /dev/rfcomm0

source: https://raspberrypi.stackexchange.com/questions/78155/using-dev-rfcomm0-in-raspberry-pi/78301#78301?s=39be540452a34b55af09cb19d04ea700

Machine Learning #7 – Menuju Klasifikasi

Pada tulisan Machine Learning #5 telah diceritakan tentang Neural Network dengan 2 input dan 1 output. Mari kita kembangkan jika menggunakan 1 input dan 2 output. Percobaan ini mengarah ke klasifikasi.

Sabagai gambaran apabila inputnya adalah suara yang diubah menjadi nilai dalam bentuk matrik x dan hasilnya adalah 2 output, yaitu output y= [0 0]. Output y = [1 0], jika hasil klasifikasinya mengarah pada output pertama, misalkan saya kata “YA”, dan outputnya y = [0 1] jika hasil klasifikasinya adalah output kedua, misalkan kata “Tidak”.

Dari model di atas, tentunya agak kesulitan untuk diterapkan di mikrokontroler. Hasil dari training dalam bentuk TFLite >5Mb. Padahal mikrokontroler, katakanlah BLE 33 Sense, tidak memiliki Flash Memori yang berkapasitas 5Mb

Cara yang pertama yaitu mengubah kuantisasi dari float menjadi int pada mikrokontoler. Berikut contoh perbandingan kuantisasi menggunakan float dibandingkan menggunakan int. Memang akurasi menjadi sedikit berubah, namun penggunaan memori jauh lebih kecil.

Menghilangkan parameter yang tidak begitu penting, dengan pruning.

Dan beberapa proses yang dapat disimpulkan seperti gambar berikut:

Machine Learning #6 – Menerapkan Machine Learning ke Mikrokontroler (via Arduino + TinyML)

Dilihat dari situs resmi TensorFlow, saat ini board yang support dengan model training TensorFlowLite adalah board berikut:

Jadi mari kita gunakan yang saya punya, yaitu ESP-EYE (murah, 200an ribu) dan Nano 33 BLE Sense (mahal, 1,2 juta).

Untuk dapat menggunakan TinyML ada penjelasan di situs resminya, tapi cukup ribet. Mari gunakan milik Simone yang bernama EloquentTinyML. Siapkan dahulu library-nya melalui Library Manager

Selanjutnya pilih papan (board) yang tepat. Untuk Nano 33 BLE Sense lihat tutorialnya di tulisan Mencoba Nano 33 BLE Sense sedangkan jika menggunakan ESP-EYS, lihat tutorialnya di tulisan Memulai Percobaan ESP-CAM. Dicontohkan untuk kali ini kita gunakan Nano 33 BLE Sense:

Tuliskan sketch pada arduino dengan kode berikut:

#include <EloquentTinyML.h>
#include "sine_model.h"

#define NUMBER_OF_INPUTS 1
#define NUMBER_OF_OUTPUTS 1
#define TENSOR_ARENA_SIZE 2*1024

Eloquent::TinyML::TfLite<NUMBER_OF_INPUTS, NUMBER_OF_OUTPUTS, TENSOR_ARENA_SIZE> ml;


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

void loop() {

    float x = 3.14 * random(100) / 100;
    float y = sin(x);
    float input[1] = { x };
    float predicted = ml.predict(input);

    Serial.print("Nilai sin(");
    Serial.print(x);
    Serial.print(") = ");
    Serial.print(y);
    Serial.print("\t Nilai prediksi: ");
    Serial.println(predicted);
    delay(1000);
}

Pada baris 2, isikan nama file hasil pengubahan tflile, misalkan hasilnya adalah sine_model.h Model yang akan digunakan adalah model 1 input dan 1 ouput sesuai pada artikel Machine Learning #3 Selanjutnya ketikkan jumlah input dan jumlah outputnya seperti yang dicontohkan di baris 4 dan 5, yaitu 1 input dan 1 output.

Di baris 8, adalah inisialisasi object EloquentTinyML sedangkan baris 13 adalah membaca model sine_model.h agar dapat diproses oleh library TinyML.

Untuk melihat hasil prediksi cukup gunakan .predict(nilai input) seperti yang terlihat di baris 21.

Saatnya upload skecth ke Nano 33 BLE Sense

Penampakan Nano 33 BLE Sense

Mari dilihat hasilnya, apakah mikrokontroler mampu memprediksi nilai y berdasarkan nilai input x? dimana rumus sebenarnya adalah y = sin(x). Mungkin ada sedikit selisih, namun untuk percobaan dengan 1 hidden layer ini bisa dimaklumi. Perlu banyak neuron dan hidden layer untuk mendapatkan nilai kesalahan (loss) yang sangat kecil.

Machine Learning #5 – Persiapan File Model untuk Mikrokontroler

Setelah mendapatkan model dari hasil training, model dapat disimpan ke file .tflite, file ini dapat kita gunakan untuk framework lain misalnya untuk mikrokontroller. Untuk membentuk file .tflite dari hasil training gunakan kode berikut:

# Convert model ke file tflite
tflite_model_name = 'sine_model'  # .tflite 

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
tflite_model = converter.convert()

#for 1.2 to 2.3
#open(tflite_model_name + '.tflite', 'wb').write(tflite_model)

#for 2.4 or later
with tf.io.gfile.GFile(tflite_model_name +'.tflite', 'wb') as f:
  f.write(tflite_model)


Hasil dari code diatas adalah file sine_model.tflite atau dapat mnegubah nama filenya di baris 2

Karena mikrokontroler yang akan digunakan dibangun menggunakan bahasa C, maka perlu mengubah tflite menjadi file header agar dapat dikenali pada bahasa pemrograman C. Ada code fungsi (prosedur) yang sudah dibuat oleh pegiat machine learning, tinggal dipakai saja.

# Function: Convert some hex value into an array for C programming
def hex_to_c_array(hex_data, var_name):

  c_str = ''

  # Create header guard
  c_str += '#ifndef ' + var_name.upper() + '_H\n'
  c_str += '#define ' + var_name.upper() + '_H\n\n'

  # Add array length at top of file
  c_str += '\nunsigned int ' + var_name + '_len = ' + str(len(hex_data)) + ';\n'

  # Declare C variable
  c_str += 'unsigned char ' + var_name + '[] = {'
  hex_array = []
  for i, val in enumerate(hex_data) :

    # Construct string from hex
    hex_str = format(val, '#04x')

    # Add formatting so each line stays within 80 characters
    if (i + 1) < len(hex_data):
      hex_str += ','
    if (i + 1) % 12 == 0:
      hex_str += '\n '
    hex_array.append(hex_str)

  # Add closing brace
  c_str += '\n ' + format(' '.join(hex_array)) + '\n};\n\n'

  # Close out header guard
  c_str += '#endif //' + var_name.upper() + '_H'

  return c_str


Selanjutnya, gunakan fungsi di atas untuk mengubah .tflite menjadi .h, nama filenya dapat diset pada baris ke-2. Kali ini dinamai dengan sine_model.h

# Write TFLite model to a C source (or header) file
c_model_name = 'sine_model'       # .h 

with open(c_model_name + '.h', 'w') as file:
  file.write(hex_to_c_array(tflite_model, c_model_name))

Machine Learning #4 – 2 input, 3 HL, 1 output

Kali ini mari membuat model untuk 2 input dan 1 output dengan menggunakan 3 hidden layer. Sebagai contoh kasus ada data dengan rumus matematika: y = cos(x1) – sin(x2) + sin(x1+x2) data ini memiliki 1 input yaitu x1 dan x2. Sedangkan nilai outputnya 1 , yaitu y. Apakah MESIN bisa memprediksi rumus matematika di atas? Mari kita mulai dengan membuat datanya.

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import math
from tensorflow.keras import layers

# Membuat 100, 77 dan 66 nilai random berdasarkan seed 1234
np.random.seed(1234)
x1_values = np.linspace(0,2*math.pi,100)
x2_values = np.linspace(0,2*math.pi,100)
x1_valuesV = np.linspace(0,2*math.pi,77)
x2_valuesV = np.linspace(0,2*math.pi,77)
x1_valuesT = np.linspace(0,2*math.pi,66)
x2_valuesT = np.linspace(0,2*math.pi,66)

# masing masing nilai dibuat dalam bentuk sinusoida, cos(x1) - sin(x2) + sin(x1+x2)
y_values = np.sin(x1_values) - np.cos(x2_values) - np.sin(x1_values+x2_values) + (0.2 * np.random.randn(x1_values.shape[0]))
y_valuesV = np.sin(x1_valuesV) - np.cos(x2_valuesV) - np.sin(x1_valuesV+x2_valuesV) + (0.2 * np.random.randn(x1_valuesV.shape[0]))
y_valuesT = np.sin(x1_valuesT) - np.cos(x2_valuesT) - np.sin(x1_valuesT+x2_valuesT) + (0.2 * np.random.randn(x1_valuesT.shape[0]))

plt.plot(x1_values, y_values, 'r.', label="Data u/ Training")
plt.plot(x1_valuesV, y_valuesV, 'b.', label="Data u/ Validasi")
plt.plot(x1_valuesT, y_valuesT, 'g.', label="Data u/ Test")
plt.legend()


Kode di atas adalah untuk membuat data training, data validasi dan data test. Hasil dari plot data x dan y adalah berikut:

Selanjutnya mari kita buat permodelan NN seperti berikut:

Karena inputnya 2, maka baris 28 kita ketikkan: input_shape=(2,)

# Membuat model dengan 3 hidden layer
model = tf.keras.Sequential()
model.add(layers.Dense(2, activation='tanh', input_shape=(2,)))
model.add(layers.Dense(10, activation='tanh'))
model.add(layers.Dense(10, activation='tanh'))
model.add(layers.Dense(10, activation='tanh'))
model.add(layers.Dense(1))
# Lihat pemodelan, lihat secara grafis di https://alexlenail.me/NN-SVG/index.html
model.summary()

Kedua input (x1 dan x2) perlu dibuat stack agar dapat diproses untuk permodelan. Kali ini, data training dan data validasi saja yang perlu dibuat stack. Lihat cara membuat stack pada baris 36-37.

x1x2_array = np.stack([x1_values, x2_values], axis=1)
x1x2V_array = np.stack([x1_valuesV, x2_valuesV], axis=1)

Saatnya membuat model. Kali ini menggunakan tensorboard untuk memvisualisasikannya. Jumlah epochnya adalah 1000 percobaan, dengan batch size 100

import datetime
%load_ext tensorboard
log_dir =  datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)

# Gunakan optimizer adam , loss function Mean square error
model.compile(optimizer='adam', loss='mse', metrics=['mse'])

# Training model
#model.fit(x1x2_array,y_values, batch_size=100, epochs=1000)
history = model.fit(x1x2_array, y_values, epochs=1000, batch_size=100,
   validation_data=(x1x2V_array, y_valuesV), 
          callbacks=[tensorboard_callback])

# %tensorboard --logdir logs/gradient_tape # buka komentar jika ingin melihat di tensorboard

Setelah proses belajar berlangsung, saatnya mencoba, membutktikan prediksi MESIN dengan data yang sebenarnya

# Plot hasil prediksi terhadap nilai sebenarnya yaitu y = sin(x)
x1x2T_array = np.stack([x1_valuesT, x2_valuesT], axis=1)

predictions = model.predict(x1x2T_array)

plt.clf()
plt.title("Perbandingan nilai Test dengan nilai Prediksi")
plt.plot(x1_valuesT, y_valuesT, 'b.', label='Nilai Test')
plt.plot(x1_valuesT, predictions, 'r.', label='Nilai  Prediksi')
plt.legend()
plt.show()

Ternyata hasil prediksi mesin mirip dengan data sebenarnya. Hanya saja pada nilai input 5 ke atas masih ada kesalahan. Titik warna merah(nilai prediksi), terletak agak jauh dengan titik warna biru(nilai seharusnya). Untuk memperbaikinya bisa dengan mengubah aktivasi, menambah neuron atau layer. Silahkan dicoba coba hingga hasil terbaik. Setidaknya MESIN sudah belajar dengan baik

Jika ingin menyimpan hasil model training, skrip kode berikut bisa digunakan untuk mengexport model hasil training ke tflite. Dengan file tflite ini kita bisa gunakan untuk menyimpan hasilnya dan dibuka di platform lain.

# Convert Keras model to a tflite model
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
tflite_model = converter.convert()

#for 1.2 to 2.3
#open(tflite_model_name + '.tflite', 'wb').write(tflite_model)

#for 2.4 or later
with tf.io.gfile.GFile('2input.tflite', 'wb') as f:
  f.write(tflite_model)