728x90

이 글은 네이버 블로그 유하님과 인터넷 크롤링을 통한 정보들을 바탕으로 작성되었습니다.

 

음성을 연구할 때 중요한 것은 소리이며, 철자는 무시한다. 오직 음에만 집중함

 

The Difference between Spelling and Sound

- 알파벳은 26, 하지만 소리는 43-44개 정도임

- 철자가 소리를 모두 나타내지 못함

- 각각의 문자를 graphemes라고 함

e.g., thorugh: t-h-r-o-u-g-h --> 7개의 graphemes, 하지만 sound‘th-r-u’ 3

e.g., phlegm: p-h-l-e-g-m --> 6개의 graphemes, 하지만 sound‘f-l-e-m’ 4

 

- Graphemes는 단지 스펠링만 알려줄 뿐, 실제 pronounce에는 어떠한 단서도 제공하지 않음

- 그리고 graphemes는 그들이 가진 sound를 정확하게 나타내지 못함

e.g., grphemes‘s’ --> size /s/, vision /z/

==> 같은 문자가 서로 다른 소리를 갖음

 

Phonetic Alphabet

 

- 개별적 소리에 대해 개별적 문자를 갖으면서 소리와 문자가 서로 1:1 관계를 이룸

- Roman Alphabet26개로 43-44개의 소리를 적절히 나타내기 때문에 하나의 알파벳이 여러 개의 소리를 갖음

 

Allographs (이문자)

- 위와는 반대로, 소리는 같은데 다른 문자를 가지기도 함

e.g., loop, through, threw, fruit, canoe

 

Digraphs

- 같은 문자가 2, 또는 완전 다른 문자가 2개씩 짝을 이루는 것을 말함

e.g., hoot, heed, tissue, shoe, steak, tried

 

 

Silent letters

- 소리를 내지 않는 grapheme

e.g., p-l-u-m-b: 5개의 문자, p-l-u-m: 4개의 소리, ==> ‘b’ = silent letter

- chord, psychosis, flea, pneumonia ==> 주로 차용어들이 대상임

이는 단어 기원과 관련이 있음

- 차용어들을 글자 그대로 간직하여 받아들이나, 소리는 영어의 소리 체계에 맞게 발음하는 것

 

 

Duration (소리의 길이)

- 소리가 발음되는 동안의 길이

e.g., through, reamins, snowman, awakens ==> 모두 똑같이 7개의 grphemes으로 이루어져 있지만, 발음되는 길이는 각각 다름

e.g., gum, thought, what, straight ==> grapheme은 각각 다르지만, 발음되는 길이가 모두 같음

 

 

Morphemes (형태소)

- 유사한 의미적() 언어 단위

- 즉, 가장 작은 의미를 가질 수 있는 언어의 최소 단위

e.g., book: ‘이라는 의미를 갖는 하나의 형태소

e.g., books: 복수의 의미를 가지고 있기에 하나의 형태소로 인정함, 즉 두 개의 형태소를 갖고 있음

walked(과거), calling(명사형), prepaid(앞서, 미리라는 의미의 접두사), reread(다시라는 의미의 접두사), construction(명사 만드는 접미사), talkative(성질을 나타내는 형용사) ==> 모두 의미를 가지고 있으므로 형태소임

 

- 같은 형태소를 공유할지라도 발음의 변화가 생길 수 있음

e.g., music /k/ -> musician /s/, phlegm /무음/ -> phlegmatic /g/, press /s/ -> pressure /\/

 

- 형태소는 2가지로 나뉨

Free morpheme

 

- 홀로 쓰일 수 있으며 독자적인 의미를 갖음

e.g., book, phlegm, candy, love ...

 

- Bound morpheme

홀로 쓰일 수 없으며, 독자적인 의미를 갖지 못함

e.g., -s, -ed, -ian, predate, retread ...

 

 

Phoneme (음소)

- 뜻의 차이를 가져오는 최소의 단위

1886, IPA창립, 말을 기록하기 위해 채택되어짐

- 음소는 형태소에 차이를 줄 수 있는 어떠한 음

IPA는 음성적 알파벳, 각각의 표기는 특정한 음소 또는 소리를 나타냄

- 음소가 바뀌면 그 의미도 달라짐

e.g., book -> cook: 한 음소의 변화는 형태소의 의미를 바꾸게 됨

 

- 이처럼 단어의 오직 한 음소만 바꾸어 의미 차이를 갖는 것을 minimal pair (최소대립쌍)이라고 함

- 이는 음소를 확인하는 중요한 방법으로 작용함

e.g., hear/beer, cat/cab ...

 

Allophones (이음)

- 음소 가족의 구성원

- 음소는 소리들의 기록으로 모든 단어에서 같은 발음으로 나지 않음

e.g., /l/ in ‘lip’, ‘ball’

‘lip’ /l/: 혀가 입 천장에서 닿으며 소리 남

‘ball’/l/: 혀 뒤쪽에서 수축되어 소리가 남. 하지만 /l/을 어떻게 발음하든 간에, 의미 변화는 생기지 않음

==> 이처럼 다양한 발음을 allophone이라고 하며, 이 역시 음소를 확인하는 중요한 방법으로 작용함

 

 

Complementary distribution (상보적 분포)

- 이음은 같은 장소에서 동시에 나타날 수 없음

‘lip’/l/‘ball’/l/각각의 음성적 제약으로 인해 서로 바뀔 수 없는데 이를 상보적 분포에 있다 라고 함

- 상보적 분포에 존재하는 음들은 이음이고, 그러지 않은 음들은 음소로 구분 됨

그래서 상보적 분포 역시 음소를 확인하는 방법으로 작용함

 

Free variation (자유변이)

e.g., keep/p/: ‘키프라고 세게 발음하든 이라고 약하게 발음하든 의미는 달라지지 않음

이러한 관계를 자유변이라고 함

 

 

728x90

'Signal, Speech Processing > Phonetics' 카테고리의 다른 글

Vowel Transcription - Five back vowels  (0) 2020.02.10
Vowel Transcription - Five front vowels  (0) 2020.02.10
Anatomy of the Speech Mechanism  (0) 2020.02.10
Phonemes, Syllables notation methods  (0) 2020.02.10
Phonetics  (0) 2020.02.10
728x90

이 글은 네이버 블로그 유하님과 인터넷 크롤링을 통한 정보들을 바탕으로 작성되었습니다.

 

Phonetics

- 음성학은 무엇을 연구하는가?

- 음성학의 연구분야는 무엇이 있는가?

- 음운론(Phonology)과 음성학(Phonetics)의 차이는 무엇인가?

- IPA는 무엇인가?

 

1. Phonetics

- Speech sounds(소리)의 생산에 대한 연구

- Speech organs(말하는 기관)에서 어떻게 소리가 형성되는가에 대한 연구

- 어떻게 각각의 소리가 만들어지는지, 음절과 단어를 만들기 위해 소리가 발음되는 동안에 어떻게 기관들이 조합되는가에 대한 연구

- 어떻게 소리가 표기되는가에 대한 연구: 소리를 표기할 수 있는 새로운 알파벳을 배우게 됨

- 방언의 다양성으로 인해 각각의 다른 소리 패턴을 보여주는 표기와 연구도 포함됨

- 어떠한 소리를 들었을 때, 일반적으로 들리는 그대로가 아닌 철자를 먼저 떠올리게 됨

ex) ‘phone’: p-h-o-n-e -> 5개의 문자, 하지만 소리는 ‘f-o-n’ 3개의 문자

‘How are you doing?’ -> 14개의 문자, 하지만 소리는 ‘How ya doin?’ 9개의 문자

==> 철자와 소리는 다르지만, 일반적으로 철자(Spelling)를 매개체(pyrameter)로 인식하게 됨

 

2. 음성학은 여러 분야와 밀접한 관련이 있는 다면적인 연구분야임

- Historical phonetics

시대에 따라 단어가 어떻게 변화되었는가를 연구

13-17세기 사이에 있었던 ‘Great Vowel Shift (대모음전이)’에 의해 많이 변하였음

ex) 1700년 이전 beet | bait | bought | boat

==> 오늘날 ->bite | beet | bait | boot

 

Physiological phonetics

- 발음이 되어지는 동안, 소리의 기능을 연구함

- 소리를 만드는 기관의 근육과 신경에 대한 지식은 소리가 만들어지는 동안 그것들의 작용을 완전히 이해하기 위해 특히 중요함

 

Acoustic phonetics

- 모음(vowel)과 자음(consonant)의 진동(vibration), 강도(intensity, strength), 지속(duration)의 차이점에 대한 연구

- 소리의 음향적 차이는 듣는 이가 소리와 음절(syllable), 단어들이 어떻게 다른 것들과 차이가 나는지 알 수 있게 해줌

mug, hug, rug, thug ==> 첫 문자가 소리를 구별시켜 줌

Perceptual phonetics

- 자질(quality), 크기, 음의 높이(pitch), 지각되는 길이에 관하여 소리에 대한 듣는 이의 인식(perception=psycho acoustic) 반응을 연구

 

Experimental phonetics

- Physiological, acoustic, perceptual phonetics에 대한 실험적 연구를 포함

 

