728x90

appropriate binary mode and that you have compiled unzip properly 과 같은 문제가 생겼을 시, 아래와 같은 방법으로 해결이 가능함

 

 

zip -FF my_zip --out my_zip_ver2.zip

 

unzip my_zip_ver2.zip

 

 

728x90
728x90

입력 가정

 

a = [1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 4, 3, 3, 2, 2, 0] 
b = [2, 2, 3, 3, 4, 4, 5, 1, 1, 1, 2, 2, 5, 5, 7, 3, 0]

 

위와 같은 값이 있을 때, 전체 array에서 중복되는 값이 아닌 [1, 1] ==> [1] 로 만들고 싶다면 아래와 같이 하면 됨

import numpy as np


def del_over(array):
    
    return array[array != np.r_[array[1:], None]]

a = [1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 4, 3, 3, 2, 2, 0]
a = np.asarray(a)
b = [2, 2, 3, 3, 4, 4, 5, 1, 1, 1, 2, 2, 5, 5, 7, 3, 0]
b = np.asarray(b)

print('origin input a = ', a) # origin input
a_a = del_over(a)
print('modified input a = ', a_a) # modified

print('origin input b = ', b) # origin input
b_b = del_over(b)
print('modified input b = ', b_b) # modified


 

결과 화면

 

728x90

'Program > Python' 카테고리의 다른 글

python logger 끄는 법 - turn off logging  (0) 2024.02.20
pip freeze path 문제  (0) 2023.06.22
ImportError: cannot import name 'main' pip  (0) 2019.10.08
pip와 pip3 차이  (2) 2018.04.12
Ubuntu Python2, Python3 버전 관련  (0) 2018.04.12
728x90

이번 논문은 음성 인식에서 널리 사용되고 있는 증강 기법인 SpecAugment [1]이다. 논문은 arxiv.org/abs/1904.08779에서 확인할 수 있다.

 

Intro, related works

기존의 음성 인식을 위한 증강 기법은 아래와 같았다.

 

1) Noise Injection

Noise Injection 

Numpy를 사용하여 데이터에 임의의 값을 추가하여 증강하는 기법 (잡음 추가)

 

2) Shifting time

Shifting time

임의의 ms로 오디오를 왼쪽 / 오른쪽으로 이동

n_ms를 사용하여 오디오를 왼쪽으로 이동하면 처음 n_ms초는 0(무음)으로 표시

n_ms를 사용하여 오디오를 오른쪽으로 이동하면 마지막 n_ms가 0(무음)으로 표시됨

 

3) Changing pitch

Changing pitch

무작위로 pitch (음 높이)를 변경할 수 있음. librosa에 의해 수행 가능

 

4) Changing speed

 

Changing speed

음 높이를 변경하는 것과 동일하게 librosa에 의해 수행할 수 있음

고정 비율로 시계열을 늘릴 수 있음

 

이러한 방법을 사용하는 도중, SpecAugment가 2019년도에 제안됨

 

Method

 

Time warping, frequency masking, time masking의 세 가지 기본 방법으로 데이터를 증강 기법을 제안함

이 논문에서는 이 증강 기법을 LibriSpeech 및 SwitchBoard dataset에 적용하여 실험함

 

사용된 네트워크는 Listen, attend and spell [2] (블로그 리뷰 참조: kaen2891.tistory.com/30?category=453454)

 

1. Time Warping

 

임의의 점이 선택되고, 해당 선을 따라 $0$에서 시간 왜곡 매개 변수 $W$까지의 균일 분포에서 선택한 거리 $w$로 왼쪽 또는 오른쪽으로 warping 함

 

2. Frequency Masking

 

주파수 채널 $[f_0,f_0 + f)$ 이 마스킹됨

여기에서 $f$는 0에서 주파수 마스크 매개 변수 $F$까지의 균일한 분포에서 선택됨

$f_0$은 $[0, v-f)$에서 선택되며, 여기에서 $v$는 주파수 채널의 수임 (80차원 mel-spectrogram이 주로 사용되므로 80이 해당됨)

 

3. Time Masking

 

연속 시간 단계 $[t_0, t_0+t)$가 마스킹됨

$t$는 0에서 시간 마스크 매개 변수 $T$까지의 균일한 분포에서 선택됨

$t_0$은 $[0,\tau-t)$에서 선택됨

 

위에서부터 아래로, log-mel spectrogram 입력, time warping, frequency masking, time masking 적용된 그림

 

4. Augmentation Policy

Frequency masking과 Time maksing을 결합하여 아래의 그림과 같이 4개의 새로운 정책이 도입됨

LB, LD, SM 및 SS 정책

여기에서,

