之前我們簡單地介紹過 Blockchain 了,但我們還是對 Blockchain 背後的技術原理不是那麼了解,我們知道 Blockchain 是因為一個數位貨幣帳本這樣的概念被創造出來的,而數位貨幣最擔心的是什麼問題呢?其實就是雙重支付(Double-Spending)這樣的問題。

數位貨幣不像實體貨幣,數位資產比起實體資產容易複製,也因此如果花用數位貨幣的行為如果沒有處理好,就會產生憑空多出其他交易,這就像是偽鈔一樣,會造成通貨膨脹而導致貨幣貶值,讓人不再信任並願意持與流通。因此數位貨幣的支付通常需要一個受信任的第三方來做驗證,這樣的做法雖然簡單,卻存在單點脆弱性,只要這第三方受到攻擊或是監守自盜也一樣會讓這個數位貨幣變成一個失敗的貨幣。

分散式去中心化帳本能解決單點脆弱性的問題,但在驗證正確性這點難度卻很高,所有的節點都有記帳的權利,要如何確定由誰來記帳、記的帳對不對?如果無法確定帳是對的,那就存在雙重支付的風險。

為了改善單點脆弱性及雙重支付這樣的問題,許多分散式的雙重支付防範方法慢慢被提出來,中本聰提出了去中心化(以受信任第三方為中心)的方法來展示解決雙重支付問題,並實作出了 Bitcoin,使用共識機制來解決記帳及驗證的問題,這帶來去中心化數位貨幣帳本的成功。

Bitcoin 的共識協議主要由「工作量證明」(Proof-of-Work, PoW)和「最長鏈機制」兩部分組成,Bitcoin 上的各個節點就是透過共識機制中的工作量證明來決定誰有記帳權,然後取得記帳權的節點就能將新的區塊記帳加到最長鏈上並給予該節點獎勵(新區塊獎勵及交易費收益)。

Bitcoin 的 工作量證明大概會做以下的事情:

  1. 收集還未記到帳上的交易
  2. 檢查每個交易中付款地址有沒有足夠的餘額
  3. 驗證交易是否有正確的簽名
  4. 把驗證通過的交易信息進行打包(組成 Merkle Tree)
  5. 為自己增加一個交易紀錄獲得 Bitcoin 獎勵金
  6. 計算合法的 hash 爭奪記帳權

計算合法 hash 的方式請見下方影片說明,個人覺得這個影片是目前將 Blockchain 加密機制說明得最清楚的影片。我這邊簡略說明一下,合法的 hash 公式大致看起來像這樣:hash(交易內容+交易簽名+nonce+上一個區塊的 hash),我們要取得記帳權,就需要找出前面開頭有 N 個 0 的 hash,由於交易內容、交易簽名及上一個區塊的 hash 都是不可變的,所以每個節點就是不斷的調整 nonce 來計算得出不同的 hash,直到找到開頭 N 個 0 的 hash 為止,第一個找的節點就能獲得記帳權,而其他的節點只要計算 hash 對不對就能驗證這個帳對不對。其中 N 個 0 開頭的 hash 就代表了計算的難度,越多 0 代表越難找到這樣的 hash,也因此可以調整計算難度。就是這樣的設計解決了去中心化分散式系統驗證資料及決定記帳順序的難題,也就改善了數位貨幣單點脆弱性及雙重支付的問題。

以上的內容看完應該就能大體了解 Blockchain 的原理了,甚至要自己做一個 Blockchain 都沒問題!了解了 Blockchain 的技術原理之後,應該能更信任去中心化的數位貨幣的安全性,或許有天大家都信任了去中心化的數位貨幣我們就真的能廣泛使用數位貨幣,為經濟活動帶來更有效率的流通。

延伸閱讀

  1. Blockchain Demo https://anders.com/blockchain/
  2. 區塊鏈 Blockchain — 共識機制之工作量證明 Proof-Of-Work https://www.samsonhoi.com/360/blockchain_proof_of_work
  3. 區塊鏈 Blockchain — 創世區塊、區塊、Merkle Tree、Hash https://www.samsonhoi.com/274/blockchain_genesis_block_merkle_tree
  4. 比特幣如何達成共識 — 最長鏈的選擇 https://hk.saowen.com/a/6e038c8f7813d07e59249c2dae9f7064018b50da1604373aa608a61b033a80e1