Clinical phonetics

- 언어 장애 치료를 목적으로 한 연구

 

Auditory phonetics (청음 음성학)

- 음성이 귀에 들어가는 과정을 연구

Articulatory phonetics (조음 음성학)

- 조음(articulation) 기관들이 어떻게 작용하여 소리를 만드는지에 대한 연구

 

3. Phonology vs Phonetics (음운론 vs 음성학)

Phonology

- 언어를 만들어 내는 것에 있어서 소리()의 체계적인 구조와 소리가 의미있는 단위가 되기 위해 구성하고 결합하는 특정한 방법을 사용하기 위한 음운적 규칙에 초점을 두고 있음

- 즉, 소리의 구성이나 구성 방법, 결합 방법 등에 관한 연구를 진행함

 

Phonetic

- 음의 음향적이고 지각적인 특징과 그것들이 어떻게 기관에서 만들어지는가에 대한 연구로써, 어떻게 음이 결합되고 언어에서 사용 되는지에 대해서는 상관이 없음

 

4. IPA (International Phonetic Alphabet)

- 철자에 의해서가 아닌, 단어의 소리를 나타내기 위해 만들어진 새로운 알파벳, 국제 음성 기호

- 영어 단어를 찾으면 그 단어 옆 괄호 속에 들어가 있는 알파벳들

 

***용어 정리

nasus (A)

alveoli 앞니 잇몸 (B)

labium 입술 (C)

dens 앞니 (D)

apex 혀끝 (E)

corona 앞 혀 (E)

larynx 목청 (F)

glotta 목청 문틈 (G)

palatum 앞 입천정 (H)

dorsum 혀의 등 (I)

velum 뒤 입천정 (J)

uvula 목젖 (K)

pharynx 목구멍 (L)

 

- 사람이 목소리를 내기 위해서 쓰이는 기관은 대개 목청(성대), 입술, 혀 그리고 코 안의 공간이 있음

- 이들 기관들은 홀로 움직이거나 쓰여서 목소리를 내기 보다는 대개 상호 작용을 거쳐서 목소리를 만들어 냄

- 오늘날 음성학에서 국제적으로 쓰이는 이들 소리 기관과 소리가 나는 자리의 이름은 주로 라틴어와 고대 그리스어(glotta, larynx, pharynx)에서 따온 말임

 

- 이들을 한국어로 번역하기는 그리 쉽지 않으며 그리고 길게 한글로 번역하지 않기 위해서 학계에서 쓰고 있는 한자어는 더러 그릇된 번역이 있는가 하면 전문가가 아니면 무엇을 뜻하는지 알기 어려운 단점이 있음

- 이 때문에 여기서는 한자어를 쓰지 않고 한글로 이를 표기함

 

Epiglottis (첫 번째): 혀뿌리, Cartilages (두번째와 세번째): 성대를 이루는 둥근 관 모양의 물렁뼈, Cricoid (네번째): 목청 입술

- 사람의 목청 또는 한자어로 성대(聲帶)는 목소리를 내는 중요한 기관의 하나임

- 그러나 목청을 목소리의 중심 기관으로 흔히 생각하는 것과 달리 생물학적으로 볼 때 목소리를 내는 역할은 목청의 부차적 기능으로 여김

- 목소리를 내는 역할 이외에 목청은 사람이 살아가는 데 필수적인 생리적 기능을 갖고 있음

- 사람이 숨을 쉴 때는 공기만 마시는 것이 아니라 더러 먼지나 다른 건강에 해로운 티끌들을 함께 마시게 됨

- 때로는 목 안에 가래와 같은 분비물이 생기는데, 이와 같은 건강에 해로운 것들이 목 안에 오래 머물러 있지 않고 밖으로 나갈 수 있도록 목청이 도와줌

 

- 그런가 하면 목청은 또한 우리가 음식을 먹고 마실 때 숨길을 막아 음식물이 허파로 들어가지 않도록 하여 줌

- 이 때문에 목청은 아래의 그림에서 살펴볼 수 있듯이 아주 복잡한 해부학적 구조를 갖고 있음

 

 

728x90
728x90

이번에 리뷰를 진행할 논문은 Parrtron 이라는 논문인데, Google에서 작성한 논문이다. 이전에 리뷰한 논문에서의 저자가 1저자로 작성한 논문이다.  https://arxiv.org/abs/1904.04169 여기에서 확인할 수 있다.

 

 

Abstract & Intro

이 논문은 Translatotron처럼 중간 이산 표현(text)를 통하지 않고, 입력 spectrum을 다른 spectrum으로 직접 매핑하는 end-to-end 음성 변환 모델이다. 인코더, 스펙트로그램 및 음소 디코더로 구성 되며, 보코더가 음성으로 변환하는 역할을 맡는다. 악센트, 프로소디 및 배경 소음에 관계없이 모든 입력 스피커의 음성을 고정 된 억양과 일관된 조음 및 단일 표준 대상 스피커의 음성으로 정규화하도록 학습하였고, 또한 청각 스피커(목소리에 장애가 있는)로부터의 음성을 표준화하도록 조정하였으며, 이는 성공하고, 이를 통한 비정형 목소리를 음성 인식기를 통한 WER measurement및 무작위 대상으로부터의 Mean Opinion Score (MOS) 측정을 통해 제안한 모델이 명료도 및 자연스러움이 얼만큼 개선되었는지 보여주고 있다. 마지막으로 화자 8명에 대하여, 1명과 나머지 7명 중 1개를 합성하고, 잡음(배경음)을 합성한 뒤 분리하는 것을 보여준다. 

 

Model Architecture

 

먼저 이 모델의 목적은, "소스 음성을 입력으로 넣고, 대상 음성을 출력으로 생성/합성하는 end-to-end Seq2Seq model architecture"를 사용하여 타겟 신호를 직접 생성하며 처음부터 합성하는 end-to-end architecture이다. 즉, 화자 특성을 포함하여 모든 비언어적 정보를 투사하고 누가, 어디서, 어떻게 말하는지가 아니라 말하는 내용만 유지 하는 것이다. 이렇기 위해서는 텍스트로부터 indenpendent한, N:1 음성 변환 작업에 해당한다. 다르게 말하면 화자는 여러명이고 target 음성의 화자는 1명이라는 것이다. 사용되는 데이터는 쌍을 이루는 입력/출력 음성 발화의 병렬 모음이 필요하다.

 

Google에서는 Parallel WaveNet 기반 TTS 시스템을 이용하여 손으로 작성한 script로 부터 TTS를 합성하여 target set을 만들었다. TTS를 사용함으로서 다음을 보장 할 수 있다고 밝히는데, 1) 대상은 항상 일관된 스피커 및 악센트로 말하고, 2) 배경 소음이나 불쾌감이 없으며, 3)마지막으로, 필요한 만큼의 데이터셋을 합성할 수 있다.

 

Google은 2천 2백만 건의 영어 음성으로 구성된 30,000시간의 교육 세트에서 모델을 훈련시켰다고 한다. 이 모음을 사용하여 TTS 시스템을 통한 여성 음성으로 대상 발화를 생성했다고 한다. (엄청난 데이터 양...)

 

이제부터 모델 아키텍처에 대해 설명한다.

Parrtron model architecture

전체 모델 아키텍처는 이렇다. Encoder, Spectrogram decoder, ASR decoder가 사용되고 있다. 

 

 

 

1) Encoder

Parrotron encoder part

빨간색 표시한 부분이 Encoder이다. Encoder에서 소개드릴 내용이 많다. 우선 이 모델에서 사용되는 핵심 아키텍처는 최근의 Attention 기반 end-to-end ASR 모델(1: Listen, Attend and Spell, 2: Spectral and Prosodic Transformations of Hearing-impaired Mandarin Speech)과 Tacotron(1: Tacotron2-Natural TTS synthesis by conditioning WaveNet on mel spectrogram predictions, 2: Tacotron-Towards end-to-end speech synthesis) 과 같은 TTS 모델을 기반으로 한다.

 

Parrotron의 기본 encoder 구성은 "Sequence-to-sequence models can directly translate foreign speech" 와 유사하며, 일부 변형이 되어있다. 위에 언급한 reference 논문에 대해 간단히 모델 부분만 체크하겠다. (https://arxiv.org/abs/1703.08581)

 

Sequence-to-sequence models can directly translate foreign speech

우선 이 논문은 음성 인식하는 논문이다.

1-1> Encoder

- 이 논문의 인코더 입력은 80channel log mel spectrogram이다.

- 25ms로 frame length를 두었고, 10ms hop을 사용하여 40%만큼 겹쳤다. 90 symbol로 출력하는데, phoneme기반의 음성인식이다.

- Encoder는 8개의 layer로 이루어져있으며, Time X 80 X 3 tensor형태이다. 

- 그 후, 2개의 CNN + ReLU 활성화를 통과한다. 여기에서 각 CNN은 32kernels로 이루어진 3 X 3 X에서 time X frequency이다. 이 CNN의 stride 는 2 X 2를 사용하였고, 결국 total factor는 4로 downsampling된다.

- 이후 Batch Normalization을 적용한다. CNN~Batch까지 다른 관점에서 바라보면 vgg랑 비슷하다고 볼 수 있지 않을까?

- 그 후, single bidrectional convolution LSTM (CLSTM)을 통과하는데, 이 때 filter 가 1 X 3 으로 통과한다.

- 마지막으로, 각 방향당 256크기의 LSTM을 갖는 BiLSTM을 통과하는데, 이 후 512차원의 Dense를 통과한다. Dense를 통해 Linear Projection을 하고 (512), Batch normalization과 ReLU가 함께 쓰인다.

- 즉 최종 Encoder의 ouptut은 512-dimensonal의 인코더 representation으로 나온다.

 

1-2> Decoder

- 64-dimensional의 word embedding된 y_{k-1}가 입력인데, 즉 text가 입력이다. 음성~ -> 인식 이므로 음성이 text로 바뀜. 심볼은 이전 time-step을 이용하며, 512-dimensional의 attention context vector를 사용한다.

- 128개의 Single hidden layer (attention)으로 이루어져있다.

- 이것들이 256-dimensional의 4개의 Unidirectional LSTM으로 통과한다.

- 마지막의 attention context와 LSTM output은 concatenation되어 출력 단어(vocabulary)를 예측하는 softmax로 통과한다.

 

1-3> Etc

- 9.8 parameter들을 가지고 있다. 생각보다 크지 않다.

- 전형적인 Seq2Seq으로, Teacher forcing을 사용하여 batch 당 64개의 utterances들을 구성하여 사용하였다.

- Adam optimizer를 사용하여 10개의 copy에서 비동기적 확률론적 경사하강(Stochastic gradient descent)를 사용하였다.

- 초기 lr은 1e-3이고, 백만 step 지나고 factor of 10을 decay한다.

- Beam search를 사용하였으며, Beam width는 3이며, 어떤 Language Model도 사용하지 않았다.

여기까지가 "Sequence-to-sequence models can directly translate foreign speech"의 Model Architecture와 Experimental Setup 부분을 정리한 내용이다.

 

다시 Parrotron으로 돌아가서,

 

16 kHz의 샘플링 된 waveform으로부터, 125-7600 Hz의 범위에서 80-channel log mel-spectrogram을 추출하였으며, 이 때, Hanning 윈도우를 사용하였고, 50ms 프레임 길이, 12.5ms 프레임을 겹쳤고, 1024-STFT 계수를 사용하여 추출하였다. (기존 위에 ref 삼은 논문보다 겹치는것을 줄였다.)

 

- 입력: 80channel log mel-spectrogram

- 2-layers CNN with 32 kernels (ReLU + BatchNormalization)

- Convolutional Bidirectional LSTM with 1x3 filter ==> 이를 통해 time step 마다 주파수 축을 통해서 뭉친다.

- 256-dimensional 3-layers LSTM

- 512 Dense + ReLU + Batchnormalization

- Get representation of Encoder input

 

위의 6줄이 Encoder의 구성이다.

 

 

2) Decoder (Spectrogram decoder)

Parrotron decoder part

최대한 쉽게 설명하기 위해 구분하여 진행해보자면,

- 디코더 타겟은 1025-dim STFT이며, 왜 이러냐면... NFFT를 1024으로 사용하고 hop을 25%사용했기 때문에 1025차원의 Spectrum을 얻는다. 마지막 1은 허수부분이다.

- Autoregressive RNN을 사용하여 decoder를 구성하였으며, 1번의 decoder step당 1 frame씩 인코딩 된 입력 sequence에서 출력 spectrogram으로 predict를 진행한다.

- previous(이전의) decoder time step으로부터의 예측은 256 ReLU가 연결된 2개의 layer를 포함하는 Pre-Net을 통과하는 것이 attention이 잘 먹힌다고 밝혔다. ***여기에서 Pre-Net은 이전에 review한 논문에 자세하게 나와 있음***

- Pre-Net 출력과 attention context vector가 연결되어 1024 unit의 2-layers Unidirectional LSTM을 통과함

- LSTM 출력과 attention context vector을 concatenation하여 Linear transformation을 통해 target spectrogram을 예측한다.

- 마지막으로, ***마찬가지로 이전 논문에서의 Post-Net이 나옴*** 5-layers CNN Post-Net을 통과한다. 각각의 Post-Net은 5 x 1 형태의 512 filter를 갖고, BatchNormalization도 있으며, tanh activation 을 통해 출력 된다.

- 예측된 spectrogram에서 오디오 신호를 합성하기 위해 Griffin-Lim 알고리즘을 사용하여 예측된 magnitude와 일치하는 phase를 추정한 뒤 Inverse Short-Time Fourier Transform을 통해 waveform으로 변환한다.

- Griffin-Lim은 음질이 그닥 좋지 않으므로, Griffin-Lim보다 시간이 오래걸리지만 음성의 품질이 더 좋은 WaveRNN을 사용하여 사람들에게 평가하였다.

 

3) ASR 디코더를 이용한 Multitask Learning

Parrotron ASR decoder part

앞서 Translatotron에서의 구조와 비슷하다. 이 ASR decoder의 목적은 기본 언어의 높은 수준의 표현을 동시에 배우기 위해 인코더 네트워크에 multitask learning 기법을 사용하여 공동으로 train을 하면, encoder 의 음성의 feature를 더 잘 배운다고 한다. 쉽게 말해서, Signal-to-Signal로의 변환이 어렵기 때문에 중간에 ASR 디코더를 달아서 음성 부분을 학습시키는 것이다. 인코더 latent 표현에 따라 출력 음성의 (grapheme:자소 or phoneme:음소) transcript를 예측하는 역할을 맡는다. 이러한 multitask learning으로 train된 인코더는 기초적인 transcript에 대한 정보를 유지하는 입력의 latent 표현을 학습하는 것으로 생각할 수 있다.

 

ASR decoder의 input은 이전 step의 grapheme에 대한 64-dimensional 임베딩과(ASR decoder part) 512-dimensional의 attention context를 concatenate하여 생성된다.  그 후 256 unit LSTM layer로 전달 되고, 마지막으로 attention context와 LSTM의 output은 concatenated되어 softmax로 전달되고, 그 후 phoneme으로 출력 될 확률을 예측한다.

 

 

Application

 

1) 음성 정규화

이 실험은 임의의 speaker로 부터 사전 정의 된 target의 음성으로 변환된 음성을 정규화하는 목적이다. 임의의 speaker는, 크게 말해서 화자 별 특성에 따라 같은 script를 말해도 신호의 크기 및 세기, 잡음, 명료도가 다를 수 있다. Google은 input speaker가 누구든지 mapping된 target data로의 변환에 정규화하는 것을 목적으로 실험을 진행했다. 

 

제안한 model의 output을 원래 입력 신호의 lingustic information을 보존하는지 평가하기 위해 음성 명료도를 측정하고(MOS), ASR 엔진을 사용하여 단어 오류율인 Word Error Rate (WER)를 평가했다. ASR 엔진은 WaveRNN으로 진행한 결과에 대해서만 평가했다. 

 

보유한 음성의 ASR WER은 8.3%이라고 한다. 표에는 기입이 안되어 있다. 고품질 TTS 모델을 사용하여 ASR 엔진으로 평가하면 WER이 7.4%이라고 논문에 밝혀져있다.

 

위의 Table 1에서 맨 윗줄은 보조 ASR decoder가 없는 결과이다. 27.1%의 비교적 낮은 WER을 갖고 있다. 두번 째 줄인 Grapheme 단위로 예측하는 ASR decoder를 추가할 경우 19.9%로 약 7.3%가량 크게 개선되었다. Phoneme 단위로 ASR decoder를 달아도 맨 윗줄과는 확연한 차이가 보이는데, CLSTM 대신 decay(parameter 미세 조정)를 사용하며 LSTM을 2개 추가할 경우 가장 좋은 성능인 WER 17.6%을 달성하였다.

 

논문에서, CLSTM을 제거하여 매개 변수 수를 줄이면 성능이 크게 저하되며, 그러나 CLSTM 대신 2개의 additonal BLSTM을 사용하면 약간 향상 되는 동시에 모델이 단순화 된다고 한다. 이것이 마지막 줄의 결과이다. 

 

위의 Table 2는 강력한 악센트와 배경 소음이 포함 된 보다 까다로운 테스트 셋에 대한 MOS 평가 와 ASR 성능의 평가 결과이다. 이 표에서 WER이 높은것이 중요한 것이 아니라, Real speech와 Parrotron의 결과에 대한 WER의 큰 차이가 없음으로 인해 언어적 내용을 보존하고 있음을 확인한다. 라고 주장하고있다.

 

정규화 실험 중 마지막으로, 모델이 동일한 TTS 음성으로 정규화 된 음성을 지속적으로 생성하는지에 대한 증명을 Table3을 통해 하였다. 8명의 영어 native들에게 발화된 model output 음성을 주고 평가하였는데, 질문 내용은 

- 5점 척도에서 Parrotron 음성이 TTS 음성과 얼마나 유사한가? ==> 4.6점

- 출력 음성에서 배경 소음이 있는가? ==> 0%

