圖片風格轉換--深度學習介紹

前言

先舉個機器學習的應用例子:圖片的風格轉換。

原圖.jpg
處理后的圖.jpg

機器學習

通過計算機強大的計算能力進行迭代運算、試錯得到相關知識。
形象生動的描述請看:機器學習

深度學習

神經(jīng)網(wǎng)絡

上圖是一個網(wǎng)絡神經(jīng)示意圖,左邊的是輸入層,最右邊的是輸出層,兩層之間的叫隱藏層,隱藏層大于2的神經(jīng)網(wǎng)絡就叫深度神經(jīng)網(wǎng)絡,深度學習就是基于深度神經(jīng)網(wǎng)絡的機器學習,深度學習是機器學習中的一種。

深度學習的相關概念

1、感知器
2、線性單元和梯度下降
3、神經(jīng)網(wǎng)絡和反向傳播算法
4、卷積神經(jīng)網(wǎng)絡

一、感知器

感知器.png
1、輸入權值:

x1,x2...是值,w1,w2....是權重。

2、激活函數(shù) :

這里舉個最簡單的例子,采用階躍函數(shù)


階躍函數(shù).png

輸入權值,經(jīng)過激活函數(shù)后就是0或1。

3、輸出:

感知器就是通過輸入的權重與值,經(jīng)過激活函數(shù)預算,再通過輸出公式得出結果

二、線性單元和梯度下降

1、什么是線性單元

激活函數(shù)為線性函數(shù)的感知器就叫做線性單元。
當面對的數(shù)據(jù)集不是線性可分的時候,『感知器規(guī)則』可能無法收斂,所以我們用可導線性函數(shù)來替代感知器的激活函數(shù),例如f(x) = x
之后,線性單元將返回一個實數(shù)值而不是0,1分類。因此線性單元用來解決回歸問題。

2、監(jiān)督學習和無監(jiān)督學習

機器學習有一類學習方法叫做監(jiān)督學習,它是說為了訓練一個模型,我們要提供這樣一堆訓練樣本:每個訓練樣本即包括輸入特征x,也包括對應的輸出y(y也叫做標記,label)。也就是說,我們要找到很多人,我們既知道他們的特征x(工作年限,行業(yè)...),也知道他們的收入y。我們用這樣的樣本去訓練模型,讓模型既看到我們提出的每個問題(輸入特征x),也看到對應問題的答案(標記y)。當模型看到足夠多的樣本之后,它就能總結出其中的一些規(guī)律。然后,就可以預測那些它沒看過的輸入所對應的答案了。

另外一類學習方法叫做無監(jiān)督學習,這種方法的訓練樣本中只有x而沒有y。模型可以總結出特征x的一些規(guī)律,但是無法知道其對應的答案y。

3、線性單元的目標函數(shù)
所有誤差之和.png
Paste_Image.png
誤差

模型的訓練,實際上就是求取到合適的w,使誤差E取得最小值。這在數(shù)學上稱作優(yōu)化問題,而就是我們優(yōu)化的目標,稱之為目標函數(shù)

4、梯度下降優(yōu)化算法

梯度是一個向量,它指向函數(shù)值上升最快的方向,梯度的反方向當然就是函數(shù)值下降最快的方向.沿著梯度相反方向去修改x的值,進行迭代獲得最小值。

Paste_Image.png

首先我們選擇一個點開始,x0,接下來迭代x1,x2,x3..一直到函數(shù)最小值。
梯度下降算法的公式如下:


梯度下降算法公式.png

三、神經(jīng)網(wǎng)絡和反向傳播算法

神經(jīng)元

神經(jīng)元就是激活函數(shù)或tanh函數(shù)的感知器。
多個神經(jīng)元構成神經(jīng)網(wǎng)絡

神經(jīng)元.png
sigmoid函數(shù).png

神經(jīng)網(wǎng)絡的輸出
神經(jīng)網(wǎng)絡實際上就是一個輸入向量x(向量,不是普通的變量,具有方向)到輸出向量y的函數(shù),即:

Paste_Image.png
神經(jīng)網(wǎng)絡的輸出.png
神經(jīng)網(wǎng)絡.png
反向傳播算法(Back Propagation)

我們需要知道一個神經(jīng)網(wǎng)絡的每個連接上的權值是如何得到的。我們可以說神經(jīng)網(wǎng)絡是一個模型,那么這些權值就是模型的參數(shù),也就是模型要學習的東西。然而,一個神經(jīng)網(wǎng)絡的連接方式、網(wǎng)絡的層數(shù)、每層的節(jié)點數(shù)這些參數(shù),則不是學習出來的,而是人為事先設置的。對于這些人為設置的參數(shù),我們稱之為超參數(shù)(Hyper-Parameters)。而我們需要做的是通過算法對神經(jīng)網(wǎng)絡進行訓練,反向傳播算法是神經(jīng)網(wǎng)絡訓練算法。

計算一個節(jié)點的誤差項,需要先計算每個與其相連的下一層節(jié)點的誤差項。這就要求誤差項的計算順序必須是從輸出層開始,然后反向依次計算每個隱藏層的誤差項,直到與輸入層相連的那個隱藏層。這就是反向傳播算法的名字的含義,最后我們可以通過計算出的誤差反過來修正權重。

就這樣,通過不斷迭代,不斷修正權重對神經(jīng)網(wǎng)絡進行訓練。

神經(jīng)網(wǎng)絡的輸出.png

四、卷積神經(jīng)網(wǎng)絡

適合圖像、語音識別任務的神經(jīng)網(wǎng)絡結構——卷積神經(jīng)網(wǎng)絡

1、Relu激活函數(shù)

在卷積神經(jīng)網(wǎng)絡中Relu函數(shù)更為適合作為激活函數(shù),公式如下:

Relu.png

Relu函數(shù)圖像如下圖所示:


采用Relu函數(shù),有以下優(yōu)點:

速度快
減輕梯度消失問題
稀疏性

2、卷積神經(jīng)網(wǎng)絡

一個卷積神經(jīng)網(wǎng)絡由若干卷積層Pooling層全連接層組成

卷積神經(jīng)網(wǎng)絡.png

我們可以發(fā)現(xiàn)卷積神經(jīng)網(wǎng)絡的層結構和全連接神經(jīng)網(wǎng)絡的層結構有很大不同。全連接神經(jīng)網(wǎng)絡每層的神經(jīng)元是按照一維排列的,也就是排成一條線的樣子;而卷積神經(jīng)網(wǎng)絡每層的神經(jīng)元是按照三維排列的,也就是排成一個長方體的樣子,有寬度高度深度

實踐應用:

一、通過深度學習對圖片進行風格轉換

原圖與名畫合成新圖片:

原圖.jpg
bigjiasuo.jpg
14764268560.0-10-bigjiasuo-googlenet-content-1e4-512.jpg
14764182840.0-10-fango-googlenet-content-1e4-512.jpg

主要的流程是:利用Caffe框架進行深度學習,通過梯度算法,完成顏色、線條等的訓練集,然后對圖片進行重繪。

1、框架、依賴等準備

(1)、安裝python、pip、numpy。
(2)、安裝深度學習框架caffe
(3)、下載訓練模型:我采用的是googlenet model
(4)、下載style-transfer代碼,根據(jù)自己的需求進行修改、優(yōu)化。
(5)、根據(jù)style-transfer文檔運行。

這幾個步驟操作起來都是比較困難的,也算是個不小的門檻。其中Caffe的安裝瑣碎,會出現(xiàn)很多意外,是個大難題;style-transfer代碼修改是最核心的部分。

2、核心代碼展示

梯度處理代碼:

def _compute_style_grad(F, G, G_style, layer):
    (Fl, Gl) = (F[layer], G[layer])
    c = Fl.shape[0]**-2 * Fl.shape[1]**-2
    El = Gl - G_style[layer]
    loss = c/4 * (El**2).sum()
    grad = c * sgemm(1.0, El, Fl) * (Fl>0)

    return loss, grad

def _compute_content_grad(F, F_content, layer):
    Fl = F[layer]
    El = Fl - F_content[layer]
    loss = (El**2).sum() / 2
    grad = El * (Fl>0)

    return loss, grad

矩陣計算

def _compute_reprs(net_in, net, layers_style, layers_content, gram_scale=1):
    (repr_s, repr_c) = ({}, {})
    net.blobs["data"].data[0] = net_in
    net.forward()

    for layer in set(layers_style)|set(layers_content):
        F = net.blobs[layer].data[0].copy()
        F.shape = (F.shape[0], -1)
        repr_c[layer] = F
        if layer in layers_style:
            repr_s[layer] = sgemm(gram_scale, F, F.T)

    return repr_s, repr_c