- $W$는 시간 왜곡 매개 변수

- $F$는 주파수 마스킹 매개 변수

- $m_F$: 적용된 주파수 마스킹 수

- $T$: 시간 마스킹 매개 변수

- $m_t$: 적용된 시간 마스킹 횟수

 

이에 따라 적용된 증강 스펙트럼 결과는 아래의 그림과 같음

위에서부터 아래로, 원본 log mel-spectrogram, LB 적용 결과, LD 적용 결과

 

Experimental setup and results

 

Setup

- 80-dimensional log-mel spectrogram 사용

- Encoder layer에서 stride size가 2 인 32 개 채널이 있는 3x3 컨볼 루션의 2 개 레이어가 포함되어 총 시간 감소 계수인 $r$ factor를 4로 설정함

- Convolutional layer위의 Encoder에는 Bi-LSTM (LAS-4-1024) layer 4 개가 포함됨

- 최대 학습률을 $1e−3$으로, batch_size를 512로, 32 개의 Google Cloud TPU를 사용하여 학습하였음

 

results

- 논문 출판 당시 SpecAugment를 이용하여 SOTA 달성함

 

Switchboard 300H WER results

SpecAugment는 overfitting 문제를 underfitting 문제로 변환함
- 아래 그림의 네트워크의 learning curve에서 볼 수 있듯이 훈련 중 네트워크는 training dataset의 loss 및 WER뿐만 아니라 augmented dataset에 대해서도 learning시 적합하지 않은 것처럼 보임

- 이것은 네트워크가 training dataset에 과도하게 맞추는 경향이 있는 일반적인 상황과는 완전히 대조적임

- 이를 통해 Data augmentation은 과적합 문제를 과소 적합 문제로 변환함을 보임

 

 

시간 왜곡이 기여하지만 성능을 향상하는 주요 요인은 아님
- 시간 왜곡, 시간 마스킹 및 주파수 마스킹이 각각 해제된 세 가지 훈련 결과를 제공하였음

- 시간 왜곡의 효과는 작다고 밝힘
- SpecAugment 작업에서 시간이 오래 걸리고 가장 영향력이 적은 Time warping은 GPU&CPU&Memory를 고려하여 가장 첫 번째로 삭제할 법한 문제로 밝힘

Label smoothing의 효과

- 레이블 평활화로 인해 훈련이 불안정해질 수 있음 

- LibriSpeech 학습 시 학습률이 점차 감소할 때, Label smoothing과 augmentation이 함께 적용되면 training이 불안정해짐을 밝힘
- 따라서 LibriSpeech에 대한 학습률의 초기 단계에서만 레이블 스무딩을 사용했다고 함

 

 

 

Conclusion & Take Away

- Time warping은 모델 성능을 많이 향상하지 못하였음
- Label smoothing은 훈련을 불안정하게 만듦
- 데이터 augmentation은 over-fitting 문제를 under-fitting 문제로 변환함 
- 증강이 없는 모델은 훈련 세트에서 거의 완벽하게 수행되는 반면 다른 데이터 세트에서는 유사한 결과가 수행되지 않음을 알 수 있음 ==> Augmentation이 일반화에 기여함을 알 수 있음

 

 

Reference

[1] Park, Daniel S., et al. "SpecAugment: A Simple Data Augmentation Method for Automatic Speech Recognition}}." Proc. Interspeech 2019 (2019): 2613-2617.

[2] Chan, William, et al. "Listen, attend and spell: A neural network for large vocabulary conversational speech recognition." 2016 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2016.

 

728x90
728x90

해당 논문은 2013년 ICLR에 accept 된 Microsoft의 논문으로서, 상당히 오래된 논문이다. arxiv.org/abs/1301.3605

 

Feature Learning in Deep Neural Networks - Studies on Speech Recognition Tasks

Recent studies have shown that deep neural networks (DNNs) perform significantly better than shallow networks and Gaussian mixture models (GMMs) on large vocabulary speech recognition tasks. In this paper, we argue that the improved accuracy achieved by th

arxiv.org

 

그래서 2021년의 기법, 계산 속도등을 어느정도 배제하고 읽을 필요가 있다.

 

Intro, related work

저자들은 음성 인식의 어려움이 주로 음성 신호의 높은 가변성에 기인한다고 주장함

 

Neural networks는 비선형 특성 변환과 로그-선형 분류기의 결합 모델로 간주될 수 있기 때문에 Neural network의 입력 특성은 작은 섭동(Perturbation: 다른 행성의 힘을 무시하고 타원방정식을 구한 뒤, 섭동에 의해 어떻게 변하는지 계산함. NN으로 따지면 outlier 학습 정도가 되지 않을까?)에 덜 민감함 차별적 내부 표현 (robustness representation)을 추출할 수 있다면, 음성 인식 정확도를 향상 시킬 수 있음

 