- 출력 음성에서 불일치가 포함되어 있는가? (Transcript와 다른지에 대한 평가인듯) ==> 0%

- 출력 언어는 일관된 조음, 표준 억양 및 prosody를 사용하는가? ==> 83.3%

 

위와 같고, 위와 같은 결과를 얻었다. 

 

2) 청각 장애 연설의 정규화

위의 정규화 모델을 사용하여 standard 음성이 아닌, 청각 장애인을 유창한 음성으로 변환 할 수 있는지에 대한 실험이다. 이를 통해 사람들의 음성을 통한 의사 소통을 향상시키는 것으로 사용 될 수 있다고 주장한다.

 

실험은 러시아에서 태어난 10대에 청각장애를 소유한채로 영어를 배운 사람을 대상으로 진행된다. 

요약하면, 표준어로부터 학습된 Parrotron 은 위의 청각 장애 언어르 완전히 정규화 하지 못하지만, 이를 해결 하기 위해 Google은 모든 매개 변수를 조정하고 모든 파라미터를 청각 장애 음성으로 적응(인코더만 미세 조정, 디코더와 음소 디코더 파라미터 모두 hold)시켰다. 그리하여 아래 표와 같은 결과를 얻었다.

 

첫째 줄의 Real speech는 청각 장애의 언어이며, MOS가 매우 낮고, 위에서 사용된 ASR 엔진의 WER은 89.2이다. 즉 워드 단위로 100개가 입력 될경우 10.8개 밖에 못맞춘 것이다.

두번째 줄의 Parrotron (male)은 위의 정규화 시스템을 그대로 사용했을 경우, MOS는 조금 나아지지만 마찬가지로 음성 인식 결과는 더 나빠졌다.

2)에서 제안한 fine tuning 기법(적응)으로 뽑은 결과는 MOS에서 1점 가량의 상승을 보였으며, WER도 일반인과 같은 성능을 내고 있다. 놀라운 결과라고 볼 수 있다.

 

위의 실험을 통해, 모든 fine tuning 전략이 음성을 이해하기 쉽고 훨씬 더 자연스러운 speech로 이어진다는 것을 밝혀냈다. 최고의 fine tuning은 모든 매개 변수를 조정하는 것이라고 논문에서 언급하고있다.

 

3) 음성 분리

이 실험은 Parrotron이 다양한 음성 응용에 사용될 수 있음을 설명하기 위해 만든 섹션이라고 한다. 중첩 된 혼합 음성 중 magnitude가 가장 큰 스피커의 신호를 재구성하는 음성 분리 작업이다. 최대 8개의 서로 다른 스피커의 즉각적인 혼합과 잡음(배경)을 넣어서 평가한다.

 

이 섹션은 SOTA separation 모델을 말하는 것이 아니다. 일반화 된 개방형 speaker set으로부터 speech를 생성할 수 있는지 평가하기 위해 분리를 진행한다고 한다. 솔직히 잘 이해가 안된다.

 

Google은 음성 신호의 즉각적인 혼합을 인위적으로 진행하기 위해, train set의 각 target 음성에 대해 1~7개의 발화를 무작위로 선택하여 배경 소음으로 혼합하였다. 백그라운드 발화 수도 임의로 선택된다. 혼합하기 전, 모든 발화를 비슷한 세기로 정규화한다.

 

배경에 대해 무작위로 샘플링 된 가중치 w(0.1~0.5)와 목표 발화에 대한 1-w로 두 신호를 평균화하여 target 발화와 배경 잡음을 혼합하였다. 이로 인해 인위적으로 구성된 모든 발화에서 12.15dB의 평균 SNR이 발생하고, 이에 대한 표준 편차는 4.7이라고 한다.

 

Parrotron이 분리 작업을 할 수 있는지 평가하기 위해 위의 정규화 파트 부분의 학습된 것을 가져와서 혼합 발화를 입력으로 넣고 모델을 훈련 시켜 해당하는 원래의 발화를 생성하는 식으로 진행하였다고 한다. 이를 ASR 엔진을 사용하여 분리 모델의 영향을 평가하였는데, 1) 배경 잡음을 넣기 전의 원래 깨끗한 발화, 2) 시끄러운 잡음인 배경 음과 음성을 혼합 한 후, 3) Parrotron을 실행하여 생성된 출력

형식으로 평가하였다고 한다.

 

위의 표를 보면, 잡음이 많은 세트인 "Noisy"에서의 WER은 33.2%이다. 이를 Parrotron을 사용하여(분리) denoising하면 17.3%의 WER를 얻었다고 한다. (음 근데 사실 이부분은 real time demonstration을 좀 보고 싶다.) 이를 통해 모델이 target speaker의 음성을 보존하고 다른 스피커로부터 분리 할 수 있음을 보여준다고 한다. 

 

 

Conclusion

위 논문에선 이전 논문처럼 End-to-End 로 음성 변환을 진행하였는데, 필수적으로 script가 필요하지 않았다. 하지만 signal-to-signal 간의 음성 변환을 위하여 multitask learning 관점에서 음성 인식 디코더를 auxiliary part로 사용하였고, 이는 성능 개선에 도움이 되었다고 밝혔다. 위 논문의 목적은 "언어적 콘텐츠를 보존하고, 다른 스피커의 음성을 단일 대상 스피커의 음성으로 표준화하는 것" 이다. 청각 장애인의 음성이 model을 거쳐 단일 대상 스피커 (TTS)로 나올 경우, 제안 된 모델의 방법이 WER 개선에 영향을 미쳤다고 밝혔다. 또한 악센트가 많은 음성을 정규화를 통하여 표준 음성으로 변환하여 명료성을 향상시켰다. 추후 input 화자의 특성을 보존하며 정규화 및 개선하는 것을 목표로 두고 있다.

 

가장 큰 novelty는 N:1의 음성 변환을 정규화로 시키면서 좋은 성능을 내고 있다는 점, ASR 엔진을 이용한 명확한 평가를 하였다는 점, 그리고 청각 장애인 데이터셋으로부터 fine tuning을 통해 성능 개선을 했다는 점이라고 뽑고 싶다.

 

추가적으로, Google의 ASR엔진을 쉽게 사용할 수 있도록 API나 weight를 공유해주면 연구용으로 비교 및 사용하기 편할텐데... 아쉽다.

 

 

728x90
728x90

이번에 진행할 논문은 Translatotron: Direct speech-to-speech translation with a sequence-to-sequence model 이다. Google Research에서 published 하였으며, https://arxiv.org/abs/1904.06037 에서 확인해볼 수 있다.

(그림을 업로드하다가 중간에 렉이먹어서 도중에 쓴 것들이 다 날아갔다... 다시 씁니다ㅜ.ㅜ)

 

Intro, Related Work

한국인과 미국인이 서로 대화를 나누려 한다. 하지만 이 둘은 서로간의 언어 정보에 대해 하나도 모른다고 가정하겠다. 즉 한국인은 영어를 하나도 할 줄 모르고, 미국인도 마찬가지라고 가정한다.

 

한국인이 미국인에게 대화를 걸려면 1) 말을 하고, 2)이를 음성 인식하여, 3)인식 된 text를 번역하고, 4)얻은 text를 음성으로 합성해야 대화가 가능하다. 너무나 복잡하다. 사실 우리는 이 방법을 사용하여 외국인들과 대화를 하고 있지 않은가? 그만큼 우리는 대단한 존재일 수 있다.

 

어찌됐든, 위의 복잡한 단계를 해결할 중요한 이유가 하나 더 있다. 바로 중간에서 잘못 된 오류를 범할 경우, 마지막으로 음성 합성 된 결과값이 미국인에게 잘못 전달 될 수 있다. 예를 들어,

 

한국인: 제가 저기에 가려면 어떻게 해야하나요?

1) 음성 인식: 제가 저기에 가려면 어떻게 해야하나요?

2) 번역: How can I get there?

3) 음성 합성: ~~

4) 미국인에게 전달

 

이렇게 잘 전달되면 문제가 없다. 하지만 가령,

 

2) 번역: Can I go there?

 

라고 번역이 잘못 되었을 경우, 미국인은 yes라 할 것이고, 한국인은 pardon?을 외칠 것이다.

 

이러한 복잡한 문제를 해결한 연구 결과가 있다. 바로 지금 review할 논문인데, translatotron이다. 내가 생각한 이 논문의 novelty는 서로 다른 언어간의 음성 번역을 한 번에 진행 한 시발점(starting research) 이라고 생각한다.

 

딥러닝은 많은 발전이 이루어 졌고, 음성 인식, 번역, 음성 합성에서 굉장한 성능을 내고 있다. 하지만 위의 사례처럼 이용하려면 음성 인식 -> 번역 -> 합성이 이루어져야 한다. 하지만 이 논문은 이것을 한 번에 다 해내고 있다. 심지어 목소리까지 바꿀 수 있다.

 

이 논문의 실험은 스페인어-영어 데이터셋으로 진행하였다.

 

자 그럼 이 논문에 대해 알아 가 봅시다.

 

 

Method

모델 구조는 별도로 훈련 된 여러 구성 요소로 구성된다. 즉 이 모델은 end-to-end가 아니고, pretrain된 것들도 사용한다.

