Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Saturday, February 14, 2026

Numpy Tingkat Lanjut

Ada beberapa perintah untuk menaikkan skill pemrograman Python Numpy (dan Scipy) ke level lanjut. Jika Anda (termasuk saya) paham dan bisa menginterpretasikan output perintah tersebut, maka kita sudah siap naik ke level Numpy selanjutnya.

1. Blok Memory (np.nbytes)

Sering kali kita hanya fokus pada bentuk (shape) array, namun melupakan "berat"nya. Perintah `np.nbytes` menginformasikan berapa banyak memori RAM yang sebenarnya kita pakai. Seseorang yang paham bahwa mengubah tipe data (dtype) dari float64 ke float32 bisa memangkas konsumsi memori hingga 50%, yang berarti mempercepat proses komputasi secara drastis. Di sini, kita belajar bahwa array bukan sekadar wadah angka, tetapi blok memori yang harus dikelola secara efisien. Contoh:
import numpy as np

a = np.zeros((1000, 1000), dtype=np.float64)
print(a.nbytes)
# Karena float64 = 8 byte, maka total memori:
# 1000 x 1000 x 8 byte = 8.000.000 byte (~8 MB)
Konsep penting:
  • Ukuran memori = jumlah elemen × ukuran tipe data.
  • Mengganti float64 ke float32 langsung mengurangi memori setengahnya.
  • Pada skala besar (misalnya deep learning atau audio processing), ini sangat krusial.
Jika kita tidak sadar ukuran memori, kita akan mudah "membunuh" RAM sendiri.

2. Stride

Jika nbytes adalah beratnya, maka stride adalah cara kita melangkah di atas memori tersebut. Stride menentukan berapa byte yang harus "diloncati" komputer untuk menuju ke elemen berikutnya di setiap dimensi. Stride adalah jarak (dalam byte) yang harus dilompati untuk berpindah ke elemen berikutnya pada setiap dimensi. Konsep inilah yang menjawab misteri mengapa operasi transpose pada array besar bisa sangat cepat. Karena Numpy tidak benar-benar memindahkan data di memori; ia hanya mengubah pola langkah (stride) tersebut. Memahami stride berarti memahami bagaimana komputer "melihat" data array secara linear di dalam RAM. Contoh:
a = np.arange(12).reshape(3, 4)
print(a.strides)
# Jika dtype=int64 (8 byte), kemungkinan output:
# (32, 8)
Artinya:
  • Untuk pindah ke baris berikutnya → lompat 32 byte (4 kolom × 8 byte).
  • Untuk pindah ke kolom berikutnya → lompat 8 byte.
Ini penting karena:
  • Operasi transpose (a.T) sering tidak membuat copy data, hanya mengubah stride.
  • Pemahaman stride membantu kita tahu kapan NumPy membuat copy atau hanya view.
  • Dalam optimasi performa, akses memori yang kontigu jauh lebih cepat.
Stride adalah jembatan antara konsep matematis array dan realitas fisik memori.

3. Broadcasting

Broadcasting adalah seni "mengada-ada" secara efisien. Broadcasting memungkinkan operasi antara array dengan ukuran yang berbeda tanpa perlu menyalin data secara fisik untuk menyamakan ukurannya. Misalnya, menjumlahkan array (3,3) dengan vektor (3,) secara otomatis. Seorang programmer biasa mungkin akan melakukan looping atau padding manual, tetapi level "Dewa" membiarkan Numpy melakukan broadcasting internal yang jauh lebih cepat karena terjadi di level C. Kita hemat memori, kita hemat waktu. Contoh:
a = np.array([[1], [2], [3]])
b = np.array([10, 20, 30])

c = a + b
Secara mental:
  • `a` bentuk (3,1)
  • `b` bentuk (3,)
  • NumPy "membentangkan" dimensi agar cocok → hasil (3,3)
Tanpa broadcasting, kita harus membuat array besar secara manual. Dengan broadcasting:
  • Kode lebih ringkas
  • Lebih hemat memori
  • Lebih cepat
Kunci memahami broadcasting:
  • Dimensi dibandingkan dari kanan ke kiri
  • Ukuran cocok jika sama atau salah satunya 1
Kalau ini sudah bisa kita prediksi tanpa menjalankan kode, berarti otak kita sudah mulai "NumPy-native".

4. Fancy Indexing

Fancy indexing adalah indexing menggunakan array atau list indeks. Berbeda dengan slicing biasa yang menghasilkan view (tampilan tanpa menyalin data), Fancy Indexing selalu menghasilkan copy (data baru). Memahami perbedaan ini krusial agar kita tidak membludakkan memori secara tidak sengaja saat memproses data besar. Contoh:
a = np.array([10, 20, 30, 40])
idx = [0, 2]
print(a[idx])
# Output: [10 30]
Perbedaan penting:
  • Slice (a[1:3]) → biasanya view (tidak copy)
  • Fancy indexing → selalu membuat copy
Ini sangat penting untuk:
  • Mengontrol penggunaan memori
  • Menghindari bug akibat modifikasi data yang tidak disengaja
Misalnya:
b = a[idx]
b[0] = 999
Di sini, a tidak akan berubah karena b adalah copy. Kalau kita tidak memahami ini, kita bisa salah kaprah saat debugging.

5. Vectorization

Vectorization adalah teknik menghilangkan loop eksplisit (perulangan for di Python) dan menggantinya dengan operasi array tunggal. Loop Python lambat karena interpretasi per-baris, namun operasi vektor Numpy terjadi di level kompilasi C/Fortran yang sangat cepat. Ketika kita memahami Broadcasting, Stride, dan Memory, Vectorization menjadi senjata utama untuk membuat kode berjalan 10x hingga 100x lebih kencang. Perulangan for (lambat):
result = []
for x in a:
    result.append(x * 2)