之前說過,Blockchain 基本上是因為金流帳本這樣的問題而被創造出來的,也就是說區塊鏈非常適合運用在金流的應用上,我們也可以建立自己的 Blockchain 來搭建自己的金流系統,不過在 Ethereum 上 Smart Contract 這種設計讓我們擁有可以在 Ethereum 區塊鏈上創造自己金流系統的能力,如此我們就不需要自己建一條鏈了。

我們使用 Smart Contract 仿造貨幣性質創造了數位資產(說穿了其實就是在 Smart Contract 上紀錄的變數而已),而這種具貨幣性質的數位資產又被稱作 Token,如此我們就可以在應用程式中使用這個去中心化的金流系統,由於 Token 的應用很普遍,大部分的功能都已經標準化了,我們只要仿造標準來實作就可以發行自己的數位貨幣了。

在這邊我們就練習一下怎麼使用 Mist 發佈 Token Smart Contract 來發行自己的數位貨幣。(目前我們還沒有學習過如何撰寫 Smart Contract,因此這邊會先直接提供範例程式碼,實作的部分我們之後再慢慢學習)

以下是我們的範例程式碼:

請打開 Mist,如下圖點擊 Contract,然後點擊 Deploy New Contract。

你會看到如下圖的頁面,請在 Solidity Contract Source Code 中貼上我們上面提供的範例程式碼。

貼上範例程式碼之後,Mist 會自動編譯程式,檢查是否有語法上的錯誤,如果沒問題,右方的 Select Contract to Deploy 就會出現選項,在這邊我們選擇 Token ERC 20。

選擇 Token ERC 20 之後,右方會出現要初始化 Contract 的參數表單,有 Initial supply、Token name、Token symbol 需要填寫。Initial supply 代表 Token 的總發行量是多少,我這邊設定成 7777777777,你可以設成你想要的數字。Token name 就是這個 Token 要叫什麼名字,這邊我設定成 7 Token,你想要取 Dog Coin 或是 Cat Coin 也都可以。Token symbol 就是這個 Token 要用什麼代號,像是美金就是用 $、Ether 是用 ETH,這邊我設定成 7token,你可以取自己覺得帥的代號。

借下來捲動頁面到底下,這邊你可以設定 Gas Fee 要用多少,這邊就看自己高興,我是沒有做任何調整。最後按下 Deploy!

與區塊鏈互動基本上就是做交易,所以發佈 Smart Contract 也就需要發出一個交易,Mist 會彈出視窗顯示交易資訊及可能的 Gas Fee,請輸入密碼進行交易。

等待一下子就可以看到我們的 Smart Contract 發佈交易已經出現在頁面底端了,只要等待交易被確認,那一個新的數位貨幣就誕生了!

Smart Contract 發佈完成後,請點擊你的帳戶,如下圖所示。

你會發現你的帳戶底下多了一個 Token 紀錄,在這邊我擁有了 7 Token 共 7,777,777,777 顆!如果這個 Token 被承認,那我就是超級有錢人啦!

接下來我們來實際轉一些 Token 給朋友看看,在區塊鏈的世界我們不需要銀行及任何中心化的系統就可以將錢轉給朋友了,也就是我們現在擁有了一個去中心化的金流系統!讓我們來實際感受一下吧!

請點擊 7 Token 選項右邊的 Send,如下圖所示:

填入朋友的 Ethereum 帳戶位址到 To 這個欄位,Amount 填入你想要匯出的 Token 數量,在這邊我填 40,然後捲動頁面到底端送出交易。

等待一下子交易確認後,40 個 Token 就完成匯出了!

我們可以到 Etherscan上確認交易是否真的完成:https://ropsten.etherscan.io/address/0xed29cd5a72b06793601da5f0c4ec3ef5224037c7#tokentxns

的確有 40 個 7 Token 轉到朋友帳戶了!

在這個練習中,我們了解了 Token 到底是什麼,然後我們也實際發行了自己的數位貨幣,完成了自己的去中心化的金流系統,當我們想要轉帳時,我們再也不需要銀行及任何中心化的系統就可以將錢轉給朋友了,只要我們雙方都信任這個數位貨幣,價值的交換就能無遠弗屆地進行了!