전체 모델 아키텍처는 아래 그림과 같다.

 

- Primary task: target spectrogram을 생성하는 attention based Seq2Seq

- Speaker Encoder: 이 부분은 선택적으로 쓰이는 부분인데, 대상의 목소리를 원할 경우 바꿔서 번역할 수 있음

- Vocoder: target spectrogram을 시간도메인인 waveform형태로(음성) 바꾸는 부분

- Auxiliary tasks: source와 target의 phoneme sequence 예측 하는 부분

 

차례차례 보도록 해봅시다.

 

- Primary task, Encoder

먼저 Translatotron의 Encoder부분은 아래 빨간 표시한 곳이다.

Translatotron Encoder Part(빨간 표시)

Encoder의 input은 80channel log-mel-spectrogram이 사용된다. 여기에서 80channel은 mel을 80 dimension으로 뽑았단 얘기이다. librosa의 n_mels와 같다. 그렇게 뽑은 mel-spectrogram에 log값을 취해준 것이다.

그 다음 8-layer Stacked Bidrectional LSTM을 사용한 것으로 나와있다. BLSTM을 8개 쌓은것이다. 이 최종 output은 speaker encoder를 사용했을 경우 i-vector와 concat하여 decoder ouptut과 transformer 에서 사용되는 multi-head attention을 통해 encoder-decoder간 scaled-dot product attention이 이루어진다. speaker encoder가 사용되지 않았을 경우엔 저 concat 부분은 사용되지 않는다. 중간에 Auxiliary recogniton tasks로 가는 화살표가 있는데 이것은 마지막에 설명할 예정

 

- Primary task, Decoder

Translatotron Decoder Part(빨간 표시)

Spectrogram Decoder는 Text-to-Speech에서 좋은 평가를 받고 있는, 마찬가지로 구글에서 published 한 Tacotron2 구조와 유사하다. Pre-net, Autoregressive LSTM, Post-net 을 포함하고 있다. 여기에서,

 

Pre-net: 2-layer FC

Autoregressive LSTM: Bi-directiona LSTM(Tacotron2 encoder), LSTM(2-Uni-directional layers in Tacotron2 decoder)

Post-net: 5-layer CNN with residual connections 으로서, mel scaled filter bank spectrogram을 개선하는 역할

 

로 정의할 수 있다.

Tacotron2 model architecture

Tacotron2의 Encoder는 text를 character 단위의 embedding을 하고, Pre-net을 거친다. Pre-net은 정확히,

Pre-net: (Dense -> ReLu -> Dropout) X 2

 

로 이루어져 있다. 그 후, CBHG를 통과하는데,

 

CBHG: Conv1D Bank -> Max pooling -> Conv1D projection -> Conv1D layer, Conv1D layer + First input(이 부분이 residual connections) -> Highway Network(4 layers of Dense - ReLu) -> Bidirectional RNN

으로 이루어져 있다. Encoder의 최종 결과는 embedding result가 나온다. 위의 모든 process를 mel-spectrogram과 최적의 alignment를 하기 위해서라고 생각하면 좋을 것 같다. 너무 복잡하지만..

 

Tacotron2의 Decoder는 Encoder와 거의 비슷한데, RNN의 구조를 띄고 있다. 즉 각 step마다 output (1개의 spectrogram frame)을 출력한다. 그리고 autoregressive 한 형태이므로, 이전 step을 사용하여 현재 step의 frame을 예측한다. 매 step마다 encoder의 context vector와 attention을 통해 output 1개를 얻는 것이다. 최종적으로 projection 하는 decoder의 hidden layer의 output은 2개의 256으로 이루어진 FC가 를 가장 먼저 통과한다. 즉 Dense 형태로, (256, 1)의 형태를 얻는다.

 

그 후 LSTM과 이루어진 context vector는 80개의 neurons을 갖는 FC로 통과한다. 이게 바로 mel-spectrogram의 channel인 n_mel와 동일하다! 이 최종 부분이 spectrogram을 frame by frame으로 예측한다. 그 후 PreNet으로 다시 들어가고, linear scale spectrogram을 얻는다. 아마 Reduction Factor 를 3으로 사용했던 것 같은데, 그렇다면 3개의 predicted spectrogram을 사용하여 1개의 linear scale spectrogram을 얻는다.

 

attended ecoder outputs

Attention 부분에 대해 조금 더 언급하고 싶어서 수식을 캡쳐했다. context vector Ci 는 encoder의 output(h)와 attention weights(alpha)의 product로 연산되는데, alpha_ij는 아래의 식에 의해 연산된다.

 

Attention weights

자 많이 보던거 나왔죠? exp/exp합은 softmax이다. 대충 눈 도장 익히면 아~확률 구하는구나 라고 생각하면 편하다.

e_ij = vaT tanh(Wsi-1 + Vhj + Ufi,j + b) 인데,

si-1: decoder LSTM의 이전 hidden state

alpha_i-1 : 이전 attention weight

hj: j번째 encoder hidden state

W, V, U, va 그리고 b: 학습시 사용된 parameter들

fi, j: 공식에 의한 계산된 위치

fi: F * alpha_i -1

F: CNN 연산

이다.. 복잡한데, 제 설명이 부족하시다 생각하신 분께서는  Tacotron2 와 attentive-attention mechanism을 읽어보시는 것을 추천드립니다.

 

정리하면, Tacotron2는 encoder에서 text를 입력받아 Pre-net, CBHG를 통해 character embedding result를 얻고, decoder에서는 80channel의 log-mel-spectrogram 입력을 받아 encoder-decoder attention을 통해, 256 dense로 1개를 예측하고, 다시 그 값이 80 dense를 통해 80channel의 spectrogram이 통과한다. 이 때, frame by frame, autoregressive방식으로 진행되고, 위의 output은 Post-Net을 통과하여 linear scale spectrogram으로 얻는다. 이게 다 ~~끝나고 vocoder를 통해 음성이 복원된다.

 

Translatotron도 유사하다. 이 떄, 4 or 6 LSTM이 성능이 좋다고 언급되어있다.

Translatotron의 decoder에서의 예측은 1025dimension의 log spectrogram의 frame을 예측한다. 각 디코딩 단계마다 2개의 스펙트로그램 frame을 예측한다. 이렇게 사용하는 이유는 음성 신호가 연속성을 띄고 있기 때문이고, decoder의 부하를 줄여주기 때문이다. 

 

쓰고 보니 Tacotron2 리뷰를 따로 안해도 될듯 ㅎㅎ

 

- Vocoder

아래 부분의 빨간색 표시가 Vocoder 부분이다.

Griffin-Lim을 기본적으로 사용하였다. 하지만 MOS테스트에서 음성의 자연성을 평가할 때 WaveRNN을 사용하였다. Griffin-Lim은 CPU로 돌릴 수 있지만, WaveRNN은 시간이 더 오래걸리고, GPU 기반이다. 그러나 음성 복원 품질은 WaveRNN이 더 좋기때문에 이를 이용하여 테스트한 듯.

 

또한 Vocoder에서 reduction factor를 사용하여 감소 계수 2로 frame을 계수만큼 예측한다. 이 계수만큼의 log-spectrogram을 생성한다. 이렇게 복원된 음성을 직접 들을 수 있다. 

 

- Speaker Encoder

이 부분에서는, D-벡터를 뽑아서 사용한다. D-벡터는 Speaker Independent System의 특징인데, 화자별 차이의 벡터값 정도로 생각하면 될 것 같다. Speaker vefirication를 위한 pretrained 된 것을 여기에서 사용한다.

 

위 논문에서, 851k 스피커, 8개 언어에 대한 정보를 사용했다고 밝혔다. training 시에는 사용하지 않았고, inference에 합성할때에만 썼다고 한다. 256차원으로 값이 나오면, 이를 linear projection을 통해 16으로 줄이고, 마지막 encoder BLSTM layer의 output과 concat했다고 밝혔다. 오직 tanfer task에만 사용되었다.

 

- Auxiliary recognition tasks

각각 attention이 구성되어 있는 소스 및 대상 음소 시퀀스를 예측하는 파트이다. BLSTM의 마지막 값이 여기에 연결된다. single head attention이 있는 2 layer LSTM으로 구성되어 있다. 여기에서, 한 입력은 소스 음소 (스페인어) 이고 다른 입력은 대상 (영어) 이다. signal-to-signal의 변환이 모델에서 버거워 하기 때문에, multitask learning 기법을 사용하여 음성을 phoneme 단위로 인식하여, 이 정보를 decoder 단에 전해주어 음성 변환을 도운 task라고 보면 되겠다. 3개의 loss가 사용되었다. 이 task를 통해 BLEU score가 개선되었다고 밝히고 있다.

 

 

Experiments & Results

아래 그림은 사용된 Hyperparameter들이다.

결과는 실제로 들어보는 것이 좋을 것 같다. 아래 사이트에서 들을 수 있다.

 

https://google-research.github.io/lingvo-lab/translatotron/

 

Speech-to-speech translation

