music generation

اطلاعات کلی درباره موسیقی:

موسیقی چیست؟ به طور خلاصه موسیقی چیزی جز یک دنباله از نت های موسیقی نیست. ورودی ما به مدل، مجموعه ای از رویدادهای موسیقی / نت ها است.

تصویر بالا نمایشی از موسیقی است که به عنوان sheet شناخته می شود. در اینجا، موسیقی توسط یک دنباله از نت های موسیقی نشان داده شده است. هر نتموسیقی با یک spaceجدا شده است.

ABC Notation

نوع دیگر نت، با استفاده از abc است.که درواقع این نوع نت گذاری شامل دو بخش است:

بخش اول:

نشان دهنده meta data است.شامل:

x: نشان دهنده تعداد بخش های مختلف از لحاظ صدا در موسیقی است

T: عنوان آهنگ

M: علامت سری زمانی نواختن(time signiture)

L: طول زمانی پیش فرض نت ها

R: ژانر موسیقی

K: سر کلید

بخش دوم:

شامل نت ها به صورت abc است.

برای مثال در کلید sol:

a=la

b=si

c=do

d=re

e=mi

f=fa

g=sol

MIDI (Musical Instrument Digital Interface)

midi درواقع خودش صدا تولید نمیکند بلکه شامل یک سری از پیام ها مانند“note on,” “note off,” “note/pitch,” “pitch-bend,… است. این پیام ها توسط ابزار midi که ممکن است سخت افزاری و یا نرم افزاری باشد تفسیر می شوند.

تصویر بالا  یک موسیقی تولید شده با استفاده از Music21 که یک کتابخانه پایتون است که موسیقی فرمت MIDI تولید می کند را نشان می دهد.(درباره کتابخانه جلوتر توضیح داده شده است)

Event1: نت B را نشان میدهد.

Event2: آکورد E,A

Music generation

از آنجایی که Rnn خالی نمی تواند موسیقی قشنگی بنوازد ، ما نیاز به کلی preprocessing و postprocessing داریم.

Preprocessing: برای آنکه نت ها را دربیاورد

Postprocessing: شامل یک سری قوانین در علم موسیقی است مثل اینکه دو تا نت ممکن است پشت هم نتوانند بیایند،اما مدل rnn این دو نت را پشت هم قرار داده است.

از کتابخانه پایتونی music21 استفاده میکنیم که یک رابط ساده برای به دست آوردن نت های موسیقی فایل های MIDI را فراهم می کند. علاوه بر این، مابه اجازه می دهد که Note و Chord را ایجاد کنیم تا بتوانیم فایل های MIDI خودمان را به راحتی ایجاد کنیم. درواقع میتوان گفت یک language model است که به جای متن، نت های موسیقی را میگیرد و آن طرف هم به جای نت موسیقی تبدیل میکند به موسیقی. و درواقع یک مدل many to many  است.

shape of x بیانگر آن است که 60 تا sample داریم و 30 تا time step و 78 تا نت موسیقیایی مختلف توانسته استخراج کند.

مقدار y درواقع برعکس مقدار x می باشد که این به این دلیل است که ضرب و تقسیم های lstm به این صورت راحت تر بوده است. حالا درواقع مقدار 30 در y بیانگر time step و 60 نمایانگر mini batch می باشد.

N_values بیانگر تعداد نت های منحصر به فرد و indices_values درواقع شامل تبدیل آن 78  نت منحصر به فرد به زبان خاص خود کتابخانه است.

77: ‘S,0.250,<dd5,d1>’

شبکه:

یک one-hot 78 تایی می دهد که این one – hot در هر  time step  به یک  lstm می رود که این lstm درواقع یک softmax است. و یک a هم داریم که به hidden state ها وارد می شود و در هر time step  مقدار خروجی a(مقدار آپدیت شده)را به lstm بعدی می دهد.

ساختن model:

در این قسمت یک مدل می سازیم و train می کنیم که درواقع pattern های موسیقی را یاد میگیرد. برای انجام این کار، نیاز به ساخت یک مدل داریم که شامل X (𝑚,𝑇𝑥,78) و Y (𝑇𝑦، 𝑚، 78) است.

از LSTM با 64 تا  hidden stateاستفاده میکنیم.

حال سه object می سازیم:

reshapor ، ابعاد را 1*78 میکند.یعنی درواقع یک بعد می خواد اضافه کند.

Densor، که در واقع همان activation های softmax ای است که در شکل مدل دیده میشود.

چون در کراس نمی توانیم به روش many to many ، ترین(train) کنیم که بعد یک کاراکتر یک کاراکتر از آن سمپل گیری کنیم.درواقع در زمان تست چون many اش رو نداریم خودمون توی زمان بازش میکنیم و train میکنیم. بنابراین آبجکت lstm رو برای یک time step می سازیم و برای تایم استپ مثلا 30 تایی یه فور روی آن میزنیم. در واقع به این صورت که در تایم استپ اول activation یا  hidden_layer لایه های قبل را برابرصفر قرار میدهیم و ورودی آن را میدهیم که activation یا hidden layer برای استپ بعد رو میدهد و ورودی بعدی یا hidden state قبلیا رو بهش میدیم و وردی یا hidden state  بعدی رو میده.