Vektorisasi (cepat):
result = a * 2
Kenapa jauh lebih cepat?
  • Loop Python berjalan di level interpreter (lambat)
  • Operasi NumPy berjalan di C (cepat)
  • Akses memori lebih efisien
Vectorization bukan sekadar "gaya", tapi filosofi berpikir: Berpikir dalam bentuk operasi matriks, bukan iterasi elemen.

Pesan Penting

Perlu diingat, bagian terpenting adalah memahami konsep array dengan perintah di atas pada tataran level otak kita, bukan simulasi komputer. Artinya, kita bisa menebak output dari komputer (simulasi/Python Numpy) dengan otak kita dan memahaminya. Bukan asal mensimulasikan array, meskipun bisa menebak hasilnya. Inilah yang terpenting: ilmu sebelum beramal.

Referensi

  1. https://shihchinw.github.io/2019/03/performance-tips-of-numpy-ndarray.html
  2. https://pythonspeed.com/articles/numpy-memory-footprint/

Wednesday, March 06, 2024

Menggunakan (Mini) Conda Untuk Komersial (Institusi Riset, dll)

Per 30 September 2020, term of service Anaconda berubah; lisensi berbayar dibutuhkan untuk menggunakan Anaconda untuk keperluan komersial (gratis untuk skala kecil, perusahaan kurang 200 orang pekerja). Miniconda dapat digunakan secara gratis, namun setting default dapat menyebabkan akses ke repository berbayarnya (meskipun gratis).

Solusi singkatnya adalah menambahkan `conda-forge` pada channel di `.condarc` untuk menggantikan konfigurasi default. Cek dengan `conda config --show channels` sebelum dan sesudah mengganti channel default (tidak tertulis di `.condarc`) dengan `conda-forge`.

Cek setting default channel:

$ conda config --show channels
channels:
  - defaults

Ganti channel default dengan menambahkan conda-forge di fail `.condarc` (default di direktori home)

 auto_activate_base: false
  channels: 
    - conda-forge

Cek kembali config conda:

$ conda config --show channels
channels:
  - conda-forge
Dengan cara ini, Miniconda dapat digunakan secara sah dan halal. Saya menggunakan Miniconda (daripada Anaconda) hanya untuk membuat virtual environment dengan versi python yang berbeda (misal dengan python3.8, python3.12, dll). Instalasi paket dalam python (seperti Numpy, Pandas) tetap saya lakukan dengan pip, bukan dengan Conda.

Friday, June 24, 2022

Membuka dan menyimpan file json

MENYIMPAN file JSON
Studi kasus
Misalkan kita ingin menyimpan dataset berikut (RAVDESS Speech) dalam format json yang berisi file dan labelnya (data speech emotion recognition). Untuk keperluan tersebut kita ingin memisahkan antara data training ('train_meta_data.json') dan data test ('test_meta_data.json'). Skrip berikut memenuhi tujuan tersebut.
import os
import glob
import json

data_dir = '/data/Audio_Speech_Actors_01-24/'
files = glob.glob(os.path.join(data_dir, 'Actor_??', '*.wav'))
files.sort()

data_train = []
data_test = []

for file in files:
    lab = os.path.basename(file).split('-')[2]
    if int(file[-6:-4]) < 20: # speaker 1-19 for training
        data_train.append({
            'path': file,
            'label': lab
        })
    else:                     # speaker 20-24 for test
        data_test.append({
            'path': file,
            'label': lab
        })

with open("train_meta_data.json", 'w') as f:
        json.dump(data_train, f)

with open("test_meta_data.json", 'w') as f:
        json.dump(data_test, f)

MEMBUKA file JSON
import json
filepath = '/data/Audio_Speech_Actors_01-24/train_meta_data.json'
with open(filepath, 'r') as f:
     data_train = json.load(f)

Wednesday, March 30, 2022

Mencoba Docker

Setelah sekian lama ingin mencoba docker, kali ini saya benar-benar mencobanya. Selama ini saya bisa menghindari docker karena venv dan conda tidak pernah gagal. Karena kali ini conda gagal mendukung GPU di tensorflow 1.15, maka mau tidak mau Docker menjadi solusi terbaik. 

Docker
Gambar 1. Diagram alir ketika venv gagal, berlanjut ke conda, berlanjut ke docker. Selama venv berhasil membuat environment yang diinginkan saya akan memakainya sebagai pilihan pertama, jika tidak baru mencoba conda dan docker, secara bertahap. 

Docker Untuk Menginstall Software (Paket/Library) Baru

Sampai saat ini saya masih memakai Ubuntu 16.04 untuk laptop-laptop pribadi dan Ubuntu 20.04 untuk laptop-laptop kantor. Permasalahan pada OS lama adalah kegagalan untuk menginstall software versi baru. Kasus saya adalah menginstall paket opensmile python versi terbaru (versi 2.4.1) yang membutuhkan library glibc di atas versi 2.31. Library glibc ini tidak bisa diupate. Pernah sekali saya mengupdatenya dan system saya (Centos 7) langsung rusak dan harus install ulang. Docker adalah solusinya.
 
# asumsi docker sudah terinstall
$ docker run -it ubuntu bash
# jika ada masalah permission, lakukan: sudo chmod 666 /var/run/docker.sock
$ apt update
$ apt install python3
$ apt install python3-pip
$ python3 -m pip install opensmile
$ apt install libsndfile1 libsndfile1-dev
$ apt install sox
$ apt insalll ffmpeg
root@6e7dd3cbfee1:/# python3
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import opensmile
>>> opensmile.__version__
'2.4.1'
>>> exit()
root@6e7dd3cbfee1:/# ldd --version ldd
ldd (Ubuntu GLIBC 2.31-0ubuntu9.7) 2.31
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

Menyimpan file docker dengan commit