Audio samples from "Direct speech-to-speech translation with a sequence-to-sequence model" Paper: arXiv Authors: Ye Jia *, Ron J. Weiss *, Fadi Biadsy, Wolfgang Macherey, Melvin Johnson, Zhifeng Chen, Yonghui Wu. Abstract: We present an attention-based seq

google-research.github.io

 

 

 

Conclusion

저자가 정리한 부분은 아래와 같다.

- 한 언어에서 다른 언어로 된 음성으로 직접 번역하는 최초의 모델

- 향후 연구점의 출발점으로 고려

- training하는 동안 speech transcripts를 사용하는것이 중요하다고 함

 

아마도 signal-to-signal간의 학습이 잘 안되었기 때문이지 않았을까 싶다.

 

내 느낌점은, 처음 이 논문이 나오고, demonstration을 들어보고나서 정말 놀라웠었다. 작년 5월에 처음 봤는데 나는 무슨 연구를 하고 있는 건가 싶었다. 새로운 길을 개척한 논문이라고 평가하고 싶다. 벌써 8개월 정도가 지났는데 어떤 성능을 갖는 end-to-end 가 나올지 기대된다.

 

728x90
728x90

오늘 포스트 할 내용은 flac 데이터셋을 wav로 변환하여 진행하는 것이다.

 

일반적으로 음성 처리 분야에서 22.5kHz, 16kHz를 많이 사용하는데,

 

TIDIGITS 데이터셋 같은 경우 20kHz로 되어 있다.

 

또한 flac 확장자로 되어 있는데, 이번 포스팅의 목표는 1) convert flac to wav, 2) downsampling 20kHz -> 16kHz 이다.

 

 

먼저 저장할 경로를 설정해주고, flac 음성을 불러온다.

그 뒤 음성의 path와 file id를 얻는다.

file id 는 file.flac 으로 되어 있기 때문에 [:-5]로 name만 얻어오는 작업을 하고,

soundfile 의 read 함수를 이용하여 data부분을 get한다.

 

그 뒤에 1단계인 flac -> wav 로 저장을 진행한다.

 

이 데이터셋은 20000Hz이기 때문에 2번째로 해야 할 일은 librosa로 wav를 read 한 뒤 16000으로 downsampling을 진행한다.

 

전체 코드는 아래와 같다.

import soundfile as sf
import librosa
import os
save_dir = '/mnt/junewoo/speech/TIDIGITS/tidigits_flac/' # save dir

w_flac = '/mnt/junewoo/speech/TIDIGITS/tidigits_flac/data/adults/train/woman/sp/o31oa.flac' # read file
m_flac = '/mnt/junewoo/speech/TIDIGITS/tidigits_flac/data/adults/train/man/st/ooo5a.flac'

_, w_id = os.path.split(w_flac) # get dir, file name for saving
_, m_id = os.path.split(m_flac)

w_id = w_id[:-5] # change name o31oa.flac -> o31oa
m_id = m_id[:-5] # change name ooo5a.flac -> ooo5a

w_data, w_sr = sf.read(w_flac) # data, sampling rate divide
m_data, m_sr = sf.read(m_flac)


sf.write(save_dir + w_id + '.wav', w_data, w_sr, format='WAV', endian='LITTLE', subtype='PCM_16') # file write for wav
sf.write(save_dir + m_id + '.wav', m_data, m_sr, format='WAV', endian='LITTLE', subtype='PCM_16')

w, sr = librosa.load(save_dir+w_id+'.wav', sr=20000)
m, _ = librosa.load(save_dir+m_id+'.wav', sr=20000)

g_sr = 16000 # goal sampling rate

w_resample = librosa.resample(w, sr, g_sr)
m_resample = librosa.resample(m, sr, g_sr)

sf.write(save_dir + w_id + '_resample16k.wav', w_resample, g_sr, format='WAV', endian='LITTLE', subtype='PCM_16') # file write for wav
sf.write(save_dir + m_id + '_resample16k.wav', m_resample, g_sr, format='WAV', endian='LITTLE', subtype='PCM_16')

 

데이터 크기는 아래의 사진과 같다.

 

o31oa.wav 의 size는 73인데, 20kHz 에서 16kHz로 즉 20%만큼 downsampling을 해버렸기 때문에

73 * 0.8  = 58.4 ==> 58kB의 크기를 갖는다.

 

그러나 실제로 음성을 들어보면 큰 차이가 없음을 알 수 있다.

728x90
728x90

tensorboard 안될 때 해결법에 대해서 얘기하고자한다.

 

1. tf-nightly

 

나는 위 라이브러리를 설치하면서 tensorboard가 안되었다. 

또한 train code를 돌려도 gpu 메모리 할당이 안되고, cpu로 돌아가는 현상이 있었다.

 

그래서 tf-nightly 를 삭제했는데, 완전 삭제도 안되고 tensorboard도 안됐다.

 

이건 꼭 필요한 이유가 아니면 설치하지말자...

 

 

2. grpcio 문제

