Regresja i kombinacje liniowe || Matematyka ∩ Programowanie

Regresja i kombinacje liniowe || Matematyka ∩ Programowanie


Ostatnio pomagałem w kursie algebry liniowej organizowanym przez Tai-Danae Bradleya i Jacka Hidary’ego i jedno z pytań, które pojawiło się kilka razy, brzmiało: „Dlaczego programiści powinni przejmować się koncepcją kombinacji liniowej?”

Dla tych, którzy nie wiedzą, dane wektory $ v_1, \dots, v_n$, a kombinacja liniowa wektorów to wybór niektórych współczynników $ a_i$, za pomocą których można ważyć wektory w sumie $ v = \sum_{i=1}^n a_i v_i$.

Muszę przyznać, że książki matematyczne słabo radzą sobie z przedstawianiem tej koncepcji jako czegoś więcej niż teoretycznego — być może kombinacje liniowe są potrzebne tylko do celów dowodowych, podczas gdy prawdziwym sednem jest mnożenie macierzy i iloczyny krzyżowe. Ale nie, kombinacje liniowe naprawdę leżą u podstaw wielu praktycznych zastosowań.

W niektórych przypadkach cały cel algorytmu polega na znalezieniu „użytecznej” kombinacji liniowej zbioru wektorów. Wektory to elementy składowe (często podstawa przestrzeni wektorowej lub podprzestrzeni), a zbiór kombinacji liniowych to legalne sposoby łączenia bloków. Prostsze bloki obsługują łatwiejsze i wydajniejsze algorytmy, ale ich liniowe kombinacje są mniej wyraziste. Stąd kompromis.

Konkretnym przykładem jest regresja. Większość ludzi myśli o regresji w kategoriach regresji liniowej. Szukasz funkcji liniowej, takiej jak $ y = mx+b$, która dobrze przybliża niektóre dane. W przypadku wielu zmiennych mamy np. $ \mathbf{x} = (x_1, x_2, x_3)$ jako wektor zmiennych wejściowych i $ \mathbf{w} = (w_1, w_2, w_3)$ jako wektor wag, a funkcją jest $ y = \mathbf{w}^T \mathbf{x} + b$.

Aby uniknąć przesunięcia o $ b$ (co sprawia, że funkcja jest afiniczna, a nie czysto liniowa; formuły funkcji czysto liniowych są łatwiejsze w użyciu, ponieważ przesunięcie jest jak nieznośny przypadek specjalny, z którym trzeba stale się liczyć), autorzy często dodają fałszywą zmienną wejściową $ x_0$, która jest zawsze stała na 1, i ponownie oznaczają $ b$ jako $ w_0$, aby otrzymać $ y = \mathbf{w}^T \mathbf{x} = \sum_i w_i x_i$ jako ostateczna forma. Problem optymalizacji do rozwiązania wygląda następująco, gdzie przybliżony zestaw danych wynosi $ \{ \mathbf{x}_1, \dots, \mathbf{x}_k \}$.

$$\displaystyle \min_w \sum_{i=1}^k (y_i – \mathbf{w}^T \mathbf{x}_i)^2$$

W tym przypadku wyuczona funkcja – wynik regresji – nie wygląda na kombinację liniową. Technicznie rzecz biorąc, jest, ale nie w interesujący sposób.

Staje się to bardziej oczywiste w przypadku kombinacji liniowych, gdy próbuje się modelować nieliniowość. Pomysł polega na zdefiniowaniu klasy funkcji tzw funkcje podstawowe $ B = \{ f_1, \dots, f_m \mid f_i: \mathbb{R}^n \to \mathbb{R} \}$ i pozwól, aby twoim przybliżeniem była dowolna liniowa kombinacja funkcji w $ B$, tj. dowolna funkcja z zakresu B.

$$\displaystyle \hat{f}(\mathbf{x}) = \sum_{i=1}^m w_i f_i(\mathbf {x})$$

Ponownie, zamiast ważyć każdą współrzędną wektora wejściowego za pomocą $ w_i$, ważymy wkład każdej funkcji bazowej (jeśli dany jest cały wektor wejściowy) w wynik. Jeśli funkcje bazowe miałyby wyprowadzić pojedynczą współrzędną ($ f_i(\mathbf{x}) = x_i$), wrócilibyśmy do regresji liniowej.

Następnie problemem optymalizacyjnym jest dobór wag tak, aby zminimalizować błąd aproksymacji.

$$\displaystyle \min_w \sum_{j=1}^k (y_j – \hat{f}(\mathbf{x}_j))^2$$