그러나 테스트셋이 학습셋과의 분포가 매우 다르면 NN의 성능이 저하 될 수 밖에 없음. 즉, NN은 학습셋과 상당히 다른 샘플이 테스트셋으로 들어오게 되면 좋은 결과를 낼 수 없음 (extrapolate 할 수 없음)

 

그러나 훈련셋의 분포와 테스트 셋의 분포가 비슷하다면, NN에서 학습한 내부 기능은 화자 차이, 대역폭 차이 및 환경 왜곡과 관련하여 상대적으로 안정적인 인식률을 보유할 수 있음

 

즉, 위처럼 해결하고자, 환경 소음에 의해 왜곡 된 narrow 및 wide band의 음성 및 음성 혼합에 대한 일련의 recognition 실험을 사용하여 이러한 문제를 해결하려는 것이 목적

(Wide band: 16kHz, narrow band: 8kHz)

 

Method
혼합 대역폭 ASR 연구 (mixed-bandwidth ASR study)

- 일반적인 음성 인식기는 8kHz로 녹음 된 narrow band 음성 신호 또는 16kHz로 녹음된 wide band 음성 신호로 훈련되지만, 단일 시스템이 narrow/wide band 음성, 즉 혼합 대역폭 ASR을 모두 인식할 수 있다면 유리하다고 가정

- 아래의 그림은 혼합 대역폭 ASR 시스템의 아키텍처이며, 이를 기반으로 동적 기능과 함께 29차원의 멜 스케일 로그 필터 뱅크 출력을 진행

NN을 사용한 mixed-bandwidth 음성 인식 그림

- 29 차원 필터 뱅크는 두 부분으로 구성
- 처음 22 개 필터는 0-4kHz에 걸쳐 있고 마지막 7 개 필터는 4-8kHz에 걸쳐 있으며, 더 높은 필터 뱅크에있는 첫 번째 필터의 중심 주파수는 4kHz임 

- 음성이 광대역이면 29 개의 모든 필터에 관찰 된 값이 있지만, 음성이 협대역이면 고주파 정보가 캡처되지 않았으므로 최종 7 개의 필터가 0으로 설정됨 

- 혼합 대역폭 훈련은 누락 된 대역을 명시 적으로 재구성 할 필요없이 여러 샘플 속도를 동시에 처리함

- 저자는 16kHz와 8kHz로 샘플링 된 데이터로 음향 모델을 훈련하며,  8kHz 입력에 대한 기능을 계산할 때 high-frequency의 log mel 대역은 0으로 설정

 

 

 

Experimental setup and results

데이터셋: mobile voice search (VS) corpus

- VS1: 72 시간의 16kHz training set

- VS2: 197 시간의 16kHz training set

- VS-T:  9562개의 발화, 총 26757개의 단어

- 8kHz인 narrow band의 훈련 및 테스트 데이터셋은 16kHz인 wide band를 다운 샘플링하여 얻음

 

협대역 훈련 데이터가 있거나 없는 광대역(16k) 및 협대역(8k) 테스트 세트의 WER(%).

결과

- 위의 표는 NN이 8kHZ 음성 유무에 관계없이 훈련되었을 때 16kHz 및 8kHz 테스트 세트에 대한 WER을 보임

- 이 표에서 모든 훈련 데이터가 16kHz이면 NN이 16kHz VS-T (27.5 % WER)에서 잘 수행되지만, 8kHz VS-T (53.5 % WER)에서는 매우 열악함

- 그러나 훈련 셋 중 VS-2를 8kHz로 변환하고 mixed-bandwidth 데이터 (두 번째 행)를 사용하여 동일한 NN을 훈련하면 NN은 16kHz 및 8kHz 음성 모두에서 잘 수행됨을 보임

 

Conclusion

- 잡음과 유사하게 mixed-bandwidth 훈련은 여러 샘플링 속도로 일반화하는데 도움이 됨

- 또한, DNN이 음성 변동성의 두 가지 중요한 소스인 화자 변동성과 환경 왜곡에 비교적 invariant한 표현을 학습할 수 있음을 보였음

728x90
728x90

python의 library를 설치하기 위해 pip, python-pip3을 주로 설치하거나 get-pip.py file을 통하여 설치할 때가 많은데, 이 때 우분투 모듈과의 버전 문제 등 호환이 일어나지 않아서 생기는 문제로 간주된다.

 

이는 아래의 명령어를 통해 해결할 수 있고, 이를 통해 잘 작동함을 볼 수 있다.

 

