CodeLab
145 subscribers
538 photos
20 videos
159 links
Говорим просто о сложном

Обсуждение, новости, материал и сплетни — все здесь https://t.me/CodeLabMLChat
Download Telegram
👨‍💻 Всем ку! Заждались? Сегодня разбираем интересное задание, в последующем разберем несколько решений.

⬇️ ВЕСЬ МАТЕРИАЛ В КОММЕНТАРИЯХ ⬇️

⚙️ Итак, надеюсь, задание вы прочитали, теперь приступаем:

0⃣ Что нам вообще нужно

‼️ Начнем с формулировки "восстановления/аппроксимации" функции. Это значит, что нам нужно заменить (ИЛИ ПРИБЛИЗИТЬ) нашу функцию🟰 f(x) = 0.1x² - sin(x) + 5 🟰 кубическим полиномом (это который 🟰a(x) = w₀ + w₁... 🟰таким образом, чтобы подобранные веса w делали среднеквадратическую ошибку MSE между a(x) — (тот самый полином) и f(x) МИНИМАЛЬНОЙ НА СЕТКЕ [-5, 5]

‼️ Если не поняли, могу сказать по-другому: нам нужно подобрать веса w в кубическом полиноме a(x) таким образом, чтобы MSE между a(x) и f(x) на отрезке [-5, 5] была МИНИМАЛЬНЫМ.

1⃣ В общем, подбираем коэффициенты w, но все по порядку:

🔵Нам нужны данные для обучения и сама функция: у нас по условию уже есть точки x на отрезке [-5. 5] и тру-значения y = f(x), функция также дана

import numpy as np

# исходная функция, которую нужно аппроксимировать моделью a(x)
def func(x):
return 0.1 * x**2 - np.sin(x) + 5


# здесь объявляйте необходимые функции


coord_x = np.arange(-5.0, 5.0, 0.1) # значения по оси абсцисс [-5; 5] с шагом 0.1
coord_y = func(coord_x) # значения функции по оси ординат

sz = len(coord_x) # количество значений функций (точек)
eta = np.array([0.1, 0.01, 0.001, 0.0001]) # шаг обучения для каждого параметра w0, w1, w2, w3
w = np.array([0., 0., 0., 0.]) # начальные значения параметров модели
N = 200 # число итераций градиентного алгоритма


👨‍💻 Все что вы видите сверху — это все, что у нас есть, теперь будем думать:

2⃣ Наша следующая функция — features, она будет строить матрицу признаков S с колонками [1, x, x², x³].

def features(x):
x = np.asarray(x)
return np.stack([np.ones_like(x), x, x**2, x**3], axis=1)


🔵Функция np.asarray() в библиотеке NumPy — используется для преобразования входных данных в объект ndarray.

🔵ndarray (N-dimensional array) — класс многомерных массивов в библиотеке NumPy

🔵Входные данные могут быть в виде списков, кортежей или других объектов, похожих на массивы. Если входные данные уже являются массивом NumPy, функция не создаёт копию

🔵В нашем коде делает из входа (список/массив) numpy-вектор формы (n,).
А нужно это, чтобы дальше работали векторные операции x**2, x**3


🔵np.ones_like(x) — делает массив единиц такой же формы и типа, как x. Это столбец для свободного члена w₀ — форма также (n, ) — т.е вектор из n единиц. В нашей функции признаков этот вектор из единиц идёт как первый столбец

Что такое формы (n,), (n,1), (n,4)

Я уже как-то разбирал данный момент, но вернуться стоит:


🟢 (n,) — одномерный вектор длины n — это просто линейный массив...

💤 СКОРО ПРОДОЛЖИМ
Please open Telegram to view this post
VIEW IN TELEGRAM
3321
🔤🔤🌹🌷 5️⃣

👨‍💻 В дополнении к формам массивов:

🟢(n,) — одномерный вектор длины n. Нет строк/столбцов, просто линейный массив, форма (3, ) буде выглядеть как то так:

x = np.array([10., 20., 30.])
x.shape # (3, )
------------
[10. 20. 30.]


🟢(n, 1) — двумерная матрица: n строк, 1 столбец, массив форму (3, 1) буде выглядеть вот так:

x_col = x.reshape(-1, 1)
x_col.shape # (3, 1)
------------
[[10.]
[20.]
[30.]]


🟢(n, 4) — матрица: n строк, 4 столбца

S = np.column_stack([np.ones_like(x), x, x**2, x**3])
S.shape
-------------
[[ 1. 10. 100. 1000.]
[ 1. 20. 400. 8000.]
[ 1. 30. 900. 27000.]]


⬇️ ПОЛЕЗНЫЕ ССЫЛОЧКИ ВНИЗУ ⬇️
Please open Telegram to view this post
VIEW IN TELEGRAM
2111
👨‍💻 Для функции f(x) = x² - 4x, стартовое значение возьмем x₀ = 3, шаг обучение (он же learning rate) η = 0.1

Какой будет x₁ после одного шага градиентного спуска?
Anonymous Quiz
0%
2.4
0%
3.4
80%
2.8
0%
3.2
0%
3.8
0%
3.6
20%
2.0
0%
1.8
Please open Telegram to view this post
VIEW IN TELEGRAM
111
Ответ выложу позже, пока думайте 💭
Please open Telegram to view this post
VIEW IN TELEGRAM
111
⬇️ НЕ ЗАБЫВАЕМ ПРО ЧАТ ГАЙС ⬇️

ЗАХОДИМ СЮДА
Please open Telegram to view this post
VIEW IN TELEGRAM
1
CodeLab
если что тут ответ 1,3, 4
👨‍💻 Следующая функция в нашем коде — predict()

def predict(w, x):
S = features(x)
return S @ w


Итак, че тут происходит? Функция вычисляет 🟰 a(x) = Sw 🟰. Откуда взялась эта запись? Это просто компактная запись кубического полинома 🟰 a(x) = w₀ + w₁.. 🟰. S — это по сути вектор признаков [1, x, x², x³] — он дан в условии.

    S = features(x)


🔵Выше мы вызываем функцию features(), которую разбирали в нескольких постах — ЗДЕСЬ МИНИ-НАВИГАЦИЯ/ В общем, features превращала каждый скаляр xᵢ в вектор признаков в вектор признаков [1, x, x², x³] — воот, и все эти векторы складываются в матрицу признаков S.

    return S @ w


⚙️ Строка выше — тут матричное умножение. Берем вектор весов w и умножаем его на матрицу S, на выходе predict() реализует формулу:

🟰 a(x) = w₀ + w₁x + w₂x² + w₃x³ = Sw 🟰

👨‍💻 Теперь код выглядит так:

import numpy as np

def func(x): # Функция
return 0.1 * x ** 2 - np.sin(x) + 5

def features(x): # Матрица признков
x = np.asarray(x)
return np.stack([np.ones_like(x), x, x ** 2, x ** 3], axis = 1)

def predict(w, x): # a(x) = Sw
S = features(x)
return S @ w
Please open Telegram to view this post
VIEW IN TELEGRAM
3111
👀
Please open Telegram to view this post
VIEW IN TELEGRAM
- так и че ты дум чат жпт нас всех убьет не
- аэээм бляяя юр тут как бы две стороны есть
- а программисты с ними че будет м
- нууу смотря какие тип там крутые или не оч там с опытом без
- а вот другие профессии чат жпт с ними что сделает а
- да тут яхззз на самом деле оно как то всегда само там разруливается
- оке я пон тя. в чем сила
- в любви
2
Друзья, сегодня пост, начинайте ждать ⌛️
Please open Telegram to view this post
VIEW IN TELEGRAM
4221
🔤🔤🌹🌷 6️⃣

👨‍💻 Итак, следующая функция — risk() — по сути это просто MSE (среднеквадратичная) между предсказаниями и тру-значениями

def risk(w, x, y):
y_hat = predict(w, x) # считаем предсказания: S @ w
n = len(x) # количество точек (должно равняться len(y))
return (1.0 / n) * np.sum((y_hat - y) ** 2) # MSE


⚙️ Теперь разбираем построчно:

y_hat = predict(w, x)


🔵Так ну строка выше это вектор предсказаний, мы вызываем функцию predict, которую разбирали — ТУТ.

Что делает predict(w, x) внутри risk? Функция predict() строит матрицу признаков S = features(x) и умножает ее на w.

‼️ Возьмем например 'свои' w и x, пусть x = [0, 1, 2], w = [1, 2, 0, 0], истинные значения возьмем из функции func(x) = 0.1*x**2 - sin(x) + 5

🔵Признаки:

x           = [0, 1, 2]
ones_like = [1, 1, 1]
x**2 = [0, 1, 4]
x**3 = [0, 1, 8]


🔵Матрица признаков S:

S = stack(ones, x, x**2, x**3, axis=1) =
[[1, 0, 0, 0],
[1, 1, 1, 1],
[1, 2, 4, 8]] # shape (3, 4) - форма массива


🔵Наши веса:

w = [1, 2, 0, 0]        # shape (4,)


🟢Теперь y_hat = S @ w (скалярно по строкам):

🔵для x=0: [1,0,0,0]·[1,2,0,0] = 1

🔵для x=1: [1,1,1,1]·[1,2,0,0] = 1 + 2 = 3

🔵для x=2: [1,2,4,8]·[1,2,0,0] = 1 + 4 = 5

Предсказания равны:

y_hat = [1, 3, 5]       # shape (3,)


🔵 Теперь считаем функцию поэлементно:

func(0) = 0.1*0 - sin(0) + 5 = 5.00000

func(1) = 0.1*1 - sin(1) + 5 ≈ 0.1 - 0.84147 + 5 = 4.25853

func(2) = 0.1*4 - sin(2) + 5 ≈ 0.4 - 0.90930 + 5 = 4.49070


🔵Ниже наши истинные y = func(x)

y ≈ [5.00000, 4.25853, 4.49070]


🔵 Что делает risk(w, x, y)?

Ошибка e = y_hat - y ≈ [1-5, 3-4.25853, 5-4.49070] ≈ [-4.00000, -1.25853, 0.50930]

Квадраты: e**2 ≈ [16.00000, 1.5839, 0.2594]

Сумма: ≈ 16 + 1.5839 + 0.2594 = 17.8433

Среднее (делим на n=3): Q ≈ 17.8433 / 3 ≈ 5.9478


‼️ То есть risk вернул MSE ≈ 5.95 для выбранных w, но позже я еще разъясню, всем сладких 💤
Please open Telegram to view this post
VIEW IN TELEGRAM
411
2
Скоро пост, друзья 👀
Please open Telegram to view this post
VIEW IN TELEGRAM
522
Друзья, занимался делами, теперь допишем пост для кода:

🧑‍💻 На данный момент наш код выглядит как-то так:

import numpy as np

def func(x):
return 0.1 * x ** 2 - np.sin(x) + 5

def features(x):
x = np.asarray(x)
return np.stack([np.ones_like(x), x, x ** 2, x ** 3], axis = 1)

def predict(w, x):
S = features(x)
return S @ w

def risk(w, x, y):
y_hat = predict(w, x)
n = len(x)
return (1.0 / n) * np.sum((y_hat - y) ** 2)


🟢 Давайте еще раз быстро пробежимся и закончим:

🔵 Функция? — Есть, за нее отвечает функция func()

🔵 Признаки мы тоже предусмотрели, за нее отвечает функция features(), входные признаки мы преобразовываем в numpy массив, и возвращаем матрицу признаков S (в матрице у нас столбец единиц — для bias, x, x², x³ ), короче говоря, features превращала каждый скаляр xᵢ в вектор признаков в вектор признаков.

🔵 Теперь нужна функция для прогноза — predict(). Функция вычисляет 🟰 a(x) = Sw 🟰— по сути, умножение нашей матрицы S (переменной мы присваиваем значение матрицу) на вектор признаков w.

🔵Теперь функция risk() — возвращает по-сути MSE — среднеквадратическая между предсказаниями и истинными значениями. Здесь подаем в функцию аж 3 аргумента — w (параметры модели, и это единственное, что мы меняем, risk() будет зависеть от w x (входные данные по которым мы считаем признаки) и делаем предсказания y_hat — это вектор предсказаний (результат матричного умножения S @ w) y — это истинные значения. Логика примерно такая: минимизируем функцию потерь по w, а x, y — это данные.
Please open Telegram to view this post
VIEW IN TELEGRAM
321
👨‍💻Друзья, всем привет! Пишите, как ваши дела, а мы займемся функциями, весь grad_risk() сам себя не разберет ➡️

🔤🔤🔤🔤🪷 🔤🔤🔤🌹🌷 8️⃣🔤

def grad_risk(w, x, y):
S = features(x)
err = S @ w - y
n = len(x)
return (2.0 / n) * (S.T @ err)


🟢Итак, возьмем для примера

🔵x = [0, 1, 2], # Это если что все упрощенный пример
🔵w = [1, 2, 0, 0],
🔵y = func(x)
🔵y_hat = [1, 3, 5]; Как получили? 🟰S = features(x)🟰; 🟰y_hat = S @ w🟰

⚙️ Итак, S — матрица признаков формы (n, 4), errнаша ошибка между предсказаниями и тру-значениями, где S @ w (предсказания) — это и есть y_hat , в конце возвращаем формулу градиента.

🔵 Самая нижняя строка это градиент по MSE: 🟰 return (2.0 / n) * (S.T @ err) 🟰

1⃣0⃣👨‍💻 Итак, финалочка, теперь нам нужны сами данные:

🔵coord_x — вектор входов x от -5.0 до 5.0 с шагом 0.1 (здесь получим 100 точек), альтернативная строка — 🟰 np.linspace(-5, 5, 100, endpoint=False) 🟰

🔵coord_y — это тру-значения, считаем с помощью функции 🟰 y = 0.1*x^2 - sin(x) + 5 🟰
coord_x = np.arange(-5.0, 5.0, 0.1)
coord_y = func(coord_x)
sz = len(coord_x) # это просто 100


1⃣1⃣ Шаги обучения, стартовые веса и количество итераций:

eta = np.array([0.1, 0.01, 0.001, 0.0001])
w = np.array([0., 0., 0., 0.])
N = 200


🔵eta — шаги обучения для w0, w1, w2, w3 ‼️ (чем выше степень признака, тем больше масштаб градиента, поэтому шаг надо уменьшать на порядок), если непонятно, то вот попроще: eta — это разные шаги для каждого из параметров, например w3 обновляется на 0.0001 за один шаг (т.е очень медленно), но и менять его нужно очень медленно, потому что x³ очень быстро (при x =5, x³ = 125)

🔵w — это стартовые веса (bias и коэффициенты x, x², x³)

🔵N — это количество итераций нашего градиентного спуска

📊 В конце у нас цикл обучения (grad_risk(w, x, y) возвращает вектор градиента по w):

for _ in range(N):
g = grad_risk(w, coord_x, coord_y)
w = w - eta * g


🔵Q — среднеквадратичная ошибка на всех 100 точках.

Q = risk(w, coord_x, coord_y)
w = list(w)


Такие вот дела
Please open Telegram to view this post
VIEW IN TELEGRAM
322
👨‍💻Когда мы работаем с данными в ML (сюда можно включить и построение модели, и визуализацию, и предварительную обработку), нужно понимать, с какими типами признаков мы работаем , ниже — основные из них:

0⃣ Численные (количественные) признаки:

🔵Здесь два вида — вещественные (могут принимать любое значение в диапазоне) и целочисленные (принимают только целые значения). Численные признаки мы используем постоянно в задачах регрессии. Если приводить пример с визуализацией, гистограмма как раз про численные признаки, столбчатая диаграмма — для категориальных


1⃣ Категориальные (номинальные) признакиэто признаки, описывающие категории или класс, между такими значениями нет естественного порядка, они не выражаются числами, а представляют собой лишь метки.

🔵При работе с такими данными, используют one-hot encoding (метод преобразования категориальных данных (городов, цветов, профессий) в числовой формат, понятный алгоритмам машинного обучения) — превращают в набор бинарных признаков


2⃣ Бинарные (двоичные) признаки — не так давно мы решили задачки на бинарную классификацию (советую ознакомиться). Вообще, это частный случай категориальных признаков — принимают только два значения:

Пол: «мужской» / «женский»
Наличие подписки: «да» / «нет»
Результат теста: «успех» / «провал»
Включение функции: 1 / 0


🔵 Бинарные признаки можно обрабатывать как численные (например, усреднять — тогда получим долю "1"), так и как категориальные. Часто их оставляют как есть (0 и 1), особенно в моделях машинного обучения.


3⃣ Ординальные (порядковые) признаки это специальный подвид категориальных признаков, где значения имеют естественный порядок, но разница между ними не обязательно одинакова, например:

Курс студента: 1, 2, 3, 4, 5

🔵Это тот случай, когда порядок важен. При обработке ординальные признаки иногда кодируют числами (например, 1–5), но важно не интерпретировать их как обычные числа — нельзя считать, что «5 в 5 раз больше, чем 1».
Please open Telegram to view this post
VIEW IN TELEGRAM
611
Сегодня пост 👀
Please open Telegram to view this post
VIEW IN TELEGRAM
3221