Załóżmy na przykład, że chcemy przeprowadzić regresję na podstawie wielomianów kwadratowych. Nasza baza dla trzech zmiennych wejściowych może wyglądać tak

$$\displaystyle \{1, x_1, x_2, x_3, x_1x_2, x_1x_3, x_2x_3, x_1^2, x_2^2, x_3^2 \}$$

Dowolny wielomian kwadratowy trzech zmiennych można zapisać jako kombinację liniową tych funkcji bazowych. Zauważ również, że jeśli potraktujemy to jako podstawę przestrzeni wektorowej, wówczas wektor będzie krotką złożoną z 10 liczb — dziesięciu współczynników wielomianu. Jest to to samo, co $ \mathbb{R}^{10}$, tylko z inną interpretacją znaczenia wpisów wektora. Dzięki temu możemy zobaczyć, jak obliczalibyśmy iloczyny skalarne, rzuty i inne przydatne rzeczy, chociaż mogą one nie mieć tej samej wrażliwości geometrycznej.

Nie są to zwykłe funkcje bazowe używane w praktyce w regresji wielomianowej (patrz uwaga na końcu tego artykułu), ale już pisząc algorytmy regresji możemy wyrządzić pewne szkody.

Proste stochastyczne zejście gradientowe

Chociaż istnieje rozwiązanie w formie zamkniętej wielu problemów regresyjnych (w tym problem regresji kwadratowej, choć z niewielkim skrętem), opadanie gradientowe jest wystarczająco prostym rozwiązaniem, aby pokazać, jak moduł optymalizacyjny może znaleźć użyteczną kombinację liniową. Ten kod zostanie napisany w Pythonie 3.9. Jest na Githubie.

Najpierw zaczniemy od kilku przydatnych aliasów typów

from typing import Callable, Tuple, List

Input = Tuple(float, float, float)
Coefficients = List(float)
Gradient = List(float)
Hypothesis = Callable((Input), float)
Dataset = List(Tuple(Input, float))

Następnie zdefiniuj prostą klasę opakowania dla naszych funkcji podstawowych

class QuadraticBasisPolynomials:
    def __init__(self):
        self.basis_functions = (
            lambda x: 1,
            lambda x: x(0),
            lambda x: x(1),
            lambda x: x(2),
            lambda x: x(0) * x(1),
            lambda x: x(0) * x(2),
            lambda x: x(1) * x(2),
            lambda x: x(0) * x(0),
            lambda x: x(1) * x(1),
            lambda x: x(2) * x(2),
        )

    def __getitem__(self, index):
        return self.basis_functions(index)

    def __len__(self):
        return len(self.basis_functions)

    def linear_combination(self, weights: Coefficients) -> Hypothesis:
        def combined_function(x: Input) -> float:
            return sum(
                w * f(x)
                for (w, f) in zip(weights, self.basis_functions)
            )

        return combined_function

basis = QuadraticBasisPolynomials()

The linear_combination funkcja zwraca funkcję, która oblicza sumę ważoną funkcji bazowych. Teraz możemy zdefiniować błąd na zbiorze danych, a także dla pojedynczego punktu

def total_error(weights: Coefficients, data: Dataset) -> float:
    hypothesis = basis.linear_combination(weights)
    return sum(
        (actual_output - hypothesis(example)) ** 2
        for (example, actual_output) in data
    )


def single_point_error(
        weights: Coefficients, point: Tuple(Input, float)) -> float:
    return point(1) - basis.linear_combination(weights)(point(0))

Następnie możemy zdefiniować gradient funkcji błędu w odniesieniu do wag i pojedynczego punktu danych. Przypomnijmy, że funkcja błędu jest zdefiniowana jako

$$\displaystyle E(\mathbf{w}) = \sum_{j=1}^k (y_j – \hat{f}(\mathbf{x}_j})^2$$

gdzie $ \hat{f}$ jest liniową kombinacją funkcji bazowych

$$\hat{f}(\mathbf{x}_j) = \sum_{s=1}^n w_s f_s(\mathbf{x}_j)$$

Ponieważ będziemy wykonywać stochastyczne opadanie w gradiencie, wzór na błąd jest nieco prostszy. Obliczamy to nie dla całego zbioru danych, ale tylko dla pojedynczego losowego punktu na raz. Więc błąd jest

$$\displaystyle E(\mathbf {w}) = (y_j – \kapelusz {f}(\mathbf {x}_j))^2$$