apt-get install python3-distutils

 

설치 전 문제

No module named 'distutils.util'

관리자 계정 통하여 설치

apt-get install python3-distutils

 

관리자 계정으로 설치 이후 해결 모습

 

* sudo 권한 필요하니 server에서 사용할 경우 관리자에게 설치를 부탁하면 된다.

728x90
728x90

Batch_size에 따라, 혹은 미리 데이터를 전처리 할 때, sequential 한 데이터셋에 대해 maximum length를 구해야 할 때가 있다.

 

이후에 Zero padding 까지 해주어야 하는데, 이번 글에서는 maximum length 구하는 것만 다룬다.

 

아주 직관적이고 쉬운 코드로 가겠다.

 

import numpy as np

a = np.random.rand(1, 7)
b = np.random.rand(1, 20)
c = np.random.rand(1, 3)
d = np.random.rand(1, 50)

print('a {}, a shape {}'.format(a, a.shape))
print('b {}, b shape {}'.format(b, b.shape))
print('c {}, c shape {}'.format(c, c.shape))
print('d {}, d shape {}'.format(d, d.shape))

dataset = list()
dataset.append(a)
dataset.append(b)
dataset.append(c)
dataset.append(d)

2차원 데이터에 대해, 예를 들어 text 라고 가정하겠다. ['안', '녕', '하', '세', '요'] 라고 되어 있는 데이터셋은 (1,5)의 shape을 갖는다. 이 데이터셋들을 전체로 모아서 처리할 땐 glob 등을 사용하지만, 예시에서는 4개를 임의로 세팅하고 dataset.append 을 이용하여 7, 20, 3, 50의 길이를 갖는 데이터셋을 임의적으로 만들었다.

 

def target_length_(p):
    return len(p[0])

length = list()
for i in range(len(dataset)):
    
    i_th_len = target_length_(dataset[i]) # return length
    length.append(i_th_len)

max_length = np.argmax(length) # find maximum length
print(max_length) # max_length index

maximum_length = length[max_length]
print(maximum_length)

그 뒤, 데이터셋을 매 번 반복하여 위의 target_length_ 함수를 이용해서 원하는 차원의 length를 구하면 된다.

 

2차원, 3차원, 4차원 등 원하는대로 설정하여 maximum length 값을 얻어 올 수 있다.

 

import numpy as np

a = np.random.rand(1, 7)
b = np.random.rand(1, 20)
c = np.random.rand(1, 3)
d = np.random.rand(1, 50)

print('a {}, a shape {}'.format(a, a.shape))
print('b {}, b shape {}'.format(b, b.shape))
print('c {}, c shape {}'.format(c, c.shape))
print('d {}, d shape {}'.format(d, d.shape))

dataset = list()
dataset.append(a)
dataset.append(b)
dataset.append(c)
dataset.append(d)

def target_length_(p):
    return len(p[0])

length = list()
for i in range(len(dataset)):
    
    i_th_len = target_length_(dataset[i]) # return length
    length.append(i_th_len)

max_length = np.argmax(length) # find maximum length
print(max_length) # max_length index

maximum_length = length[max_length]
print(maximum_length)
    
728x90
728x90

오늘은 간단하면서도, 막상 찾아보긴 힘든, 벡터를 여러개로 복사하는 것에 대해 글을 쓰겠다.

 

먼저 아래와 같은 변수가 있다고 가정

 

A = tf.random.uniform(shape=[64, 100, 256])

B = tf.random.uniform(shape=[64, 256])

 

하고 싶은 것은, A에 B를 concat 하고싶다고 가정하겠다.

 

이럴 경우 어떻게 해야하나?

 

먼저 Concat을 하려면, 차원이 맞아야 되는데, A의 2차원 즉 100에 해당하는 것이 B에는 없다.

 

이럴 경우 B에서 256짜리를 100번 복사해서 해야된다.

 

즉 A = [Batch, T, hidden], B = [Batch, hidden] 일 경우, B의 2번째 dimension에 B를 T번 복사해야된다.

 

최종으로 원하는것은 B = [Batch, T, hidden] 인 것이다.

 