Mist 跟前回介紹的 MetaMask 一樣是可以與 Ethereum 進行互動的工具,除了可以管理 Ethereum 相關密鑰之外,Mist 還包含了 Ethereum 節點以及網頁瀏覽器,方便大家瀏覽 Dapp 網頁。

首先請到這邊安裝 Mist,請選擇適於自己的作業系統安裝。

由於 Mist 會安裝節點在你的電腦裡,也因此會同步整個帳本下來,所以會花上不少時間同時也會佔用許多硬碟空間。我們目前僅是要使用測試鏈,所以請切換到 Ropsten 測試鏈(如下圖),這樣就不用花這麼多時間與空間了。

在 Mist 的左下角可以觀察目前已同步到你的電腦的區塊數(如下圖),如果這個數字跟 Etherscan(Etherscan 是一個可以查看 Ethereum 區塊鏈所有交易的網站) 上的最新區塊數一致的話,那就代表已經同步完成了。

接下來讓我們用 Mist 開一個 Ethereum 帳戶,請點擊 Add Account,並依指示輸入密碼後創建帳號,密碼請務必要記下來,將來交易時都會需要輸入你的密碼。

學會創建 Ethereum 帳戶之後,我們要來看一下 Mist 要怎麼備份帳號,請點擊 Mist 上方選單的 File -> Backup ->Accounts(如下圖),這樣就會打開帳號存放的資料夾,所有的帳號都會加密存在這邊,所以只要備份這些檔案及當時設定的密碼,你就可以在別台電腦復原你的帳號。

現在你這個 Ethereum 帳戶還沒有任何 Ether,我們仿造之前用 MetaMask 來跟水龍頭要 Ether 的步驟來取得 Ether 看看。

我個人提供了一個水龍頭 Dapp,請前往這個網址來取得 Ether:https://blog.fukuball.com/dapp/faucet/

由於 Mist 也是一個 Dapp 網頁瀏覽器,請在 Mist 上方的網址列輸入:https://blog.fukuball.com/dapp/faucet/

Mist 在揭露你的 Ethereum 帳戶資訊給 Dapp 網頁時都會詢問你的同意,請先選擇要瀏覽這個 Dapp 網頁的帳號(你可能在 Mist 有多個帳號,所以就需要選擇目前要用哪個帳號瀏覽這個網頁)。

然後點擊 Authorize,這樣就可以連上 Dapp 網頁了。

你可以看到跟 MetaMask 一樣,Ethereum 帳號(public address)已經被填寫到 Send To 欄位了,只要按下 Send To 之後不久你就可以從水龍頭收到 Ether 了。

果然不久之後我們就收到了 0.5 Ether!

接下來我們一樣練習一下把 0.1 Ether 匯回給水龍頭,請在 Credit 欄位輸入 0.1,然後按下 Credit。

這時 Mist 跟 MetaMask 一樣會彈出一個視窗顯示 Gas Fee 等資訊,不同的地方是 Mist 需要輸入密碼來授權這個交易。

交易進行時,你會收到一個 Tx id,在我這邊的例子是:0x82407e0aac7cc5d3ef485ffba78f279b37aaba50e64396c477b1b19ee5590793,你可以到 Etherscan 去查看這筆交易進行的狀態:https://ropsten.etherscan.io/tx/0x82407e0aac7cc5d3ef485ffba78f279b37aaba50e64396c477b1b19ee5590793

不久之後,等交易確認,你就可以看到 Ether 變成 0.4 了,你成功匯回了 0.1 Ether。

如同使用 MetaMask,我們也可以使用官方提供的 Mist 來與 Ethereum 區塊鏈做互動,其實都不錯用,但 Mist 相對肥大很多,也因此有時候交易會卡住,畢竟 Mist 在你的機器上安裝了 Ethereum 節點,所以比起 MetaMask 複雜許多,也比較容易遇到問題。如果你遇到問題了,可能重開 Mist 就能解決,如果還是不能解決,那就 google 吧!

Appendix

Mist 在系統背景開了一個叫 geth 的程序,這個 geth 就是主要用來與 Ethereum Network 互動的程式,未來我們會再多說一點 geth,在這邊我們先稍微看一下就好。

請在 Terminal 輸入指令:

ps aux | grep geth

你會看到 geth 真的有被跑在背景執行:

我們也可以進入 geth 的指令介面來使用 geth 更多功能,請在 Terminal 輸入指令:

/Users/username/Library/Application\ Support/Mist/binaries/Geth/unpacked/geth attach ~/Library/Ethereum/geth.ipc

你會看到像這樣的互動介面:

在這邊可以使用 geth 更多與 Ethereum 互動的指令,我們後續會學到更多,在這邊先簡單感受一下就好,你可以輸入指令:

net.peerCount

這樣 geth 就會回覆目前你的節點有多少的 peer 連結,其他的功能,我們就以後再說吧!

前一回稍微對 Blockchain、Bitcoin、Ethereum 做了一個科普的簡介,我們可以知道 Blockchain 就是一個帳本,每一個加入 Blockchain 的節點都會下載整個帳本在本地端,所以我們就可以在自己的節點(系統)寫入資料到帳本並透過 Blockchain 背後的機制同步到所有的節點。

但實際在節點帳本上寫入交易紀錄前,我們先使用 MetaMask 這個工具來跟 Ethereum 互動吧,不然要裝好 Ethereum 節點、下載好帳本可能會花上不少時間,在這之前就失去耐性的話可不是一個好的開始。

MetaMask 這個工具可以讓你不用安裝節點就跟 Ethereum 上的帳本做互動,這背後的原理其實就是使用別人幫忙維護的節點,如此就可以不用自己安裝節點、同步帳本。

首先請到 MetaMask 上安裝 Chrome(或 Firefox)外掛,並請依指示安裝,MetaMask 會創建 Ethereum 帳戶及相關密鑰,MetaMask 也會管理密鑰,讓你可以方便地使用密鑰來與 Ethereum 互動,請記下密碼及 12 個單字的帳戶復原字,這 12 復原字可以用來讓你回復 Ethereum 帳戶,如下圖。

Ethereum 上流通的貨幣就是 Ether,它用來當成 Ethereum Blockchain 得以運作的貨幣,Ethereum 上的節點想在 Ethereum 上做運算或是記下資料,那就需要付 Ether 當手續費,而在 Ethereum 上當礦工的節點就可以提供運算資源收取 Ether 當報酬。就如同現實世界一樣,貨幣的流通形成了資源的流通,讓世界可以正常運作。

我們先切換到 Ropsten Test Network(Ethereum 的測試鏈,上面的 Ether 是沒有任何價值的)來感受一下在 Blockchain 上怎麼進行交易。

現在我們還沒有任何 Ether 可以使用,這樣我們就沒辦法與 Ethereum 做互動,也就是無法做任何交易,讓我們來跟水龍頭要一些 Ether 來花吧!(在測試鏈上有佛心水龍頭,但正式鏈上就要自己挖礦或是花錢買 Ether 了!)

我個人提供了一個水龍頭 Dapp,請前往這個網址來取得 Ether:https://blog.fukuball.com/dapp/faucet/

這個 Dapp 會讀取你的帳戶位址到 Send To 欄位,你也可以自己複製位址到 Send To 欄位,點擊 Send To 之後不久就可以收到 Ether 了!

如上圖,我們不久之後就收到了 0.5 Ether,接下來我們來把 0.1 Ether 捐回去給水龍頭提供者看看。

請在 Credit 欄位上輸入 0.1,並點擊 Credit。

這時 MetaMask 會彈出交易視窗,顯示將要匯出 0.1 Ether(約 22.78 美金),然後手續費 Gas Fee(礦工運算顯)是 0.0001 Ether。(手續費現實世界通用的,但在 Ethereum 的世界叫 Gas Fee,之後文章將都統一使用 Gas Fee)

你可以點擊 Edit 調整 Gas Fee,簡易說明下 Gas Fee,Gas Fee 就是 Gas Price(以 Gwei 為單位)X Gas Limit 的計算結果,因此這個例子的 Gas Fee 就是 0.0001 Ether,Gas Price 影響的是礦工運算的優先度,Gas Limit 影響的則是可用多少運算資源。

不久之後,我們的 Ether 降到了 0.399978,我們成功地匯回了 0.1 Ether,而 Gas Fee 沒有花完所以得到的 balance 是 0.399978,並非 0.3999(Gas Fee 花光會有交易失敗風險)。

我們成功地透過了 MetaMask 在 Ethereum 上做交易,我們可以不用透過銀行就可以將錢匯來匯去了!只要會寫 Dapp,我們就可以從世界各地賺錢,讓使用者直接與我們交易,中間不需要再接銀行的金流了,這樣的世界是不是很棒呢!

網際網路發展至今,大家已經很習慣上網使用系統與服務了,這樣普遍存在網路上的系統大部分都是 Client-Server 式的系統,這樣的系統會有自己的內部網路與資料庫,當不同的系統之間要溝通或同步資料的時候,通常會透過 API 這樣的管道來溝通與同步資料,而 API 需要工程師撰寫,並不是在這些系統原生就會有的機制與功能,這就會產生開發成本,也因此不同系統之間的資料交換一直是一個需要被解決的問題。

Blockchain 的特性上,若系統是屬於 Blockchain 上的節點,那麼所有的系統節點就是共享同一份資料,當其中一個系統更改了 Blockchain 上的資料,那這一份更改就會同步到所有的系統。

這樣的特性除了泛用的資料同步分享之外,其實也非常適合使用作為「帳本」(可同步、且不可竄改),Bitcoin 是第一個將這樣帳本特性發揚光大的應用,雖然 Bitcoin 被製造出來時還沒有 Blockchain 這樣的概念,但背後的技術及運用的特性就是現在大家在講的 Blockchain。Blockchain 的思想基本上就是以「帳本」這樣的概念產生的,這個帳本上記錄所有的交易紀錄(也就是資料紀錄),且只能新增紀錄,不能修改或刪除紀錄,所有的紀錄像鏈子一樣結合起來,就像一個 chian of block,並透過加密機制讓鏈結的資料不可被竄改,也因此所有的交易紀錄(也就是資料)被紀錄到帳本之中,那就永遠不會消失。要算帳時只要將個人所擁有的所有交易紀錄進帳與出帳加總起來,就可以得到這個帳戶的結餘。Bitcoin 運用了早已存在的 P2P 運算、共識機制、加密機制、Chain of Block 及 Merkle Tree 整合出了現在大家在說的 Blockchain,而這一切的出發點就是為了製造出一個去中心化的金流系統(資料交換系統)。

Bitcoin 帶來了第一波 Blockchain 革命,第二波 Blockchain 革命就是在 Ethereum 開始的。由於在 Bitcoin 上的交易紀錄只是紀錄資料,假設我們將一個可執行的程式紀錄在 Blockchain 交易紀錄上會發生什麼事呢?

這樣這個程式就可以共享在整個 Blockchain 上,大家都可以在 Blockchain 上運行程式,而程式運行的資料可以在 Blockchain 上存取,讓整個 Blockchain 作為資料庫,這樣的程式就叫做 Smart Contract。這樣將程式放到 Blockchain 上運行的想法帶來了 Ethereum 的成功,如此 Ethereum Blockchain 就成了一個非常龐大的運算平台,讓許多去中心化的應用如雨後春筍地開發出來,讓未來的網路應用充滿了更多想像!

這份筆記將會紀錄在 Ethereum 上開發應用所學習到的知識,作為自己的回憶,也分享給想一起學習的開發者。

之前看到〈『致敬赵雷』基于TensorFlow让机器生成赵雷曲风的歌词〉這篇文章覺得非常有趣,因此一直都想自己動手試試看,中國有趙雷,那台灣要找什麼值得紀念的音樂人來作這個歌詞機器學習模型呢?我想張雨生應該會是台灣非常值得令人紀念的音樂人之一了。

程式的基礎我使用了之前在 GitHub 上有點小小貢獻的一個 Project 作為程式碼基礎,這個 Project 是 char-rnn-tf,可以用於生成一段中文文本(訓練與料是英文時也可以用於生成英文),訓練語料庫我收集了張雨生的百餘首歌詞(包含由張雨生演唱或作曲的歌詞),由於這樣的歌詞語料還是有些不足,因此也加入了林夕、其他著名歌詞、新詩作為輔助,整個語料庫大致包含 74856 個字、2612 個不重複字(其實語料庫還是不足)。

演算法基本上就是 LSTM,細節在此就不多加著墨,若有興趣可以在這篇文章了解一下,沒有時間的人,也可以看看 char-rnn-tf 這個 Project 作者所做的這張圖(見下圖),對概念了解一下。

https://github.com/hit-computer/char-rnn-tf/blob/master/model.jpg?raw=true

相關程式碼我放在這邊:Tom-Chang-Deep-Lyrics,如何安裝環境、如何訓練、如何生成歌詞,基本上都寫在 Readme 了,大家可以前往瞧瞧。


歌詞產生結果

範例一:夢想

訓練完模型之後(用 macbook air 大致上需要 1 天的時間),由於大眾對張雨生歌詞的印象應該就是「我的未來不是夢」,因此我首先使用「夢想」作為 seed,結果產生歌詞如下:

夢想會有心
我不願再區福 也不是一種把你一樣偷偷
我的心中有無奈

在我的心裡流 你的身影 你的轉身 你的沈靜 框進畫裡印象派的意

我有個朋友聽我說故舊 這一路悠揚的街長
我是天堂飄輝在天空裡
期待愛人看不同的眼睛
我等待與你身邊
你的歡念 你的灑明 在我心底都是飄逸水墨

我想你 愛過了我的一切
為你一起孤定我的美麗

產生的結果,歌詞機器學習模型先把詞補成句子「夢想會有心」,其實補得蠻好的啊!

「我不願再區福 也不是一種把你一樣偷偷 我的心中有無奈」

這邊雖有錯字,但也不至於不能理解。

「在我的心裡流 你的身影 你的轉身 你的沈靜 框進畫裡印象派的意」

這裡則結合了一首新詩,自創了歌詞。’

「我有個朋友聽我說故舊 這一路悠揚的街長」

這一句歌詞結合了張雨生的歌曲永公街的街長,說明歌詞機器學習模型的確有張雨生的影子,但悠揚的街長感覺怪怪的 XD


範例二:我的未來不是夢

從上一個範例,我們可以了解這個歌詞機器學習模型的效果還算不錯,且看起來比起〈『致敬赵雷』基于TensorFlow让机器生成赵雷曲风的歌词〉這篇所產生的歌詞還要好,仔細看趙雷歌詞產生的結果就會覺得歌詞有點不知所云,而我這邊訓練完的結果,看起來語意會比較明確一些。

接著上個範例,我們來試試看「我的未來不是夢」作為 seed。

我的未來不是夢
我只是真的勇敢

我是一棵秋天的樹 枯少的葉片顯過我
如果有愛能值得這些愁
這個世界保持安靜的距離

熱鬧容易 難得孤寂
我才捨不得問自己
從哪裡來又沒有用 感情和你的歸懷

你是我的姊妹
你是我的 BABY
讓我們的是 BAD BOY 難道我曾經默默縱容 那全是你犯的錯 喔

你贏 我不想與你再爭辯
我說你贏 我再也不想爭辯 請你轉過頭 我有哭泣的尊嚴
我是你的 BABY 我說得再多

「我的未來不是夢 我只是真的勇敢」

如果少了「只」感覺會更好一些。

「我是一棵秋天的樹 枯少的葉片顯過我 如果有愛能值得這些愁」

這邊則是致敬了張雨生的「我是一棵秋天的樹」的歌詞。

「你是我的姊妹」、「讓我們的是 BAD BOY」、「你贏 我不想與你再爭辯」

這邊則結合了「姊妹」「BAD BOY」「你贏」三首歌詞,有些地方說得通,但其實很難讓整首歌詞語意一致,這是目前這個歌詞機器學習模型需要改善的地方。


範例三:永遠不回頭

接下來試試經典歌曲「永遠不回頭」作為 seed。

永遠不回頭
我只能誠實你只能真摰 你無需幻想你無需作夢

當舞台來喝采聲星 為你的心呢的旋律
我是如此的愛 被我無深在心靈
我的愛沒有書香的清澈 我的愛沒有酒醇的狂語
我的愛沒有鑽石的雨 我是真的 人是假的唯

我要你的愛不曾衰竭 只要越來越不知道那無遲

別用你的眼 用我的心
好好一些感動

我在你心裡面看不見
我的世界裡用天地溫柔
永遠的感覺你和你

「永遠不回頭 我只能誠實你只能真摰 你無需幻想你無需作夢」

語意上蠻貼切的。

「別用你的眼 用我的心 好好一些感動」

「我在你心裡面看不見 我的世界裡用天地溫柔 永遠的感覺你和你」

這邊看不出是致敬哪首歌詞,比較像是歌詞機器學習模型自己從看過的語料中創作出來的,在字彙這麼少的情況下能夠這樣創作真的很不容易,想想自己小時候寫作文就知道這有多難,機器等於是一天學會作文。


範例四:我學會飛翔

接下來使用「我學會飛翔」作為 seed,這是範例中唯一由張雨生寫的歌詞,其他範例都是合作過的歌曲(雖然也都放在語料庫中),哎呀,真不會選範例!

我學會飛翔
深空之前如何困見 那裡有愛的人
為誰呼喚我 那一天我依稀回來
我們的愛情是迷霧 我總是深彎

我不能相信 何難自己

當風和日麗 陽春三月天
燦爛的心境 醉人的詩篇
或許紅磚上 或許小湖沿
繽紛的足跡 飛揚的笑靨
純潔的性靈 仿如剛清醒
又似蒙蔽 你的輪廓 在汗水中穿梭的角梗
吐著濃濃的煙霧恣任冥思出星
燦爛的陽光溫暖不到這樣的角落
一想到你呀 就讓我快樂
就好比蜻猴呀穿梭梭林 聚成了身邊

「我們的愛情是迷霧」

這也是歌詞機器學習模型自己創作出來的,覺得蠻厲害的。

「當風和日麗 陽春三月天 燦爛的心境 醉人的詩篇」

這邊的詞有點高水準,所以其實是 Overfitting,抄了張雨生的「三月的天真」這首歌詞。


範例五:沒有菸抽的日子

接下來試試另一首經典歌曲「沒有菸抽的日子」作為 seed。

沒有菸抽的日子 喔

蒼匆的年宴不想留念你的存在
等待那一天鐘
不能說
我不會知道該怎麼做

當秋天葉落 西風來臨後
樹靈的枯枝 曳搖千萬萬 搖積不再有不停 是否不能呼吸
你也能夠 不顧

常常常覺得對自己嗎 難道我真的更好

oh 不醉 就學不會

好男人是不是都躲在家裡
為何身邊六塊肌全對女人沒興趣
有時我真懷疑 纏綿悱惻的劇情
幸福結局 只出現在日劇
女人的心 好比 放大鏡

「沒有菸抽的日子 喔」

「oh 不醉 就學不會」

這兩句真的喔的很貼切啊!很可惜後面 Overfitting 了~


範例六:漂向北方

最後我們來試試不是張雨生的歌曲看看,刻意選了近期還蠻紅的歌曲「漂向北方」作為 seed。

漂向北方 別問我家鄉
直到昏景 等到癡邊

我期待 在我的窗中
你給我一個感覺
肯定的愛情
擁有工作我的愛 請我的愛沒有書醇的狂向
直到傻風上煙中深起
你知道我不會猜你

我的笑容隨著煦煦和風 溫暖吹襲一股月色迷濛
我的歌聲衝出節節喉嚨 騷動八方就該天地星座 快同我怒吼

大度能寬容 滄海樂悠悠 誰又不想放下身段快意自由
失意也會有 得意也會有 反正都是生不帶來死不帶走

「漂向北方 別問我家鄉 直到昏景 等到癡邊」

補完的詞還不錯,「等到癡邊」比較不能理解,但算是有趣的創作吧。

「我期待 在我的窗中 你給我一個感覺 肯定的愛情」

致敬了我期待,感覺真的有在期待的感覺。

後面好像 Overfitting 了張雨生的「門外還有愛」,但整首詞的語意還算一致,算是一個不錯的結果。


以上就是這個「基於 LSTM 深度學習方法研發而成的張雨生歌詞產生模型」的實驗結果,產生的詞算是可讀,而且有些還蠻有意思的,比較大的問題是上下文的語意可能會不一致,這樣的問題目前也有很多論文在解了,大體上就是用多層的 LSTM,可以將句子為 level 做 Encode 之後做一層 LSTM,將段落為 level 做 Encode 之後做一層 LSTM,結合原本的字詞 level 的 LSTM 模型,應該就可以做出上下文語意一致的歌詞產生模型了,如果大家有做出來,別忘了分享一下啊!

前言

本系列部落格文章將分享我在 Coursera 上台灣大學林軒田教授所教授的機器學習技法(Machine Learning Techniques)課程整理成的心得,並對照林教授的投影片作說明。若還沒有閱讀過 第 15 講 的碼農們,我建議可以先回頭去讀一下再回來喔!

範例原始碼:FukuML - 簡單易用的機器學習套件

我在分享機器學習基石課程時,也跟著把每個介紹過的機器學習演算法都實作了一遍,原始碼都放在 GitHub 上了,所以大家可以去參考看看每個演算法的實作細節,看完原始碼會對課程中的數學式更容易理解。

如果大家對實作沒有興趣,只想知道怎麼使用機器學習演算法,那 FukuML 絕對會比起其他機器學習套件簡單易用,且方法及變數都會跟林軒田教授的課程類似,有看過課程的話,說不定連文件都不用看就會使用 FukuML 了。不過我還是有寫 Tutorial 啦,之後會不定期更新,讓大家可以容易上手比較重要!

熱身回顧一下

上一講中我們學到了如何使用矩陣分解方法來解推薦問題,機器學習技法課程也到這邊告一段落了,這一講終將會總結回顧一下我們在機器學習技法中學到的所有機器學習演算法,也許還有許多算法沒有介紹到,但基本概念都可以延伸。

特徵技巧:Kernel

我們學習到了如何使用 Kernel 來表現資料特徵,使用到 Kernel 技巧的相關演算法如下:

特徵技巧:Aggregation

我們也可以使用 Aggregation 方法來結合資料特徵,藉以合成更強大的學習演算法,使用到 Aggregation 技巧的相關演算法如下:

特徵技巧:Extration

我們可以使用 Extration 技巧來取得重要的資料特徵,使用到 Extration 技巧的相關演算法如下:

特徵技巧:Low-Dim

我們也會使用降維這個特徵技巧來取得資料的重要特徵,用到降維技巧的相關演算法如下:

優化技巧:Gradient Decent

在類神經網路大量用到了 Gradient Decent 技巧來進行 Error 優化,用到 Gradient Decent 技巧的相關演算法如下:

優化技巧:Equivalent Solution

在許多困難的問題,我們很難找到優化的方法,我們會使用 Equivalent Solution 找到優化的方法,例如 Dual SVM 我們使用 covex QP、Kernel LogReg 我們用 representer、PCA 我們用 eigenproblem 來解。

未來若需要發展自己的演算法,也可以朝 Equivalent Solution 去想優化方法,只是這可能需要大量的數學推理知識。

優化技巧:Multiple Steps

有一些演算法我們會用 Multiple Steps 來一步一步進行優化,,用到 Multiple Steps 技巧的相關演算法如下:

過擬似技巧:正規化

由於演算法的能力越來越強,也因此很容易過擬似(Overfitting),所以我們必須要有方法來避免過擬似,其中一個方式就是正規化,我們大致學過的正規化方法如下:

過擬似技巧:Validation

另外我們也需要使用 Validation 方法讓我們在訓練過程就可以避免過擬似,在機器學習技法中我們學到的一些演算法有因為演算法特性而發展出來的 Valdation 方法:

機器學習叢林

林軒田老師在機器學習技法課程的一開始就有放過這樣一張投影片,我們進入的是一個機器學習的叢林,從一開始可能對這投影片的所有演算法都不了解,但在這課程的尾聲我們重新回顧,相信大家多少都已經認識了這個叢林的險惡,也了解這個叢林是個多麽有趣與豐富!

Fukuball

我是林志傑,網路上常用的名字是 Fukuball。我使用 PHP 及 Python,對機器學習及區塊鏈技術感到興趣。 https://www.fukuball.com

Co-Founder / Head of Engineering at OurSong

Taipei, Taiwan