یک تابع lambda تعریف کرده که در کل lambda  یک تابع بی نام است .که درواقع در این مثال یک mini batch ای است در تعداد time step در feature vector هایی که دارد است. که درواقع وقتی مثلا  t برابر 7 است ،n*78 برگردانده می شود.و وقتی n*30*78 است یعنی تمام mini batch در تایم استپ 7   را برمیگرداند.

مدل:

آرگومان ها شامل:

Tx : تعداد time step های ورودی

n_a : تعداد hidden state های lstm

n_values: تعداد نت های منحصر به فرد

X را با ابعاد Tx در n_values تعریف میکنیم. برای آنکه ورودی many بسازیم.

Hidden state های LSTM را می سازیم.a0,c0

به اندازه time step های ورودی (Tx) فور میزنیم.

lambda ای که توضیح دادیم را تعریف میکنیم در زمان t که در واقع زمان t آن زمانی هست که الان هستیم.

x مربوط به همان time step را برداشته و reshape میکنیم کهdimention  هایی برابر با mimibatch*1*78 داشته باشیم.

در مرحله بعد LSTM_cell را با مقادیر x,a,c فراخوانی میکنیم.به این صورت که a و c در مرحله اول مقداری برابر با 0  دارند و در دفعه های بعد خروجی این قسمت است.

حال مقدار a خروجی را به densor که شامل activation function است میدهیم. و خروجی آن را در outputs،append میکنیم.

حال تابع model را با a0,c0,X و خروجی outputs فراخوانی میکنیم:

حال مدل را با ویژگی های زیر می سازیم و train  میکنیم:

m برابر با تعداد time step است.

 Generating music

در generation، شبکه Lstm داریم که در واقع یک hidden state به آن پاس داده و یک رندم و یا صفر هم به عنوان ورودی به آن میدهیم، که در نتیجه آن یک softmax هفتاد هشت تایی داریم که index ماکسیمم را برداشته و یک one-hot هفتاد و هشت تایی دیگر درست کرده و آن را به عنوان ورودی به lstm بعدی می دهیم. مانند language model

در هر مرحله از sampeling، به عنوان ورودی activation  a و cell state c را از LSTM حالت قبلی ، به صورت مرحله به مرحله ارسال می شود و یک activation  خروجی جدید و همچنین cell state جدید دریافت می شود.

LSTM_cell,densor,n_values,n_a  را که قبلا تعریف کردیم که هرکدام چه هستند اما Ty بیانگر time step موزیک خروجی می باشد.

x0,a0,c0 را مانند قبل تعریف میکنیم و مقدار اولیه آنها را میتوان یا صفر گذاشت یا چند تا نت به عنوان ورودی به ان پاس داد.

به اندازه ty، فور میزنیم.که این ty درواقع می تواند مقدارهای بالاتر از مقداری که برای train داده ایم هم باشد.

در این قسمت x,a,c را به LSTM_cell میدهیم و مانند قبل a تولید شده را به densor میدهیم و خروجی آن را به outputs،append میکنیم و همچنین خروجی را به تابع one_hot میدهیم و خروجی را در x میریزیم.

تابع one_hot در music_utils تعریف شده است.

که درواقع 78  تا prediction میگیرد و argmax میزند و ایندکس بزرگترین prediction را میگیرد و دوباره one_hot 78 تایی  از آن می سازد و برای آن که dimention آن به dimention مدل جور در بیاد RepeatVector  روی آن میزنیم.

سپس inference_model  را با ورودی ها و خروجی ها میسازیم:

در مرحله بعد سه تا بردار صفر ساخته:

تابع زیر را صدا میزنیم که سه بردار بالا و inference_model را به عنوان آرگومان به آن پاس میدهیم.

تابع generate_music را بر روی inference_model صدا میزنیم.

Corpus: مجموعه 193 تا صدا به صورت

‘C,0.333,<P1,d-5>’

            abstract_grammars: لیست از grammer ها مانند:

‘S,0.250,<m2,P-4> C,0.250,<P4,m-2> A,0.250,<P4,m-2>’

            Tones:مجموعه ای صداهای منحصر به فرد:

‘A,0.250,<M2,d-4>’

            tones_indices: دیکشنری بین تن های منحصر به فرد از 0 تا 77

indices_tones: برعکس tones_indices

chord:درواقع مجموعه ای از نت ها می باشد. که برای پیانو 18 تا chord مختلف داریم.

یک حلقه روی 18تا که در هر بار یک sequence صدا تولید میکند.

یک curr_chords می سازیم تا روی آن تغییرات ایجاد کرده و آن را به موزیک تبدیل میکنیم.

اضافه کردن آکورد به آکورد فعلی با آفست مناسب

حال تابع predict_and_sample  را روی inference_model صدا میزنیم تا یک sequence از صداهای مختلف ایجاد کنیم.

حال به جای A و X ، نت C را جایگذاری میکنیم.

ساده سازی و سلیس کردن

با استفاده از predicted_tones, curr_chords صدا تولید میکنیم و صداهای یکسان و نزدیک به هم را حذف میکنیم و out_stream را ساخته و روی my_music.midi صدا را ذخیره میکنیم.