Docker tidak didesain untuk menyimpan file, untuk menyimpan file (dan perubahan/update) dari docker yang sedang berjalan dan docker-docker sebelumnya gunakan perintah commit berikut.
Format:
docker commit CONTAINER_ID IMAGE
$ docker ps -a # bisa juga dengan ps -l untuk docker yang sedang berjalan
$ dokcer commit ef7d7090e3c7 ubuntu:opensmile

Docker Untuk Menginstall Software Lama (Tensorflow 1.15 dengan GPU support) 


Skenario: Saya ingin menjalankan kode di repository berikut: Efficient Bigan, dengan GPU RTX 3090, yang saat itu (saat repo itu dibuat dengan tensorflow 1.15) belum diproduksi.
Solusi:
# asumsi docker belum terinstall
$ sudo apt install docker.io
$ curl https://get.docker.com #install curl jika belum ada
$ sudo systemctl --now enable docker
  
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
      && curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - \
      && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
$ sudo apt update
$ docker images      # list images docker 	 	
REPOSITORY                  TAG             IMAGE ID       CREATED       SIZE
nvcr.io/nvidia/tensorflow   22.04-tf1-py3   8b2abbd886f0   2 years ago   9.51GB
$ docker run --gpus all -it --rm nvcr.io/nvidia/tensorflow:22.04-tf1-py3
$ git clone https://github.com/houssamzenati/Efficient-GAN-Anomaly-Detection.git
$ cd Efficient-GAN-Anomaly-Detection
$ python3 main.py gan mnist run --nb_epochs=10 --label=0 
______   _____       _____       ____                                                                                                                   
|_     `.|_   _|     / ___ `.   .'    '.                                                                                                                 
  | | `. \ | |      |_/___) |  |  .--.  |                                                                                                                
  | |  | | | |   _   .'____.'  | |    | |                                                                                                                
 _| |_.' /_| |__/ | / /_____  _|  `--'  |                                                                                                                
