Sunday, 29 December 2019

Working with Multiple Git Remotes

Git clone from main remote:
git clone -b dev https://.../PROJECT.git

Git add another remote:
git remote add project2 https://.../PROJECT2.git
git fetch project2
git checkout -b dev-project2 project2/dev

Git merge and copy files:
git checkout branch1
git merge    branch2   #merge branch2 into current branch
git checkout branch2 . #copy branch2 into current dir

Git push to remotes
git push origin HEAD:dev
git push project2 HEAD:dev

Local branches:
  • dev
  • dev-project2
  • dev-project3
  • ...
Main remote branches:
  • dev
  • master
Other remote branches:
  • dev
  • master

Create Custom Syntax Colouring in Amazon Cloud9

Amazon AWS Cloud9 IDE by now (2019) is having no feature to create custom syntax colouring, only choose from available ones. But there's a work-around here:
  1. Make theme CSS
    Go to some temporary dir:
    git clone https://github.com/ajaxorg/ace
    cd ace/tool
    npm i
    node tmtheme.js THEME-NAME \
    /path/to/some-theme.tmtheme /path/to/output/dir
  2. Edit the theme CSS
    Go to /path/to/output/dir
    Open THEME-NAME.css
    Replace the prefix CSS class ".ace-XXX" to ".ace_content"
    Ctrl-A (Select all CSS), Ctrl-C (Copy)
  3. Apply the theme CSS
    Open Cloud9 IDE, go to Preferences >> Themes >> Edit your stylesheet
    Ctrl-V (Paste the CSS), Ctrl-S (Save)
  4. See it applied!
    Open any file, to enjoy the custome theme.
Reference:
https://community.c9.io/t/how-do-i-upload-a-custom-theme-to-my-workspace/20893/3

Saturday, 28 December 2019

Prevent Some Commands from Running in Bash

Bash loads these files when start and exit:
  • All users:
    • Start up file: /etc/profile (TTY only)
    • Start up file: /etc/bashrc (TTY & PTY, CentOS)
    • Start up file: /etc/bash.bashrc (TTY & PTY, Ubuntu)
    • Exit file:     /etc/bash.bash_logout (TTY only)
  • Specific user:
    • Start up file: ~/.bash_profile (TTY only)
    • Start up file: ~/.bashrc (TTY & PTY, All Linuxes)
    • Exit file:     ~/.bash_logout (TTY only)
To prevent some commands from running, for example "sudo rm", add a function similar to this to the a start up  file:

function sudo {
  if [[ $1 == "rm" ]]; then
    echo "Command not allowed: sudo rm";
  else
    #the doublequotes are important to run
    #commands with quotes/doublequotes
    command sudo "$@";
  fi
}

Thursday, 26 December 2019

A Full-feature Low-level TensorFlow Programme (Update)

The following code implements a full-feature low-level TensorFlow programme with:
  • Model based on tf.Module
  • A sample Keras layer tf.keras.layers.Dense
  • A sample raw TensorFlow layer with tf.Variable
  • Initialisation of layers with tf.random.uniform
  • Use of rectifier and sigmoid-like in model
  • Autograph with @tf.function
  • Load and normalise data
  • Create a batch generator (tf.data.Dataset)
  • Sample user of loss function and optimiser
  • Train model (adjust weights) loop with gradient calculation and applying gradient
  • A simple way to calculate average loss after a number of batches
  • Save model to a directory with tf.saved_model.save
  • Load a model from a directory with tf.saved_model.load
  • Continue training the model
  • Infer the training data with the trained model.
Source code:
%tensorflow_version 2.x
%reset -f

#libs
import tensorflow as tf;
from tensorflow.keras.layers import *;

#constants
DSIZE = 4;
BSIZE = 2;

#model
class model(tf.Module):

  #constructor
  def __init__(this):
    #utilise a keras layer
    this.Layer1 = Dense(30, tf.nn.leaky_relu, name="layer1");

    #raw tf layer
    this.W2 = tf.Variable(tf.random.uniform([30,20], -1,1, tf.float32), name="layer2w");
    this.B2 = tf.Variable(tf.random.uniform([   20], -1,1, tf.float32), name="layer2b");

    #single neuron output layer, also raw
    this.W3 = tf.Variable(tf.random.uniform([20,1], -1,1, tf.float32), name="layer3w");
    this.B3 = tf.Variable(tf.random.uniform([   1], -1,1, tf.float32), name="layer3b");

  #model call
  @tf.function(input_signature=[tf.TensorSpec([BSIZE,2], tf.float32)])
  def __call__(this,Inp):
    H1  = this.Layer1(Inp);
    H2  = tf.nn.leaky_relu(tf.matmul(H1,this.W2) + this.B2);
    Out = tf.sigmoid(tf.matmul(H2,this.W3) + this.B3); 
    return Out;

#PROGRAMME ENTRY POINT==========================================================
#data (XOR data for example)
X = tf.constant([[0,0],[0,1],[1,0],[1,1]], tf.float32);
Y = tf.constant([[0  ],[1  ],[1  ],[0  ]], tf.float32);

#normalise data to range [0,1]
X = X/tf.reduce_max(X);
Y = Y/tf.reduce_max(Y);

#make batch generator
Data = tf.data.Dataset.from_tensor_slices((X,Y));
Data = Data.repeat().shuffle(DSIZE).batch(BSIZE,drop_remainder=True);

#train
Model = model();
Loss  = tf.losses.MeanSquaredError();
Optim = tf.optimizers.SGD(1e-1);
Steps = 1000;
Laft  = 100;
Lsum  = 0;
Iter  = iter(Data);

for I in range(Steps):
  Batch = next(Iter);
  Inp   = Batch[0]; #input
  Exp   = Batch[1]; #expected

  with tf.GradientTape() as T:
    Lval  = Loss(Exp,Model(Inp));
    Lsum += Lval.numpy();

  Grads = T.gradient(Lval, Model.trainable_variables);
  Optim.apply_gradients(zip(Grads, Model.trainable_variables));

  if I%Laft==Laft-1:
    print("Average Loss:",Lsum/Laft);
    Lsum = 0;

#save
print("\nSaving model...");
Model_Dir = "/tmp/my-model";
tf.saved_model.save(Model,Model_Dir);
%ls -laX --group-directories-first /tmp/my-model

#load back model
print("\nLoading back model...");
Model = tf.saved_model.load(Model_Dir);
print(vars(Model).keys());

#continue training the model
print("\nContinue training...");
for I in range(Steps):
  Batch = next(Iter); #load another dataset or use back the infinite Iter above
  Inp   = Batch[0];
  Exp   = Batch[1];

  with tf.GradientTape() as T:
    Lval  = Loss(Exp,Model(Inp));
    Lsum += Lval.numpy();

  Params = Model.Layer1.trainable_variables + [Model.W2,Model.B2,Model.W3,Model.B3];
  Grads  = T.gradient(Lval, Params);
  Optim.apply_gradients(zip(Grads, Params));

  if I%Laft==Laft-1:
    print("Average Loss:",Lsum/Laft);

#infer the training data
print("\nInferring the training data...");
Data = tf.data.Dataset.from_tensor_slices((X,Y));
Data = Data.batch(BSIZE,drop_remainder=True);

for Inp,Exp in Data:
  print("Input:");
  print(Inp.numpy());
  print("Expected:");
  print(Exp.numpy());
  print("Prediction:");
  print(Model(Inp).numpy());
  print();
#eof

