<jupyter_start><jupyter_text>Разбор домашней работы<jupyter_code>import warnings
warnings.filterwarnings("ignore")

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
plt.style.use('ggplot')

%matplotlib inline

# Подгружаем pytorch 
import torch

print(torch.__version__)

import torch.nn as nn # содержит функции для реалзации архитектуры нейронных сетей
import torch.nn.functional as F # содержит различные функции активации и не только
import torch.optim as optim
import torch.utils.data as data_utils

from pytorch_lightning.metrics import Accuracy

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import StandardScaler
def load_dataset():
    X = pd.read_csv('./data/X_cat.csv', sep='\t', index_col=0)
    target = pd.read_csv('./data/y_cat.csv', sep='\t', index_col=0, names=['status'])  # header=-1,

    print(X.shape)
    print(X.head())

    target = target.iloc[:, :].values
    target[target == 'Died'] = 'Euthanasia'

    le = LabelEncoder()
    y = le.fit_transform(target)

    return X, y
features, labels = load_dataset()
features.columns.values
features['Year']<jupyter_output><empty_output><jupyter_text>1. Характеристика __Year__ принимает большие значения.  При ненормализованных значениях поверхность оптимизируемой функции становится вытянутой, и найти локальный минимум становится сложнее. !["Unnormalized"](./images/Unnormalized.png 'Unnormalized') При обучении градиентный метод сходится медленно, и чтобы обучение шло, необходимо learning rate делать небольшим, то есть гораздо меньше, чем если данные были бы нормализованы. !["Unnormalized"](./images/BadSurface.png 'UnnormalizedSurface') При нормализованных характеристиках оптимизируемая поверхность становится симметричной, и метод сходится __быстрее__, т.е. сеть обучается быстрее. !["Normalized"](./images/Normalized.png 'Normalized') Другими словами, при прохождения через слои, нейроны будут уделять больше всего внимания именно этой характеристике, так как значение будет оставться большим, и зависимости между другими характеристиками искать не будут. Чтобы предотвратить все выше описанное, небходимо всегда делать __нормализацию__ входных данных. 2. Используемая функция активации `Sigmoid`, как уже упоминалось, она может приводить к обнулению градиентов, и сеть перестают хорошо обучаться. Поэтому можно попробовать другие нелинейные функции, например, `ReLU`. Но наиболее остро проблема с `Sigmoid` ощущается именно в глубоких нейронных сетях. 3. Так же можно изменить количество слоев и количество нейронов в скрытом слое. Нет четкого теоритического обоснования, сколько именно нейронов должно быть. Но есть некоторые эвристики, которые помогут уменьшить количетсво экспериментов для подбора нужного числа. __Rules of Thumb__ (количество скрытых слоев) 1. В работах `Hornik, Stinchcombe and White 1989; Hornik 1993; Bishop 1995, 130, and Ripley, 1996, 173-180` указано, что можете взять __один слой__ и много нейронов и с этим аппроксимировать все, что угодно ("universal approximation"). Но нигде теоритически не подкреплено, сколько именно нейронов нужно, чтобы аппроксимировать любую функцию.2. Но можно "подстраховаться" на случай, если целевая функция сложная и/или на оптимизируемой поверхности есть несколько возвышений, то тогда лучше сделать __два слоя__, и количество __нейронов не меньше двух__. (`<NAME>. (1990), "Why Two Hidden Layers are Better than One"`) __Rules of Thumb__ (количество нейронов в скрытом слое) 1. Количество нейронов в скрытом слое: в промежутке сколько входных характеристик, и сколько выходных значений (<NAME>. (1992), Neural Networks in C++, NY: Wiley)2. (Number of inputs + outputs) * (2/3)3. Количество нейроной в скрытом слое не должно быть больше, чем в __два раза__ размера входного тензора. <NAME>. (1996), Applying Neural Networks: A Practical Guide, London: Academic Press.4. Зависит от количество наблюдений в обучающей выборке. Для данных размером от 150 до 2500 элементов __20__ нейронов достаточно для одного скрытого слоя.<jupyter_code>INPUT_SIZE = 37
HIDDEN_SIZE = 25
OUTPUT_SIZE = 4
LEARNING_RATE = 1e-3
EPOCHS = 100
BATCH_SIZE = 128<jupyter_output><empty_output><jupyter_text>Для того чтобы подавать данные в нейронную сеть, создадим `DataLoader`, который предоставляет гибкий API для работы с входными данными. __DataLoader__ для обучения сети<jupyter_code>def create_data_loader(X, y):
    X_train, X_test, y_train, y_test = train_test_split(X.iloc[:, :], y,
                                                        test_size=0.2, stratify=y, random_state=42)


    scaler = StandardScaler()
    X_train = scaler.fit_transform(X_train)
    X_test = scaler.transform(X_test)
    
    train_tensor = data_utils.TensorDataset(torch.tensor(X_train.astype(np.float32)), torch.tensor(y_train))
    train_loader = data_utils.DataLoader(dataset=train_tensor,
                                         batch_size=BATCH_SIZE,
                                         shuffle=True)

    test_tensor = data_utils.TensorDataset(torch.tensor(X_test.astype(np.float32)), torch.tensor(y_test))
    test_loader = data_utils.DataLoader(dataset=test_tensor,
                                        batch_size=BATCH_SIZE,
                                        shuffle=False)
    return train_loader, test_loader
train_loader, test_loader = create_data_loader(X, y)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07549595885378398, 'fraction_numerical': 0.014878765613519472, 'mean_word_length': 4.573183213920164, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '185459', 'license': 'MIT', 'n_tokens_mistral': 1974, 'n_tokens_neox': 2140, 'n_words': 534, 'path': 'week04/intro_NN_pytorch.ipynb', 'repo_name': 'ak-sergeev/SiriusDL', 'size': '5456'}