|______.'|________| |_______|(_)'.____.'                                                                                                                 
                                                                                                                                                         
                                                                                                                                                         
[09:48:37 INFO @AnomalyDetection] Running script at gan.run_mnist                                                                                        
2022-03-30 09:48:37.916727: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0        
[09:48:37 WARNING @tensorflow] Deprecation warnings have been disabled. Set TF_ENABLE_DEPRECATION_WARNINGS=1 to re-enable them.                          
[09:48:38 WARNING @tensorflow] From /TA/demo/Efficient-GAN-Anomaly-Detection/gan/run_mnist.py:4: The name tf.ConfigProto is deprecated. Please use tf.com
pat.v1.ConfigProto instead.                                                     
...
2022-03-30 09:48:44.229713: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcublas.so.11
2022-03-30 09:48:44.683684: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudnn.so.8
[09:48:51 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 0 | time = 7s | loss gen = 0.7218 | loss dis = 1.3530 
[09:48:54 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 1 | time = 3s | loss gen = 0.7747 | loss dis = 1.2383 
[09:48:57 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 2 | time = 3s | loss gen = 0.8793 | loss dis = 1.0877 
[09:49:01 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 3 | time = 3s | loss gen = 1.0170 | loss dis = 0.9235 
[09:49:04 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 4 | time = 3s | loss gen = 1.1724 | loss dis = 0.7746 
[09:49:07 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 5 | time = 3s | loss gen = 1.3378 | loss dis = 0.6493 
[09:49:11 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 6 | time = 3s | loss gen = 1.5056 | loss dis = 0.5522 
[09:49:14 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 7 | time = 3s | loss gen = 1.6597 | loss dis = 0.4744 
[09:49:17 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 8 | time = 3s | loss gen = 1.7992 | loss dis = 0.4116 
[09:49:21 INFO @GAN.train.mnist.fm.0] Epoch terminated
Epoch 9 | time = 3s | loss gen = 1.8616 | loss dis = 0.3848 
[09:49:21 WARNING @GAN.train.mnist.fm.0] Testing evaluation...
[09:54:19 INFO @GAN.train.mnist.fm.0] Testing : mean inference time is 1.5292
Testing | PRC AUC = 0.7183

Me-mount direktori 

Alih-alih membuat commit setiap kali kita mengedit, kita bisa memount direktori saat memanggil docker.
Skenario: Mengedit file diluar docker, mengeksekusi file (misal python) didalam docker. Caranya adalah sebagai berikut.
$ docker run --gpus all -it --mount type=bind,source=/TA,target=/TA tf1.15:py3
Dimana `source` adalah sumber direktori, dan `target` adalah target direktori. Image docker sebelumnya sudah saya commit menjadi `tf1.15` dengan tag `py3`. 

Menambahkan docker ke sudoers

Ketika membuka docker, terlihat bahwa tanda di baris kiri terminal adalah sharp #, ini menandakan kita masuk sebagai super user (sudo). Karenanya ada error saat membuka docker pertama kali (harus chmod 666 dulu). Solusi ini hanya berjalan sementara, untuk solusi permanen kita bisa menambahkan docker ke grup sudoers sebagai berikut.
# menambahkan grup baru bernama docker
$ sudo groupadd docker
# menambahkan $USER ke grup docker
$ sudo usermod -aG docker $USER
# merefresh grup
$ newgrp docker
Demikian tutorial singkat docker ini, semoga bermanfaat.

Referensi;
[1] https://docs.docker.com/engine/install/linux-postinstall/

Thursday, October 21, 2021

Argumen "self" pada Python OOP (temasuk __init__ dan instance variable)

Saat pertama kali mengetahui banyaknya kata "self" pada bahasa pemrograman Python, saya terhenyak. Teknik ini banyak sekali dipakai (a must!), dan saya sama sekali tidak memahaminya. Dua tahun lebih berlalu sejak saya ingin mengenal "self" pada Python (2019-02-02), dan kali ini saya ingin serius berkenalan dengannya.

"Kelas" dan OOP

Bahasa pemrograman python diadopsi secara meluas karena keluwesannya, baik secara prosedural maupun object-oriented programming (OOP). Pada kasus pertama, yakni prosedural, cukup sederhana dan intuitif. Misal:

def kali(x, y):
    return x*y

Secara singkat kita bisa paham bahwa "kali" adalah sebuah fungsi untuk mengalikan dua variabel, x dan y. Hal ini berbeda dengan kelas berikut

class kaliX (object):
    def __init__(self, data):
        self.data = int(data)
    def kali(self, other):
        return self.data * other.data
Disinilah saya kebingungan memahami apa itu self. Kembali ke dua potongan kode di atas. Kalau kita run di IPython, akan terlihat hasilnya sama sebagai berikut (hanya terlihat ketika mengakses blog ini via PC).



Jadi apa itu self?

Sebelum masuk ke self, kita masuk ke __init__ dulu karena __init__ disebut lebih dulu pada OOP, pada contoh di atas. __init__ adalah inititalization method pada badan OOP atau kelas. Fungsi pertama kelas ini, yakni didefinisikand dengan def __init__ akan dipanggil setiap instance dari kelas dibuat. Instance sederhananya ya kelas itu sendiri. Nah self adalah variabel pertama dari fungsi __init__. Variabel kedua fungsi __init__ adalah `data`. Berbeda dengan bahasa pemrograman lain (yang saya juga tidak mengerti), Python mengizinkan satu __init__ saja pada satu kelas [3].


Instance Variable

Sebagai tambahan dari self dan __init__ adalah `instance variable`. Instance variable adalah DASAR dari OOP dalam Python. Dalam contoh kelas "kaliX" di atas, instance variable-nya adalah sebagai berikut: `data` pada `self.data`. Maknanya, variabel data sebagai input kelas kaliX akan diubah menjadi integer dan menempati tempat `data` pada `self.data`. Pada fungsi `kali` yang menjadi bagian dari kelas `kaliX`, variabel `other` akan menempati `data` pada `other.data` melalui fungsi __init__ tadi. Begitu seterusnya jika ada variabel lain. Beginilah secara sederhana OOP bekerja. Instance variable bisa diisi secara eksplisit lewat `Namakelas.NamaInstanceVariable  = <nilai>`. Misalnya `my_circle.radius = 5` pada contoh berikut.

>>> class Circle:
         def __init__(self):
             self.radius = 1
    
>>> my_circle = Circle()
>>> print(my_circle.radius)
>>> 1
>>> my_circle.radius = 5
>>> print(my_circle.radius)
>>> 5


Kesimpulan

Telah dikelaskan apa itu __init__  -- sebagai fungsi initial di kelas --, self --sebagai argumen pertama __init__ --, dan instance variable -- sebagai dasar OOP di Python --.


Referensi:

  1. https://www.programiz.com/article/python-self-why
  2. https://www.digitalocean.com/community/tutorials/how-to-construct-classes-and-define-objects-in-python-3
  3. Naomi Ceder, The Quick Python Book, 2nd ed. Manning Publishing, 2018.

Monday, August 16, 2021

Install sox locally in cluster without root

This time, I can't install homebrew in (AIST) cluster as I previously did in JAIST cluster. Here are steps to documents how to install SoX, one of the most important library in sound processing, locally in cluster. I tried these steps in abci.ai.

# download sox package, in this case
wget https://nchc.dl.sourceforge.net/project/sox/sox/14.4.2/sox-14.4.2.tar.gz

# extract sox package
tar xvfz sox-14.4.2.tar.gz

# change to extracted sox directory
cd sox-14.4.2

# configure in local directory, I used $HOME
./configure --prefix=$HOME

# make
make

# make install
make install
Then check it by its version
[user13432@es2 ~]$ sox --version
sox:      SoX v14.4.2
You may also need to update $PATH to make it works in your enviroment.

Wednesday, August 04, 2021

Extracting Emobase Feature Using Python-Opensmile under Windows (WSL)

This article documents my steps to extract acoustic features with "emobase" configuration on opensmile-python under Windows. I used WSL (Window Sub-System for Linux) with Ubuntu Latest (20.04). Click each image for larger size and clarity.

0. Windows Version

Here is my Windows version in which I experimented with. Other versions may give errors. To show your version, simply press the Windows button and type "about PC".
Edition	        Windows 10 Pro
Version	        20H2
Installed on	‎4/‎2/‎2021
OS build        19042.1083
Experience      Windows Feature Experience Pack 120.2212.3530.0

1. Activate WSL2

Here are the steps to activate WSL2 on Windows 10. WSL2 only works on Windows 10 version 1903 or higher, with Build 18362 or higher. For the older version, you can use WSL instead of WSL2.
a. Activate WSL using PowerShell. Press the Windows key, and enter the following.
 dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart 
b. Install Linux kernel update package. Download from here.
https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi
Double click and install that .msi package.
Select WSL2 as default.
 wsl --set-default-version 2 

You need to ensure the wsl version after installing Ubuntu distro below.

2. Install Ubuntu

Press windows key and type "Microsoft Store". I choose Ubuntu (latest) instead of Ubuntu 20.04 or other versions. See image below; I already installed it.


Ensure that Ubuntu uses WSL2 as default. Check-in PowerShell with the following command (wsl -l -v).

Then click launch Ubuntu from the previous image/step, or you can type "Ubuntu" di search dash.
When launching Ubuntu for the first time, you will be prompted for the user name and password. Remember this credential. See the image below for example.

3. Install Python and pip

In Ubuntu do/type
 sudo apt update && sudo apt -y upgrade 
Enter your password. Type "y" when it is prompted.
Install Python using apt. I chose python3.7 as follows.
 sudo apt install python3.7-full 
Type "y" when it asked. See the image below for reference.

Test if the installation is successful. Type "python3.7" in Ubuntu to enter python3.7 console.

Next, we need pip to install python packages. Hence, we need to install pip first as follows.
 python3.7 -m ensurepip --upgrade 

4. Install Python-Opensmile

Since this version of python in Ubuntu is already equipped with pip, we can directly use it to install opensmile.
 python3.7 -m pip install opensmile 
See the image below for a reference.

Same as previous step, I installed IPython for my convenience. You may also need to install numpy, scipy, and matplotlib.
 python3.7 -m pip install ipython numpy scipy audb

We also need to install sox since it is required by opensmile
 sudo apt install sox 

5. Extract Emobase Feature

Now is the time to use opensmile. First, open IPython console for this python3.7.
 python3.7 -m IPython 
Import Opensmile and download emodb dataset with a specific configuration.
See the image below for your reference. Skip the parts with red cross since they contain errors (I forgot to add a comma between arguments).

Configure opensmile to extract EMOBASE feature.
smile = opensmile.Smile(
    feature_set=opensmile.FeatureSet.emobase,
    feature_level=opensmile.FeatureLevel.Functionals,
)
smile.feature_names
See image below for your reference. You can change feature_level value to "opensmile.FeatureLevel.LowLevelDescriptors" if you want LLD (LowLevelDescriptors, extracted per frame) instead of functionals (statistics of LLD). The number of emobase functional is 988 features [len(smile.features_names)].

Finally, we extract acoustic features based on these configuration.
smile.process_signal(
    signal,
    sampling_rate
)
See below image for your reference.


That's all. Usually, I save the extracted acoustic features in other format like numpy .npy files or .csv files. From my experience, this is my first extraction of emobase feature set. Previously I used gemaps, egemaps, compare2016, and emo_large configuration. Let see if this kind of feature set has advantages over others. Although intended for Windows 10, this configuration may also works for other distribution. Still, I prefer to use Ubuntu since the process is simple and straightforward. No need to set WSL2 and other things just pip and pip.

The full script to extract emobase functional features from all utterances in emodb dataset is given below. Please note that it takes a long time to process since it will download all utterances in emodb dataset according to "audb" format and extract acoustic features from them.

Example 1: Extract emobase feature from an excerpt of emodb dataset and save it as an .npy file.

import os
import time

import numpy as np
import pandas as pd

import audb
import audiofile
import opensmile

sr = 16000

# if you change code below, it will download the dataset again 
db = audb.load(
    'emodb',
    version='1.1.1',
    format='wav',
    mixdown=True,
    sampling_rate=sr,
    full_path=False,
    verbose=True,
)

smile = opensmile.Smile(
    feature_set=opensmile.FeatureSet.emobase,
    feature_level=opensmile.FeatureLevel.Functionals,
)

# If you run this program for the second time
# comment the whole db above and change db.root and db.files to (uncomment)
# db_root = audb.cached().index[0]
# db_files = pd.read_csv('/home/bagus/audb/emodb/1.1.1/fe182b91/db.files.csv')['file']

feats = []
for i in db.files:
    file = os.path.join(db.root, db.files[i])
    signal, _ = audiofile.read(
            file,
            always_2d=True,
            )
    feat = smile.process_signal(
            signal,
            sr
            )
    feats.append(feat.to_numpy().reshape(-1))

# this will save all emodb emobase feature in a single npy file
# make sure you have 'data' dir first
np.save('data/emodb_emobase.npy', feats)
  

Example 2: Extract emobase features from files under a directory ("ang") and save it in a csv file.
import os
import opensmile
import numpy as np
import glob
#from scipy.io import wavfile

# jtes angry path, 50 files
data_path ="/data/jtes_v1.1/wav/f01/ang/"
files = glob.glob(os.path.join(data_path, "*.wav"))
files.sort()

# initiate opensmile with emobase feature set
smile = opensmile.Smile(
    feature_set=opensmile.FeatureSet.emobase,
    feature_level=opensmile.FeatureLevel.Functionals,
)
smile.feature_names

# read wav files and extract emobase features on that file
feat = []

for file in files:
    print("processing file ... ", file)
    #sr, data = wavfile.read(file)
    #feat_i = smile.process_signal(data, sr)
    feat_i = smile.process_file(file)
    feat.append(feat_i.to_numpy().flatten())

# save feature as a csv file, per line, with comma
np.savetxt("jtes_f01_ang.csv", feat, delimiter=",")

  


If you face problems during following this article, let me see in comments below.

Reference:
[1] https://docs.microsoft.com/en-us/windows/wsl/install-win10
[2] https://audeering.github.io/opensmile-python/usage.html

Monday, August 02, 2021

Python: memanggil nama variabel secara dinamis dalam loop for

Misalkan kita punya data seperti ini:
a_1 = 1
a_2 = 2
a_3 = 3
Kemudian kita ingin memanggi variabel tersebut secara berurutan dalam loop for. Karena nama-nama variabel tersebut mirip dan hanya berbeda karakter terakhir saj, maka pemanggilan variabel tersebut bisa kita permudah, misalnya dengan cara "a_[i}", dimana "i" adalah indeks mulai dari i. Saya menggunakan kurung kurawal karena implementasi pada teknik yang dipakai juga seperti itu. Pemanggilan nama variabel secara dinamis seperti ini dalam Python bisa menggunakan fungsi "globals()" seperti berikut.
for i in range(1,4):
    print(globals()[f"a_{i}"])
Outputnya adalah nilai a_1, a_2, dan a_3 secara berurutan.
1
2
3

Perbedaan dengan list biasa 

Untuk menampilkan output di atas bisa saja dengan teknik berikut.
for i in [a_1, a_2, a_3]:
    print(i)
Namun tujuan saya bukan output, tapi proses pemanggilannya. Dalam banyak hal, kita butuh memanggil nama variabelnya saja dan mengakses anggota kelasnya. Misal jika variabel "a_" memiliki child (anak) .panjang, .lebar, .tinggi, maka metode tsb (methods dalam pengertian pemrograman) bisa dipanggil dengan teknik nama variabel dinamis di atas. Akan sulit jika memakai list biasa.

Tuesday, June 22, 2021

Sympy: Menyelesaikan Persamaan Matrik

Sympy melakukan proses komputasi yang tidak bisa dilakukan oleh Numpy: simbolik. Misal kita punya persamaan berikut

$$2.10^{6}\left[\begin{array}{crr} 1 & -1 & 0 \\ -1 & 2 & -1 \\ 0 & -1 & 1 \end{array}\right]\left\{\begin{array}{l} 0 \\ u_{2} \\ u_{3} \end{array}\right\}=\left[\begin{array}{c} F_{1}+1500 \\ 9000 \\ 7500 \end{array}\right] $$
Dalam bentuk gambar, persamaan di atas dapat ditampilkan di bawah ini (rendering kode Latex/mathjax di atas kadang Luama....).
Untuk menyelesaikan persamaan di atas (u1=0), maka solusi dengan Sympy adalah seperti kode di bawah ini:
from sympy import *

# buat symbol
u2, u3, F1 = symbols('u2 u3 F1')

# matrik sebelah kiri (left-hand)
K = Matrix([[ 1, -1, 0], [-1, 2, -1], [0, -1, 1]]) 
Ke1 = 2e6*K
U = Matrix([0, u2, u3]).reshape(3,1)

# matrik sebelah kanan
F = Matrix([F1+1500, 9000, 7500])

# selesaikan: cari u2, u3, dan F1
sol = solve(Ke1*U-F, (u2, u3, F1))


Jika dijalankan, hasilnya adalah sebagai berikut.
print(sol)
{u2: 0.00825000000000000, u3: 0.0120000000000000, F1: -18000.0000000000}

Monday, September 07, 2020

Python check if file/directory exist

This is a documentation for myself. To check if a file or directory already exists, use the following ways.
 
Check file or directory
import os
os.path.exists('filename')
Check file only
import os
os.path.isfile('filename')
Create the file if not exist
if not os.path.exists('file'): 
 os.mknod('file') 
Create a directory if not exist
if not os.path.exists('file'): 
 os.mkdir('file') 
Please note that the last commands will complain (shows error) if the file or directory 'file' exists. To throw complain, it is better to use `os.makedirs` with argument `exist_ok=True`. It also enables creation of subdirectories with their parent (like bash `mkdir -p`).
os.makedirs('parent-dir/sub-dir', exist_ok=True)
The last one is my favourite since it will create folder if not exist and don't throw error if it is exist.

Thursday, June 11, 2020

Benchmarking Intel-based Numpy packages

Intel has their own distribution (modified version) of Numpy, Scipy, and scikit-learn packages. They claim that these packages are optimized from those existing packages. To prove this claim, I made a little following benchmark. I used two similar machines MBP 2012 and Lenovo G580. Both have similar specs, i7-3520 processors, and 16GB RAM. The following code I used to benchmark.

Monday, April 06, 2020

Berpindah ke vscode (dari gEdit)

Hidup itu harus dinamis, tidak harus saklek pada satu hal (tool/perangkat). Ketika ada perangkat lain yang lebih mudah, meskipun awalnya saya membencinya, maka kita harus berpindah ketika ternyata perangkat tersebut memberikan kemudahan dan kecepatan dari perangkat lama.

Kali ini saya berbicara tentang "editor", perangkat lunak yang digunakan untuk mengetik. Contoh editor sederhana adalah notepad di Windows. Di Linux, sejak pertama kali menggunakannya secara intensif tahun 2009 sampai sekarang, editor bawaan dari Gnome, yakni gEdit, adalah editor default saya, selain vim. Dua hal utama yang saya gunakan dengan editor: (1) mengkoding Python, dan (2) membuat manuskrip dengan Latex. Hal-hal lainnya adalah menulis dengan markdown, txt, dan format-format lainnya. Jadi, editor yang saya gunakan paling tidak harus mendukung Python dan Latex, dan gEdit sudah mendukung keduanya dengan beberapa kekurangan (code completion, snippets, dll).

Setelah mencoba beberapa editor lain: Atom, Sublime text, Spyder, PyCharm, dan vscode, akhirnya saya memutuskan vscode sebagai editor saya untuk seterusnya. Tulisan ini mengupas kenapa saya berpindah dari gEdit ke vscode.


Wednesday, February 26, 2020

Menghitung rataan dengan mengabaikan nilai nol di Python Numpy

Ada kalanya kita ingin menghitung nilai rata-rata dari suatu data, namun kita ingin mengabaikan (skip) jika
ada nilai 0 (atau kosong, atau NaN, Not a Number) dalam data tersebut. Screencast di bawah ini menjelaskan tentang hal tersebut.

Tuesday, April 09, 2019

Python: konversi array ND ke 1D

Misal kita memiliki matriks sebagai berikut:

In [4]: x = np.arange(9.).reshape(3, 3)
In [5]: x
Out[5]: array([[0., 1., 2.],
       [3., 4., 5.],
       [6., 7., 8.]])
Apabila kita cari tahu panjang dan bentuk vektor x

In [6]: x.shape                                                                 
Out[6]: (3, 3)
In [179]: len(x)
Out[179]: 3

In [180]: x.size
Out[180]: 9

Artinya, kita memiliki array 3D (N-dimensional atau ND) dengan panjang 3 baris dan total berisi 9 elemen. Kita ingin merubah matrix 3x3 tersebut menjadi matrikx 1x9 (atau 9x1). Berikut caranya:

x.flatten()

Cek panjang vektor x.flatten sebagai berikut:

len(x.flatten())

Update:
2019-04-22: Selain dengan `flatten`, konversi ke 1D dilakukan dengan ravel dan ini cara lebih cepat.

Monday, April 08, 2019

Implementasi Deep Learning dengan Keras: Terminologi dasar

Berikut konsep deep learning dengan Keras dalam 30 detik (6 detik per baris membaca):
model = Sequential()
model.add(Dense(XX, input_dim=Y)
model.add(Dense(Z))
model.compile(loss='nama_loss_function', optimizer='nama_optimizer', metrics=['nama_metrik'])
model.fit(training_input, training_ouput, epochs=AA)

Terminologi penting (tak kenal maka tak paham?!):

Model: Tipe model yang digunakan. Ada dua: sekuensial dan functional API.
Contoh:
model = Sequential()

Dense: Menambahkan unit atau node beserta argumennya, dari satu layer ke layer selanjutnya. Dengan kata lain, "fully-connected layer", atau "feed forward network", atau "multi-layer perceptron".


Contoh:

model.add(Dense(32, input_dim=2)
Kode di atas membuat layer dengan jumlah 32 unit dan 16 unit input. Jumlah learnable parameternya adalah 16*32+32 = 544. Check dengan model.summary(). Jika kita tambahkan lagi,
model.add(32) 
Maka sekarang kita mempunyai dua layer yang masing-masing berisi 32 unit. Total learnabale parameternya adalah 544+ (32*32+32) = 1600. Check dengan kode yang telah diberikan di atas.

Compile: Mengkonfigurasi model untuk melatih data yang diberikan
Contoh:
model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])
Fit: Mencari hubungan input dan output data, dengan kata lain: membangun/melatih model.
Contoh:
model.fit(train_input, train_output, batch_size=16, epochs=500)

Empat terminologi di atas merupakan step dasar untuk melakukan training data dengan deep learning. Namun masing-masing terminologi memiliki argumen. Agar lengkap, berikut penjelasan singkat argumen-argmunen tersebut.

Thursday, April 04, 2019

Numpy: Menggabungkan dua list menjadi N x 2 vektor

Misalkan kita memiliki dua list sebagai berikut:

kata = ["Bagus!", "Ampuh!", "cantik!", "Mantap!", "Cakep!", 
        "Jelek", "Rusak", "Nol", "Omong kosong", "Busuk", "Tidak"]
label = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]

Kita ingin menggabungkan dua list tersebut sehingga menjadi seperti ini:
array([['Bagus!', '1'],
       ['Ampuh!', '1'],
       ['cantik!', '1'],
       ['Mantap!', '1'],
       ['Cakep!', '1'],
       ['Jelek', '0'],
       ['Rusak', '0'],
       ['Nol', '0'],
       ['Omong kosong', '0'],
       ['Busuk', '0'],
       ['Tidak', '0']])

Maka, kita dapat menggunakan skrip berikut:
kata_label = hstack([np.array(kata, ndmin=2).T, np.array(label, ndmin=2).T])

Friday, March 29, 2019

Word Embedding dan Implementasinya dalam Python (Keras)

Tulisan ini merupakan implementasi dari tulisan sebelumnya, "Vektor dari Kata dan GloVe Embedding". Word embedding merupakan representasi dari kata. Dua teknik yang paling umum dipakai dalam word embedding telah dipaparkan sebelumnya: vektor kata dan GloVe embedding. Tulisan ini adalah implementasi dari teknik tersebut dengan menggunakan bahasa pemrograman Python dan modul Keras.

Misalkan kita punya kumpulan lima kata-kata baik dan enam kata-kata jelek seperti dibawah. Kata-kata baik kita labelkan dengan angka "1" sedangkan kata-kata jelek kita labelkan dengan angka "0".

import numpy as np
kata = ["Bagus!", "Ampuh!", "cantik!", "Mantap!", "Cakep!", 
        "Jelek", "Rusak", "Nol", "Omong kosong", "Busuk", "Tidak"]
label = np.array ([1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0])

Kemudian kata-kata di atas kita rubah menjadi integer
# merubah kata menjadi integer
from keras.preprocessing.text import one_hot
vocab_size = 50
encoded_docs = [one_hot(d, vocab_size) for d in kata]
print(encoded_docs)

Karena panjang maksimal dari elemen kata adalah dua buah (yakni kata "Omong kosong"), kita jadikan kata-kata lainnya memiliki panjang dua buah kata.

Thursday, November 16, 2017

Tutorial python virtualenv

Bahasa pemrograman python sedang boooming, menurut IEEE programming language rank, python menempati urutan pertama. Setelah membuat tutorial singkat, learning python: the hardway, saya jarang membukanya dan menggunakannya. Untuk memaksa hal tersebut, saya membuat tutorial lagi, yang saya sadur dari software carpentry. Kali ini saya akan mencatat tentang penggunaan `virtualenv`, module python yang digunakan untuk mengisolasi environment, seperti menggunakan modul versi tertentu dan setup tertentu. Hal ini sangat penting karena beberapa kode yang dibuat hanya berjalan pada versi yang sama, bukan versi di atasnya atau di bawahnya, misalnya deep learning untuk klasifikasi genre musik ini. Virtualenv ini sangat mirip dengan `modulefile` pada HPC (high performance computing).

Instalasi
Ada dua cara yang saya rekomendasikan untuk menginstall virtualenv, cara pertama dengan apt(-get), cara kedua dengan pip. Saya lebih merekomendasikan cara kedua.

Jika memakai cara pertama (apt untuk ubuntu, apt-get untuk debian-based)
sudo apt install virtualenv

Cara kedua (lebih direkomendasikan),
sudo -H pip install virtualenv

Pip adalah `python installing packages`, karena kita sedang menggunakan python, karena itulah saya lebih merekomendasikan cara kedua. Argument -H artinya agar installasi di-set ke user dari Home (alaiu, as long as i understood). Kemudian untuk mengecek apakah sudah terinstal, seperti biasa, cek dengan argumen --version.
virtualenv --version

Membuat virtualev
Untuk membuat python virtualennv, caranya cukup mudah sbb:
virtualenv nama_virtual_python
source nama_virtual_python/bin/activate

Denga perintah itu virtualenv dengan nama `nama_vitual_python` telah dibuat dan diaktivas dengan perintah berikutnya yakni `source activate`. Setelah perintah itu dijalankan, maka kita sudah berada pada python virtual environment dimana kita bisa menginstall dan menggunakan modul/package python dengan versi selain versi modul yang terinstall di komputer. Contohnya sebagai berikut,
pip install tensorflow==1.0.0 sugartensor==1.0.0.2 pandas>=0.19.2 librosa==0.5.0 sckits.audiolab==0.11.0 numpy==1.13.3

Menon-aktifkan virtualenv

Sebagai kebalikan perintah `source activate`, kita bisa menggunakan perintah `deactivate` saja tanpa argumen untuk menon-aktifkan virtualenv python dan kembali ke environment python secara umum di PC kita.
deactivate

Integrasi dengan Jupyter notebook

Dengan Jupyter notebook, pemorgraman python menjadi lebih interaktif seperti Matlab. Kita bisa melihat variabel, mengganti parameter, dan megedit baris tertentu saja tanpa menjalankan keseluruhan program. Seperti halnya alasan kenapa kita menggunakan virtualenv: yakni kita hanya ingin menggunakan paket python versi tertentu saja pada project/direktori tertentu saja, begitu juga pada Jupyter notebook. Alih-alih menggunakan python2 atau python3 sebagai kernel jupyter, kita bisa membuat custom kernel python sendiri dengan menginstall ipykernel dalam virtualenv.

Langkah-langkahnya adalah sebagai berikut,
$ source nama_virtual_python/bin/activate
(nama_virtual_python)$ pip2 install ipykernel
(nama_virtual_python)$ ipython kernel install --user --name=nama_virtual_python
installed kernelspec nama_virtual_python in /home/user/.local/share/jupyter/kernels/nama_virtual_python
(nama_virtual_python)$ jupyter-notebook

Perhatikan bahwa string sebelum tanda dolar $ bukan merupakan perintah. Singkatnya, baris kedua diatas akan menginstall paket ipykernel pada environment python saat ini, kemudian baris ketiga mengaktifkan paket (kernel) tersebut pada jupyter. Terakhir kita buka jupyter, dan disitu terdapat kernel baru: nama_virtual_python. Selamat mencoba!

Update:

Pada Ubuntu 16.04, by default perintah `pip` akan mengeksekusi pip3 (python3), bukan pip2 (python2), jika virtualenv sudah terinstall dan ada ketika di jalankan keluar "using base prefix '/usr' ", maka tambahkan opsi `--python=python2" saat menjakankan virtualenv sebagai berikut:
virtualenv --python=python2 nama_virtual_python

Update 2018/11/12
Untuk python3, gunakan venv daripada virtualenv. Lebih lengkapnya silahkan ikuti panduannya disini.

TL;DR untuk python 3:
1. python3 -m venv .env
2. source .env/bin/activate
3. pip3 install namapaket

Update untuk python3.6 (2020/07/31)
1. sudo apt install python3.6-venv
2. ... (step 1-3 di atas)

Referensi:
  1. http://www.pythonforbeginners.com/basics/how-to-use-python-virtualenv
  2. https://anbasile.github.io/programming/2017/06/25/jupyter-venv/

Thursday, March 17, 2016

Learn Python the Hardway : The work flow

Really, I want to say; I hate python programming. But, when I said something bad, the bad will come to me again and again. So, let's to to stop it. Python is interpreter language or scripted language. It doesn't need to compile like C or C++. It seems the easiest (programming) language to learn. How to learn it? How to master it? what is the hard way to learn as fast as possible? Here the work flow:

Tutorial:
  1. Do all exercise in Learn Python The Hardway by hand (type, not copy paste), from Exercise 1 to Exercise 39.
  2. Solve the Project Euler Problem, Problem number 1, 2, 3, 14, 17, 57, 79 and 102 with Python.
  3. Learn the basic concept of python and advanced it with python object oriented programming. 
  4. Learn Tutorial-python.
  5. Learn from software carpentry python lesson.
Free online MOOC (interactive coding, RECOMMENDED):
  1. Datacamp's intro to Python for Data Science
  2. EdX Intro to Python for Data Science (Connected to DataCamp)
  3. EdX introdution to Programming Using Python
  4. MITx 6.00.1x Introduction to Computer Science and Prorgramming Using Python
  5. EdX Using Python for Research

That's all, do it. You'll master the python on the hard way method. That is one of the most important thing that I got from the workshop of scientific computing.

Sunday, July 05, 2015

Intro to Matlab: From Beginner to Advance

Senin, 29 Juni 2015 saya memulai hand-on-research di Trieste, Italy, dengan menu favorit saya, Matlab. Karena Matlab dipakai hampir di semua materi hand-on-research, maka saya memilih menu ini di awal. Hands-on kali ini diampu oleh Brian Storey, Professor of Mechanical Engineering di Olin Collage, US, yang juga telah menulis banyak ebook gratis untuk Matlab dan CFD. Semua materi yang digunakan ada pada link attachment di halaman paling bawah artikel ini (saya akan mengupdate permissionnya dalam beberapa minggu lagi).

Once to be remembered, learning Matlab is not learning the programming, but the physical phenomenon behind it. So, you must understand clearly from physical phenomena to mathematical model (equation), from equation and logic to (Matlab) programming language. When you didn't understand about math and physics of your program, it will very hard to bring the solution to (Matlab) programming language.

OK, Let's start. Prof. Storey divide the student into two: the beginner who never knows about Matlab, and advance user with someone in between (intermediate). For beginner on Matlab, the following books has been recommended and you can study it by your self,