tf.repeat 함수 (https://www.tensorflow.org/api_docs/python/tf/repeat)를 사용할 건데, 나는 현재 tensorflow 2.0 버전을 쓰고 있고, 여기에서 tf.repeat을 그대로 가져오면 없다고 오류 메시지가 뜬다.

 

tf.repeat 함수는 아래와 같은데,

 

tf.repeat(
    input
, repeats, axis=None, name=None
)

 

위에서 말 했듯이 나는 이게 안되므로,

tf.keras.backend.repeat(https://www.tensorflow.org/api_docs/python/tf/keras/backend/repeat) 함수를 사용 할 것이다.

 

tf.keras.backend.repeat 함수는 아래와 같은데,

 

tf.keras.backend.repeat(
    x
, n
)

 

tf.repeat과 다른 점은 딱히 없는 것 같다. 

 

B = [Batch, hidden] 인 것을, T=100으로 가정하여 B=[Batch, T, hidden]으로 만드는 코드는 아래와 같다.

 

import tensorflow as tf

batch_size = 100
seq_len = 100
hidden_size = 256

a = tf.random.uniform(shape=[batch_size, seq_len, hidden_size])
b = tf.random.uniform(shape=[batch_size, hidden_size])

print('a shape {} b shape {}'.format(a.shape, b.shape))

new_b = tf.keras.backend.repeat(b, n=100)

print('new_b shape {}'.format(new_b.shape))

concat_output = tf.concat(values=(a, new_b), axis=-1)

print('concat_output shape', concat_output.shape)

 

실행 결과는 아래와 같고,

이제 검증을 해야되는데, 100개로 늘렸을 경우 모든 100개가 기존 b의 hidden_size 내의 vector와 값이 같은가? 를 검증해야 된다.

 

아래와 같이 할 수 있다.

 

for i in range(len(new_b[0])):
    check = (b[0] == new_b[0][i])
    print('{}th check {}'.format(i, check))

 

이에 대한 결과는 모두 True

전체 코드

import tensorflow as tf

batch_size = 100
seq_len = 100
hidden_size = 256

a = tf.random.uniform(shape=[batch_size, seq_len, hidden_size])
b = tf.random.uniform(shape=[batch_size, hidden_size])

print('a shape {} b shape {}'.format(a.shape, b.shape))

new_b = tf.keras.backend.repeat(b, n=100)

print('new_b shape {}'.format(new_b.shape))

concat_output = tf.concat(values=(a, new_b), axis=-1)

print('concat_output shape', concat_output.shape)
 
for i in range(len(new_b[0])):
    check = (b[0] == new_b[0][i])
    print('{}th check {}'.format(i, check))

 

 

728x90
728x90

글이 많이 늦었습니다. 졸업 준비하느라 바빠져서...

 

 

이전 포스팅에 TfRecord로 모든 음성 데이터에 대해 byte로 읽고, 저장하는 것 까지 처리하였다.

 

이제 해야되는 것은? 모델 설계 한 이후 tensorflow 에서 제공하는 tf.Data를 사용하여 shuffle -> prefetch -> batch로 데이터를 나눈 뒤 모델에 넣는 것을 해주면 된다.

 

 

import tensorflow as tf

record_file = './tf_records_example.tfrecords' # previously saved tfrecords dataset
batch_size = 20

 

먼저 https://kaen2891.tistory.com/65 글을 참조해주셔서, record file이 저장되는것을 확인한 뒤, 이 파일을 불러오면 된다. 이 파일을 record_file='' << ' ' 사이에 directory에 넣는다.

 

그 후, 매 train step 마다 몇 개의 batch_size로 할 지에 대해 선언한다.

 

spectrum_feature_description = {
    'enc_inp': tf.io.FixedLenSequenceFeature ([], tf.float32, allow_missing=True),
    'dec_inp': tf.io.FixedLenSequenceFeature ([], tf.float32, allow_missing=True),
    'tar_inp': tf.io.FixedLenSequenceFeature ([], tf.float32, allow_missing=True)
}

def _parse_spec_function(example_proto):
    # Parse the input tf.Example proto using the dictionary above.
    return tf.io.parse_single_example(example_proto, spectrum_feature_description)

def input_fn(record_file, batch_size, buffer_size):
    dataset = tf.data.TFRecordDataset(record_file)
    print('raw_dataset', dataset) # ==> raw_dataset <TFRecordDatasetV2 shapes: (), types: tf.string>    

    parsed_spec_dataset = dataset.map(_parse_spec_function)
    print('map', parsed_spec_dataset)
    
    #parsed_spec_dataset = parsed_spec_dataset.cache()
    #print('cache', parsed_spec_dataset)
    
    train_dataset = parsed_spec_dataset.shuffle(buffer_size).batch(batch_size, drop_remainder=True)
    print('buffer + batch', train_dataset)
    
    train_dataset = train_dataset.prefetch(tf.data.experimental.AUTOTUNE)
    print('train_dataset autotune', train_dataset)
    
    return train_dataset
   
 
 
train_dataset = input_fn(record_file, batch_size=batch_size, buffer_size=10)
print(train_dataset)

 

그 다음 할 일은, input_fn 의 함수에서 매 dataset을 불러오는 것을 만들어 줄 것이다.

 

input_fn에는 record_file과 batch_size, buffer_size 를 함수 인자로 받은 뒤 record_file을 읽는다.

 

여기까지 해주면 byte type의 data들을 읽은 것이고, 이전 글에서 나는 데이터를 3가지 형태로 받았다.

 

enc_inp, dec_inp, tar_inp 이렇게 3개로 받았다.

 

즉 이 3가지의 data 형태로 복원해주기 위해서는 _parse_spec_function이 필요하다. 

 

여기에서 spectrum_feature_description dictionary 를 호출하여 이 dict 형태로 저장할 수 있다.

 

이렇게까지 받은 것이, parsed_spec_dataset 이다. 그 이후, 일반적인 tensorflow의 dataset 처리해주는 것처럼 해주면 된다.

 

위에서 처리된 parsed_spec_dataset에 shuffle을 buffer_size 넣어서 해주고, 이것을 batch_size 만큼 batch 형태로 해준다.

 

drop_remainder는 데이터 개수가 batch에 나뉘어지지 않을 경우, 마지막에는 빈 만큼 넣어주는 것으로 이해하면 된다. 

 

마지막으로, prefetch를 사용하여 queue에 넣어준 뒤, dataset을 model에 넣어주면 된다.

 

for (batch, spec) in enumerate(train_dataset):
    enc_raw = spec['enc_inp'].numpy()
    enc_raw = tf.reshape(enc_raw, [batch_size, 201, 21]) # batch, d_model, seq_len        
             
            
    dec_raw = spec['dec_inp'].numpy()
    dec_raw = tf.reshape(dec_raw, [batch_size, 201, 22])
            
    tar_raw = spec['tar_inp'].numpy()
    tar_raw = tf.reshape(tar_raw, [batch_size, 201, 22])
    
    print('batch = {}, enc_raw = {}, dec_raw = {}, tar_raw = {}'.format(batch, enc_raw.shape, dec_raw.shape, tar_raw.shape))
    
    print(enc_raw[0])

 

실제로 모델에 넣어서 돌리는 것이 아닌, 가상으로 위의 코드처럼 짜보았다. train_dataset은 현재 TfRecordfile을 batch_size 만큼 받아올 수 있다.

 

 

여기에서 끝인가? 아니다. batch, spec 에서 spec에는 위의 dictionary형태로 저장되어 있다. 이것을 긁어와야 한다. 어떻게? key를 사용하여

 

enc_raw = spec['enc_inp'].numpy() 를 사용하여 spec에서 enc_inp를 가져온다.

 

그럼 이대로 쓰면 되지 않냐고 할 수 있는데, 안된다. 

 

왜냐하면 위의 dictionary를 사용하여 3개의 데이터를 받았고, 이를 numpy 형태로 바꾸었지만, 우리는 아직 이 데이터셋의 shape에 대해서는 모른다.

 

그래서 바로 아래의 enc_raw = tf.reshape(enc_raw, [batch_size, 201, 21]) 을 하여 shape을 살려줘야 한다. 

 

batch, enc_raw, dec_raw, tar_raw의 shape을 출력하면 아래와 같은 결과를 얻을 수 있다.

 

 

마지막으로 enc_raw[0]를 출력하면, (20, 201, 21)의 첫 번째 vector를 가져오는 것이므로 (201, 21)의 tensorflow Tensor를 볼 수 있다.

 

 

 

전체 코드는 아래와 같으며,

import tensorflow as tf

'''
This code is for read form tfrecords file and get batch for training in tensorflow 2.0
In tf_records_example.tfrecords files, dataset is consist of 2d array with 50 batch size. So the enc_inp shape is (50, 201, 21) and the dec_inp and tar_inp shape is (50, 201, 22)
You can use this code for tfrecords file to training
Authors: June-Woo Kim (kaen2891@gmail.com)
'''

spectrum_feature_description = {
    'enc_inp': tf.io.FixedLenSequenceFeature ([], tf.float32, allow_missing=True),
    'dec_inp': tf.io.FixedLenSequenceFeature ([], tf.float32, allow_missing=True),
    'tar_inp': tf.io.FixedLenSequenceFeature ([], tf.float32, allow_missing=True)
}

def _parse_spec_function(example_proto):
    # Parse the input tf.Example proto using the dictionary above.
    return tf.io.parse_single_example(example_proto, spectrum_feature_description)


def input_fn(record_file, batch_size, buffer_size):
    dataset = tf.data.TFRecordDataset(record_file)
    print('raw_dataset', dataset) # ==> raw_dataset <TFRecordDatasetV2 shapes: (), types: tf.string>    

    parsed_spec_dataset = dataset.map(_parse_spec_function)
    print('map', parsed_spec_dataset)
    
    #parsed_spec_dataset = parsed_spec_dataset.cache()
    #print('cache', parsed_spec_dataset)
    
    train_dataset = parsed_spec_dataset.shuffle(buffer_size).batch(batch_size, drop_remainder=True)
    print('buffer + batch', train_dataset)
    
    train_dataset = train_dataset.prefetch(tf.data.experimental.AUTOTUNE)
    print('train_dataset autotune', train_dataset)
    
    return train_dataset


record_file = './tf_records_example.tfrecords'
batch_size = 20
train_dataset = input_fn(record_file, batch_size=batch_size, buffer_size=10)
print(train_dataset)

for (batch, spec) in enumerate(train_dataset):
    enc_raw = spec['enc_inp'].numpy()
    enc_raw = tf.reshape(enc_raw, [batch_size, 201, 21]) # batch, d_model, seq_len        
             
            
    dec_raw = spec['dec_inp'].numpy()
    dec_raw = tf.reshape(dec_raw, [batch_size, 201, 22])
            
    tar_raw = spec['tar_inp'].numpy()
    tar_raw = tf.reshape(tar_raw, [batch_size, 201, 22])
    
    print('batch = {}, enc_raw = {}, dec_raw = {}, tar_raw = {}'.format(batch, enc_raw.shape, dec_raw.shape, tar_raw.shape))
    
    print(enc_raw[0])

 

출력 output은 아래와 같다.

 

 

 

 

제 코드는  https://github.com/kaen2891/utils 에서 깔끔하게 확인하실 수 있습니다.

728x90
728x90

Tensorflow는 pytorch의 dataloader처럼 queue를 사용하여, 전체 데이터셋을 가져온 뒤 그것을 batch 만큼 쪼개서 하는 것이 살짝 번거롭다.

 

즉 이말을 다시 풀어보면, pytorch에서는 dataloader를 사용하여 여러 queue를 사용해서 batch 만큼 데이터셋을 가져온 뒤, 이것을 tensor로 바꿔서 model에 넣는 것이 수월한데 비해

 

Tensorflow에서는 tf.data.Dataset.from_tensor_slices 를 사용해서 전체 데이터셋을 가져오는 예제가 많다.

 

게다가 대용량 데이터셋을 사용하게 될 경우, 데이터셋의 총 사이즈가 3GB 정도가 넘어가면 tensorflow 는 API 관련 오류가 생기면서 data load가 안 될 때가 있다.

 

근 3일 정도 고생하면서 찾아본 정보들을 합쳐서, 음성 데이터셋의 stft 한 결과인 2차원 데이터셋을 tfrecord로 저장하는 방법을 소개한다.

 

 

# 전처리

음성(.wav)파일 모두에 대해, 2차원 stft를 얻었다고 가정하고 진행하겠다.

stft를 바꾸는 방법은 이 블로그 내에 있다.

 

import tensorflow as tf
print(tf.__version__)
import os
import librosa
from glob import glob
import numpy as np


list_inp = sorted(glob('/your/input/dataset/*/*.npz'))
list_tar = sorted(glob('/your/target/dataset/*/*.npz'))

print(len(list_inp))

위의 코드는 모든 음성 파일을 .npz 라는 numpy 형태의 data format으로 미리 저장해둔 상태이고, 이것을 glob으로 가져오는 모습이다. Seq2Seq 모델의 Encoder input인 list_inp와 Decoder input, Real value input인 list_tar의 전체를 가져온다.

 

 

# Writing Tfrecords file


def serialize_example(batch, list1, list2):
    filename = "./train_set.tfrecords"
    writer = tf.io.TFRecordWriter(filename)
    
    for i in range(batch):
        feature = {}
        feature1 = np.load(list1[i])
        feature2 = np.load(list2[i])
        print('feature1 shape {} feature2 shape {}'.format(feature1.shape, feature2.shape)) 
        feature['input'] = tf.train.Feature(float_list=tf.train.FloatList(value=feature1.flatten()))
        feature['target'] = tf.train.Feature(float_list=tf.train.FloatList(value=feature2.flatten()))
        
        features = tf.train.Features(feature=feature)
        example = tf.train.Example(features=features)
        serialized = example.SerializeToString()
        writer.write(serialized)
        print("{}th input {} target {} finished".format(i, list1[i], list2[i]))
        

serialize_example(len(list_inp), list_inp, list_tar)

 

먼저 저장할 tfrecords filename을 정해주고, tensorflow에서 제공해주는 TFRecordWriter로 writer를 선언한다.

for i in range(batch)는 전체 batch 사이즈만큼 반복하는 것이다. 즉 전체 데이터셋을 저장할 것이다. (나의 경우에는 총 8백만개이다.)

 

numpy 형태의 파일을 sorted(glob())으로 가져왔기 때문에, 현재 함수의 인자값인 list1과 list2는 파일 경로이다. 그러므로, np.load를 사용하여 feature1과 feature2에 값을 넣어준다.

 

그 뒤 tfrecords에 저장할 feature['name'] tf.train.Feature(float_list=tf.train.FloatList(value=feature1.flatten()))을 하여 선언해준다.

 

2d numpy 값을 그대로 value=feature1 를 해주면, 오류가 생긴다. 이를 찾아보게 되면, tensorflow에서의 FloatList는 1차원 값만 넣어줄 수 있기 때문이다. 그러므로, flatten()을 하여 넣어준다.

 

나 같은 경우 input과 target을 모두 maximum legnth를 구하고 zeropadding하여 shape을 아는 상태이지만, 만약 데이터셋이 모두 다를 경우 feature['shape'] = tf.train.Feature(int_list=tf.train.IntList(value=feature1.shape) 을 대입하여 나중에 데이터셋을 실제로 model에 넣을 때 shape을 기억하여 변환할 수 있다.

 

그다음 features = tf.train.Features(feature=feature)를 통해 tensorflow의 tensor로 변환해주고,

example 또한 마찬가지로 변환해준다.

 

serialized = example.SerializeToString() 을 통하여 binary? 로 변환해준다. 마지막으로 tf.records 파일을 write 해주는 writer.write(serialized)를 해주면 끝난다.

이것을 batch size만큼 해준다...

 

전체코드는 아래와 같다.

 

 

# 전체 코드

import tensorflow as tf
print(tf.__version__)
import os
import librosa
from glob import glob
import numpy as np


def serialize_example(batch, list1, list2):
    filename = "./train_set.tfrecords"
    writer = tf.io.TFRecordWriter(filename)
    
    for i in range(batch):
        feature = {}
        feature1 = np.load(list1[i])
        feature2 = np.load(list2[i])
        print('feature1 shape {} feature2 shape {}'.format(feature1.shape, feature2.shape)) 
        feature['input'] = tf.train.Feature(float_list=tf.train.FloatList(value=feature1.flatten()))
        feature['target'] = tf.train.Feature(float_list=tf.train.FloatList(value=feature2.flatten()))
        
        features = tf.train.Features(feature=feature)
        example = tf.train.Example(features=features)
        serialized = example.SerializeToString()
        writer.write(serialized)
        print("{}th input {} target {} finished".format(i, list1[i], list2[i]))
        


list_inp = sorted(glob('/your/input/dataset/*/*.npz'))
list_tar = sorted(glob('/your/target/dataset/*/*.npz'))

print(len(list_inp))
serialize_example(len(list_inp), list_inp, list_tar)

 

input, target 각각 8백만개 씩 있는데, 이것들이 과연 tfrecords를 통해 저장하였을 때의 공간적 이득과, 시간이 얼마나 걸리는지 체크해봐야겠다.

 

체크 해본 뒤, Tfrecord 파일을 다시 원래대로 음성 데이터 spectrogram으로 복구하는 것을 이번주내로 올릴 예정이다.

728x90
728x90

우분투로 apt-get install package, apt install package 를 실행하여도 반응이 없거나 시간이 오래걸릴 때가 있는데, 

 

인터넷에서 찾아본 결과

1) kr.archive.ubuntu.com 을 카카오로 변경하는 법

2) dns-server ip를 변경하는 법

 

이 있었다.

 

1)의 경우에는 apt-get 패키지 다운로드 서버를 변경하는 방법이다.

 

vi /etc/apt/sources.list 를 열고,

 

:%s/kr.archive.ubuntu.com/ftp.daumkakao.com

를 실행하면 된다.

 

이것을 해도 안될 경우 2)로 넘어간다.

 

2)의 경우에는,

 

vi /etc/network/interfaces 를 열고,

 

dns-nameservers 8.8.8.8 8.8.4.4

를 추가해준 뒤, :wq!를 한다.

 

그 후, vi /etc/resolv.conf 를 열고,

기존의 nameserver를 주석 처리 (#) 한 뒤,

nameserver 8.8.8.8

nameserver 8.8.4.4

를 추가해주면 된다.

 

참고로 pip install 도 안 될 경우, 이 방법을 통해서 해결 가능하다.

728x90

+ Recent posts