Result:
Average Loss: 0.10872401443310081 Average Loss: 0.01269742899108678 Average Loss: 0.00553579420549795 Average Loss: 0.0033595020952634515 Average Loss: 0.0023345320229418575 Average Loss: 0.001752474318491295 Average Loss: 0.0013855347724165768 Average Loss: 0.0011406122986227273 Average Loss: 0.0009637939184904098 Average Loss: 0.0008266885939519853 Saving model... INFO:tensorflow:Assets written to: /tmp/my-model/assets total 36 drwxr-xr-x 2 root root 4096 Dec 26 10:57 assets/ drwxr-xr-x 2 root root 4096 Dec 26 11:06 variables/ drwxr-xr-x 4 root root 4096 Dec 26 11:06 ./ drwxrwxrwt 1 root root 4096 Dec 26 11:06 ../ -rw-r--r-- 1 root root 18839 Dec 26 11:06 saved_model.pb Loading back model... dict_keys(['_self_setattr_tracking', '_self_unconditional_checkpoint_dependencies',
'_self_unconditional_dependency_names', '_self_unconditional_deferred_dependencies',
'_self_update_uid', '_self_name_based_restores',
'Layer1', 'W2', 'B2', 'W3', 'B3',
'signatures', '__call__', 'tensorflow_version', 'tensorflow_git_version']) Continue training... Average Loss: 0.000725053078494966 Average Loss: 0.001368767161620781 Average Loss: 0.0019466301079955884 Average Loss: 0.0024687587827793324 Average Loss: 0.002944960643653758 Average Loss: 0.00338194992946228 Average Loss: 0.003784944185754284 Average Loss: 0.0041586664071655835 Average Loss: 0.004504695165960584 Average Loss: 0.0048269858321873475 Inferring the training data... Input: [[0. 0.] [0. 1.]] Expected: [[0.] [1.]] Prediction: [[0.01820062] [0.98395973]] Input: [[1. 0.] [1. 1.]] Expected: [[1.] [0.]] Prediction: [[0.9820526] [0.0182383]]

ML in TensorFlow: Single Neuron Linear Activation Regression

The most basic model in machine learning is a model of:
  • Single neuron 
  • With linear (identity) activation, 
  • That does regression.
The training process loop:
  • 1. Generate a batch (should not generate them all before training loop as the steps may be real high like hundreds of thousands and it takes all the RAM)
  • 2. Feed the batch of samples to the model
  • 3. Show average loss after certain number of steps
The steps 1 and 2 above affect the total performance, so it is suggested to use all the features of TensorFlow together for the best, ie. use tf.data.Dataset together with the model decorated by @tf.function.

Source code:
%tensorflow_version 2.x
%reset -f

#libs
import tensorflow as tf;

#constants
DSIZE = 4#num samples in the whole dataset
BSIZE = 2#num samples in a batch

#model
class model(tf.Module):

  #constructor
  def __init__(this):
    this.W1 = tf.Variable(tf.random.uniform([2,1], -1,1, tf.float32));
    this.B1 = tf.Variable(tf.random.uniform([  1], -1,1, tf.float32));

  #model call
  @tf.function(input_signature=[tf.TensorSpec([BSIZE,2], tf.float32)])
  def __call__(this,Inp):
    Out = tf.identity(tf.matmul(Inp,this.W1) + this.B1);
    return Out;

#PROGRAMME ENTRY POINT==========================================================
#data
X = tf.constant([[1,2],[3,4],[5,6],[7,8]], tf.float32);
Y = tf.constant([[3  ],[5  ],[7  ],[9  ]], tf.float32);

Data = tf.data.Dataset.from_tensor_slices((X,Y));
Data = Data.repeat().shuffle(DSIZE).batch(BSIZE,drop_remainder=True);
Iter = iter(Data);

#train
Model = model();
Loss  = tf.losses.MeanSquaredError();
Optim = tf.optimizers.SGD(1e-3);
Steps = 1000#number of batches to process
Laft  = 100;  #log loss after every this num batches
Lsum  = 0;

for I in range(Steps):
  Batch = next(Iter);
  Inp   = Batch[0];
  Exp   = Batch[1];

  with tf.GradientTape() as T:
    Lval  = Loss(Exp,Model(Inp));
    Lsum += Lval.numpy();

  Grads = T.gradient(Lval, Model.trainable_variables);
  Optim.apply_gradients(zip(Grads, Model.trainable_variables));

  if I%Laft==Laft-1:
    print("Average Loss:",Lsum/Laft);
    Lsum = 0;
#eof

Result:
Average Loss: 2.1378963772580026 Average Loss: 0.21530249016243033 Average Loss: 0.19278635787957682 Average Loss: 0.17028992957601305 Average Loss: 0.15324589672891306 Average Loss: 0.13415179751318645 Average Loss: 0.12121034623822197 Average Loss: 0.10616741587153228 Average Loss: 0.09501745967809257 Average Loss: 0.08556641670929821

Wednesday, 25 December 2019

Amazon AWS Cloud9 IDE and What Can Be Done with It

Cloud9 IDE was bought by Amazon and added to Amazon AWS a few years ago, it's a full IDE with all necessary features including a true terminal in which to run commands and also text editors like Vim, Nano, Micro, etc. Cloud9 IDE connects to servers through SSH protocol.