Następnie obliczamy gradient w odniesieniu do poszczególnych wpisów $ \mathbf{w}$, korzystając z reguły łańcuchowej i zauważając, że jedynym wyrazem kombinacji liniowej, który ma niezerowy wkład w gradient dla $ \frac{\partial E}{\partial w_i}$ jest człon zawierający $ w_i$. Jest to jedna z głównych zalet stosowania kombinacji liniowych: obliczenia gradientu są łatwe.

$ $ \ Displaystyle \ frac {\ częściowe E} {\ częściowe w_i} = -2 (y_j – \ kapelusz {f} (\ mathbf {x} _j)) \ frac {\ częściowe \ kapelusz {f}} {\ częściowe w_i} (\ mathbf {x} _j) = –2 (\ mathbf {x} _y) = –2 \hat{f}(\mathbf{x}_j)) f_i(\mathbf{x}_j)$$

Kolejną zaletą liniowości jest to, że formuła ta jest niezależna od zawartości podstawowych funkcji bazowych. Będzie tak tak długo, jak wagi nie pojawią się we wzorze na funkcje bazowe. Jako ćwiczenie: spróbuj zmienić implementację, aby używać radialnych funkcji bazowych wokół każdego punktu danych. (zobacz uwagę na końcu, dlaczego byłoby to problematyczne w prawdziwym życiu)

def gradient(weights: Coefficients, data_point: Tuple(Input, float)) -> Gradient:
    error = single_point_error(weights, data_point)
    dE_dw = (0) * len(weights)

    for i, w in enumerate(weights):
        dE_dw(i) = -2 * error * basis(i)(data_point(0))

    return dE_dw

Wreszcie rdzeń gradientowy z pomocnikiem debugowania.

import random

def print_debug_info(step, grad_norm, error, progress):
    print(f"{step}, {progress:.4f}, {error:.4f}, {grad_norm:.4f}")


def gradient_descent(
        data: Dataset,
        learning_rate: float,
        tolerance: float,
        training_callback = None,
) -> Hypothesis:
    weights = (random.random() * 2 - 1 for i in range(len(basis)))
    last_error = total_error(weights, data)
    step = 0
    progress = tolerance * 2
    grad_norm = 1.0

    if training_callback:
        training_callback(step, 0.0, last_error, 0.0)

    while abs(progress) > tolerance or grad_norm > tolerance:
        grad = gradient(weights, random.choice(data))
        grad_norm = sum(x**2 for x in grad)

        for i in range(len(weights)):
            weights(i) -= learning_rate * grad(i)

        error = total_error(weights, data)
        progress = error - last_error
        last_error = error
        step += 1

        if training_callback:
            training_callback(step, grad_norm, error, progress)

    return basis.linear_combination(weights)

Następnie utwórz przykładowe dane i uruchom optymalizację

def example_quadratic_data(num_points: int):
    def fn(x, y, z):
        return 2 - 4*x*y + z + z**2

    data = ()
    for i in range(num_points):
        x, y, z = random.random(), random.random(), random.random()
        data.append(((x, y, z), fn(x, y, z)))

    return data


if __name__ == "__main__":
    data = example_quadratic_data(30)
    gradient_descent(
        data,
        learning_rate=0.01,
        tolerance=1e-06,
        training_callback=print_debug_info
    )

W zależności od losowości może to zająć kilka tysięcy kroków, ale zazwyczaj kończy się błędem

Regresja i kombinacje liniowe || Matematyka ∩ Programowanie

Zejście gradientowe przedstawiające log (błąd całkowity) w funkcji liczby kroków dla problemu regresji kwadratowej.

Jądra i regularyzacja

Zakończę wyjaśnieniami dotyczącymi powyższych nawiasów.

Prawdziwe jądro wielomianu. Wybraliśmy prosty zbiór funkcji wielomianowych. Jest to ściśle powiązane z koncepcją „jądra”, ale „prawdziwe” jądro wielomianowe wykorzystuje nieco inne funkcje bazowe. Skaluje niektóre funkcje bazowe o $ \sqrt{2}$. Jest to w porządku, ponieważ kombinacja liniowa może to kompensować za pomocą współczynników odpowiednio podzielonych przez $ \sqrt{2}$. Ale dlaczego ktoś miałby chcieć to zrobić? Odpowiedź sprowadza się do techniki wydajności obliczeniowej zwanej „sztuczką jądra”. Krótko mówiąc, umożliwia obliczenie iloczynu skalarnego między dwiema liniowymi kombinacjami wektorów w tej przestrzeni wektorowej bez bezpośredniego przedstawiania wektorów w przestrzeni. Jeśli algorytm regresji używa w swoim kodzie wyłącznie iloczynów skalarnych (co ma miejsce w przypadku rozwiązania regresji w formie zamkniętej), można uzyskać korzyści z modelowania cech nieliniowych bez kosztów bezpośredniego obliczania cech. Jest tu o wiele więcej teorii matematycznej do omówienia (por. Odtwarzanie przestrzeni jądra Hilberta), ale na razie muszę to zostawić.

