Upload 8 files
Browse files- .gitattributes +1 -0
- SO-NMF-main/H.npy +3 -0
- SO-NMF-main/License.txt +31 -0
- SO-NMF-main/README.md +36 -0
- SO-NMF-main/SO-NMF.py +145 -0
- SO-NMF-main/W.npy +3 -0
- SO-NMF-main/WH.npy +3 -0
- SO-NMF-main/WIN.npy +3 -0
- SO-NMF-main/sample_data_for_SONMF.txt +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
SO-NMF-main/sample_data_for_SONMF.txt filter=lfs diff=lfs merge=lfs -text
|
SO-NMF-main/H.npy
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9261f02573309b66218051515118b3e452e92232fc924464543cf403d471a35a
|
| 3 |
+
size 936128
|
SO-NMF-main/License.txt
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright (C) 2025, Yokohama National University, all rights reserved
|
| 2 |
+
|
| 3 |
+
ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any academic institution or non-profit organization (hereinafter referred to as "Licensee") to use, copy, modify, and distribute this software and its associated documentation files (the "Software") for noncommercial research purposes, subject to the following conditions:
|
| 6 |
+
|
| 7 |
+
1. Purpose
|
| 8 |
+
The Software is provided exclusively for academic or non-profit organization noncommercial research use. Commercial use, or use by any for-profit entity, is strictly prohibited without prior written permission from the copyright holder.
|
| 9 |
+
|
| 10 |
+
2. Attribution
|
| 11 |
+
Any use of the Software must include proper attribution to the original author(s) and this license. Publications that result from using the Software must cite the following reference:
|
| 12 |
+
M. Imamura, A. Tashiro, S. Kumano and K. Otsuka, "Synergistic Functional Spectrum Analysis: A Framework for Exploring the Multifunctional Interplay Among Multimodal Nonverbal Behaviours in Conversations," IEEE Transactions on Affective Computing, , 2024, doi: 10.1109/TAFFC.2024.3491097.
|
| 13 |
+
|
| 14 |
+
3. Redistribution
|
| 15 |
+
Redistributions of the Software, whether in source code or binary form, must retain this license and the above copyright notice, as well as this list of conditions.
|
| 16 |
+
|
| 17 |
+
4. Modifications
|
| 18 |
+
Modifications to the Software are permitted under this license, provided that the modified version is also made available under this license and appropriately attributed.
|
| 19 |
+
|
| 20 |
+
5. Prohibited Uses
|
| 21 |
+
The following uses are explicitly prohibited:
|
| 22 |
+
*Commercial applications or deployment, including integration into for-profit services or products.
|
| 23 |
+
*Use by any for-profit entity, including, but not limited to, corporations and private companies.
|
| 24 |
+
*Distribution or sublicensing of the Software for financial gain or commercial benefit.
|
| 25 |
+
|
| 26 |
+
6. Disclaimer of Warranty
|
| 27 |
+
THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
| 28 |
+
|
| 29 |
+
7. Termination
|
| 30 |
+
The rights granted under this license will automatically terminate if the Licensee fails to comply with the terms and conditions of this license.
|
| 31 |
+
|
SO-NMF-main/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
SO-NMF Python Implementation
|
| 2 |
+
|
| 3 |
+
This repository contains the Python implementation of SO-NMF, as described in the paper:
|
| 4 |
+
“Synergistic Functional Spectrum Analysis: A Framework for Exploring the Multifunctional Interplay Among Multimodal Nonverbal Behaviours in Conversations”
|
| 5 |
+
Published in IEEE Transactions on Affective Computing (doi: 10.1109/TAFFC.2024.3491097).
|
| 6 |
+
This code has been verified with Python 3.8.16.
|
| 7 |
+
|
| 8 |
+
1. Overview
|
| 9 |
+
SO-NMF (Semi Orthogonal Non-negative Matrix Factorization) is the core computational module employed in the framework of synergistic functional spectrum analysis (sFSA), dedicated to analyzing the communicative functions of multimodal nonverbal behaviors that appear in human conversations.
|
| 10 |
+
|
| 11 |
+
2. Preliminary preparation
|
| 12 |
+
Dependency: onmf.py
|
| 13 |
+
This project uses the onmf.py module from the torch-onmf repository to implement Orthogonal Non-negative Matrix Factorization (O-NMF).
|
| 14 |
+
Steps:
|
| 15 |
+
1. Download the onmf.py file from the following link: https://github.com/signofyouth/torch-onmf/blob/main/onmf.py
|
| 16 |
+
2. Import onmf.py into your project directory.
|
| 17 |
+
|
| 18 |
+
3. Example of use
|
| 19 |
+
Sample data:
|
| 20 |
+
・File: sample_data_for_SONMF.txt
|
| 21 |
+
・Description: The file contains 24 columns of waveform data with a length of 19500 frames, each representing different amplitudes and frequencies. This waveform data is just dummy data. As we mentioned in our paper, the actual data used in the paper is not publicly available. We plan to create another dataset and make it publicly available in 2026 (limited to academic research in universities or public research institutes. The detailed licensing is TBA).
|
| 22 |
+
Output:
|
| 23 |
+
Running SO-NMF on the sample data will generate the following output files:
|
| 24 |
+
WIN.npy: The orthonormal basis matrix (the initial basis matrix for the NMF).
|
| 25 |
+
W.npy: The basis matrix resulting from SO-NMF.
|
| 26 |
+
H.npy: The coefficient matrix resulting from SO-NMF.
|
| 27 |
+
WH.npy: The product of the basis and coefficient matrices.
|
| 28 |
+
Note:
|
| 29 |
+
The default number of bases in SO-NMF.py is set to 6, as per the paper. However, this parameter can be adjusted based on user requirements.
|
| 30 |
+
|
| 31 |
+
5. Citation
|
| 32 |
+
If you use any of the resources provided on this page in any of your publications, we ask you to cite the following work.
|
| 33 |
+
M. Imamura, A. Tashiro, S. Kumano and K. Otsuka, "Synergistic Functional Spectrum Analysis: A Framework for Exploring the Multifunctional Interplay Among Multimodal Nonverbal Behaviours in Conversations," IEEE Transactions on Affective Computing, 2024, doi: 10.1109/TAFFC.2024.3491097.
|
| 34 |
+
|
| 35 |
+
4. Article Link
|
| 36 |
+
For more information, please refer to the original paper: https://ieeexplore.ieee.org/document/10742505
|
SO-NMF-main/SO-NMF.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#--------------------------------------------------------------------------------
|
| 2 |
+
# Copyright (C) 2025, Yokohama National University, all rights reserved.
|
| 3 |
+
# See License.txt in the project root for license information.
|
| 4 |
+
#--------------------------------------------------------------------------------
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
import numpy as np
|
| 8 |
+
import numpy as np
|
| 9 |
+
from sklearn.metrics import mean_squared_error,mean_absolute_error
|
| 10 |
+
from sklearn.decomposition import NMF
|
| 11 |
+
from sklearn.metrics import mean_squared_error,mean_absolute_error
|
| 12 |
+
# Import Asteris's public code (onmf.py) for ONMF. https://github.com/signofyouth/torch-onmf/blob/main/onmf.py
|
| 13 |
+
from onmf import onmf, low_rank_nnpca, _local_opt_w, local_opt_w_single, local_opt_w_batch, binarize, sphere_sample_cartesian
|
| 14 |
+
|
| 15 |
+
def fix_seed_ONMF(seed):
|
| 16 |
+
np.random.seed(seed)
|
| 17 |
+
torch.manual_seed(seed)
|
| 18 |
+
torch.cuda.manual_seed_all(seed)
|
| 19 |
+
torch.backends.cudnn.deterministic = True
|
| 20 |
+
|
| 21 |
+
# Extract an orthogonal basis
|
| 22 |
+
def orthogonal_check(basis,new_basis):
|
| 23 |
+
for i in range(basis.shape[0]):
|
| 24 |
+
if np.dot(basis[i],new_basis)==0:
|
| 25 |
+
if i+1==basis.shape[0]:
|
| 26 |
+
basis=np.vstack((basis,new_basis))
|
| 27 |
+
else:
|
| 28 |
+
break
|
| 29 |
+
return basis
|
| 30 |
+
|
| 31 |
+
def fix_seed_NMF(seed):
|
| 32 |
+
np.random.seed(seed)
|
| 33 |
+
|
| 34 |
+
if __name__=='__main__':
|
| 35 |
+
|
| 36 |
+
input_file = "sample_data_for_SONMF.txt"
|
| 37 |
+
|
| 38 |
+
basis = 6
|
| 39 |
+
W_dict = {} # dictionary to store W for each SEED
|
| 40 |
+
|
| 41 |
+
for SEED in range(0,100):
|
| 42 |
+
fix_seed_ONMF(SEED)
|
| 43 |
+
bs = 2
|
| 44 |
+
m = 3
|
| 45 |
+
k = 2
|
| 46 |
+
A = torch.randn(bs, m, k)
|
| 47 |
+
sgns = binarize(torch.Tensor([i for i in range(2**k)]).int(), k)
|
| 48 |
+
|
| 49 |
+
data_load = np.loadtxt(input_file)
|
| 50 |
+
# Convert a NumPy array to a PyTorch tensor
|
| 51 |
+
data_t = torch.tensor(data_load, dtype=torch.float32)
|
| 52 |
+
data = data_t.T
|
| 53 |
+
data_numpy = data.to('cpu').detach().numpy().copy()
|
| 54 |
+
|
| 55 |
+
W, H = onmf(data, basis, rank=10, max_iter=1000)
|
| 56 |
+
WH = W @ H
|
| 57 |
+
w_numpy = W.to('cpu').detach().numpy().copy()
|
| 58 |
+
h_numpy = H.to('cpu').detach().numpy().copy()
|
| 59 |
+
wh_numpy = WH.to('cpu').detach().numpy().copy()
|
| 60 |
+
|
| 61 |
+
# Binarize using a threshold
|
| 62 |
+
threshold = 0.1
|
| 63 |
+
W_dict[SEED] = np.where(w_numpy >= threshold,1,0)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
w_all = None
|
| 67 |
+
|
| 68 |
+
for SEED in range(0,100):
|
| 69 |
+
if SEED == 0:
|
| 70 |
+
# Process 1st SEED (set first w_0)
|
| 71 |
+
w_0 = W_dict[SEED]
|
| 72 |
+
w_0_t = w_0.T
|
| 73 |
+
w_all = w_0_t
|
| 74 |
+
else:
|
| 75 |
+
w = W_dict[SEED]
|
| 76 |
+
w_t = w.T
|
| 77 |
+
w_all = np.append(w_all, w_t, axis=0)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
count_list = np.empty((0, 2), dtype=object) # array (elements and number of occurrences)
|
| 81 |
+
|
| 82 |
+
while len(w_all) > 0:
|
| 83 |
+
index = [0]
|
| 84 |
+
criterion = w_all[0]
|
| 85 |
+
|
| 86 |
+
for i in range(1, len(w_all)):
|
| 87 |
+
if all(w_all[i] == criterion):
|
| 88 |
+
index.append(i)
|
| 89 |
+
|
| 90 |
+
count_index = len(index)
|
| 91 |
+
|
| 92 |
+
# Store only if count_index is non-zero
|
| 93 |
+
if count_index != 0:
|
| 94 |
+
count_list = np.append(count_list, np.array([[criterion, count_index]]), axis=0)
|
| 95 |
+
|
| 96 |
+
# Remove elements once stored from w_all
|
| 97 |
+
for idx in sorted(index, reverse=True):
|
| 98 |
+
w_all = np.delete(w_all, idx, 0)
|
| 99 |
+
|
| 100 |
+
# Sort in descending order according to count_index
|
| 101 |
+
sorted_list = count_list[count_list[:, 1].argsort()[::-1]]
|
| 102 |
+
|
| 103 |
+
w_candi = sorted_list[:, 0]
|
| 104 |
+
|
| 105 |
+
# Create basis matrix
|
| 106 |
+
w = np.empty((0, len(w_candi[0])), dtype=np.float64)
|
| 107 |
+
for i in range(w_candi.shape[0]):
|
| 108 |
+
if not all(w_candi[i]==0):
|
| 109 |
+
if len(w)==0:
|
| 110 |
+
w=w_candi[i][np.newaxis,:].astype(np.float64)
|
| 111 |
+
elif w.shape[0]<basis:
|
| 112 |
+
w=orthogonal_check(w,w_candi[i].astype(np.float64))
|
| 113 |
+
else:
|
| 114 |
+
break
|
| 115 |
+
|
| 116 |
+
W = np.ascontiguousarray(w.T) # orthogonal basis matrix (WIN)
|
| 117 |
+
if W.shape[1]<basis:
|
| 118 |
+
print(f'Only {W.shape[1]} bases were obtained.')
|
| 119 |
+
else:
|
| 120 |
+
np.save('WIN.npy',W)
|
| 121 |
+
|
| 122 |
+
# NMF
|
| 123 |
+
nmf = NMF(n_components=basis , init = 'custom')
|
| 124 |
+
|
| 125 |
+
SEED = 0
|
| 126 |
+
fix_seed_NMF(SEED)
|
| 127 |
+
|
| 128 |
+
# initial basis matrix (WIN)
|
| 129 |
+
w_init = W
|
| 130 |
+
|
| 131 |
+
# random initial coefficient matrix
|
| 132 |
+
h_init = np.random.rand(basis,data.shape[1])
|
| 133 |
+
|
| 134 |
+
W = nmf.fit_transform(data, W = w_init , H = h_init)
|
| 135 |
+
H = nmf.components_
|
| 136 |
+
WH = W @ H
|
| 137 |
+
|
| 138 |
+
# Results output
|
| 139 |
+
np.save("W", W)
|
| 140 |
+
np.save("H", H)
|
| 141 |
+
np.save("WH", WH)
|
| 142 |
+
|
| 143 |
+
# MSE evaluation
|
| 144 |
+
mse = mean_squared_error(data, WH)
|
| 145 |
+
print("mse",mse)
|
SO-NMF-main/W.npy
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8baec6ae901236b3a1ee8be3e3328e52e5fb9d0f5a0963ddbfda4fa1108558fd
|
| 3 |
+
size 1280
|
SO-NMF-main/WH.npy
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d4e011a54a53c4d8b4e508c90d98414459182b62962d76474f5b955c38222348
|
| 3 |
+
size 3744128
|
SO-NMF-main/WIN.npy
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5a3659c4266e1b34c6d9b378858098970a92f3bba3848e25c6ea3bd6b87aabb9
|
| 3 |
+
size 1280
|
SO-NMF-main/sample_data_for_SONMF.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cfdd01705f49b54eaa388cba0cca19d43c49ff7455c77b99c021b9208526f195
|
| 3 |
+
size 11719500
|