Access point:
https://console.aws.amazon.com/cloud9

What can be done with Cloud9 IDE:
  • Do web programming for webapps, websites.
  • Do console programming for text-output-only programmes.
  • Do AI & ML programming on servers as text output is enough.
  • Do system administration programming in shell, eg. Bash.
What CAN'T be done with Cloud9 IDE:
  • Desktop programming (can't build and run desktop apps)
  • Mobile programming (can't build and run mobile apps on emulators)
  • Browser extension programming (can't load dev mode extension from server)
Cloud9 IDE show syntax highlighting more most of the major programming languages. It has some tens of syntax themes, however, they can't be customised like on desktop which Sublime Text is very powerful to customise any syntax; use what available only.

Commonly described, Cloud9 IDE is a good option for projects with online aspect. For offline projects, it's hard to use this IDE.

Embed Programming for Browser

Browser embed programming (not embedded programming that is ASIC programming) for browser can be these presently:
  • ActiveX (Windows only, dead technology)
  • Java Applet (disabled by all browsers, dead technology)
  • Flash (disabled by all browsers, dead technology)
  • Canvas (programmed with JavaScript, recommended technology)
  • WebAssembly (programmed with any programming language)
Canvas is recommended, WebAssembly is useful when porting applications from mobile, desktop to browser by compiling C/C++ into WebAssembly so the apps won't need to be coded twice.

How Should Google V8 JIT Compiler Compile Better

Node.js (JavaScript) is a very convenient programming language but it has a drawback: It's a non-typed language.

Google V8 is a JIT (Just-in-Time) compiler that compiles JS code to native code. However, JS is non-typed language so for primitive variables, the compiled code has to look-up for variables all the times as primitive variables are stored as pointers instead of direct values.

How to solve the primitive pointer problem?
Google V8 should compile to typed binary code by automatically assign the types for variables when their values first set.

Automatic type assignment will lead to run-time error (not compile-time error) when changing the variable value to another type, but for good practice in programming, a variable should keep its type through out the programme.

With automatic type assignment, the compiled Node.js/Cython code will be as fast as C/C++. Oh mum, why hasn't Google done this?

Performance of Programming Languages

Generations of programming languages:
  1. Generation 1(A): Punched card (Binary)
  2. Generation 2(B): Assembly (Text)
  3. Generation 3(C): High-level (Text, eg. C, Pascal)
  4. Generation 4(D): High-level with OOP (Text, eg. C++, Pascal)
  5. Generation 5(E): High-level with OOP and markup (Text, eg. Qt-over-C++)
Performance of programming languages, the later the slower:
  1. Assembly (top performance, but labourious development)
  2. Typed languages, run natively on CPU (eg. C/C++) - Performance
    1. Compiler/JIT compiler (faster)
    2. Interpreter (slower)
  3. Typed languages, run on VM (eg. Java) - No points
    1. Compiler/JIT compiler (faster)
    2. Interpreter (slower)
  4. No-type languages, run natively on CPU (eg. Node.js, Cython) - Convenient
    1. Compiler/JIT compiler (faster)
    2. Interpreter (slower)
  5. No-type languages, run on VM (eg. Python) - AI and ML
    1. Compiler/JIT compiler (faster)
    2. Interpreter (slower)
There's most likely no languages nowadays that has interpreter to process code files directly; interpreters compile code files to bytecode, for example: .pyc is Python compiled bytecode to be run in Python virtual machine.

Tuesday, 24 December 2019

A Full-feature Low-level TensorFlow Model

A low-level TensorFlow model should be created with tf.Module, and for the ease of save and load, use tf.saved_model APIs.

Beside the raw tf.Variable(s), a full-feature TensorFlow model should contain Keras layers too: Dense, ConvXD, LSTM, MaxPoolXD, RNN, GRU, etc.

Remember to use the decorator @tf.function to convert Python code into graph in C++ for performance.

Data feeding is also a matter in model training performance, use APIs in  tf.data module for this.

Source code:
%tensorflow_version 2.x
%reset -f

#libs
import tensorflow as tf;
from tensorflow.keras.layers import *;

#global constants
BSIZE=4;

#model
class model(tf.Module):

  #constructor
  def __init__(this):
    #example Keras layer to use inside tf.Module
    this.Layer1 = Dense(30, tf.nn.leaky_relu); 

    #raw params
    this.W2 = tf.Variable(tf.random.uniform([30,20], -1,1, tf.float32));
    this.B2 = tf.Variable(tf.random.uniform([   20], -1,1, tf.float32));
    this.W3 = tf.Variable(tf.random.uniform([201], -1,1, tf.float32));
    this.B3 = tf.Variable(tf.random.uniform([    1], -1,1, tf.float32));

  #model call
  @tf.function(input_signature=[tf.TensorSpec([BSIZE,2], tf.float32)])
  def __call__(this,Inp):
    H1  = this.Layer1(Inp);
    H2  = tf.nn.leaky_relu(tf.matmul(H1,this.W2) + this.B2);
    Out = tf.nn.leaky_relu(tf.matmul(H2,this.W3) + this.B3);
    return Out;

#PROGRAMME ENTRY POINT==========================================================
#data
X = tf.constant([[0,0],[0,1],[1,0],[1,1]], tf.float32);
Y = tf.constant([[0  ],[1  ],[1  ],[0  ]], tf.float32);

#train
Model = model();
Loss  = tf.losses.MeanSquaredError();
Optim = tf.optimizers.SGD(1e-1);
Steps = 20;
print("Training model...");

for I in range(Steps):
  if I%(Steps/10)==0:
    Lv = Loss(Y,Model(X));
    print("Loss:",Lv.numpy());

  with tf.GradientTape() as T:
    Lv = Loss(Y,Model(X));

  Grads = T.gradient(Lv, Model.trainable_variables);
  Optim.apply_gradients(zip(Grads, Model.trainable_variables));

#get final loss
Lv = Loss(Y,Model(X));
print("Loss:",Lv.numpy(),"(Final)");

#save model
print("\nSaving model...");
Dir = "/tmp/my-model";
tf.saved_model.save(Model,Dir);

#note that the saved_model.pb is not frozen (containing constants)
#its param values are still in /tmp/my-model/variables
%ls -laX --group-directories-first /tmp/my-model

#load back model
print("\nLoading back model...");
Model = tf.saved_model.load(Dir);
print(vars(Model).keys());

#continue training
print("\nContinue training...");

for I in range(Steps):
  if I%(Steps/10)==0:
    Lv = Loss(Y,Model(X));
    print("Loss:",Lv.numpy());

  with tf.GradientTape() as T:
    Lv = Loss(Y,Model(X));

  #this is a little bit different from the loop above
  #only Keras layers now have trainable_variables, list out the rest manually
  Params = Model.Layer1.trainable_variables+[Model.W2,Model.B2,Model.W3,Model.B3];
  Grads = T.gradient(Lv, Params);
  Optim.apply_gradients(zip(Grads, Params));

#get final loss
Lv = Loss(Y,Model(X));
print("Loss:",Lv.numpy(),"(Final)");
#eof

Wednesday, 18 December 2019

Machine Virtualisation and OS Emulation

Machine virtualisation (emulation):
  • VirtualBox, VMWare, Hyper-V, etc.
  • VirtualBox is totally free while one has to pay to use VMWare
OS container (simulation) using host kernel:
  • Docker: The most common OS emulation using host kernel, not a fully separated environment like virtual machines.
OS container orchestration:
  • Kubernetes: Not a direct competitor of Docker, Kubernetes utilises Docker containers and orchestrate them into a service crossing between machines.

Tuesday, 3 December 2019

Comparison of Some Process Management and Monitoring Services

Nodemon (Node.js Monitoring):
  • Node.js only, no auto-restart on crash, auto-restart on file changes only.
  • No Node.js clustering
Forever (Forever Running):
  • Any command, auto-restart on crash.
  • No Node.js clustering
PM2 (Process Management and Monitoring):
  • Any command, auto-restart on crash.
  • With Node.js clustering.

Monday, 2 December 2019

Fix Locale Warning in Terminal

Sometimes, or maybe accidentally, warnings are shown in terminal this way:
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
/bin/sh: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)

These changes should be made:
(1) Add to file /etc/environment
export LC_ALL=""

(2) Add to file ~/.bash_profile
export LC_ALL=""

(3) Add to file ~/.bashrc
export LC_ALL=""