#python #numpy #logistic-regression
#python #numpy #логистическая регрессия
Вопрос:
В настоящее время я работаю над созданием многоклассового классификатора с использованием numpy и, наконец, получил рабочую модель с использованием softmax следующим образом:
class MultinomialLogReg:
def fit(self, X, y, lr=0.00001, epochs=1000):
self.X = self.norm_x(np.insert(X, 0, 1, axis=1))
self.y = y
self.classes = np.unique(y)
self.theta = np.zeros((len(self.classes), self.X.shape[1]))
self.o_h_y = self.one_hot(y)
for e in range(epochs):
preds = self.probs(self.X)
l, grad = self.get_loss(self.theta, self.X, self.o_h_y, preds)
if e%10000 == 0:
print("epoch: ", e, "loss: ", l)
self.theta -= (lr*grad)
return self
def norm_x(self, X):
for i in range(X.shape[0]):
mn = np.amin(X[i])
mx = np.amax(X[i])
X[i] = (X[i] - mn)/(mx-mn)
return X
def one_hot(self, y):
Y = np.zeros((y.shape[0], len(self.classes)))
for i in range(Y.shape[0]):
to_put = [0]*len(self.classes)
to_put[y[i]] = 1
Y[i] = to_put
return Y
def probs(self, X):
return self.softmax(np.dot(X, self.theta.T))
def get_loss(self, w,x,y,preds):
m = x.shape[0]
loss = (-1 / m) * np.sum(y * np.log(preds) (1-y) * np.log(1-preds))
grad = (1 / m) * (np.dot((preds - y).T, x)) #And compute the gradient for that loss
return loss,grad
def softmax(self, z):
return np.exp(z) / np.sum(np.exp(z), axis=1).reshape(-1,1)
def predict(self, X):
X = np.insert(X, 0, 1, axis=1)
return np.argmax(self.probs(X), axis=1)
#return np.vectorize(lambda i: self.classes[i])(np.argmax(self.probs(X), axis=1))
def score(self, X, y):
return np.mean(self.predict(X) == y)
И у меня было несколько вопросов:
- Является ли это правильной реализацией многочленной логистической регрессии?
- Требуется 100 000 эпох с использованием скорости обучения 0,1, чтобы потери составили 1-0, 5 и получили точность 70-90% в тестовом наборе. Будет ли это считаться плохой производительностью?
- Каковы некоторые способы повышения производительности или ускорения обучения (чтобы требовалось меньше эпох)?
- Я видел эту функцию затрат онлайн, которая дает лучшую точность, она выглядит как кросс-энтропия, но она отличается от уравнений кросс-энтропийной оптимизации, которые я видел, может кто-нибудь объяснить, чем они отличаются:
error = preds - self.o_h_y
grad = np.dot(error.T, self.X)
self.theta -= (lr*grad)
Ответ №1:
- Это выглядит правильно, но я думаю, что предварительная обработка, которую вы выполняете в функции подгонки, должна выполняться вне модели.
- Трудно понять, хорошо это или плохо. Хотя ландшафт потерь выпуклый, время, необходимое для получения минимумов, варьируется для разных задач. Один из способов убедиться, что вы получили оптимальное решение, — это добавить пороговое значение, которое проверяет размер нормы градиента, которая мала, когда вы близки к оптимуму. Что — то вроде
np.linalg.norm(grad) < 1e-8
. - Вы можете использовать лучший оптимизатор, такой как метод Ньютона, или квази-ньютоновский метод, такой как LBFGS. Я бы начал с метода Ньютона, поскольку его проще реализовать. LBFGS — это нетривиальный алгоритм, который аппроксимирует гессиан, необходимый для выполнения метода Ньютона.
- Это то же самое; градиенты не усредняются. Поскольку вы выполняете градиентный спуск, усреднение является константой, которую можно игнорировать, поскольку в любом случае требуется правильно настроенная скорость обучения. В целом, я думаю, что усреднение немного упрощает получение стабильной скорости обучения по разным разделениям одного и того же набора данных.
Вопрос к вам: когда вы оцениваете свой набор тестов, вы предварительно обрабатываете их так же, как вы выполняете обучающий набор в своей функции fit?
Комментарии:
1. Спасибо за ваш ответ. Я выполняю предварительную обработку всех данных одинаково, потому что все данные взяты из одного файла. Я читаю file> random shuffle> выполняю стратифицированное разделение, чтобы получить поезд и тестовые наборы. Перед тестированием моей модели я использую mlr.norm_x в тестовом наборе. Я хотел спросить, будет ли лучшим подходом использование подхода «один против всех»?
2. При использовании подхода «один против всех» в вашем пространстве решений могут быть области, которые классифицируются неоднозначно (Бишоп 4.1.2). С другой стороны, подход «один против всех» обладает лучшими свойствами распараллеливания. Например, scikit-learn может вычислить функцию принятия решения «один против всех», используя k потоков для задачи логистической регрессии k-класса.
3. Хорошо, поэтому я просто продолжу использовать регрессию softmax. Знаете ли вы, как закодировать векторизованную реализацию, чтобы найти гессиан? Все реализации, которые я видел в Интернете, проходят через это с помощью циклов
4. Я не могу придумать решение с головы до ног, но я думаю, вы могли бы справиться с этим с
einsum
помощью (см. numpy.org/doc/stable/reference/generated/numpy.einsum.html ).