From 3d70d8a7ec174f54877b2f1ee9de2f52f247e59e Mon Sep 17 00:00:00 2001 From: Filip Gralinski Date: Wed, 5 May 2021 13:35:25 +0200 Subject: [PATCH] =?UTF-8?q?Przyk=C5=82ady=20w=20PyTorchu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wyk/pytorch-regression/analyzer.py | 44 ++++++++++ .../analyzer_classification.py | 41 ++++++++++ wyk/pytorch-regression/linear0-infer.py | 24 ++++++ wyk/pytorch-regression/linear0.py | 68 ++++++++++++++++ wyk/pytorch-regression/linear1-infer.py | 23 ++++++ wyk/pytorch-regression/linear1.py | 70 ++++++++++++++++ wyk/pytorch-regression/linear1b.py | 70 ++++++++++++++++ wyk/pytorch-regression/linear2.py | 72 +++++++++++++++++ wyk/pytorch-regression/linear3-infer.py | 20 +++++ wyk/pytorch-regression/linear3.py | 64 +++++++++++++++ wyk/pytorch-regression/linear4-batches.py | 81 +++++++++++++++++++ wyk/pytorch-regression/linear4.py | 64 +++++++++++++++ wyk/pytorch-regression/linear5.py | 81 +++++++++++++++++++ wyk/pytorch-regression/linear6.py | 81 +++++++++++++++++++ wyk/pytorch-regression/logistic6.py | 81 +++++++++++++++++++ wyk/pytorch-regression/my_linear_regressor.py | 12 +++ .../my_linear_regressor2.py | 10 +++ wyk/pytorch-regression/my_neural_network.py | 15 ++++ 18 files changed, 921 insertions(+) create mode 100644 wyk/pytorch-regression/analyzer.py create mode 100644 wyk/pytorch-regression/analyzer_classification.py create mode 100755 wyk/pytorch-regression/linear0-infer.py create mode 100755 wyk/pytorch-regression/linear0.py create mode 100755 wyk/pytorch-regression/linear1-infer.py create mode 100755 wyk/pytorch-regression/linear1.py create mode 100755 wyk/pytorch-regression/linear1b.py create mode 100755 wyk/pytorch-regression/linear2.py create mode 100755 wyk/pytorch-regression/linear3-infer.py create mode 100755 wyk/pytorch-regression/linear3.py create mode 100755 wyk/pytorch-regression/linear4-batches.py create mode 100755 wyk/pytorch-regression/linear4.py create mode 100755 wyk/pytorch-regression/linear5.py create mode 100755 wyk/pytorch-regression/linear6.py create mode 100755 wyk/pytorch-regression/logistic6.py create mode 100644 wyk/pytorch-regression/my_linear_regressor.py create mode 100644 wyk/pytorch-regression/my_linear_regressor2.py create mode 100644 wyk/pytorch-regression/my_neural_network.py diff --git a/wyk/pytorch-regression/analyzer.py b/wyk/pytorch-regression/analyzer.py new file mode 100644 index 0000000..35496e5 --- /dev/null +++ b/wyk/pytorch-regression/analyzer.py @@ -0,0 +1,44 @@ +import regex as re +from sklearn.feature_extraction.text import HashingVectorizer +import torch + + +token_root_len = 7 + + +class Analyzer(object): + + def __init__(self): + self.token_pat = re.compile(r'(?:\p{L}|\d)+') + + def __call__(self, doc): + return [tok[0:token_root_len] for tok in self.token_pat.findall(doc)] + + +# hiperparametr - liczba bitów hasza +vector_length = 2**18 + + +vectorizer = HashingVectorizer(n_features=vector_length, analyzer=Analyzer()) + +midpoint = 1913.0 + + +def vectorize_text(content): + # musimy przekonwertować macierz sklearn => macierz numpy => tensor pytorcha + return (torch.from_numpy(vectorizer.fit_transform([content]).toarray()))[0] + + +def vectorize_batch(contents): + # musimy przekonwertować macierz sklearn => macierz numpy => tensor pytorcha + return (torch.from_numpy(vectorizer.fit_transform(contents).toarray())) + + + +def process_line(line): + fields = line.strip('\n').split('\t') + + year_from, year_to, _, _, content = fields + # normalizujemy lata do wartości (-1,1) + year_normalized = ((float(year_from) + float(year_to)) / 2 - midpoint) / 100.0 + return (content, torch.tensor(year_normalized)) diff --git a/wyk/pytorch-regression/analyzer_classification.py b/wyk/pytorch-regression/analyzer_classification.py new file mode 100644 index 0000000..2cea69c --- /dev/null +++ b/wyk/pytorch-regression/analyzer_classification.py @@ -0,0 +1,41 @@ +import regex as re +from sklearn.feature_extraction.text import HashingVectorizer +import torch + + +token_root_len = 7 + + +class Analyzer(object): + + def __init__(self): + self.token_pat = re.compile(r'(?:\p{L}|\d)+') + + def __call__(self, doc): + return [tok[0:token_root_len] for tok in self.token_pat.findall(doc)] + + +# hiperparametr - liczba bitów hasza +vector_length = 2**18 + + +vectorizer = HashingVectorizer(n_features=vector_length, analyzer=Analyzer()) + +def vectorize_text(content): + # musimy przekonwertować macierz sklearn => macierz numpy => tensor pytorcha + return (torch.from_numpy(vectorizer.fit_transform([content]).toarray()))[0] + + +def vectorize_batch(contents): + # musimy przekonwertować macierz sklearn => macierz numpy => tensor pytorcha + return (torch.from_numpy(vectorizer.fit_transform(contents).toarray())) + + + +def process_line(line): + fields = line.strip('\n').split('\t') + + label, content = fields + # normalizujemy lata do wartości (-1,1) + y = float(label) + return (content, torch.tensor(y)) diff --git a/wyk/pytorch-regression/linear0-infer.py b/wyk/pytorch-regression/linear0-infer.py new file mode 100755 index 0000000..0a565bf --- /dev/null +++ b/wyk/pytorch-regression/linear0-infer.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +import sys + +from analyzer import midpoint, vectorize_text +import torch + +w = torch.load('model.bin') + + +def model(w, x): + return x @ w + + +for line in sys.stdin: + line = line.strip('\n') + content = line + + x = vectorize_text(content) + + y_hat = model(w, x) + + # na wyjściu musimy mieć z powrotem rok + print(max(1814.0, min(2013.999, y_hat.item() * 100.0 + midpoint))) diff --git a/wyk/pytorch-regression/linear0.py b/wyk/pytorch-regression/linear0.py new file mode 100755 index 0000000..4e93bae --- /dev/null +++ b/wyk/pytorch-regression/linear0.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import sys +import torch + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_text + +# Nasz model to zestaw wag w. Na koniec dojdziemy do modeli +# Transformer o wielu milionach wag; w pewnym sensie algorytm +# uczenia się nie zmieni. +# W naszym zadaniu lepiej zacząć od zerowych wag zamiast losowych. +# Znaczenie `requires_grad` zostanie omówione w kolejnym skrypcie. +w = torch.zeros(vector_length, dtype=torch.double, requires_grad=False) + +# Hiperparametr uczenia +learning_rate = torch.tensor(.0032, dtype=torch.double) + + +def model(w, x): + # @ to iloczyn wektorów/macierzy w PyTorchu + return x @ w + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return (y_hat - y_exp)**2 + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 5000 +i = 1 +closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + +for line in sys.stdin: + content, y_exp = process_line(line) + + x = vectorize_text(content) + + # wartość z predykcji + y_hat = model(w, x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + # Obliczamy gradient i aktualizujemy wagi. + # TU SIĘ ODBYWA UCZENIE! + grad = (y_hat - y_exp) + w = w - learning_rate * x * grad + + # (Niedogodność tej wersji: jeśli zmienimy model lub funkcję kosztu, + # będziemy musieli zróżniczkować wszystko i ustalić formułę na grad. + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + closs += loss + if i % step == 0: + print("Sample item: ", y_exp.item(), " => ", y_hat.item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(w, "model.bin") diff --git a/wyk/pytorch-regression/linear1-infer.py b/wyk/pytorch-regression/linear1-infer.py new file mode 100755 index 0000000..3870a22 --- /dev/null +++ b/wyk/pytorch-regression/linear1-infer.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import sys + +from analyzer import vectorizer +import torch + +w = torch.load('model.bin') + + +def fun(w, x): + return x @ w + + +for line in sys.stdin: + line = line.strip('\n') + content = line + + x = (torch.from_numpy(vectorizer.fit_transform([content]).toarray()))[0] + + y_hat = fun(w, x) + + print(max(1814.0, min(2013.999, y_hat.item() * 100.0 + 1913.0))) diff --git a/wyk/pytorch-regression/linear1.py b/wyk/pytorch-regression/linear1.py new file mode 100755 index 0000000..026c009 --- /dev/null +++ b/wyk/pytorch-regression/linear1.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +# To samo co linear0.py tylko z automatycznym różniczkowaniem + +import sys +import torch + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_text + +# Nasz model to zestaw wag w. Na koniec dojdziemy do modeli +# Transformer o wielu milionach wag; w pewnym sensie algorytm +# uczenia się nie zmieni. +# W naszym zadaniu lepiej zacząć od zerowych wag zamiast losowych. +# Tym razem zaznaczamy, że względem w będziemy różniczkować +w = torch.zeros(vector_length, dtype=torch.double, requires_grad=True) + +# Hiperparametr uczenia +learning_rate = torch.tensor(.0032, dtype=torch.double) + + +def model(w, x): + # @ to iloczyn wektorów/macierzy w PyTorchu + return x @ w + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return (y_hat - y_exp)**2 + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 5000 +i = 1 +closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + +for line in sys.stdin: + content, y_exp = process_line(line) + + x = vectorize_text(content) + + # wartość z predykcji + y_hat = model(w, x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + w = w - learning_rate * w.grad + closs += loss + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp.item(), " => ", y_hat.item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + + i += 1 + + # ponownie ustawiamy (i zerujemy) wagi + w.requires_grad_(True) + + +# serializujemy nasz model +torch.save(w, "model.bin") diff --git a/wyk/pytorch-regression/linear1b.py b/wyk/pytorch-regression/linear1b.py new file mode 100755 index 0000000..7622205 --- /dev/null +++ b/wyk/pytorch-regression/linear1b.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +# To samo co linear0.py tylko z automatycznym różniczkowaniem + +import sys +import torch + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_text + +# Nasz model to zestaw wag w. Na koniec dojdziemy do modeli +# Transformer o wielu milionach wag; w pewnym sensie algorytm +# uczenia się nie zmieni. +# W naszym zadaniu lepiej zacząć od zerowych wag zamiast losowych. +# Tym razem zaznaczamy, że względem w będziemy różniczkować +w = torch.zeros(vector_length, dtype=torch.double, requires_grad=True) + +# Hiperparametr uczenia +learning_rate = torch.tensor(.0032, dtype=torch.double) + + +def model(w, x): + # @ to iloczyn wektorów/macierzy w PyTorchu + return torch.tanh(x @ w) + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return (y_hat - y_exp)**2 + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 5000 +i = 1 +closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + +for line in sys.stdin: + content, y_exp = process_line(line) + + x = vectorize_text(content) + + # wartość z predykcji + y_hat = model(w, x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + w = w - learning_rate * w.grad + closs += loss + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp.item(), " => ", y_hat.item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + + i += 1 + + # ponownie ustawiamy (i zerujemy) wagi + w.requires_grad_(True) + + +# serializujemy nasz model +torch.save(w, "model.bin") diff --git a/wyk/pytorch-regression/linear2.py b/wyk/pytorch-regression/linear2.py new file mode 100755 index 0000000..02c6975 --- /dev/null +++ b/wyk/pytorch-regression/linear2.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +# To samo co linear0.py tylko z automatycznym różniczkowaniem + +import sys +import torch +from torch import optim + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_text + +# Nasz model to zestaw wag w. Na koniec dojdziemy do modeli +# Transformer o wielu milionach wag; w pewnym sensie algorytm +# uczenia się nie zmieni. +# W naszym zadaniu lepiej zacząć od zerowych wag zamiast losowych. +# Tym razem zaznaczamy, że względem w będziemy różniczkować +w = torch.zeros(vector_length, dtype=torch.double, requires_grad=True) + +# Tym razem użyjemy optymalizatora +optimizer = optim.SGD([w], lr=.0064) + + +def model(w, x): + # @ to iloczyn wektorów/macierzy w PyTorchu + return x @ w + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return (y_hat - y_exp)**2 + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 5000 +i = 1 +closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + +for line in sys.stdin: + optimizer.zero_grad() + + content, y_exp = process_line(line) + + x = vectorize_text(content) + + # wartość z predykcji + y_hat = model(w, x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + closs += loss + + # Optymalizator automagicznie zadba o aktualizację wag! + optimizer.step() + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp.item(), " => ", y_hat.item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(w, "model.bin") diff --git a/wyk/pytorch-regression/linear3-infer.py b/wyk/pytorch-regression/linear3-infer.py new file mode 100755 index 0000000..ec792f9 --- /dev/null +++ b/wyk/pytorch-regression/linear3-infer.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import sys + +from analyzer import midpoint, vectorize_text +import torch + +model = torch.load('model.bin') + + +for line in sys.stdin: + line = line.strip('\n') + content = line + + x = vectorize_text(content) + + y_hat = model(x) + + # na wyjściu musimy mieć z powrotem rok + print(max(1814.0, min(2013.999, y_hat.item() * 100.0 + midpoint))) diff --git a/wyk/pytorch-regression/linear3.py b/wyk/pytorch-regression/linear3.py new file mode 100755 index 0000000..d03cc5d --- /dev/null +++ b/wyk/pytorch-regression/linear3.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# To samo co linear0.py tylko z automatycznym różniczkowaniem + +import sys +import torch +from torch import optim + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_text + +from my_linear_regressor import MyLinearRegressor + +regressor = MyLinearRegressor(vector_length) + +# Tym razem użyjemy optymalizatora +optimizer = optim.SGD(regressor.parameters(), lr=.0064) + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return (y_hat - y_exp)**2 + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 5000 +i = 1 +closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + +for line in sys.stdin: + optimizer.zero_grad() + + content, y_exp = process_line(line) + + x = vectorize_text(content) + + # wartość z predykcji + y_hat = regressor(x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + closs += loss + + # Optymalizator automagicznie zadba o aktualizację wag! + optimizer.step() + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp.item(), " => ", y_hat.item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(regressor, "model.bin") diff --git a/wyk/pytorch-regression/linear4-batches.py b/wyk/pytorch-regression/linear4-batches.py new file mode 100755 index 0000000..adc0be0 --- /dev/null +++ b/wyk/pytorch-regression/linear4-batches.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +# Wprowadzamy minibatche + +import sys +import torch +from torch import optim +import itertools + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_batch + +from my_linear_regressor import MyLinearRegressor + +regressor = MyLinearRegressor(vector_length) + +# Rozmiar minibatcha +batch_size = 16 + +# Pomocnicza funkcja do batchowania +def grouper(n, iterable): + it = iter(iterable) + while True: + chunk = tuple(itertools.islice(it, n)) + if not chunk: + return + yield chunk + + +# Tym razem użyjemy optymalizatora +optimizer = optim.Adam(regressor.parameters()) + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return torch.sum((y_hat - y_exp)**2) / batch_size + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 500 +i = 1 +closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + +for batch in grouper(batch_size, sys.stdin): + t = [process_line(line) for line in batch] + contents = [entry[0] for entry in t] + # y_exp będzie teraz wektorem! + y_exp = torch.tensor([entry[1] for entry in t], dtype=torch.double) + + optimizer.zero_grad() + + x = vectorize_batch(contents) + + # wartość z predykcji (też wektor!) + y_hat = regressor(x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + closs += loss + + # Optymalizator automagicznie zadba o aktualizację wag! + optimizer.step() + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp[0].item(), " => ", y_hat[0].item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(regressor, "model.bin") diff --git a/wyk/pytorch-regression/linear4.py b/wyk/pytorch-regression/linear4.py new file mode 100755 index 0000000..ba1f948 --- /dev/null +++ b/wyk/pytorch-regression/linear4.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# To samo co linear0.py tylko z automatycznym różniczkowaniem + +import sys +import torch +from torch import optim + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_text + +from my_linear_regressor import MyLinearRegressor + +regressor = MyLinearRegressor(vector_length) + +# Tym razem użyjemy optymalizatora +optimizer = optim.Adam(regressor.parameters()) + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return (y_hat - y_exp)**2 + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 5000 +i = 1 +closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + +for line in sys.stdin: + optimizer.zero_grad() + + content, y_exp = process_line(line) + + x = vectorize_text(content) + + # wartość z predykcji + y_hat = regressor(x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + closs += loss + + # Optymalizator automagicznie zadba o aktualizację wag! + optimizer.step() + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp.item(), " => ", y_hat.item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.double, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(regressor, "model.bin") diff --git a/wyk/pytorch-regression/linear5.py b/wyk/pytorch-regression/linear5.py new file mode 100755 index 0000000..c59f612 --- /dev/null +++ b/wyk/pytorch-regression/linear5.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +# Wprowadzamy minibatche + +import sys +import torch +from torch import optim +import itertools + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_batch + +from my_linear_regressor2 import MyLinearRegressor2 + +# Rozmiar minibatcha +batch_size = 16 + +regressor = MyLinearRegressor2(vector_length) + +# Pomocnicza funkcja do batchowania +def grouper(n, iterable): + it = iter(iterable) + while True: + chunk = tuple(itertools.islice(it, n)) + if not chunk: + return + yield chunk + + +# Tym razem użyjemy optymalizatora +optimizer = optim.Adam(regressor.parameters()) + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return torch.sum((y_hat - y_exp)**2) / batch_size + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 500 +i = 1 +closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + +for batch in grouper(batch_size, sys.stdin): + t = [process_line(line) for line in batch] + contents = [entry[0] for entry in t] + # y_exp będzie teraz wektorem! + y_exp = torch.tensor([entry[1] for entry in t], dtype=torch.float) + + optimizer.zero_grad() + + x = vectorize_batch(contents).float() + + # wartość z predykcji (też wektor!) + y_hat = regressor(x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + closs += loss + + # Optymalizator automagicznie zadba o aktualizację wag! + optimizer.step() + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp[0].item(), " => ", y_hat[0].item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(regressor, "model.bin") diff --git a/wyk/pytorch-regression/linear6.py b/wyk/pytorch-regression/linear6.py new file mode 100755 index 0000000..e2710af --- /dev/null +++ b/wyk/pytorch-regression/linear6.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +# Wprowadzamy minibatche + +import sys +import torch +from torch import optim +import itertools + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer import vectorizer, vector_length, process_line, vectorize_batch + +from my_neural_network import MyNeuralNetwork + +# Rozmiar minibatcha +batch_size = 16 + +regressor = MyNeuralNetwork(vector_length) + +# Pomocnicza funkcja do batchowania +def grouper(n, iterable): + it = iter(iterable) + while True: + chunk = tuple(itertools.islice(it, n)) + if not chunk: + return + yield chunk + + +# Tym razem użyjemy optymalizatora +optimizer = optim.Adam(regressor.parameters()) + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return torch.sum((y_hat - y_exp)**2) / batch_size + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 500 +i = 1 +closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + +for batch in grouper(batch_size, sys.stdin): + t = [process_line(line) for line in batch] + contents = [entry[0] for entry in t] + # y_exp będzie teraz wektorem! + y_exp = torch.tensor([entry[1] for entry in t], dtype=torch.float) + + optimizer.zero_grad() + + x = vectorize_batch(contents).float() + + # wartość z predykcji (też wektor!) + y_hat = regressor(x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + closs += loss + + # Optymalizator automagicznie zadba o aktualizację wag! + optimizer.step() + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp[0].item(), " => ", y_hat[0].item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(regressor, "model.bin") diff --git a/wyk/pytorch-regression/logistic6.py b/wyk/pytorch-regression/logistic6.py new file mode 100755 index 0000000..79344fd --- /dev/null +++ b/wyk/pytorch-regression/logistic6.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +# Wprowadzamy minibatche + +import sys +import torch +from torch import optim +import itertools + +# Preprocessing i wektoryzację tekstów wydzialamy do osobnego modułu, +# z którego będzie korzystał zarówno kod do uczenia, jak i predykcji. +from analyzer_classification import vectorizer, vector_length, process_line, vectorize_batch + +from my_neural_network import MyNeuralNetwork + +# Rozmiar minibatcha +batch_size = 16 + +regressor = MyNeuralNetwork(vector_length) + +# Pomocnicza funkcja do batchowania +def grouper(n, iterable): + it = iter(iterable) + while True: + chunk = tuple(itertools.islice(it, n)) + if not chunk: + return + yield chunk + + +# Tym razem użyjemy optymalizatora +optimizer = optim.Adam(regressor.parameters()) + + +# Funkcja kosztu. +def loss_fun(y_hat, y_exp): + return torch.sum((y_hat - y_exp)**2) / batch_size + + +# Co ile kroków będziemy wypisywali informacje o średniej funkcji kosztu. +# To nie jest hiperparametr uczenia, nie ma to żadnego, ani pozytywnego, ani +# negatywnego wpływu na uczenie. +step = 500 +i = 1 +closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + +for batch in grouper(batch_size, sys.stdin): + t = [process_line(line) for line in batch] + contents = [entry[0] for entry in t] + # y_exp będzie teraz wektorem! + y_exp = torch.tensor([entry[1] for entry in t], dtype=torch.float) + + optimizer.zero_grad() + + x = vectorize_batch(contents).float() + + # wartość z predykcji (też wektor!) + y_hat = regressor(x) + + # wyliczamy funkcję kosztu + loss = loss_fun(y_hat, y_exp) + + loss.backward() + + with torch.no_grad(): + closs += loss + + # Optymalizator automagicznie zadba o aktualizację wag! + optimizer.step() + + # za jakiś czas pokazujemy uśrednioną funkcję kosztu + if i % step == 0: + print("Sample item: ", y_exp[0].item(), " => ", y_hat[0].item(), + " | Avg loss: ", (closs / step).item()) + closs = torch.tensor(0.0, dtype=torch.float, requires_grad=False) + + i += 1 + + +# serializujemy nasz model +torch.save(regressor, "model.bin") diff --git a/wyk/pytorch-regression/my_linear_regressor.py b/wyk/pytorch-regression/my_linear_regressor.py new file mode 100644 index 0000000..6a450db --- /dev/null +++ b/wyk/pytorch-regression/my_linear_regressor.py @@ -0,0 +1,12 @@ +import torch.nn as nn +import torch + + +class MyLinearRegressor(nn.Module): + def __init__(self, vlen): + super(MyLinearRegressor, self).__init__() + self.register_parameter(name='w', param=torch.nn.Parameter( + torch.zeros(vlen, dtype=torch.double, requires_grad=True))) + + def forward(self, x): + return x @ self.w diff --git a/wyk/pytorch-regression/my_linear_regressor2.py b/wyk/pytorch-regression/my_linear_regressor2.py new file mode 100644 index 0000000..d1677c7 --- /dev/null +++ b/wyk/pytorch-regression/my_linear_regressor2.py @@ -0,0 +1,10 @@ +import torch.nn as nn + + +class MyLinearRegressor2(nn.Module): + def __init__(self, vlen): + super(MyLinearRegressor2, self).__init__() + self.w = nn.Linear(vlen, 1, bias=False) + + def forward(self, x): + return self.w(x).squeeze() diff --git a/wyk/pytorch-regression/my_neural_network.py b/wyk/pytorch-regression/my_neural_network.py new file mode 100644 index 0000000..86874cf --- /dev/null +++ b/wyk/pytorch-regression/my_neural_network.py @@ -0,0 +1,15 @@ +import torch.nn as nn +import torch + + +class MyNeuralNetwork(nn.Module): + def __init__(self, vlen): + super(MyNeuralNetwork, self).__init__() + self.w1 = nn.Linear(vlen, 1) + self.w2 = nn.Linear(vlen, 1) + + self.u1 = torch.nn.Parameter(torch.rand(1, dtype=torch.float, requires_grad=True)) + self.u2 = torch.nn.Parameter(torch.rand(1, dtype=torch.float, requires_grad=True)) + + def forward(self, x): + return self.u1 * torch.nn.functional.tanh(self.w1(x).squeeze()) + self.u2 * torch.nn.functional.tanh(self.w2(x).squeeze())