Setidaknya ada tiga alasan kenapa seharusnya kita tidak membeli barang dari TEMU. Bahkan memboikotnya. Semurah apapun harga produknya, sebesar apapun diskonnnya.
1. Laporan DPR Amerika Serikat
Dalam laporan DPR AS, mereka melaporkan bahwa TEMU tidak memiliki complience untuk memenuhi Uyghur Forced Labor Prevention Act (UFLPA). UFLPA mencegah penggunaan tenaga kerja Uyghur tanpa bayaran (lihat alasan 3). Artinya, karena tidak memenuhi UFLPA, besar kemungkinan TEMU menjual barang yang berasal dari perusahaan yang tidak menggaji karyawannya (kerja paksa); karenanya harga barangnya menjadi murah sekali.
2. Laporan Seorang Teman Uyghur
Iklan TEMU yang betul-betul menggiurkan (Shops like billionaire!) membuat saya bertanya kepada seorang teman yang berasal dari Uyghur sebelum memutuskan membeli di TEMU. Saya bertanya kepada dia apakah benar TEMU tidak membayar pekerjanya (Orang Uyghur yang bekerja di perusahaan yang memproduksi barang dijual di TEMU). Jawabannya sangat mencengangkan, tidak hanya TEMU dari juga online shop yang lain menggunakan tenaga yang tidak dibayar; bahkan teman saya sendiri pernah mengalami bekerja tanpa di gaji. Tip singkatnya, jangan membeli barang yang country of origin nya dari China atau online shop dari China.
3. Laporan Pribadi
Karena massifnya promo Temu di Jepang, dan saya beberapa kali tergiur untuk membeli barang di Temu (harganya sangat murah sekali bahkan banyak yang gratis katanya), saya mengontak perwakilan mereka (Jepang) via messenger. Mereka tidak mau mengkonfirmasi kalau tidak comply dengan UFLPA; jadi saya asumsikan mereka, TEMU, benar-benar menggunakan tenaga saudara-saudara kita di Uyghur tanpa di bayar.
Two of my papers were accepted in TENCON 2024. Here is the list of titles:
Multi-label Emotion Share Regression From Speech Using Pre-Trained Self-Supervised Learning Models
Evaluating Hyperparameter Optimization for Machinery Anomalous Sound Detection
The first paper talks about emotion (share) recognition, meaning how to predict more than a single emotion from utterance. It differs from general speech emotion recognition (SER), although we can select n highest probabilities from SER. In the former, the total share should be 1 (or 100%). In the latter, the probabilities of each emotion category are independent, i.e., each could have 0.85 and 0.75 of probabilities. Usually, the highest probability is selected.
Here is a more detailed example.
Emotion (share) recognition
Angry: 0.54
Fear: 0.43
Other: 0.03
Speech emotion recognition
Angry: 0.64
Fear: 0.53
Sad: 0.23
In the first, the sum up of all probabilities is 1; this is not the case for the second approach (SER).
In the second article, I optimized anomalous machine sound detection via Optuna. The results on two different databases show different values of optimal parameters; however, the top three parameters to optimize remain the same (learning rate, patience, and type of loss function).
F-score (sebelum masuk ke F1 score) adalah harmonic mean (kebalikan arithmetic mean) dari precision dan recall. Jadi kalau (arithmetic) mean dari precision dan recall adalah (precision + recall) / 2 maka F-score adalah 2 * (1/precision + 1/recall) atau dapat ditulis dengan
$$ F-score = 2 \frac{\text { precision } \cdot \text { recall }}{\text { precision }+ \text { recall }} = \frac{2 \mathrm{tp}}{2 \mathrm{tp}+\mathrm{fp}+\mathrm{fn}} $$
Dari rumus di atas terlihat bahwa nilai F-score bergantung pada tp (true positive), fp (false positive), dan fn (false negative).
Kemudian dengan menggunakan scikit-learn "classification report" saya mendapatkan hasil berikut:
Gambar 1. Output "classification report" dari scikit-learn
Mana diantara nilai F1-score (kotak merah) yang harus saya pakai/laporkan?
Dari Scikit-learn
Keterangan lebih jauh tentang F1-score bisa dipelajari dari manual Scikit-learn. Ada beberapa nilai F1-score yang bisa dipakai yakni: binary, micro, macro, dan average. Untuk kasus saya (Gambar 1 atau dari output "classification report" secara umum), hanya ada tiga: binary (n atau p), macro, dan weighted. Berikut penjelasannya.
Binary, untuk binary classification, yang dilaporkan adalah F1-score untuk positive label, yakni 0.81 dengan mengambil label "p" sebagai label positif.
Macro avg, menghitung metrik untuk tiap label seperti rumus di atas, dan menghitung rata-ratanya (tanpa memperhitungkan jumlah sample/support).
Weighted avg, menghitung metrik untuk tiap label seperti rumus di atas dengan memperhitungkan jumlah sample/support.
Jadi mana yang harus dipakai/dilaporkan?
Berdasarkan keterangan Scikit-learn di atas maka:
Jika task adalah binary classification, yang dilaporkan adalah binary F1-score untuk positive label (yakni 0.81 atau 81% dari Gambar 1 di atas)
Jika task adalah multiclass, maka yang dilaporkan adalah weighted average (avg), contohnya 0.79 atau 79% dari Gambar 1 di atas.
Secara default, scikit-learn menggunakan label "1" untuk label positif jika argumen "pos_label" tidak diberikan. Saya curiga, dari sinilah asal kata F1-score bermula, yakni F-score untuk label "1" (atau bisa saja F-score untuk maksimal 1, tapi hampir semua metrik nilai maksimalnya adalah 1).
I tried to add a recipe to Nkululeko for pathological voice detection using the Saarbrueken Voice Database (SVD, the dataset currently perhaps cannot be downloaded due to a server problem). Using Nkululeko is easy; I just need two working days (with a lot of play and others) to process the data and get the initial result. The evaluation was mainly measured with F1-Score (Macro). The initial result is an F1-score of 71% obtained using open smile ('os') and SVM without any customization.
On the third day, I made some modifications, but I am still using the 'os' feature (so I don't need to extract the feature again, using the same 'exp' directory to boost my experiments). The best F1 score I achieved was 76% (macro). This time, the modifications were: without feature scaling, feature balancing with smote, and using XGB as a classifier. My goal is to obtain an F1 score of 80% before the end of the fiscal year (March 2025).
Here is the configuration (INI) file and a sample of outputs (terminal).
Configuration file:
[EXP]
root = /tmp/results/
name = exp_os
[DATA]
databases = ['train', 'dev', 'test']
train = ./data/svd/svd_a_train.csv
train.type = csv
train.absolute_path = True
train.split_strategy = train
train.audio_path = /data/SaarbrueckenVoiceDatabase/export_16k
dev = ./data/svd/svd_a_dev.csv
dev.type = csv
dev.absolute_path = True
dev.split_strategy = train
dev.audio_path = /data/SaarbrueckenVoiceDatabase/export_16k
test = ./data/svd/svd_a_test.csv
test.type = csv
test.absolute_path = True
test.split_strategy = test
test.audio_path = /data/SaarbrueckenVoiceDatabase/export_16k
target = label
; no_reuse = True
; labels = ['angry', 'calm', 'sad']
; get the number of classes from the target column automatically
[FEATS]
; type = ['wav2vec2']
; type = ['hubert-large-ll60k']
; type = []
type = ['os']
; scale = standard
balancing = smote
; no_reuse = True
[MODEL]
type = xgb
Outputs:
$ python3 -m nkululeko.nkululeko --config exp_svd/exp_os.ini
DEBUG: nkululeko: running exp_os from config exp_svd/exp_os.ini, nkululeko version 0.88.12
DEBUG: dataset: loading train
DEBUG: dataset: Loaded database train with 1650 samples: got targets: True, got speakers: False (0), got sexes: False, got age: False
DEBUG: dataset: converting to segmented index, this might take a while...
DEBUG: dataset: loading dev
DEBUG: dataset: Loaded database dev with 192 samples: got targets: True, got speakers: False (0), got sexes: False, got age: False
DEBUG: dataset: converting to segmented index, this might take a while...
DEBUG: dataset: loading test
DEBUG: dataset: Loaded database test with 190 samples: got targets: True, got speakers: False (0), got sexes: False, got age: False
DEBUG: dataset: converting to segmented index, this might take a while...
DEBUG: experiment: target: label
DEBUG: experiment: Labels (from database): ['n', 'p']
DEBUG: experiment: loaded databases train,dev,test
DEBUG: experiment: reusing previously stored /tmp/results/exp_os/./store/testdf.csv and /tmp/results/exp_os/./store/traindf.csv
DEBUG: experiment: value for type is not found, using default: dummy
DEBUG: experiment: Categories test (nd.array): ['n' 'p']
DEBUG: experiment: Categories train (nd.array): ['n' 'p']
DEBUG: nkululeko: train shape : (1842, 3), test shape:(190, 3)
DEBUG: featureset: value for n_jobs is not found, using default: 8
DEBUG: featureset: reusing extracted OS features: /tmp/results/exp_os/./store/train_dev_test_os_train.pkl.
DEBUG: featureset: value for n_jobs is not found, using default: 8
DEBUG: featureset: reusing extracted OS features: /tmp/results/exp_os/./store/train_dev_test_os_test.pkl.
DEBUG: experiment: All features: train shape : (1842, 88), test shape:(190, 88)
DEBUG: experiment: scaler: False
DEBUG: runmanager: value for runs is not found, using default: 1
DEBUG: runmanager: run 0 using model xgb
DEBUG: modelrunner: balancing the training features with: smote
DEBUG: modelrunner: balanced with: smote, new size: 2448 (was 1842)
DEBUG: modelrunner: {'n': 1224, 'p': 1224})
DEBUG: model: value for n_jobs is not found, using default: 8
DEBUG: modelrunner: value for epochs is not found, using default: 1
DEBUG: modelrunner: run: 0 epoch: 0: result: test: 0.771 UAR
DEBUG: modelrunner: plotting confusion matrix to train_dev_test_label_xgb_os_balancing-smote_0_000_cnf
DEBUG: reporter: Saved confusion plot to /tmp/results/exp_os/./images/run_0/train_dev_test_label_xgb_os_balancing-smote_0_000_cnf.png
DEBUG: reporter: Best score at epoch: 0, UAR: .77, (+-.704/.828), ACC: .773
DEBUG: reporter:
precision recall f1-score support
n 0.65 0.76 0.70 67
p 0.86 0.78 0.82 123
accuracy 0.77 190
macro avg 0.76 0.77 0.76 190
weighted avg 0.79 0.77 0.78 190
DEBUG: reporter: labels: ['n', 'p']
DEBUG: reporter: Saved ROC curve to /tmp/results/exp_os/./results/run_0/train_dev_test_label_xgb_os_balancing-smote_0_roc.png
DEBUG: reporter: auc: 0.771, pauc: 0.560 from epoch: 0
DEBUG: reporter: result per class (F1 score): [0.703, 0.817] from epoch: 0
DEBUG: experiment: Done, used 11.065 seconds
DONE
Update 2024/08/30:
Using praat + xgb (no scaling, balancing: smote) achieves higher F1-score, i.e., 78% (macro) and 79% (weighted)
I am delightful to show that my paper was accepted at the ACM MM 2024. This was my first ACM paper and was written by myself solely (solo author). Here is an abstract from the screenshot of the paper above.
Abstact
Automatic social perception recognition is a new task to mimic the measurement of human traits, which was previously done by humans via questionnaires. We evaluated unimodal and multimodal systems to predict agentive and communal traits from the LMU-ELP dataset. We optimized variants of recurrent neural networks from each feature from audio and video data and then fused them to predict the traits. Results on the development set show a consistent trend that multimodal fusion outperforms unimodal systems. The performance-weighted fusion also consistently outperforms mean and maximum fusions. We found two important factors that influence the performance of performance-weighted fusion. These factors are normalization and the number of models.
Once the link of the paper is available in ACM Library, I will put the link here.
Link: XXX.
Behind The Scene and Tips!
I have participating in MuSe challenge (Multimodal Sentiment Analysis Challenge and Workshop) for several years. This challenge, along with other challenges in conference like ICASSP and Interspeech, usually provides baseline program (code) and the respected dataset (e.g., ComParE). From this baseline, we can further analyze, make experiments, and often get new ideas to implement. My idea for that challenge (social perception challenge) is two parts: parameter optimization and multimodal fusion. I implement a lot of ideas (e.g., tuning more than 15 parameters) and some works. Once I get improvement with consistent results/phenomena (science must consistent!), I documented my work and submit a paper. This time, my paper got accepted!
This paper discusses the importance of accommodating uncertainty in addressing the issue of different models in speech classification. We used several variants of uncertainty-based ensemble learning (aka late fusions) to combine predictions of machine learning methods.
Every machine learning models has uncertainty, which, for instance, can be calculated from logits or probabilities. Entropy can be calculated from distribution. This distribution is multiplication of logits with softmax. Then, we can use several models to find the lowest uncertainty score and infer the label from that score. Or, we can weigh the probabilities by those uncertainty scores. We evaluated four variants of uncertainty-based ensemble learning.
Our work is highly beneficial to the community as it will help you improve the prediction of speech classification using ensemble learning.
Some areas that still need further development are stability and generalization. We see the trends that ensemble learning tends to improve the recognition rate of different models, but it is not always the case. We invite readers to collaborate in addressing the various unanswered questions.
We extend our thanks to AIST for their full support of our research.
Entropy yang dibahas ini bukan entropi pada termodinamika, melainkan pada teori informasi, meski secara konsep sama. Yakni, entropi adalah derajat ketidakturan, atau ketidakpastian.
Seperti biasa, proses belajar saya dokumentasikan dengan bantuan asciinema. Perangkat yang saya gunakan adalah scipy.stat.entropy, bisa juga dikodekan manual dengan Numpy. Materi pembelajaran saya kembangan dari manual Scipy.
Berikut dokumentasi pembelajaran saya untuk Entropy.
Keterangan:
Makna koin bias pada pembelajaran di atas adalah bahwa peluang gambar dan angka menjadi tidak 50:50, tetapi 90:10. Bisa jadi karena secara fisik berat sebelah ataupun sebab lain yang menjadikan peluang munculnya gambar jauh lebih besar dari peluang munculnya angka.
Bash, salah satu Unix Shell yang paling banyak digunakan, merupakan salah satu (bahasa) pemrograman yang saya pakai selain Python. Fungsi Bash layaknya lem perekat, melekatkan program yang satu dengan yang lain, Python dengan C, Python dengan C++, dan yang paling sering, Python dengan Sistem Unix (Linux Kernel, OS, dl). Simpelnya, saya menulis program utama dengan Python dan memanggilnya dengan Bash.
Ada salah satu konsep yang selama ini belum sepenuhnya saya pahami: return value. Kalau dalam Python return value sangat jelas, nilai yang dikembalikan dari fungsi tersebut. Dalam bash, maka nilai return value hanya ada dua: sukses atau gagal. Nilai return value tersebut bisa banyak, dari 0 sampai 255. Nilai 0 untuk sukses (perintah yang dieksekusi), nilai selainnya untuk gagal.
Kode bash di bawah ini mendemonstrasikan return value dalam bash. Tugasnya adalah mendeteksi nilai yang diberikan, saya masukkan dari 5 sampai 15. Jika nilainya lebih dari 10 maka sukses, jika kurang atau sama dengan 10 maka gagal ("failure").
#!/bin/bash
# bash_return_value_demo.sh
# set counter
failure_count=0
success_count=0
# Zero (0) return value as sign of success
success_function() {
if [ $1 -gt 10 ]; then # greater than
echo "Success!"
success_count=$((success_count+1))
return 0
fi
}
# Non-zero (1-255) return value as sign of failure
failure_function() {
if [ $1 -le 10 ]; then # less equal
echo "Failure!"
failure_count=$((failure_count+1))
return 1
fi
}
# loop from 5 to 15
for x in {5..15}; do
# print the value of x
echo "Value of x: $x"
success_function $x # input x to success_function
failure_function $x # input x to failure_function
# Print the last return values via $?
echo "Return value: $?"
done
# count the number of successful and failed commands
echo "Number of successful commands: $success_count"
echo "Number of failed commands: $failure_count"
Kode di atas sebenarnya self explanatory, bisa jelas sendiri per baris plus komentar di atas/sampingnya. Sederhananya, kita set counter di baris 7-8. Kemudian kita buat fungsi sukses dan gagal di baris 8 dan 17. Argument untuk fungsi di Bash di masukkan dalam fungsi yakni lewat $1 (untuk argumen pertama, $2 untuk argumen kedua dst). Kemudian buat loop untuk X mulai dari 5 sampai 15 (5..15), batas atas, 15, diproses juga, tidak seperti dalam bahasa Python. Di akhir skrip kita tampilkan jumlah perintah yang sukses dan gagal. Outputnya 5 untuk gagal, 6 untuk sukses, sesuai logika kode tersebut.
Jika program di atas dijalankan (setelah disimpan dalam fail bash_return_value_demo.sh), maka hasilnya adalah sebagai berikut, sesuai dengan penjelasan di atas.
./bash_return_value_demo.sh
Value of x: 5
Failure!
Return value: 1
-----------------
Value of x: 6
Failure!
Return value: 1
-----------------
Value of x: 7
Failure!
Return value: 1
-----------------
Value of x: 8
Failure!
Return value: 1
-----------------
Value of x: 9
Failure!
Return value: 1
-----------------
Value of x: 10
Failure!
Return value: 1
-----------------
Value of x: 11
Success!
Return value: 0
-----------------
Value of x: 12
Success!
Return value: 0
-----------------
Value of x: 13
Success!
Return value: 0
-----------------
Value of x: 14
Success!
Return value: 0
-----------------
Value of x: 15
Success!
Return value: 0
-----------------
Number of successful commands: 5
Number of failed commands: 6
Beberapa perangkat berikut saya gunakan secara masif satu tahun terakhir ini untuk riset, yakni untuk pengodean (coding). Urutan perangkat AI di bawah ini saya susun berdasarkan prioritas, mana yang paling penting saya urutkan paling atas.
1. Cody.dev
Saya menggunakan cody.dev versi berbayar (USD 9/bulan). Perangkat ini sangat efektif untuk mencari bug, code completion, dan chat tentang kode-kode kita. Fitur utamanya, Cody bisa membaca codebase kita (sampai 15 file) dan menggunakan LLM, paling ampuh Claude 3 Opus, untuk menjelaskan, menyarankan, dan mengedit code secara otomatis. Selain versi VS Code-nya, saya juga menggunakan versi web-chat van search-nya di sourcegraph.com.
2. Github copilot
Perangkat ini adalah perangkat AI pertama yang saya gunakan dan sangat fungsional (meski kalah dari Cody). Saya menggunakan code completion dan chatnya (kadang-kadang). Perangkat ini secara intensif saya gunakan sebelum menggunakan Cody dengan bantuan email kampus untuk registrasi.
3. Cursor.sh
Cursor adalah fork dari vscode yang dikhususkan untuk AI. Fitur utamanya adalah copilot++ yang lebih handal dari Github Copilot dan juga bisa membaca codebase seperti Cody namun lebih pintar (lebih solutif dibanding Cody). Kelemahannya adalah biaya yang lebih mahal dan kuota terbatas LLM Claude 3 Opus (10 limit perhari untuk versi berbayarnya, 20 USD/bulan). Saya menggunakan versi gratisnya. Tips: untuk membuat alias "code" ke "cursor" untuk terminal Cursor, ikuti arahan di issue ini.
4. Deepseek Coder
DeepSeek Coder adalah LLM khusus untuk pengodean gratis dan opensource. Saya menggunakan versi webnya. DeepSeek Coder, jika tanpa codebase (hanya satu kasus saja), akan menghasilkan hasil terbaik sepengalaman saya (mengalahkan Claude Opus).
5. Ollama
Ollama adalah platform untuk menggunakan LLM secara offline. Perangkat ini sangat bermanfaat ketika tidak bisa koneksi internet. Kelemahannya, butuh spek komputer yang tinggi (RAM ideal minimal 16GB dan CPU/GPU modern).
Kehadiran LLM (large language model) spt GPT-4 membuat riset menjadi berbeda. Sebelum adanya LLM (large-language model, seperti ChatGPT, Claude Opus, dll), saya membagi waktu kerja saya menjadi 2, riset dan menulis (proses/hasil riset). Masing-masing porsinya 50:50. Setelah adanya LLM, porsinya berubah, menjadi sekitar 65:35. Lebih banyak risetnya ketimbang menulisnya. Kenapa? Karena masalah yang dulu banyak ditemui ketika riset bisa diselesaikan dengan bantuan LLM (kebanyakan masalah algoritma, koding, percepatan waktu komputasi). Hasilnya, riset saya lebih produktif tapi tulisannya saya (pertahun) lebih sedikit. Semoga tahun depan bisa lebih banyak porsi untuk menulis kembali.
Ketika bekerja dalam tim, atau dengan tim, tempat penyimpanan data menjadi masalah. Si A menyimpan data di "download", si B di "my document", dan si C di "Files". Untuk menyamakan tempat penyimpanan data di komputer, saya merekomendasikan hal berikut.
Komputer dengan satu harddisk (SSD/HDD)
Untuk komputer dengan satu hardisk, tempat penyimpanan data terbaik adalah di "home", atau "/home/$USER/data", dimana $USER adalah nama user, misal "bagus" (sehingga menjadi "/home/bagus/data"). Di Linux, kita hanya butuh mengetik "cd" untuk "pulang ke rumah". Untuk memanggil path "data", siapapun usernya, dalam python, kita bisa menggunakan Path dari pathlib berikut.
from pathlib import Path
data = Path.home() / "data"
Oya, di era sekarang ini, kita tidak perlu membuat partisi tersendiri untuk data. Beda dengan zaman saya kuliah dulu yang perlu mempartisi satu HDD menjadi beberapa drive agar ketika drive satu rusak, drive lainnya masih bisa digunakan.
Komputer dengan multi harddisk
Untuk komputer dengan multi harddisk, tempat penyimpanan data yang saya rekomendasikan adalah di root, yakni "/data". Siapapun usernya, pathnya pasti akan sama dalam hal ini.
Pro-kontra:
Kenapa satu harddisk di "home" dan multi-hardisk di "/data"? Sebetulnya "/data" lebih universal karena tidak bergantung "User", namun karena lokasinya di "/" (root), menurut saya hal ini rentan masalah. Misalnya jika sistem korup atau clash, biasanya data di bawah root akan terkena juga. Alasan kedua karena sekuriti/akses terhadap root. Home bisanya lebih terisolasi.
Dalam filosofi, permasalahan siapa pencipta Tuhan (problem of the creator of God) adalah topik perdebatan yang tiada habisnya. Argumennya adalah: "Jika alam semesta diciptakan oleh Tuhan, maka siapa pencipta Tuhan?"
Saya ingin menjawab pertanyaan itu dengan sederhana. Begini analoginya.
Analogi #1
Jika alam semesta, sebagai ciptaan, diibaratkan oleh angka 2, maka sebelum angka dua itu pastilah ada angka sebelumnya, yaitu 1. Angka 2 adalah alam semesta dan angka 1 adalah Tuhan. Lalu, siapa/apa sebelum 1? Tidak ada alias nol, 0. Begitu juga dengan Tuhan, tidak ada penciptanya.
Analogi #2.
Dari video ini, adanya Tuhan Allah merusak teori sebab-akibat. Karena adanya penciptanya, maka siapa pencipta pencipta? Jawabannya adalah bahwa teori sebab-akibat tidak wajib ada (not necessarily exist). Dari mana hukum sebab-akibat itu berasal? Dari Fisika. Darimana Hukum Fisika itu berasal? Dari Matematika. Jadi pasti ada ujungnya, sebagaimana kita saat ini (fixed ada). Pencipta alam semesta tidak punya pencipta!
Jika semua, anggap, ada sebab-akibatnya, apa sebab dari hukum sebab-akibat (cause-effect relantionship)? Allah!
Untuk membuat alias untuk Github Copilot, misal ?? untuk menggantikan `gh copilot suggest`, beberapa baris alias berikut dapat ditambahkan pada fail `.bashrc`.
alias '??'='gh copilot suggest -t shell'
alias 'git?'='gh copilot suggest -t git'
alias 'explain'='gh copilot explain'
Dengan cara ini kita bisa mempermudah hidup dan menghemat waktu. Berikut contohnya:
bagus@m049:~$ ?? list WAV files less than 1 MB
Welcome to GitHub Copilot in the CLI!
version 0.5.4-beta (2024-01-04)
I'm powered by AI, so surprises and mistakes are possible. Make sure to verify any generated code or suggestions, and share feedback so that we can learn and improve. For more information, see https://gh.io/gh-copilot-transparency
Suggestion:
find . -name "*.wav" -size -1M
? Select an option
> Exit
bagus@m049:~$ git? show history
Welcome to GitHub Copilot in the CLI!
version 0.5.4-beta (2024-01-04)
I'm powered by AI, so surprises and mistakes are possible. Make sure to verify any generated code or suggestions, and share feedback so that we can learn and improve. For more information, see https://gh.io/gh-copilot-transparency
Suggestion:
git log
? Select an option
> Exit
bagus@m049:~$ explain "make -j 5"
Welcome to GitHub Copilot in the CLI!
version 0.5.4-beta (2024-01-04)
I'm powered by AI, so surprises and mistakes are possible. Make sure to verify any generated code or suggestions, and share feedback so that we can learn and improve. For more information, see https://gh.io/gh-copilot-transparency
Explanation:
• make is a build automation tool used to compile and build projects.
• -j 5 specifies the maximum number of jobs (parallel tasks) that make can
run simultaneously. In this case, it is set to 5.
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`.
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.
Pada bulan ini, saya melakukan dua kali kerja jarak jauh setengah hari dan tiga kali kerja jarak jauh sepanjang hari. Isi dari pekerjaan jarak jauh ini entah menulis laporan (makalah penelitian) untuk pengembangan sistem pengenalan emosi ucapan waktu nyata atau melihat sistem e-learning di kantor (Kursus Pelatihan Dasar untuk Karyawan Asing). Saya terus membangun adapter WavLM untuk sistem pengenalan emosi ucapan Jepang, tetapi hasilnya belum diperoleh. Saya juga meninjau beberapa pengenalan emosi ucapan dan ekspresi vokal termasuk dataset dari Vietnam (dari Konferensi APSIPA 2023), Korpus Ucapan Emosional Anak Rusia (EmoChildRu), vokalisasi nonverbal Jepang (JNV), dan Ucapan Emosional Jepang dengan Konten Verbal dan Ekspresi Nonverbal (JVNV). Saya juga sedang menyiapkan tanggapan untuk sebuah makalah yang diajukan ke LREC/Coling 2024. Dalam diskusi tertulis, saya menjelaskan daya saing model pra-pelatihan dengan HuBERT Large yang mencapai hasil terbaik di antara model-model pra-pelatihan lainnya, dan juga kesulitan dengan model-model pra-pelatihan lain seperti UniSpeech-SAT dan XLSR-2B. Kesulitan pertama disebabkan oleh desain UniSpeech-SAT yang ditujukan untuk verifikasi pembicara dengan informasi terpisah di antara pembicara, sementara kesulitan kedua disebabkan oleh batasan memori GPU (saat ini saya melatih model saya dengan RTX3090 24 GB VRAM). Komputasi sebelumnya menggunakan model besar seperti XLSR 2B tidak dapat dilakukan karena masalah out-of-memory. Meskipun masalah ini dapat diatasi dengan meningkatkan memori (misalnya, dengan mengupgrade GPU ke A6000 dengan 48 GB VRAM), model yang dihasilkan akan besar ukurannya, yang dapat memperpanjang waktu pemuatan model untuk inferensi. Selain itu, saya juga melakukan pekerjaan administratif menyiapkan dokumen untuk perpanjangan visa.
Dulu saya pernah bertanya-tanya, adakah platform atau aplikasi note-taking yang sederhana, aplikasi tersebut hanya bersifat aplikasi (seperti word processor) namun filenya disimpan dalam file teks sederhana seperti text (TXT) dan markdown (MD)? Bukan menyatu dengan aplikasi seperti Google Keep atau Evernote (bukan app-over-file tapi file-over-app). Ternyata ada, dan saya pernah mencobanya. Dulu saya saya tidak melanjutkan mencobanya karena apa yang saya cari tersebut tidak ketemu, ternyata memang ada. Ketidaktahuan saya memblokade penggunaan aplikasi tersebut waktu itu. Aplikasi itu adalah Obsidian.
Setelah menggunakan evernote, kemudian pindah ke Google Keep, dan Simplenote, ada beberapa perubahan mendasar yang saya alami. Versi free dari evernote memiliki kemampuan terbatas. Google Keep kemudian mematikan versi luring (offline) sehingga saya tidak bisa melihat catatan saya lewat PC ketika tidak bisa konek internet. Simplenote menjadi second brain bagi saya, namun, ketika catatan saya bertambah banyak dan saya menginginkan catatan terstruktur (linked-notes, notes in note), simplenote menjadi terbatas. Saya pernah mencoba Obsidian sekitar beberapa tahun yang lalu, namun apa yang saya cari (sync dan structured notes) tidak saya temukan karena ketidaktahuan saya.
Organisasi Obsidian (vaults)
1. Diary -- untuk catatan harian
2. Fiksi -- untuk mencatat kisah fiksi, seperti draft cerpen atau novel
3. Non-fiksi -- untuk catatan non-fiksi
4. Google keep -- archive dari Google Keep yang saya export ke Obsidian
5. Pengajian -- catatan pengajian dll., ada plugin Quran juga.
Demikian, Obsidian telah menjadi otak keempat saya setelah simplenote dan Standard Notes.
Akhirnya, ada platform offline dan online dalam satu portal. Dan platform itu ternyata sudah ada sejak lama. Namanya Standard Notes. Bisa diinstal via snap dengan perintah berikut di Ubuntu.
sudo snap install standard-notes
Saya suka menulis blog, baik itu di blogger, wordpress, medium, atau tumblr. Masalahnya, sejauh pengetahuan saya saat itu, belum ada platform digital yang bisa berlaku baik untuk offline dan online. Misalnya, saat saya punya ide, saya menuliskannya di editor, word processor, atau note taking app. Kemudian saat saya ingin mempublikasikannya, saya salin tulisan offline tadi ke platform blog yang bersangkutan, misalnya Blogger. Sampai saya menemukan platform/aplikasi Standard Notes yang menyatu dengan listed.to.
Dengan platfom ini saya bisa menulis blog on-the-go secara luring, kemudian mempublikasikannya dari perangkat tersebut tanpa harus menyalin dan menempelnya ke internet. Cukup sekali-dua kali klik. Bagi anda yang belum tahu caranya, berikut cara publikasi blog lewat Standard Notes and Listed (www.listed.to).
1. Buka Stantard Notes app atau web app 2. Klik ikon Preferences in sisi kanan bawah 3. Buka seksi Listed 4. Pilih Create New Author
Untuk publikasi dari Standard Notes ke Listed (lihat gambar di bawah). 1. Klik kanan judul note yang akan dipublish 2. Pilih "Listed action" kemudian pilih "Publih to Blog"
Voilla, sekarang catatan datam Standard Notes tersebut telah terpublish dalam Listed.to.
Karena kemudahan itu, besar kemungkinan saya akan mengeblog di Listed. Blog di blogspot ini mungkin akan dormant, wallahua'lam. Saya belum tahu pastinya, mungkin topik-topik professional akan saya taruh disini, catatan harian di Listed, dan quotes di Tumblr.
Dengan demikian, Standard Noted menjadi otak ketiga saya setelah simplenote.
If research misconduct occurs, including guest/gift authorship, the integrity of a researchers is questionable; this can PERMANENTLY and NEGATIVELY affect their career.
Salah salah praktek tercela di bidang akademik adalah ghost dan gift authorship, menuliskan nama mereka yang tidak berkontribusi di dalam penulisan paper. Penerbit seperti Elsevier dan Springer memiliki peraturan ketat dalam kasus ini, sekali praktek ini ditemukan, karya yang bersangkutan bisa ditarik. Saya sendiri sudah beberapa kali melaporkan kasus ini, tak peduli rekan sejawat, atasan, atau orang lain. Ada kalanya, mungkin, anda "dipaksa" menuliskan nama teman anda, baik kenalan, teman se-lab, se-kampus, atau se-jurusan. Untuk dimasukkan menjadi penulis (authors), setidaknya ada tiga syarat [1]: 1. Kontribusi subtansial dalam riset 2. Ikut menulis draft 3. Menyetujui versi final dari draft
Cara mengetes ghost author, menurut elsevier, adalah bahwa semua penulis mempunyai kemampuan dan kewajiban yang sama dalam mempertahankan ide di dalam tulisannya. Oleh karena itu, jika ada seorang penulis (co-authors) yang tidak bisa menjelaskan atau menjawab pertanyaan terkait tulisannya, bisa jadi penulis itu adalah ghost, guest atau gift author.
Compliance is more than just obeying laws.
Dalam publikasi ilmiah, kita memiliki code of conduct. Dalam setiap submisi artikel, kita diwajibkan menuliskan kontribusi setiap penulis dalam artikel. Secara common sense, setiap mereka yang namanya ada pada paper pasti berkontribusi. Hukum penulisan ini wajib kita patuhi. Bahkan diatasnya, ada etika yang seharusnya kita taati juga: menghindari research misconduct termasuk gift, ghost atau honorary authorship ini.
Jika ada orang lain yang meminta namanya ditulis dalam sebuah paper, sebaliknya ada juga orang yang melarang namanya ditulis dalam sebuah paper. Seorang teman S3 pernah bercerita bahwa professornya, meminta namanya tidak dimasukkan dalam publikasi teman saya tersebut karena dia tidak berkontribusi sama sekali.
Institusi kita punya visi dan misi mulia yang ingin diraih. Kita tidak bisa menghalalkan segala cara untuk meraih visi dan misi itu. You CANNOT choose just any method to achieve your goal. There is a "path we should take" among them. Goal adalah visi institusi kita yang ingin kita capai. Jelas disini bahwa ghost dan gift authorship tidak termasuk dalam "path we should take".
Rezeki tidak hanya dari insentif publikasi. Masih banyak jalan dan pintu rezeki berkah dan halal lainnya daripada memasukkan nama istri, teman, atau atasan yang tidak berkontribusi pada publikasi ilmiah kita. Praktek tercela ini membahayakan insitusi kita. Semoga kita terhindar dari praktek tercela ini.
Ghost authorship untuk memperbesar peluang diterimanya paper
Ini disebut efek Chaporone [3]. Penulis Chaperone adalah penulis senior yang telah menulis beberapa journal, katakanlah di jurnal A. Untuk memperbesar kans diterima di journal A, penulis junior mengajak atau memasukkan nama penulis Chaperone saat submisi ke Jurnal A. Tujuannya adalah untuk mempertinggi kans diterima di jurnal A.
Ada kasus dimana peneliti yang sudah meninggal tetap dilibatkan dalam pembuatan paper. Kasus ini [2], ditengarai untuk memperbesar kans diterimanya paper tersebut di sebuah jurnal. Anggaplah peneliti yg sudah meninggal tsb adalah peneliti terkenal, misal peraih nobel. Dengan memasukkan namanya sebagai co-author maka kans diterimanya sebuah paper dalam jurnal mungkin akan bertambah besar. Hal yang tidak mungkin dilakukan oleh peneliti yang sudah meninggal adalah pada persyaratan nomor 3 authorship di atas: menyetujui versi final. Pun demikian, hal ini (memasukkan penulis yang sudah meninggal) bisa saja dilakukan bila penulis yang telah meninggal tersebut benar-benar berkontribusi dan disebutkan dalam "Aknowledgement" bahwa salah satu penulis telah meninggal sebelum paper diterbitkan.
Kenapa ada praktek Ghost Authorship, khususnya di negeri kita?
Seorang sejawat bertanya, kenapa kondisi ideal (tidak ada ghost authorship) tidak bisa diterapkan di, khususnya, negeri kita tercinta. Banyak faktor. Diantara banyak faktor, menurut saya yang paling penting adalah mental peneliti dan kecukupan ekonominya. Di negeri kita, mental peneliti belum terbentuk secara ideal. Alih-alih melakukan "impactful research"; yang dilakukan peneliti adalah bagaimana mendapatkan cuan dari penelitian, entah itu dari insentif, kenaikan pangkat, dll. Disini mental peneliti yang bersangkutan bermasalah. Bisa jadi karena tidak ada pendidikan "Compliance and Researcher Ethics" untuk para peneliti (di institusi saya, setiap peneliti diwajibkan mengambil e-learning ini setiap tahunnya dan wajib lulus ujian e-learning tsb). Kondisi ini diperparah dengan kecukupan ekonomi peneliti yang bersangkutan. Selama kebutuhan dasar belum terpenuhi (sandang, pangan, papan), maka dia akan mencari segala cara (dan mungkin saja menghalalkan segala cara) untuk memenuhi kebutuhan tersebut. Salah satunya dengan meminta rekannya untuk memasukkan namanya saat publikasi. Agar, ketika mendapat insentif, dia juga ikut kecipratan. Sekaligus mempercepat proses kenaikan pangkat.
Lalu, Bagaimana solusinya?
Alih-alih menuliskan teman atau orang lain sebagai ghost authorship, kita bisa menawari mereka untuk berkontribusi, misalnya:
Funding, membiayai biaya publikasi
Proof-read, misalnya menemukan minimal 10 kesalahan dalam draft dan merevisinya
Dengan cara itu, seorang menjadi layak menjadi co-author. Dengan catatan, sekali lagi, kontribusinya substansial (dua diatas adalah contoh kotribusi yang substansial).
[3]V. Sekara, P. Deville, S. E. Ahnert, A. L. Barabási, R. Sinatra, and S. Lehmann, “The chaperone effect in scientific publishing,” Proc. Natl. Acad. Sci. U. S. A., vol. 115, no. 50, pp. 12603–12607, 2018, doi: 10.1073/pnas.1800471115.
tl;dr: Kadang kita seharusnya mendengarkan kata orang, kadang kita seharusnya tidak mendengarkan kata orang
Kapan seharusnya tidak mendengarkan kata orang
Ada dua kisah diantara banyak kisah. Kisahnya Abu Thalib dan seorang yang menaiki keledainya bersama ayahnya. Abu Thalib ingin mengikuti agama nabi Muhammad diakhir hayatnya namun tidak jadi karena mendengarkan apa kata orang.
Menjelang wafatnya, Nabi mengajak kembali pamannya Abu Thalib untuk bersyahadat, namun Abu Thalib menjawab, "Seandainya kaum Quraisy tidak mencelaku dengan berkata, 'Tidak ada yang mendorongnya mengucapkannya kecuali karena kesedihannya menghadapi maut,' niscaya aku mengucapkannya untukmu."
Dari sini terlihat bahwa Abu Thalib lebih memilih apa kata orang daripada mengikuti ajakan nabi Muhammad. Abu Thalib tidak ingin dianggap oleh kaum Quraisy bahwa dirinya takut menghadapi kematian sehingga mengubah agamanya.
Cerita kedua adalah kisah masyhur tentang anak, bapak, dan keledai mereka. Suatu hari ada anak dan bapak yang akan melakukan perjalanan. Mereka adalah 2 orang yang tanggung. Si anak belum dewasa, ia masih remaja yang beranjak. Sedangkan si bapak adalah seorang yang sudah tidak muda lagi, namun belum terlalu tua. Mereka melakukan perjalanan menuju pasar menggunakan keledai tua, namun tubuhnya masih kuat. Hanya saja memang tubuh keledai umumnya berukuran kecil.
Berangkatlah mereka. Si bapak menunggangi kuda, sedangkan anaknya jalan kaki. Di kampung pertama, mereka disoraki oleh wanita. "Kok, kamu yang naik, sedangkan anakmu yang kecil itu kelelahan berjalan dibelakang?"
Mendengar itu si Bapak pun turun dari keledai dan menyuruh anaknya untuk naik keledai. Kemudian tak berapa lama, mereka melewati segerombolan orang tua sedang duduk dibawah pohon. Mereka berkata "Mengapa kamu berjalan kaki, kamu kan sudah tua, sedangkan anakmu yang masih muda. Harusnya anakmulah yang jalan, dan engkaulah yang menunggangi kuda? Si anak pun kemudian turun.
Kemudian di desa lain mereka pun mendapat komentar lagi dari seorang pria berbadan tegap yang terluhat gagah. "Kok cuma satu orang yang naik keledai, kenapa enggak berdua ?". Mendengar itu merekapun menaiki keledai itu bersama-sama. Dua orang naik seekor keledai.
Mereka melintai kampung berikutnya. Tetapi, ditengah perjalanan, mereka melewati sekelompok orang pecinta binatang. Melihat pemandangan itu, para pecinta binatang ini berkomentar "Kasihanilah binatang yang kurus kering itu. Kalian berdua menungganginya, padahal kalian lebih berat dari pada keledai ini."
Mendengar itu, bapak dan anak ini lantas turun dari keledai. "Kalau begitu, mari kita berjalan bersama-sama dan kita biarkan keledai ini berjalan di hadapan kita." Kata si Bapak.
Tak habis sampai disitu mereka masih mendapat komentar lagi. Mereka bertemu orang yang sedang mabuk dan berkata. "Yang pantas itu keledai yang menaiki kalian berdua, sehingga kalian dapat membuatnya terhindar dari kendala-kendala di jalan". Sang bapak yang terpengaruh omongan pun lansgung mengendong si keledai.
Namun di depan, mereka lagi lagi ditertawakan oleh orang-orang asbab pemandangan aneh itu. Kemudian si bapak berhenti dan menoleh kepada anaknya sambil berkata, "Wahai anakku, jika mendengar dan mengikuti semua omongan manusia. Tidak akan ada habis - habisnya." Dan mereka berdua pun tertawa. [1]
Dari kisah ini kita mendapat pelajaran bahwa tidak perlu mendengarkan kata orang, selama apa yang kita lakukan itu baik.
Kapan seharusnya mendengarkan apa kata orang
Ada dua kisah juga. Kisah pertama saat sahabat menawarkan untuk membunuh munafiq di Madinah dan Nabi tidak mengiyakannya karena takut apa kata orang. Kedua, kisah saat nabi berjalan berdua bersama istrinya di malam hari dan sahabat menghindar.
Kisah pertama adalah seperti ini.
Setelah Rasulullah selesai menghadapi perang dengan Banu Mustaliq, ada dua orang dari kalangan Muslimin yang bertengkar memperebutkan mata air; yang seorang dari kalangan Muhajirin dan yang seorang lagi dari Anshar. Mereka yang dari Muhajirin berteriak: “Saudara-saudara Muhajirin!” Dibalas oleh Anshar: “Saudara-saudara Anshar!” Pada waktu itulah Abdullah bin Ubay bin Salul, pemimpin kaum munafik di Madinah berkata kepada orang-orang di sekitarnya: "Di kota kita ini sudah banyak kaum Muhajirin. Penggabungan kita dengan mereka akan seperti kata peribahasa: 'Seperti membesarkan anak harimau.' Sungguh, kalau kita sudah kembali ke Madinah, orang yang berkuasa akan mengusir orang yang lebih hina."
Muhammad Husain Haekal dalam "Umar bin Khattab" menceritakan bahwa kata-kata Abdullah bin Ubai itu oleh sahabat disampaikan kepada Rasulullah, yang ketika itu ada Sayidina Umar bin Khattab. Umar naik pitam mendengar laporan itu dan katanya: “Rasulullah, perintahkan kepada Abbad bin Bisyir supaya membunuhnya.” Tetapi Rasulullah menjawab: “Umar, bagaimana kalau sampai menjadi pembicaraan orang, bahwa Muhammad membunuh sahabat-sahabatnya sendiri. Lalu ia meminta diumumkan supaya kaum Muslimin segera berangkat pada waktu yang tidak biasa mereka lakukan.” [2]
Jadi nabi tidak membunuh Ubay bin Salul karena takut apa kata orang.
Kisah terakhir adalah ketika Nabi berjalan bersama istrinya pada malam hari yang gelap. Hadistnya sebagai berikut: "Rasulullah shallallahu ‘alaihi wa sallam pernah beriktikaf di masjid, lantas aku (shafiyah) mengunjungi beliau pada malam hari lalu berbincang-bincang dengan beliau, lalu aku berdiri. Kemudian Nabi shallallahu ‘alaihi wa sallam mengantarkanku pulang ke rumah.”
Rumah Shafiyyah Ketika itu di rumah Usamah bin Yazid. Ketika mengantarkan pulang, lewatlah dua orang Anshar di jalan. Dua orang Anshar itu memandang Nabi shallallahu ‘alaihi wa sallam (dengan penuh curiga), kemudian mereka bergegas melewati Nabi shallallahu ‘alaihi wa sallam. Nabi shallallahu ‘alaihi wa sallam pun berkata, “Tak perlu curiga seperti itu, ini adalah istriku Shafiyyah binti Huyay.” Mereka berdua pun mengatakan, “Subhanallah, wahai Rasulullah.” Nabi shallallahu ‘alaihi wa sallam pun bersabda, “Sesungguhnya setan mengalir dalam diri manusia melalui pembuluh darahnya. Aku benar-benar khawatir ada sesuatu prasangka jelek yang ada dalam diri kalian berdua" [3].
Dari cerita di atas, filter sederhana untuk kapan mendengarkan apa kata orang adalah dengan melihat dampak/akibat yang kita terima dari mendengarkan atau tidak mendengarkan kata orang tersebut. Jika terjadi dampak besar (fitnah, masuk neraka, dll) maka kita perlu mengambil mana yang bisa menghindari dampak buruk tersebut. Misal dalam kasus Abu Thalib dan kisah bapak, anak, dan keledai, sudah seharusnya mereka tidak mendengarkan apa kata orang. Sebaliknya, bila dampaknya besar, kita mungkin perlu mendengar apa kata orang.
Sudah lama saya ingin mencoba (membuat) teknologi text-to-speech (TTS) atau speech synthesis bahasa Indonesia. Percobaan pertama saya beberapa tahun lalu gagal. Disini reponya: Expressive-FastSpeech2. Pada percobaan tersebut, saya langsung mencoba membuat suara (bukan Bahasa Indonesia) yang memiliki emosi, seperti suara orang marah, sedih, atau senang. Alih-alih suara, saya hanya mendengar derau/bising saja dari algoritma FastSpeech2.
Ketika Meta/Facebook mengumumkan salah satu riset mereka, yakni MMS (Massively Multilingual Speech), saya langsung tertarik mencobanya. MMS bisa diaplikasikan untuk ASR (automatic speech recognition, atau STT, speech-to-text) dan TTS. Untuk TTS, sepemahaman saya, Meta hanya mengaplikasikan dataset yang besar pada Variational Inference with adversarial learning for end-to-end Text-to-Speech (VITS). Saya coba ASRnya tidak lebih baik dari OpenAI Whisper, khususnya dari sisi latency. Saya coba TTSnya, kebetulan hasilnya memuaskan, khususnya untuk yang belum pernah berhasil membuat TTS sendiri.
Repository
Untuk keperluan TTS ini, saya buat repository khusus di Github: TTS-Bahasa. TTS-Bahasa sebenarnya tidak khusus untuk bahasa Indonesia, tapi semua bahasa yang didukung oleh MMS (ada lebih dari 1000 bahasa). Repo tersebut saya adaptasi dari tutorial di laman MMS, yakni tutorial Google Colabnya. Saya hanya menambahkan satu skrip python CLI (command line interface) untuk memudahkan pembuatan audio file suara sintesis berdasarkan input kalimat. Contohnya seperti ini.
python3 mms_tts_ind.py --text "Selamat datang di Indonesia"
Suara berbahasa Indonesia akan diperdengarkan setelah eksekusi program selesai (berbunyi: "Selamat datang di Indonesia"). Luaran suara tersebut juga bisa disimpan dalam format WAV atau MP3, misalnya.
python3 mms_tts_ind.py --text "Selamat datang di Indonesia" -s -o selamat_datang.wav
Untuk mencobanya, tidak perlu menginstall. Cukup clone repo tersebut, dan ikuti petunjuk di READMEnya. Jika ada kendala, anda bisa membuka "issues" di repo tersebut.
Demo
Jika anda bukan programmer, coder, researcher, mahasiswa teknik, atau tidak terbiasa dengan Python, anda bisa langsung mencoba demo-nya disini: https://bagustris.github.io/tts-bahasa/.
Tulisan berikut merupakan catatan singkat instalasi ESPNET dengan Conda (OS: Ubuntu 20.04~).
Dari dokumentasi ESPNET, cara yang disarankan untuk menginsall ESPNET adalah melalui Conda.
./setup_anaconda.sh miniconda espnet 3.8
Namun dengan cara ini, environment conda menjadi tidak bernama sehingga kita perlu me-load conda dengan fullpath.
Solusinya adalah dengan memberikan argumen yang tepat untuk `setup_anaconda.sh`, yakni $CONDA_ROOT. Pada Ubuntu, default CONDA_ROOT ada di `/home/$USER/miniconda3` (Setelah menginstall miniconda). Contohnya adalah sebagai berikut.
Dengan cara ini kita bisa berpindah ke perintah instalasi selanjutnya, yakni `make`. Setelah terinstall, kita bisa mengaktifkan ESPNET dengan `conda activate espnet`.
Catatan:
- Sebelum menginstall ESPNET, kita perlu menginstall cmake, python3-dev, sox, flac, dan build-essential via apt-get.
Minggu ini saya memutuskan untuk melanggan Medium. Biaya langganannya 5 USD/bulan. Medium, bagi yang belum tahu, adalah platform penerbitan daring yang menyediakan ruang bagi penulis dari berbagai bidang untuk berbagi pandangan, pengetahuan, cerita, dan pengalaman mereka. Saya tertarik dengan Medium karena menawarkan beragam konten menarik, dari esai inspiratif hingga artikel informatif yang membahas berbagai topik.
Ada beberapa alasan kuat mengapa saya memutuskan untuk melanggan Medium untuk setahun kedepan:
Beberapa konten dengan kualitas tinggi hanya bisa diakses dengan melanggan. Medium menempatkan kualitas konten di atas hal lain; banyak penulisnya adalah penulis buku. Mereka menggali topik dengan mendalam dan menawarkan sudut pandang yang unik, membuat saya selalu terinspirasi dan berpikir lebih jauh.
Bisa dibayar dari program partner. Agar mendapatkan bayaran dari artikel yang kita tulis, kita harus menjadi pelanggan melalui Medium Partner Program.
Beragam Topik yang Menarik: Medium menawarkan berbagai macam topik yang bisa dipilih sesuai minat dan hobi saya. Entah itu teknologi, pengembangan diri, psikologi, budaya, atau bisnis, saya selalu menemukan konten yang relevan dan bermanfaat bagi pengetahuan saya.
Komunitas dan Interaksi: Medium juga memiliki komunitas yang aktif dan ramah. Saya senang membaca komentar dan tanggapan dari pembaca lain yang menambah wawasan saya tentang suatu topik. Selain itu, Medium memiliki fitur "clap" yang memungkinkan saya untuk memberikan apresiasi atas tulisan yang saya nikmati.
Memotivasi untuk menulis lebih. Saya pernah menulis untuk menulis satu artikel per minggu (https://bagustris.blogspot.com/2020/03/new-article-every-weekend.html). Namun, hal ini sangat sulit ternyata! Dengan medium, saya berharap target ini bisa tercapai (logika: karena berbayar saya harus menulis, tidak saja membacanya).
Saya akan lihat (evaluasi) setahun mendatang apakah Medium ini memberikan benefit yang lebih dari 5 USD/per bulan. Harapan saya untuk setahun mendatang adalah:
Lebih Banyak Artikel saya yang Menarik: Saya berharap untuk menemukan lebih banyak artikel yang mendalam dan berbobot di Medium. Semakin banyak penulis berbakat yang bergabung dan berkontribusi, semakin kaya pula konten yang akan tersedia bagi para pembaca.
Pengembangan Diri sebagai Penulis (baik dari sisi kuantitas dan kualitas): Dengan membaca dan belajar dari penulis-penulis hebat di Medium, saya berharap untuk terus mengembangkan kemampuan menulis saya sendiri. Saya ingin mengasah kemampuan untuk menyajikan informasi dengan cara yang menarik dan dapat dipahami oleh pembaca.
Berbagi Kontribusi yang berdampak: Saya bermimpi suatu hari nanti bisa berkontribusi dengan menulis artikel berdampak tinggi di Medium. Bagaimana mengukur dampaknya? Medium menyediakan statistik siapa yang hanya melihat artikel kita dan siapa yang benar-benar membaca artikel kita. Metrik kedua ini yang saya kejar.
Menjalin Lebih Banyak Koneksi: Medium adalah tempat yang tepat untuk menjalin hubungan dan koneksi dengan penulis dan pembaca dari seluruh dunia. Saya berharap bisa berinteraksi lebih banyak dengan mereka, berdiskusi, dan berbagi inspirasi.
Demikianlah cerita mengapa saya memilih untuk melanggan Medium.com dan harapan saya untuk tahun mendatang.Selanjutnya, tulisan-tulisan dalam bahasa Indonesia akan saya tulis di Blogger ini sedangkan artikel bahasa Inggris akan saya tulis di akun Medium saya.
Evaluasi 2024:
Setelah satu tahun melanggan Medium, saya putuskan berhenti. Selama setahun saya hanya mempublikasikan enam artikel atau rata-rata hanya satu artikel per dua bulan. Dengan membayarpun (dan kemungkinan dapat bayaran juga), belum bisa memotivasi saya untuk lebih masif menulis di Medium. Ada banyak alasan; mungkin saya lebih terbiasa dan nyaman di Blogger ini daripada di sana.
Are you interested in visualizing live audio data from your microphone? Do you want to see the waveform of your voice or any other sound in real time? In this blog post, we’ll explore a Python script that utilizes Matplotlib to plot live microphone signals. This script is a useful tool for understanding and analyzing audio input in real time.
Before we begin, make sure you have sounddevice, Matplotlib, and NumPy installed. If not, you can install them using the following command:
pip install matplotlib numpy sounddevice
Now, let’s dive into the code and see how it works.
The Code
#!/usr/bin/env python3"""Plot the live microphone signal(s) with matplotlib.Matplotlib and NumPy have to be installed."""import argparseimport queueimport sysfrom matplotlib.animation import FuncAnimationimport matplotlib.pyplot as pltimport numpy as npimport sounddevice as sd
The script starts with the usual shebang (#!/usr/bin/env python3) and a brief docstring explaining the purpose of the code. It also imports the necessary modules: argparse, queue, sys, FuncAnimation from matplotlib.animation, plt (alias for matplotlib.pyplot), numpy, and sounddevice.
Next, the code defines two helper functions and two main functions.
def int_or_str(text):"""Helper function for argument parsing."""try:returnint(text)exceptValueError:return textdef audio_callback(indata, frames, time, status):"""This is called (from a separate thread) for each audio block."""if status:print(status, file=sys.stderr)# Fancy indexing with mapping creates a (necessary!) copy: q.put(indata[::args.downsample, mapping])
The int_or_str function is a helper used for parsing command-line arguments. It tries to convert the input text to an integer and returns it if successful; otherwise, it returns the input text as it is.
The audio_callback function is called for each audio block received from the microphone. It receives indata (the audio data), frames (the number of frames), time (the timestamp of the audio data), and status (the status of the audio stream). It prints any status messages to the standard error and puts a copy of the audio data (filtered using downsampling and channel mapping) into a queue (q) for processing later.
def update_plot(frame):"""This is called by matplotlib for each plot update. Typically, audio callbacks happen more frequently than plot updates, therefore the queue tends to contain multiple blocks of audio data. """global plotdatawhileTrue:try: data = q.get_nowait()except queue.Empty:break shift =len(data) plotdata = np.roll(plotdata, -shift, axis=0) plotdata[-shift:, :] = datafor column, line inenumerate(lines): line.set_ydata(plotdata[:, column])return lines
The update_plot function is called by Matplotlib for each plot update. It retrieves audio data from the queue (q) and shifts the existing data to accommodate the new audio block. The function then updates the y-data of the lines on the plot with the new audio data.
if__name__=="__main__":# ... (continued in the next code block)
The script uses the standard Python if __name__ == "__main__": guard to ensure that the following code is only executed when the script is run directly, not when it’s imported as a module.
parser = argparse.ArgumentParser(add_help=False) parser.add_argument('-l', '--list-devices', action='store_true',help='show list of audio devices and exit') args, remaining = parser.parse_known_args()if args.list_devices:print(sd.query_devices()) parser.exit(0)
The code sets up an argument parser with argparse to handle command-line arguments. It allows the user to list available audio devices and exit the program without running the main functionality. If the user specifies the --list-devices flag, the script will print a list of audio devices using sd.query_devices() and then exit.
parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, parents=[parser]) parser.add_argument('channels', type=int, default=[1], nargs='*', metavar='CHANNEL',help='input channels to plot (default: the first)') parser.add_argument('-d', '--device', type=int_or_str,help='input device (numeric ID or substring)') parser.add_argument('-w', '--window', type=float, default=200, metavar='DURATION',help='visible time slot (default: %(default)s ms)') parser.add_argument('-i', '--interval', type=float, default=30,help='minimum time between plot updates (default: %(default)s ms)') parser.add_argument('-b', '--blocksize', type=int, help='block size (in samples)') parser.add_argument('-sr', '--samplerate', type=float, default=16000, help='sampling rate of audio device') parser.add_argument('-n', '--downsample', type=int, default=1, metavar='N',help='No downsample (default: %(default)s)') args = parser.parse_args(remaining)
The script creates another argument parser, this time with a description based on the script’s docstring. It defines several command-line arguments:
channels: The channels to plot. If not specified, it will default to the first channel.
device: The input audio device to use. It can be specified either by a numeric ID or a substring of the device name.
window: The visible time slot in milliseconds. This controls how much of the audio history is displayed on the plot.
interval: The minimum time between plot updates in milliseconds.
blocksize: The block size (number of samples) for audio processing. If not specified, the default block size of the audio stream will be used.
samplerate: The sampling rate of the audio device. If not specified, it will default to 16000 Hz.
downsample: The factor by which the audio data is downsampled. By default, no downsampling is applied.
The parse_args method is called to parse the remaining command-line arguments (remaining) after handling the --list-devices option.
ifany(c <1for c in args.channels): parser.error('argument CHANNEL: must be >= 1') mapping = [c -1for c in args.channels] # Channel numbers start with 1 q = queue.Queue()
The code checks if any of the specified channels are less than 1. If so, it raises an error with an appropriate message. It then creates a mapping list for the channel indices, as the channel numbers in args.channels start from 1.
Full code is listed below. Actually, it is based on an example from sounddevice documentation [1].
#!/usr/bin/env python3
"""Plot the live microphone signal(s) with matplotlib.
Matplotlib and NumPy have to be installed.
"""
import argparse
import queue
import sys
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import sounddevice as sd
def int_or_str(text):
"""Helper function for argument parsing."""
try:
return int(text)
except ValueError:
return text
def audio_callback(indata, frames, time, status):
"""This is called (from a separate thread) for each audio block."""
if status:
print(status, file=sys.stderr)
# Fancy indexing with mapping creates a (necessary!) copy:
q.put(indata[::args.downsample, mapping])
def update_plot(frame):
"""This is called by matplotlib for each plot update.
Typically, audio callbacks happen more frequently than plot updates,
therefore the queue tends to contain multiple blocks of audio data.
"""
global plotdata
while True:
try:
data = q.get_nowait()
except queue.Empty:
break
shift = len(data)
plotdata = np.roll(plotdata, -shift, axis=0)
plotdata[-shift:, :] = data
for column, line in enumerate(lines):
line.set_ydata(plotdata[:, column])
return lines
if __name__ == "__main__":
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
'-l', '--list-devices', action='store_true',
help='show list of audio devices and exit')
args, remaining = parser.parse_known_args()
if args.list_devices:
print(sd.query_devices())
parser.exit(0)
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parser])
parser.add_argument(
'channels', type=int, default=[1], nargs='*', metavar='CHANNEL',
help='input channels to plot (default: the first)')
parser.add_argument(
'-d', '--device', type=int_or_str,
help='input device (numeric ID or substring)')
parser.add_argument(
'-w', '--window', type=float, default=200, metavar='DURATION',
help='visible time slot (default: %(default)s ms)')
parser.add_argument(
'-i', '--interval', type=float, default=30,
help='minimum time between plot updates (default: %(default)s ms)')
parser.add_argument(
'-b', '--blocksize', type=int, help='block size (in samples)')
parser.add_argument(
'-sr', '--samplerate', type=float, default=16000, help='sampling rate of audio device')
parser.add_argument(
'-n', '--downsample', type=int, default=1, metavar='N',
help='No downsample (default: %(default)s)')
args = parser.parse_args(remaining)
if any(c < 1 for c in args.channels):
parser.error('argument CHANNEL: must be >= 1')
mapping = [c - 1 for c in args.channels] # Channel numbers start with 1
q = queue.Queue()
try:
if args.samplerate is None:
device_info = sd.query_devices(args.device, 'input')
args.samplerate = device_info['default_samplerate']
length = int(args.window * args.samplerate / (1000 * args.downsample))
plotdata = np.zeros((length, len(args.channels)))
fig, ax = plt.subplots()
lines = ax.plot(plotdata)
if len(args.channels) > 1:
ax.legend([f'channel {c}' for c in args.channels],
loc='lower left', ncol=len(args.channels))
ax.axis((0, len(plotdata), -1, 1))
ax.set_yticks([0])
ax.yaxis.grid(True)
ax.tick_params(bottom=False, top=False, labelbottom=False,
right=False, left=False, labelleft=False)
ax.text(0.01, 0.99, f'Sample rate: {args.samplerate/args.downsample} Hz', transform=ax.transAxes, va='top', ha='left')
fig.tight_layout(pad=0)
stream = sd.InputStream(
device=args.device, channels=max(args.channels),
samplerate=args.samplerate, callback=audio_callback)
ani = FuncAnimation(fig, update_plot, interval=args.interval, blit=True)
with stream:
plt.show()
except Exception as e:
parser.exit(type(e).__name__ + ': ' + str(e))
Save it as sd_plot_input.py (or whatever name.py) and run it with the following commands. See the video above for the sample output.
Setelah upgrade ke kernel 5.19, terjadi masalah "screen flickering" pada Laptop (kantor) saya, Dell XPS 9320. Padahal laptop ini adalah certified hardware, Link: https://ubuntu.com/certified/202112-29761. Hanya saja Canonical sudah berdalih, karena saya membelinya dengan pre-installed Windows (11), bukan Ubuntu.
...Standard images of Ubuntu may not work well, or at all. (https://ubuntu.com/certified/202112-29761)
Karena menyebabkan sakit mata jika screen flickering ini dibiarkan, saya mencari solusinya. Biasanya ini adalah permasalahan yang disebabkan karena update kernel, dan benar saja AskUbuntu memberikan jawaban yang serupa:
Untuk mengecek kernel di Ubuntu, saya menggunakan perintah berikut.
$ uname -a
Linux bagus-XPS-9320 linux-image-5.19.0-46-generic #6-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 24 18:24:09 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Permasalahannya ada di kernel 5.19 yang saya gunakan tersebut.
Untuk melihat list kernel yang tersedia bisa dengan cara berikut (bisa juga lewat Advanced options saat booting).
Solusinya adalah mengganti kernel. Cara pertama untuk mengetes solusi ini adalah reboot dan masuk ke Advanced options dan memilih kernel lain (dalam hal ini 6.1) dan cek apakah screen flickering masih terjadi.
Cara kedua adalah dengan mengganti kernel 5.19 menjadi 6.1 by-default secara otomatis. Ini adalah yang saya gunakan, tapi carannya beda dengan cara yang diterangkan oleh AskUbuntu di atas (tapi didapat dari AskUbuntu lainnya [2]).
Pertama back-up file grub.
sudo cp /etc/default/grub /etc/default/grub.bak
Kedua edit `LINUX_DEFAULT=0` menjadi kernel yang dituju. Dalam hal ini saya menggunakan menu "Advanced options for Ubuntu" dan kernelnya, digabung dengan tanda ">". Berikut isi grub saya. Perhatikan dua baris teratas, baris pertama adalah konfigurasi lama (dikomen) dan baris kedua adalah konfigurasi baru.
$ sudo vim /etc/default/grub
#GRUB_DEFAULT=0
GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.1.0-1006-oem"
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX=""
#GRUB_CMDLINE_LINUX_DEFAULT="i915.enable_dc=0 intel_idle.max_cstate=2"
Terakhir adalah update-grub
$ sudo update-grub
Dan reboot laptop. Setelah sekian lama mengetik tulisan ini, screen flickering tidak terjadi.
Sudah lama saya bertanya-tanya, ketika naik pesawat, kenapa tidak ada nomor tempat duduk "I" di pesawat. Dan hari ini, ketika sesorang menanyakan hal itu (lebih tepatnya komplain), saya langsung googling. Jawaban Google, berdasarkan Wikipedia, adalah sebagai berikut:
On many aircraft, the rightmost seats have letter designations HJK, skipping the letter I. This is because each seat has a row number followed by letter; letters that may be confused with numbers (I, O, Q, S, or Z) must be avoided, usually for people with dyslexia.
Jadi jawabannya, kenapa tidak ada huruf I, juga tidak ada huruf O, Q, S, dan Z, di pesawat adalah untuk menghindari keambiguan.
I ambigu dengan angka 1,
O dan Q ambigu dengan angka 0,
S ambigu dengan angka 5, dan
Z ambigu dengan angka 2.
Orang dengan disleksia, kondisi di mana seseorang mengalami kesulitan belajar yang menyebabkan masalah pada proses menulis, mengeja, berbicara, dan membaca, akan sulit membedakan huruf-huruf di atas sehingga akan kesulitan menemukan tempat duduknya di pesawat.
Memaksa anggaran untuk hal yang tidak perlu. Saya pernah mendapatkan anggaran yang harus dipakai. Karena tidak ada kebutuhan khusus, saya ngasal aja memakai anggaran tsb untuk membeli PC dengan spek rendah. Walhasil PC tersebut tidak terpakai (meski foldable, touch screen, dll).
Membuat peraturan yang terlalu keras dan tidak ada relevansinya. Contohnya, kalau tidak menjalankan XXX maka akan mendapatkan YYY. Cek lagi, apakah YYY berkorelasi (positif) dengan XXX? Apakah YYY, misalnya sanksi, itu produktif?
Media sosial, termasuk YouTube, IG, dll. Kadang kita membuka youtube dengan tujuan untuk belajar, untuk berbagi. Cek lagi, apakah dari 100% waktu kita bermedsos atau menonton youtube, IG, Facebook 90% tercapai? Jika tidak, berhenti dari memakai aplikasi tsb, meski bermanfaat.
Ketika kita sudah belajar untuk tidak menggunakan waktu kita untuk hal sia-sia, maka jangan biarkan orang lain (baligh mukallaf) untuk melakukan hal yang serupa sia-sia.
Cari hiburan? Apakah Nabi cari hiburan? Kebanyakan hiburan adalah hal yang sia-sia, hanya sedikit yang tidak termasuk di dalamnya. Memanah, berkuda, dan berenang adalah hiburan, tapi bukan sia-sia.
Cara mudah untuk mendeteksi apakah hal tersebut sia-sia adalah: apakah ada manfaatnya ketika kita melakukan hal tersebut?
Ingat kembali misi (hidup, organisasi), cek apakah yang yang dilakukan sudah selaras dengan misi tsb.
Seperti biasa, bulan April adalah tahun barunya jepang (Fiscal year、年度). Satu tahun (akademik, fiskal, kerja, dll. kecuali pajak) dihitung per 1 April dan berakhir 31 Maret. Jadi kalau bisa, pas hidup di Jepang, lahir tanggal 1 April, meninggal tanggal 31 Maret. Kenapa begitu? Kalau lahir 20 April, anda tidak bisa mengikuti sekolah (SD, SMP, SMA) tahun itu juga kalau belum umurnya. Misalnya umur minimal SD adalah 6 tahun per 1 April. Kalau lahir 20 April berarti nunggu tahun depannya. Begitu juga beasiswa, kerja, dll, hampir semua dimulai per 1 April.
Singkat saja, berikut adalah rencana penelitian saya satu tahun mendatang. Tahun ini saya akan fokus mengembangkan sistem multilingual speech emotion recognition (SER) dengan riset tambahan tentang anomaly detection (vibration and sound) dan melanjutkan riset sebelumnya tentang text-independent speech emotion recognition. Semoga semua luaran tahun ini bisa tercapai, alih-alih bisa melebihi luaran yang diharapkan.