Co jest nie tak z promieniowym ćwiczeniem funkcji bazowej? W tym ćwiczeniu należało utworzyć rodzinę funkcji bazowych, po jednej dla każdego punktu danych. Problem polega na tym, że posiadanie tak wielu funkcji bazowych sprawia, że ​​przestrzeń kombinacji liniowych jest zbyt wyrazista. Optymalizacja spowoduje nadmierne dopasowanie danych. Przypomina to tabelę przeglądową: każdemu punktowi danych przypisany jest jeden wpis. Nowe punkty danych, które nie są ujęte w szkoleniu, rzadko będą dobrze obsługiwane, ponieważ nie znajdują się w „tabeli przeglądowej” znalezionej przez algorytm optymalizacji. Aby obejść ten problem, w praktyce należałoby dodać dodatkowy człon do błędu odpowiadającego normie L1 lub L2 wektora wag. Pozwala to zapewnić, że całkowity rozmiar wag jest mały i w przypadku L1 zwykle odpowiada to większości wag wynoszących zero, a tylko kilku wagom (najważniejszym) jest niezerowych. Nazywa się proces karania „wielkości” kombinacji liniowej regularyzacja.





Source link

Postagens Similares

  • Pisz tak, jak mówisz

    Październik 2015 Oto prosty trik, dzięki któremu więcej osób przeczyta to, co piszesz: pisz językiem mówionym. Większość ludzi coś przychodzi na myśl, gdy zaczynają pisać. Piszą w innym języku, niż używaliby, rozmawiając z przyjacielem. Struktura zdania, a nawet słowa są różne. W mówionym języku angielskim nikt nie używa słowa „pen” jako czasownika. Poczułbyś się jak…

  • 你怎麼知道的

    2014年12月 我讀過維爾哈杜安關於第四次十字軍東徵的編年史至少兩遍,也許三次。然而,如果我必須寫下我所記得的一切,我懷疑它會比一頁多得多。乘以幾百,當我看著我的書架時,我有一種不安的感覺。如果我對這些書的記憶如此之少,那麼閱讀所有這些書有什麼用呢? 幾個月前,當我閱讀康斯坦斯·里德(Constance Reid)撰寫的出色的希爾伯特傳記時,我找到了這個問題的答案,即使不是這個問題的答案,至少也讓我感覺更好了。她寫道: 希爾伯特對數學講座沒有耐心,因為數學講座向學生灌輸大量事實,卻沒有教他們如何提出問題並解決問題。他經常告訴他們「問題的完美表述已經是解決方案的一半」。 在我看來,這一點一直很重要,在聽到希爾伯特的證實後,我更加確信這一點。 但我最初是如何相信這個想法的呢?結合了我自己的經驗和我讀過的其他內容。那一刻我什麼都不記得了!最後我忘了希爾伯特也證實了這一點。但我對這個想法重要性的日益增強的信念仍然是我從這本書中學到的東西,即使在我忘記了我學過它之後。 閱讀和經驗可以訓練你的世界觀。即使你忘記了這段經歷或你讀過的內容,它對你的世界模型的影響仍然存在。你的頭腦就像一個已編譯的程序,但你卻失去了它的來源。它有效,但你不知道為什麼。 我從維爾哈杜安的編年史中尋找的地方不是我從中記住的東西,而是我對十字軍東徵、威尼斯、中世紀文化、攻城戰等的心智模型。這並不意味著我不能更用心地閱讀,但至少閱讀的收穫並不像看起來那麼小。 回想起來,這是顯而易見的事情之一。但這對我來說是一個驚喜,想必對任何其他因為(顯然)忘記他們讀過的東西而感到不安的人來說也是如此。 不過,意識到這一點不僅能讓你對遺忘感覺好一點。有具體的影響。 例如,閱讀和經驗通常是在發生時使用您當時的大腦狀態進行「編譯」的。同一本書在你人生的不同階段會有不同的編輯方式。這意味著重要的書籍非常值得多次閱讀。我過去常常對重讀書籍感到有些疑慮。我無意識地將閱讀與木工等工作混為一談,木工等工作必須重新做某件事就表明你第一次做錯了。而現在「已讀」這個短語似乎幾乎是格式錯誤。 有趣的是,這種意義不僅限於書籍。科技將越來越多地使重溫我們的經驗成為可能。今天,當人們這樣做時,通常是為了再次享受它們(例如,當查看旅行的照片時)或在編譯的代碼中找到某些錯誤的根源(例如,當斯蒂芬·弗萊(Stephen Fry)成功地記住了阻止他唱歌的童年創傷時)。但隨著記錄和回放生活的技術不斷進步,人們在沒有任何目標的情況下重溫經歷可能會變得很常見,只是為了再次從中學習,就像重讀一本書時一樣。 最終,我們不僅能夠回放體驗,還能夠索引甚至編輯它們。因此,儘管不知道如何知道事情似乎是人類的一部分,但事實可能並非如此。 謝謝 感謝 Sam Altman、Jessica Livingston 和 Robert Morris 閱讀本文的草稿。 Source link

  • Classificato al primo posto su HN nella zona morta di dicembre

    Per coloro che non ne erano a conoscenza (lo saresti se fossi iscritto via e-mail!), quest’anno ho aperto un blog separato sull’intelligenza artificiale, L-space Diaries, per 1) provare Substack con rabbia e 2) creare un feed mirato su un argomento piuttosto che su una persona (ho anche avviato DX Tips per la scrittura di devtools/devrel,…

  • பரவல் நிலையை ஒழுங்கமைத்தல்++

    ஐ வெளிப்படுத்தப்பட்டது நேற்றைய “ஸ்டெட் ஆஃப் டிஃப்யூஷன்++” சந்திப்பு வெற்றிகரமாக இருப்பதாக நான் உணர்ந்தேன். 200 பேர் பதிவு செய்தனர்! இதோ சில புகைப்படங்கள்! கடந்த வார இறுதியில் தனிஷ்க் ஆபிரகாம் என்னை SF-ல் சந்திக்கவும், ஒரு சிறிய சந்திப்பை மேற்கொள்ளவும் என்னை அழைத்தார். அவர் எனக்கு இரண்டு தேதிகளைக் கொடுத்தார், நான் அதை வியாழக்கிழமை அமைத்தேன். இதன் விளைவாக இருந்தது: இடத்தின் பிரதிநிதிகளுடனான சமீபத்திய தொடர்புகளின் அடிப்படையில், இது இருந்ததை விட இது எளிதாக இருக்கும்…

  • অভ্যাস স্কোরকার্ড: আপনার কোন অভ্যাস পরিবর্তন করা উচিত তা আবিষ্কার করতে এই সাধারণ অনুশীলনটি ব্যবহার করুন

    এই নিবন্ধটি পারমাণবিক অভ্যাস থেকে একটি উদ্ধৃতি, আমার নিউ ইয়র্ক টাইমস বেস্ট সেলিং বই। জাপানের রেল ব্যবস্থাকে বিশ্বের অন্যতম সেরা হিসেবে গণ্য করা হয়। আপনি যদি কখনও নিজেকে টোকিওতে একটি ট্রেনে চড়তে দেখেন, আপনি লক্ষ্য করবেন যে কন্ডাক্টরদের একটি অদ্ভুত অভ্যাস রয়েছে। যেহেতু প্রতিটি অপারেটর ট্রেন চালায়, তারা বিভিন্ন বস্তুর দিকে নির্দেশ করে এবং আদেশ…

  • Wydarzenie inaugurujące VIP Shelby CSX2900 w Muzeum Motoryzacji Petersen

    {“@context”:”http:\/\/schema.org\/”,”@id”:”https:\/\/johnchow.com\/shelby-csx2900-vip-launch-event-at-petersen-automotive-museum\/#arve-youtube-oxn3uwte5yq-2″,”type”:”Vi deoObject”,”embedURL”:”https:\/\/www.youtube-nocookie.com\/embed\/oxN3uWtE5YQ?feature=oembed&iv_load_policy=3&modestbranding=1&rel=0&autohide=1&playsinline=0&autoplay=0″} Odwiedzam Petersen Automotive Museum, aby wziąć udział w premierze VIP nowego CSX2900 firmy Shelby Legendary Cars. Model CSX2900 jest ograniczony do zaledwie dziesięciu egzemplarzy, a każdy z nich będzie kosztować 650 000 dolarów. Seria roadsterów Shelby Cobra CSX Tribute to najwyższy hołd dla Carrolla Shelby’ego. Do aluminiowych nadwozi wykorzystano oryginalne projekty fabryczne, które…

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *