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

Обсуждение, новости, материал и сплетни — все здесь https://t.me/CodeLabMLChat
Download Telegram
Только попробуйте ответить неправильно
3221
🟢 Что может означать подобное выражение?

🟰w = (X.T @ y) @ np.linalg.inv(X.T @ X)🟰

‼️ Прежде всего — это формула вычисления весов (характерна для задач регрессии или классификации по прямой)


🟰w = (X.T @ y) @ np.linalg.inv(X.T @ X)🟰

🔵X — матрица признаков, например, [1, x1, x2] )

🔵y — вектор целевых значений

🔵X.T — транспонированная матрица X

🟢Допустим, мы имеем такой вот X:

X =
[[1, 5.8, 1.2],
[1, 5.6, 1.5],
[1, 6.5, 1.5]]


🔵X.shape = (3, 3) ➡️ 3 точки, каждая имеет 3 признака (включая 1 для смещения w0)

🟢Теперь y:

y = [-1, -1, 1]


🔵y.shape == (3,) ➡️ просто вектор из 3 чисел

🟢Транспонируем X.T:

X.T =
[[1.0, 1.0, 1.0], # w0
[5.8, 5.6, 6.5], # x1
[1.2, 1.5, 1.5]] # x2


🔵X.T.shape = (3, 3) ➡️ транспонировали (строки стали столбцами)

🟢Теперь матрица XTX = X.T @ X:

🔵XTX = (3, 3) @ (3, 3)

🔵XTX.shape = (3, 3)

🟢 inv_XTX = np.linalg.inv(X.T @ X)обратная матрица размерность не меняет, поэтому inv_XTX.shape == (3, 3)

🟢Матрица XTy = X.T @ y

🔵XTy = X.T @ y

🔵X.T = (3, 3)
🔵y = (3,)

🔵XTy.shape == (3,) → вектор из 3 чисел

🟢Результат получается таким:

🔵w = inv_XTX @ XTy

‼️🔵 (3, 3) @ (3,) = (3,)

👨‍💻 Вот вам некоторые необходимы понятия:

2⃣ Существуют объекты и признаки: размерность наших данных, к примеру. равна (3,2) — то есть, 3 разных объекта (их мы и классифицируем) и 2 признака на каждый объект

3⃣ Затем, мы добавляем bias и получаем размерность (3, 3), что вполне логично.

X = [(1,  5.6, 1.5),
(1, 6.5, 1.5),
(1, 6.1, 1.3)
]

X.shape == (3, 3)


4⃣ X.T — транспонируем, матрица квадратная, ничего кароч не меняется.

X.T.shape = (3, 3)


5⃣ X.T @ y — перемножаем на метки нашу транспонированную матрицу — получаем размерность (3,) — по сути просто каждый элемент в X.T (bias + признаки) перемножаем на вектор и ‼️ суммируем.

Вот такие вот дела
Please open Telegram to view this post
VIEW IN TELEGRAM
2111
👀
Please open Telegram to view this post
VIEW IN TELEGRAM
📱 Если у модели высокое смещение (bias) и низкая дисперсия — это значит, что:

📊 P.S| Дисперсия это насколько сильно разбросаны значения/предсказания вокруг среднего — это изменчивость предсказаний модели при изменении данных.
Anonymous Quiz
45%
A) Модель точно предсказывает тренировочные данные, но плохо на тесте
9%
B) Модель хорошо предсказывает тест, но переобучена
27%
C) Модель слишком проста и недообучена
18%
D) Модель идеально сбалансирована
2111
👀Самое интересное — это аниме тянка и 18+ режимы для голосового общения. Прикрепил мысли o3, мб интересно будет 🤷. Как по мне, Маск сделал очень...

ДОЧИТЫВАЕМ В НАШЕМ ЧАТИКЕ
Please open Telegram to view this post
VIEW IN TELEGRAM
511
Новый пост после 140 подписичников будет
1111
👏
Please open Telegram to view this post
VIEW IN TELEGRAM
1111
2111
👨‍💻 Друзья, пост про библиотеки для ML уже в нашем чате ⬇️

СМОТРИМ ЗДЕСЬ
Please open Telegram to view this post
VIEW IN TELEGRAM
2111
This media is not supported in your browser
VIEW IN TELEGRAM
Снова роботы бесоёбят
2211
👀 Всем ку, подписичники прибавились, а значит пора выложить пост. Я вдруг понял, что задачки с бинарной классификацией закончились, но поводов расстраиваться нет, ведь мы переходим к градиентному спуску.

Здесь
, здесь, здесь и здесь мы уже рассмотрели эту тему (и весьма неплохо), но теперь будем углубляться и решать задачки.

🔤🌹🔤🔤🔤🔤🔤🌷 🔤🔤🔤🔤🔤🔤🌷

🔵Я все же настаиваю на том, чтобы вы изучили материал, что я дал выше ⬆️ —там объяснение формул и сама база. Сейчас держите краткое резюме для тех, кто забыл:

‼️ Градиентный спуск — это алгоритм оптимизации, который итеративно изменяет внутренние параметры модели (веса, смещение).

Для чего ему их изменять? — Для минимизации функции потерь.

Что такое функция потерь? — По сути это оценка модели (разница между предсказаниями модели и реальными целевыми значениями).

‼️ Итак, получается, что Градиентный спуск это алгоритм, который меняет параметры чтобы уменьшить разницу между предсказаниями и истинными значениями.


👨‍💻Базу вспомнили, теперь про сам алгоритм:

Как работает?

1⃣ Берем начальное значение параметра

2⃣ Считаем градиент (первая производная функции)

3⃣ Делаем шаг в сторону противоположную градиенту, чтобы уменьшить значение функции f(x)

4⃣ Повторяем, пока не дойдём до минимума

⚙️ Итак, разберем простой пример:

🟰 x = x - η * f'(x) 🟰— вот формула градиентного спуска, теперь, представим, что у нас есть такая простенькая функция:

🟰 f(x) = x² 🟰

🟰 f'(x) = 2x 🟰 — теперь берем производную

‼️ Итак, допустим, x = 4, тогда f'(x) = 8 (умножили на 2) ➡️ значит, функция возрастает, надо идти влево по графику (пример в комментах)

Вот тут нам и нужна формула:

🟰 f'(4) = 2 * 4 = 8 🟰 ➡️4 - 0.1 * 8 = 4 - 0.8 = 3.2 — это новый x (старый был 4). Тоже самое можно проделывать до того момента, пока не найдем минимум функции

‼️ А если x = -3? Тогда f'(x) = -6 ➡️ функция возрастает влево, и чтобы её уменьшить, надо идти вправо

Это правило работает везде — в отрицательной и положительной области

🟢Градиент подсказывает, в какую сторону растёт функция

🟢Мы идём в противоположную сторону, чтобы уменьшить значение функции


👨‍💻Скоро продолжим
Please open Telegram to view this post
VIEW IN TELEGRAM
3211
👨‍💻Всем сап! В прошлом посте разбирали градиентный спуск, теперь самое интересное ➡️ КОД (пост оказался сложнее, чем я думал, приходится сидеть и думать 🤔🤔)

🔵Функцию берем вот эту 🟰 f(x) = x² - 5x + 5 🟰

🔵Теперь производная 🟰 f'(x) = 2x - 5 🟰


0⃣ Библиотеки:

import time
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np


1⃣ Функции, которые я прописал выше (просто переписываем):

def f(x): # Функция f(x)
return x * x - 5 * x + 5

def df(x): # Проивзодная функции f(x)
return 2 * x - 5


2⃣ Теперь вводим некоторые переменные:


🔵(Число итераций (N); — проще говоря, сколько шагов градиентного спуска мы делаем

🔵Начальное значение (xx); — стартовая точка, c нее мы начнем ползти по антиградиенту (это вниз если что, градиент указывает направление наискорейшего роста функции, антиградиент — направление наискорейшего убывания)

🔵Шаг сходимости (lmd) — проще говоря, это learning rate (длина шага).

🟰 xₖ₊₁ = xₖ - λf'(xₖ) 🟰 — вот по такой формуле делает шаг градиентный спуск. Если мы подставим 🟰 f'(x) = 2x - 5 🟰то получим 2.5

‼️ Кстати, эту формулу также записывают как 🟰 xₖ₊₁ = xₖ - λ∇ f'xₖ) 🟰Разница лишь в том, что в первом случае f'(x) — это обычная производная по одной переменной, а в другом — f(x) — вектор частных производных (как итог, формула одна и та же)

N = 20 
xx = 0
lmd = 0.1


👨‍💻 Итак, мы хотим найти x, где функция потерь f(x) минимальная, формулу шага градиентного спуска мы уже разобрали, хотя, можно еще один момент разобрать:

∇f(x) — стрелка вверх (т.е куда быстрее всего растет f) — это направление наискорейшего роста

-∇f(x)направление наискорейшего убывания (в комментах материал)

Можем кстати подставить в нашу формулу пример 🟰 xₖ₊₁ = xₖ - λf'(xₖ) 🟰 ➡️ получаем 🟰 xₖ₊₁ = xₖ - λ * (2x - 5)) 🟰 ➡️ 🟰(1 - 2λ) * xₖ + 5λ🟰 — это правило обновления итераций (наша функция)

‼️САМА СУТЬ — НАЙТИ ТОЧКУ, ГДЕ ДВИЖЕНИЕ ПРЕКРАЩАЕТСЯ (итерации прекращаются) — еще проще, найти глобальный минимум.


🔵А так, я нашел, что глобальный минимум можно найти кучей способов, самый простой — вершина параболы: напомню, у нас функция 🟰 f(x) = x² - 5x + 5 🟰

🔵 x (вершина параболы) = -b / 2a = 2.5 (просто подставляем наши значения, вот вам и глобальный минимум)

Совсем скоро продолжим 💤
Please open Telegram to view this post
VIEW IN TELEGRAM
2111
👨‍💻 Итак, продолжаем:

⚙️Наш код на данный момент выглядит так:

import numpy as np
import matplotlib.pyplot as plt

def f(x): # f(x) = x^2 - 5x + 5 # парабола
return x*x - 5*x + 5

def df(x): # f'(x) = 2x - 5 # наклон графика в точке x
return 2*x - 5

N = 20 # число итераций
x = 0.0 # стартовая точка x0
lr = 0.1 # шаг обучения (λ)


🔵N — это количество обновлений

🔵lr — это длина шага

Возможно, вы заметили, что я убрал библиотеку time, ее я заменил привычной нам matplotlib, суть не поменялась (все это не влияет на наш алгоритм, исключительно для плавной анимации спуска)

3⃣ Создаем массив точек из 400 точек, по этим точкам и будем рисовать кривую f(x)

xs = np.linspace(-1, 5, 400)


4⃣ Включаем интерактивный режим Matplotlib (для анимации в цикле). ‼️ Важно, анимация у меня в колабе не отобразилась, мб это особенность блокнотов, в VS все нормально.

🔵Что касаемо остальных строк, fig, ax = plt.subplots() — будет создавать окошко Figure и систему координат Axes (сетка, подписи и две оси — x, y)

🔵ax.grid(True) — включает сетку на осях

🔵ax.plot(xs, f(xs), label="f(x)") — рисует линию функции f(x) по сетке xs. ‼️ В общем, мы создавали массив из 400 точек, так вот когда мы вызываем f(xs), Numpy поэлементно будет считать y = f(x) для каждого из этих 400 точек

🔵pt = ax.scatter([x], [f(x)], c='red', s=50) рисует красную точку в текущем положении (x, f(x)) для визуализации текущего x на каждом шаге спуска.

🔵ax.set_xlim(xs.min(), xs.max()) фиксирует границы оси X от минимума до максимума нашей сетки (таким образом, будем отображаться ровно тот интервал, где мы нарисовали кривую + масштаб во время анимации не будет прыгать)

🔵ax.set_ylim(f(xs).min()-1, f(xs).max()+1) фиксирует границы оси Y по значениям функции. Почему берём min/max именно от xs и f(xs) Потому что это левые/правые границы, где мы считали и рисовали функцию.

🔵plt.show(block=False) — показывает окно не блокируя выполнение кода.

plt.ion()
fig, ax = plt.subplots()
ax.grid(True)
ax.plot(xs, f(xs), label="f(x)")
pt = ax.scatter([x], [f(x)], c='red', s=50)
ax.set_xlim(xs.min(), xs.max())
ax.set_ylim(f(xs).min()-1, f(xs).max()+1)
plt.show(block=False)


5⃣ Самое важное: градиентный спуск и анимация

🔵Это и есть обновление по формуле 🟰 xₖ₊₁ = xₖ - λ * (2x - 5)) 🟰Если lr = 0.5 ➡️ сразу попадаем в глобальный минимум

🔵pt — это объект, который вернул 🟰 pt = ax.scatter([x], [f(x)], c='red', s=50) 🟰

for _ in range(N):
x = x - lr * df(x) # шаг: x_{k+1} = x_k - λ f'(x_k)
pt.set_offsets([[x, f(x)]]) # кладет новые (x, y) в объект точки (грубо говоря, это обновление уже нарисованной точки, будет переносить маркер в новые корды)
fig.canvas.draw_idle() # Рисует содержимое окна ; перерисовывает
plt.pause(0.03) # фигура перерисовывается + пазуа


6⃣ Фиксируем результаты:

plt.ioff()   # выключить интерактив
ax.scatter([x], [f(x)], c='blue', s=50, label="финал") # финальная точка (это куда мы пришли, глобальный минимум)
ax.axvline(2.5, ls='--', label="x* = 2.5") # вертикальная линия минимума
ax.legend()
print(x)
plt.show()


‼️ Теперь пройдемся по логике кода (САМОЕ САМОЕ ВАЖНОЕ): мы взяли 400 точек по оси x ➡️подставляем каждую точку в функцию f(x) ➡️ ax.plot соединяет точки линией (xs — это x корды, f(xs) — это y корды) ➡️ далее, у нас есть текущая точка x, считаем производную f'(x) и делаем шаг вниз (это антиградиент) ➡️ f'(x) задает направление и масштаб, λ — длина шага
Please open Telegram to view this post
VIEW IN TELEGRAM
3221
Сегодня пост
5331
👨‍💻 Всем ку! Заждались? Сегодня разбираем интересное задание, в последующем разберем несколько решений.

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

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

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