pkg_resources.VersionConflict: (grpcio 1.24.1 (dir), Requirement.parse('grpcio>=1.24.3')

 

위의 문제가 생겼을 때, pip로 grpcio를 지우고 하여도 안된다.

 

Duplicate plugins for name projector 라는 에러가 생기면서 안된다.

 

3. 완전 삭제가 안됨

tensorflow-gpu, tensorboard 를 지우고, 재설치하여도 안될때가 있다.

 

 

** 해결법

아래의 코드를 그대로 복사하여 하나의 .py 로 만들고, 실행하면 다음과 같은 step을 알려준다.

 

# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Self-diagnosis script for TensorBoard.

Instructions: Save this script to your local machine, then execute it in
the same environment (virtualenv, Conda, etc.) from which you normally
run TensorBoard. Read the output and follow the directions.
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# This script may only depend on the Python standard library. It is not
# built with Bazel and should not assume any third-party dependencies.
import collections
import errno
import functools
import hashlib
import inspect
import logging
import os
import pipes
import shlex
import socket
import subprocess
import sys
import tempfile
import textwrap
import traceback


# A *check* is a function (of no arguments) that performs a diagnostic,
# writes log messages, and optionally yields suggestions. Each check
# runs in isolation; exceptions will be caught and reported.
CHECKS = []


# A suggestion to the end user.
#   headline (str): A short description, like "Turn it off and on
#     again". Should be imperative with no trailing punctuation. May
#     contain inline Markdown.
#   description (str): A full enumeration of the steps that the user
#     should take to accept the suggestion. Within this string, prose
#     should be formatted with `reflow`. May contain Markdown.
Suggestion = collections.namedtuple("Suggestion", ("headline", "description"))


def check(fn):
  """Decorator to register a function as a check.

  Checks are run in the order in which they are registered.

  Args:
    fn: A function that takes no arguments and either returns `None` or
      returns a generator of `Suggestion`s. (The ability to return
      `None` is to work around the awkwardness of defining empty
      generator functions in Python.)

  Returns:
    A wrapped version of `fn` that returns a generator of `Suggestion`s.
  """
  @functools.wraps(fn)
  def wrapper():
    result = fn()
    return iter(()) if result is None else result
  CHECKS.append(wrapper)
  return wrapper


def reflow(paragraph):
  return textwrap.fill(textwrap.dedent(paragraph).strip())


def pip(args):
  """Invoke command-line Pip with the specified args.

  Returns:
    A bytestring containing the output of Pip.
  """
  # Suppress the Python 2.7 deprecation warning.
  PYTHONWARNINGS_KEY = "PYTHONWARNINGS"
  old_pythonwarnings = os.environ.get(PYTHONWARNINGS_KEY)
  new_pythonwarnings = "%s%s" % (
      "ignore:DEPRECATION",
      ",%s" % old_pythonwarnings if old_pythonwarnings else "",
  )
  command = [sys.executable, "-m", "pip", "--disable-pip-version-check"]
  command.extend(args)
  try:
    os.environ[PYTHONWARNINGS_KEY] = new_pythonwarnings
    return subprocess.check_output(command)
  finally:
    if old_pythonwarnings is None:
      del os.environ[PYTHONWARNINGS_KEY]
    else:
      os.environ[PYTHONWARNINGS_KEY] = old_pythonwarnings


def which(name):
  """Return the path to a binary, or `None` if it's not on the path.

  Returns:
    A bytestring.
  """
  binary = "where" if os.name == "nt" else "which"
  try:
    return subprocess.check_output([binary, name])
  except subprocess.CalledProcessError:
    return None


def sgetattr(attr, default):
  """Get an attribute off the `socket` module, or use a default."""
  sentinel = object()
  result = getattr(socket, attr, sentinel)
  if result is sentinel:
    print("socket.%s does not exist" % attr)
    return default
  else:
    print("socket.%s = %r" % (attr, result))
    return result


@check
def autoidentify():
  """Print the Git hash of this version of `diagnose_tensorboard.py`.

  Given this hash, use `git cat-file blob HASH` to recover the relevant
  version of the script.
  """
  module = sys.modules[__name__]
  try:
    source = inspect.getsource(module).encode("utf-8")
  except TypeError:
    logging.info("diagnose_tensorboard.py source unavailable")
  else:
    # Git inserts a length-prefix before hashing; cf. `git-hash-object`.
    blob = b"blob %d\0%s" % (len(source), source)
    hash = hashlib.sha1(blob).hexdigest()
    logging.info("diagnose_tensorboard.py version %s", hash)


@check
def general():
  logging.info("sys.version_info: %s", sys.version_info)
  logging.info("os.name: %s", os.name)
  na = type("N/A", (object,), {"__repr__": lambda self: "N/A"})
  logging.info("os.uname(): %r", getattr(os, "uname", na)(),)
  logging.info(
      "sys.getwindowsversion(): %r",
      getattr(sys, "getwindowsversion", na)(),
  )


@check
def package_management():
  conda_meta = os.path.join(sys.prefix, "conda-meta")
  logging.info("has conda-meta: %s", os.path.exists(conda_meta))
  logging.info("$VIRTUAL_ENV: %r", os.environ.get("VIRTUAL_ENV"))


@check
def installed_packages():
  freeze = pip(["freeze", "--all"]).decode("utf-8").splitlines()
  packages = {line.split(u"==")[0]: line for line in freeze}
  packages_set = frozenset(packages)

  # For each of the following families, expect exactly one package to be
  # installed.
  expect_unique = [
      frozenset([
          u"tensorboard",
          u"tb-nightly",
          u"tensorflow-tensorboard",
      ]),
      frozenset([
          u"tensorflow",
          u"tensorflow-gpu",
          u"tf-nightly",
          u"tf-nightly-2.0-preview",
          u"tf-nightly-gpu",
          u"tf-nightly-gpu-2.0-preview",
      ]),
      frozenset([
          u"tensorflow-estimator",
          u"tensorflow-estimator-2.0-preview",
          u"tf-estimator-nightly",
      ]),
  ]

  found_conflict = False
  for family in expect_unique:
    actual = family & packages_set
    for package in actual:
      logging.info("installed: %s", packages[package])
    if len(actual) == 0:
      logging.warning("no installation among: %s", sorted(family))
    elif len(actual) > 1:
      logging.warning("conflicting installations: %s", sorted(actual))
      found_conflict = True

  if found_conflict:
    preamble = reflow(
        """
        Conflicting package installations found. Depending on the order
        of installations and uninstallations, behavior may be undefined.
        Please uninstall ALL versions of TensorFlow and TensorBoard,
        then reinstall ONLY the desired version of TensorFlow, which
        will transitively pull in the proper version of TensorBoard. (If
        you use TensorBoard without TensorFlow, just reinstall the
        appropriate version of TensorBoard directly.)
        """
    )
    packages_to_uninstall = sorted(
        frozenset().union(*expect_unique) & packages_set
    )
    commands = [
        "pip uninstall %s" % " ".join(packages_to_uninstall),
        "pip install tensorflow  # or `tensorflow-gpu`, or `tf-nightly`, ...",
    ]
    message = "%s\n\nNamely:\n\n%s" % (
        preamble,
        "\n".join("\t%s" % c for c in commands),
    )
    yield Suggestion("Fix conflicting installations", message)


@check
def tensorboard_python_version():
  from tensorboard import version
  logging.info("tensorboard.version.VERSION: %r", version.VERSION)


@check
def tensorflow_python_version():
  import tensorflow as tf
  logging.info("tensorflow.__version__: %r", tf.__version__)
  logging.info("tensorflow.__git_version__: %r", tf.__git_version__)


@check
def tensorboard_binary_path():
  logging.info("which tensorboard: %r", which("tensorboard"))


@check
def addrinfos():
  sgetattr("has_ipv6", None)
  family = sgetattr("AF_UNSPEC", 0)
  socktype = sgetattr("SOCK_STREAM", 0)
  protocol = 0
  flags_loopback = sgetattr("AI_ADDRCONFIG", 0)
  flags_wildcard = sgetattr("AI_PASSIVE", 0)

  hints_loopback = (family, socktype, protocol, flags_loopback)
  infos_loopback = socket.getaddrinfo(None, 0, *hints_loopback)
  print("Loopback flags: %r" % (flags_loopback,))
  print("Loopback infos: %r" % (infos_loopback,))

  hints_wildcard = (family, socktype, protocol, flags_wildcard)
  infos_wildcard = socket.getaddrinfo(None, 0, *hints_wildcard)
  print("Wildcard flags: %r" % (flags_wildcard,))
  print("Wildcard infos: %r" % (infos_wildcard,))


@check
def readable_fqdn():
  # May raise `UnicodeDecodeError` for non-ASCII hostnames:
  # https://github.com/tensorflow/tensorboard/issues/682
  try:
    logging.info("socket.getfqdn(): %r", socket.getfqdn())
  except UnicodeDecodeError as e:
    try:
      binary_hostname = subprocess.check_output(["hostname"]).strip()
    except subprocess.CalledProcessError:
      binary_hostname = b"<unavailable>"
    is_non_ascii = not all(
        0x20 <= (ord(c) if not isinstance(c, int) else c) <= 0x7E  # Python 2
        for c in binary_hostname
    )
    if is_non_ascii:
      message = reflow(
          """
          Your computer's hostname, %r, contains bytes outside of the
          printable ASCII range. Some versions of Python have trouble
          working with such names (https://bugs.python.org/issue26227).
          Consider changing to a hostname that only contains printable
          ASCII bytes.
          """ % (binary_hostname,)
      )
      yield Suggestion("Use an ASCII hostname", message)
    else:
      message = reflow(
          """
          Python can't read your computer's hostname, %r. This can occur
          if the hostname contains non-ASCII bytes
          (https://bugs.python.org/issue26227). Consider changing your
          hostname, rebooting your machine, and rerunning this diagnosis
          script to see if the problem is resolved.
          """ % (binary_hostname,)
      )
      yield Suggestion("Use a simpler hostname", message)
    raise e


@check
def stat_tensorboardinfo():
  # We don't use `manager._get_info_dir`, because (a) that requires
  # TensorBoard, and (b) that creates the directory if it doesn't exist.
  path = os.path.join(tempfile.gettempdir(), ".tensorboard-info")
  logging.info("directory: %s", path)
  try:
    stat_result = os.stat(path)
  except OSError as e:
    if e.errno == errno.ENOENT:
      # No problem; this is just fine.
      logging.info(".tensorboard-info directory does not exist")
      return
    else:
      raise
  logging.info("os.stat(...): %r", stat_result)
  logging.info("mode: 0o%o", stat_result.st_mode)
  if stat_result.st_mode & 0o777 != 0o777:
    preamble = reflow(
        """
        The ".tensorboard-info" directory was created by an old version
        of TensorBoard, and its permissions are not set correctly; see
        issue #2010. Change that directory to be world-accessible (may
        require superuser privilege):
        """
    )
    # This error should only appear on Unices, so it's okay to use
    # Unix-specific utilities and shell syntax.
    quote = getattr(shlex, "quote", None) or pipes.quote  # Python <3.3
    command = "chmod 777 %s" % quote(path)
    message = "%s\n\n\t%s" % (preamble, command)
    yield Suggestion("Fix permissions on \"%s\"" % path, message)


@check
def source_trees_without_genfiles():
  roots = list(sys.path)
  if "" not in roots:
    # Catch problems that would occur in a Python interactive shell
    # (where `""` is prepended to `sys.path`) but not when
    # `diagnose_tensorboard.py` is run as a standalone script.
    roots.insert(0, "")

  def has_tensorboard(root):
    return os.path.isfile(os.path.join(root, "tensorboard", "__init__.py"))
  def has_genfiles(root):
    sample_genfile = os.path.join("compat", "proto", "summary_pb2.py")
    return os.path.isfile(os.path.join(root, "tensorboard", sample_genfile))
  def is_bad(root):
    return has_tensorboard(root) and not has_genfiles(root)

  tensorboard_roots = [root for root in roots if has_tensorboard(root)]
  bad_roots = [root for root in roots if is_bad(root)]

  logging.info(
      "tensorboard_roots (%d): %r; bad_roots (%d): %r",
      len(tensorboard_roots),
      tensorboard_roots,
      len(bad_roots),
      bad_roots,
  )

  if bad_roots:
    if bad_roots == [""]:
      message = reflow(
          """
          Your current directory contains a `tensorboard` Python package
          that does not include generated files. This can happen if your
          current directory includes the TensorBoard source tree (e.g.,
          you are in the TensorBoard Git repository). Consider changing
          to a different directory.
          """
      )
    else:
      preamble = reflow(
          """
          Your Python path contains a `tensorboard` package that does
          not include generated files. This can happen if your current
          directory includes the TensorBoard source tree (e.g., you are
          in the TensorBoard Git repository). The following directories
          from your Python path may be problematic:
          """
      )
      roots = []
      realpaths_seen = set()
      for root in bad_roots:
        label = repr(root) if root else "current directory"
        realpath = os.path.realpath(root)
        if realpath in realpaths_seen:
          # virtualenvs on Ubuntu install to both `lib` and `local/lib`;
          # explicitly call out such duplicates to avoid confusion.
          label += " (duplicate underlying directory)"
        realpaths_seen.add(realpath)
        roots.append(label)
      message = "%s\n\n%s" % (preamble, "\n".join("  - %s" % s for s in roots))
    yield Suggestion("Avoid `tensorboard` packages without genfiles", message)


# Prefer to include this check last, as its output is long.
@check
def full_pip_freeze():
  logging.info("pip freeze --all:\n%s", pip(["freeze", "--all"]).decode("utf-8"))


def set_up_logging():
  # Manually install handlers to prevent TensorFlow from stomping the
  # default configuration if it's imported:
  # https://github.com/tensorflow/tensorflow/issues/28147
  logger = logging.getLogger()
  logger.setLevel(logging.INFO)
  handler = logging.StreamHandler(sys.stdout)
  handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
  logger.addHandler(handler)


def main():
  set_up_logging()

  print("### Diagnostics")
  print()

  print("<details>")
  print("<summary>Diagnostics output</summary>")
  print()

  markdown_code_fence = "``````"  # seems likely to be sufficient
  print(markdown_code_fence)
  suggestions = []
  for (i, check) in enumerate(CHECKS):
    if i > 0:
      print()
    print("--- check: %s" % check.__name__)
    try:
      suggestions.extend(check())
    except Exception:
      traceback.print_exc(file=sys.stdout)
      pass
  print(markdown_code_fence)
  print()
  print("</details>")

  for suggestion in suggestions:
    print()
    print("### Suggestion: %s" % suggestion.headline)
    print()
    print(suggestion.description)

  print()
  print("### Next steps")
  print()
  if suggestions:
    print(reflow(
        """
        Please try each suggestion enumerated above to determine whether
        it solves your problem. If none of these suggestions works,
        please copy ALL of the above output, including the lines
        containing only backticks, into your GitHub issue or comment. Be
        sure to redact any sensitive information.
        """
    ))
  else:
    print(reflow(
        """
        No action items identified. Please copy ALL of the above output,
        including the lines containing only backticks, into your GitHub
        issue or comment. Be sure to redact any sensitive information.
        """
    ))


if __name__ == "__main__":
  main()

 

이대로 따라한 뒤 다시 설치하면 잘 되는것을 볼 수 있다.

 

결과사진

 

 

reference: https://github.com/pytorch/pytorch/issues/22676

728x90
728x90

Ubuntu LTS 16.04에서 pip3 을 통해 matplotlib을 설치하려면, pip를 업데이트 하라고 나오는데,

 

업데이트를 하게 되면, 아래와 같은 에러가 생긴다.

 

File "/usr/bin/pip3", line 9, in <module>

from pip import main

ImportError: cannot import name 'main'

위의 에러를 해결하려면 아래의 명령어를 이용하여 다시 설치해야 된다.

 

sudo python3 -m pip uninstall pip && sudo apt-get install python3-pip --reinstall

 

추가적으로, matplotlib의 버전을 3.0.3을 설치하게 된다면 문제가 없다...(python3.5, Ubuntu16.04, pip3 기본 버전)

 

pip3 install --user matplotlib==3.0.3

 

728x90

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

python logger 끄는 법 - turn off logging  (0) 2024.02.20
pip freeze path 문제  (0) 2023.06.22
numpy를 이용한 연속적인 중복값 제거  (0) 2021.01.22
pip와 pip3 차이  (2) 2018.04.12
Ubuntu Python2, Python3 버전 관련  (0) 2018.04.12
728x90

많은 사람들이 tmux 사용법을 모르는 것 같다.

 

나는 개인적으로 pycharm에서 코딩하는 것 보다, terminal 상에서 vim을 이용하여 주로 코딩하는데, 그 중 가장 큰 단점은 1개의 terminal로 모든걸 하기가 힘들단 것이다.

 

이 때, terminal을 여러개 사용할 수 있고,

어디에서든 명령어 하나로 그 terminal의 모든 saved 들을 가져오면 편할 것이라 생각했는데, tmux가 이런 기능을 해준다.

 

설치: sudo apt-get install tmux

 

tmux << 치면 바로 창이 열리는데,

 

나는 .tmux.conf 라는 파일을 사용하여 ctrl+a+c 를 누르면 새 창이 열리도록 하였고, ctrl+a+% 를 사용하여 창을 나눌 수 있다.

 

.tmux.conf에 대한 source들은 인터넷에 많으니 찾아본 뒤 본인 입맛에 맞는 것을 사용하면 될 것 같다.

 

예를 들어, 직장 desktop에서 tmux로 5개의 창을 열어놓고 작업한 뒤, 귀가 후 집에서 자기전에 돌려본 것을 확인하고싶을 때,

 

tmux at -d

 

사용하면 어디서든 그 환경을 그대로 유지할 수 있다.

 

tmux 여러 창

 

 

위의 사진처럼 여러 창을 열 수 있고,

세로, 가로로 분할도 가능하다.

 

728x90
728x90

최근 tensorflow 2.0이 release 된 이후로, cuda 설치가 매우 간단해졌다.

(저는 cuda+cudnn 설치하는 시간 5분 걸렸습니다.)

 

Ubuntu 16.04 (CUDA 10) + cudnn + driver 설치

 

# Add NVIDIA package repositories
# Add HTTPS support for apt-key
sudo apt-get install gnupg-curl
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_10.0.130-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu1604_10.0.130-1_amd64.deb
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
sudo apt-get update
wget http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64/nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
sudo apt install ./nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
sudo apt-get update

# Install NVIDIA driver
# Issue with driver install requires creating /usr/lib/nvidia
sudo mkdir /usr/lib/nvidia
sudo apt-get install --no-install-recommends nvidia-driver-418
# Reboot. Check that GPUs are visible using the command: nvidia-smi

# Install development and runtime libraries (~4GB)
sudo apt-get install --no-install-recommends \
    cuda-10-0 \
    libcudnn7=7.6.2.24-1+cuda10.0  \
    libcudnn7-dev=7.6.2.24-1+cuda10.0


# Install TensorRT. Requires that libcudnn7 is installed above.
sudo apt-get install -y --no-install-recommends libnvinfer5=5.1.5-1+cuda10.0 \
    libnvinfer-dev=5.1.5-1+cuda10.0

 

Ubuntu 16.04 (CUDA 9.0 for TensorFlow < 1.13.0) + cudnn + driver 설치

# Add NVIDIA package repository
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_9.1.85-1_amd64.deb
sudo apt install ./cuda-repo-ubuntu1604_9.1.85-1_amd64.deb
wget http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64/nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
sudo apt install ./nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
sudo apt update

# Install the NVIDIA driver
# Issue with driver install requires creating /usr/lib/nvidia
sudo mkdir /usr/lib/nvidia
sudo apt-get install --no-install-recommends nvidia-410
# Reboot. Check that GPUs are visible using the command: nvidia-smi

# Install CUDA and tools. Include optional NCCL 2.x
sudo apt install cuda9.0 cuda-cublas-9-0 cuda-cufft-9-0 cuda-curand-9-0 \
    cuda-cusolver-9-0 cuda-cusparse-9-0 libcudnn7=7.2.1.38-1+cuda9.0 \
    libnccl2=2.2.13-1+cuda9.0 cuda-command-line-tools-9-0

# Optional: Install the TensorRT runtime (must be after CUDA install)
sudo apt update
sudo apt install libnvinfer4=4.1.2-1+cuda9.0

위에는 cuda-10.0, 아래는 cuda-9.0 인데, 2개 모두 동시 설치 가능하다.

 

본인 계정 -> basrhc 에 들어가서 아래와 같이 사용할 버전을 typing 한다.

 

vi ~/.bashrc

export PATH=/mnt/junewoo/bin:/mnt/junewoo/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin 

# Path for cuda-9.0
export PATH=$PATH:/usr/local/cuda-9.0/bin



# Path for cuda-10.0

#export PATH=$PATH:/usr/local/cuda-10.0/bin



# Path for cudnn with cuda-9.0
#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/mnt/junewoo/utils/cuda-9.0/lib64



# Path for cudnn with cuda-10.0
export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64:/mnt/junewoo/utils/cuda-10.0/lib64

 

만약 특정 폴더에 cudnn이 있을 경우(하지만 위의 명령어대로 설치할 경우 usr/local/cuda-n.m에 설치된다.

# Path for cudnn with cuda-10.0
export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64:/where/your_dir/cuda-10.0/lib64

그 뒤,

source ~/.bashrc



nvcc -V

 

확인해보면 설치된 cuda version 체크할 수 있다.

진짜 5분만에 설치할 수 있다 매우 간단...

 

ref: https://www.tensorflow.org/install/gpu?hl=ko

728x90
728x90

최근들어 비트코인 등 해킹이 빈번하게 일어나는 것 같다.

 

특히 대학 및 연구소의 GPU 자원을 해킹하여 채굴하고 본인들 지갑(미국, 아랍 등)으로 송신하는 경우가 있는데, 학교 특성상 VPN이 없다보니, 본인이 사용하는 컴퓨터의 IP만 허용하는 법이 필요하다

 

본인의 사용 PC IP가 192.168.10.125 이면

 

sudo ufw allow from 192.168.10.125/0

 

본인의 사용 PC IP가 192.168.X.X 이면

 

sudo ufw allow from 192.168.0.0/16

 

이렇게 설정하면 가능하다.

728x90

+ Recent posts