#!/usr/bin/env python
# coding: utf-8

# Kody źródłowe do książki: Python. Uczenie maszynowe w przykładach
#  
# Rozdział 10.: Dobre praktyki uczenia maszynowego
#  
# Autor: Yuxi (Hayden) Liu (yuxi.liu.ece@gmail.com)

# ## Dobra praktyka nr 14. Wyodrębnianie cech z danych tekstowych

# ### Osadzenia słów

from gensim.models import Word2Vec


# Przykładowe zdanie do trenowania
sentences = [
   ["uwielbiam", "tę", "książkę", "o", "uczeniu", "maszynowym"],
   ["uczenie", "maszynowe", "i", "uczenie", "głębokie", "są", "fascynujące"],
   ["osadzenia", "słów", "są", "używane", "w", "wielu", "zastosowaniach", "nlp"],
   ["word2vec", "generuje", "osadzenia", "słów"]
]


# Tworzymy i trenujemy model Word2Vec
model = Word2Vec(sentences=sentences, vector_size=100, window=5, min_count=1, sg=0)

# Pobieramy i wyświetlamy wektor dla słowa
vector = model.wv["maszynowe"]
print("Vector dla słowa 'maszynowe':", vector)


import torch
import torch.nn as nn

# Dame przykładowe
input_data = torch.LongTensor([[1, 2, 3, 4], [5, 1, 6, 3]])

# Definiujemy warstwę osadzeń
vocab_size = 10  # Całkowita liczba unikatowych słów
embedding_dim = 3  # Liczba wymiarów osadzeń
embedding_layer = nn.Embedding(vocab_size, embedding_dim)

# Przekazujemy dane wejściowe przez warstwę osadzeń
embedded_data = embedding_layer(input_data)

# Wyświetlamy osadzone dane
print("Osadzone dane:\n", embedded_data)


# # Dobre praktyki wdrażania i monitorowania modelu

# # Dobra praktyka nr 19. Zapisywanie, ładowanie i wielokrotne stosowanie modelu

# ### Zapisywanie i ładowanie modelu za pomocą modułu pickle

from sklearn import datasets
dataset = datasets.load_diabetes()
X, y = dataset.data, dataset.target

num_new = 30    # 30 ostatnich próbek tworzy nowy zbiór danych
X_train = X[:-num_new, :]
y_train = y[:-num_new]
X_new = X[-num_new:, :]
y_new = y[-num_new:]


# Wstępne przetworzenie danych
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)


import pickle
# Zapisanie obieku scalar
pickle.dump(scaler, open("scaler.p", "wb" ))


X_scaled_train = scaler.transform(X_train)


# Trenowanie modelu regresyjnego
from sklearn.svm import SVR
regressor = SVR(C=20)
regressor.fit(X_scaled_train, y_train)


# Zapis obiektu regressor
pickle.dump(regressor, open("regressor.p", "wb"))


# Wdrożenie
my_scaler = pickle.load(open("scaler.p", "rb" ))
my_regressor = pickle.load(open("regressor.p", "rb"))


X_scaled_new = my_scaler.transform(X_new)
predictions = my_regressor.predict(X_scaled_new)


# Kontrola
from sklearn.metrics import r2_score
print(f'Sprawdzenie działania modelu, wskaźnik R^2: {r2_score(y_new, predictions):.3f}')


# ### Zapisywanie i ładowanie modelu za pomocą pakietu TensorFlow

import tensorflow as tf
from tensorflow import keras

cancer_data = datasets.load_breast_cancer()
X = cancer_data.data
X = scaler.fit_transform(X)
y = cancer_data.target


learning_rate = 0.005
n_iter = 10

tf.random.set_seed(42)

model = keras.Sequential([
    keras.layers.Dense(units=1, activation='sigmoid')
])

model.compile(loss='binary_crossentropy',
              optimizer=tf.keras.optimizers.Adam(learning_rate))


model.fit(X, y, epochs=n_iter)


model.summary()


path = './model_tf'
model.save(path)


new_model = tf.keras.models.load_model(path)

new_model.summary()


# ### Zapisywanie i ładowanie modelu za pomocą pakietu PyTorch

X_torch = torch.FloatTensor(X)
y_torch = torch.FloatTensor(y.reshape(y.shape[0], 1))


torch.manual_seed(42)
 
model = nn.Sequential(nn.Linear(X.shape[1], 1),
                      nn.Sigmoid())
 
loss_function = nn.BCELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)


def train_step(model, X_train, y_train, loss_function, optimizer):
    pred_train = model(X_train)
    loss = loss_function(pred_train, y_train)
    model.zero_grad()
    loss.backward()
    optimizer.step()
    return loss.item()


for epoch in range(n_iter):
    loss = train_step(model, X_torch, y_torch, loss_function, optimizer)
    print(f"Epoka {epoch} - strata: {loss}")


print(model)


path = './model.pth'
torch.save(model, path)


new_model = torch.load(path)
print(new_model)


# ---

# Czytelnicy mogą pominąć następną komórkę.

get_ipython().system('jupyter nbconvert --to python ch10_part2.ipynb --TemplateExporter.exclude_input_prompt=True')