進行轉換:

def transfer_style(self, img_style, img_content, length=512, ratio=1e5,
                       n_iter=512, init="-1", verbose=False, callback=None):
      

        # assume that convnet input is square
        orig_dim = min(self.net.blobs["data"].shape[2:])

        # rescale the images
        scale = max(length / float(max(img_style.shape[:2])),
                    orig_dim / float(min(img_style.shape[:2])))
        img_style = rescale(img_style, STYLE_SCALE*scale)
        scale = max(length / float(max(img_content.shape[:2])),
                    orig_dim / float(min(img_content.shape[:2])))
        img_content = rescale(img_content, scale)

        # compute style representations
        self._rescale_net(img_style)
        layers = self.weights["style"].keys()
        net_in = self.transformer.preprocess("data", img_style)
        gram_scale = float(img_content.size)/img_style.size
        G_style = _compute_reprs(net_in, self.net, layers, [],
                                 gram_scale=1)[0]

        # compute content representations
        self._rescale_net(img_content)
        layers = self.weights["content"].keys()
        net_in = self.transformer.preprocess("data", img_content)
        F_content = _compute_reprs(net_in, self.net, [], layers)[1]

        # generate initial net input
        # "content" = content image, see kaishengtai/neuralart
        if isinstance(init, np.ndarray):
            img0 = self.transformer.preprocess("data", init)
        elif init == "content":
            img0 = self.transformer.preprocess("data", img_content)
        elif init == "mixed":
            img0 = 0.95*self.transformer.preprocess("data", img_content) + \
                   0.05*self.transformer.preprocess("data", img_style)
        else:
            img0 = self._make_noise_input(init)

        # compute data bounds
        data_min = -self.transformer.mean["data"][:,0,0]
        data_max = data_min + self.transformer.raw_scale["data"]
        data_bounds = [(data_min[0], data_max[0])]*(img0.size/3) + \
                      [(data_min[1], data_max[1])]*(img0.size/3) + \
                      [(data_min[2], data_max[2])]*(img0.size/3)

        # optimization params
        grad_method = "L-BFGS-B"
        reprs = (G_style, F_content)
        minfn_args = {
            "args": (self.net, self.weights, self.layers, reprs, ratio),
            "method": grad_method, "jac": True, "bounds": data_bounds,
            "options": {"maxcor": 8, "maxiter": n_iter, "disp": verbose}
        }

        # optimize
        self._callback = callback
        minfn_args["callback"] = self.callback
        if self.use_pbar and not verbose:
            self._create_pbar(n_iter)
            self.pbar.start()
            res = minimize(style_optfn, img0.flatten(), **minfn_args).nit
            self.pbar.finish()
        else:
            res = minimize(style_optfn, img0.flatten(), **minfn_args).nit

        return res

二、其他比較出名的應用:

1、谷歌的deepdream:可以讓你的機器自己做夢。

效果圖.png

2、雅虎的色情圖片檢測神經(jīng)網(wǎng)絡:效果不知道,千萬不能結合爬蟲去爬圖片,違法的。

參考鏈接:

感知器
線性單元和梯度下降
DeepDream安裝
雅虎NSFW
谷歌DeepDream
caffe官網(wǎng)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 你來到我身邊時我還只是個孩子,當我長大后才發(fā)現(xiàn)你只是陪伴我長大教我成長的一個知己,我愿意把你留在自己的心里,而你卻...
    大木子_f923閱讀 394評論 0 3
  • 你們中間誰是有智慧有見識的呢?他就當在智慧的溫柔上顯出他的善行來。 (雅各書 3:13 和合本) 分享:原來有智慧...
    探路者James閱讀 572評論 0 1
  • PS:作者很懶,所以能展示源碼他就不會多說話 先來測試一下簡書的Markdown語法支持,再bb 首先是簡書支持的...
    譚雅翔閱讀 350評論 4 3
  • Linux proc system proc 文件系統(tǒng)是由內核創(chuàng)建的虛擬文件系統(tǒng),被內核用來向外界報告信息的一個文...
    Creator_Ly閱讀 2,996評論 0 7