介绍
最近几年人工智能异常火热,随之而来的就是各种针对入门者的学习资源,其中不乏很多经典的教程,例如吴恩达的《机器学习》、《深度学习工程师》,但是也有很多千篇一律、照本宣科的学习资源。在学习进阶过程中很多人会到GitHub寻找一些可以动手实践的机器学习项目,会发现GitHub上会有和机器学习相关的各种awesome,恨不得把所有和机器学习、深度学习的资源都囊括进去。这样虽然全面,但是我认为它的价值并不高。我们之所以希望有经验者推荐学习资源,就是因为时间、精力有限,希望能够在鱼龙混杂的学习资源里筛选出真正有价值,或者与众不同的,能够让我们利用有限的精力和时间内真正学会一些东西。近期GitHub有一个关于机器学习的热门开源项目,homemade-machine-learning,目前已经11k+个star,近一周增加1.1k+,经过一段时间的学习发现这的确一个不错的学习项目,下面就详细介绍一下这个项目。
Homemade Machine Learning
开门见山,这个开源项目主要有以下几个优点:
- 少而精
- 不依赖python第三方库
- 详细解释它们背后的数学原理
- 交互式Jupyter notebook演示程序
- 丰富易懂的示例
这个项目用Python实现了目前热门、使用的一些机器学习算法,而不是像很多开源项目那样,从头至尾把每个机器学习算法都实现一遍。换句话说,这个开源项目追求“少而精”,它分别从监督学习、非监督学习、神经网络、异常检测、回归、分类这些类别中选择一种算法进行详细阐述算法背后的数学原理,然后使用jupyter notebook交互式的演示,随后会用多个示例进行实现,动手操作,不依赖集成的python第三方库,更容易理解机器学习算法的原理。
项目概括
该项目主要包括如下几个方面的机器学习算法:
- 监督学习
- 无监督学习
- 异常检测
- 神经网络
其中监督学习又分为回归和分类,回归算法选取的是比较常用的线性回归,分类算法选取的是比较实用的逻辑回归。无监督学习中主要针对聚类进行讲解,项目中选取的是热门的k-means。异常检测是指通过大多数数据来检测出有显著差异的事件、观测结果,在数据处理、图像处理都有应用。神经网络中选择的是多层感知机。
安装
首先要保证电脑上正确的安装了Python,然后安装一些项目依赖,
$ pip install -r requirements.txt
requirements:
jupyter==1.0.0 matplotlib==3.0.1 numpy==1.15.3 pandas==0.23.4 plotly==3.4.1 pylint==2.1.1 scipy==1.1.0
如果要使用jupyter notebook,需要在命令行输入下面命令,
jupyter notebook
然后会在浏览器中打开如下窗口,
详细介绍
数学原理
我认为这是这个项目吸引人的地方,也是它与众不同的地方,它和很多项目不同,浮于表面,把很多环节都认为是既定的去阐述,有一些初学者会看的云里雾里,不明白“为什么是这样?”这个项目则不同,它详细、深入的阐述每个算法背后的数学原理,循序渐进,配合可视化很容易让人理解。
详细编码过程
该项目不过多依赖tensorflow、pytorch、keras这些高度集成的机器学习平台,它从梯度下降到损失函数、从训练到预测都是一步一步实现,尽量减少对高度集成第三方库的依赖。
@staticmethod def gradient_descent(data, labels, initial_theta, lambda_param, max_iteration): """Gradient descent function. Iteratively optimizes theta model parameters. :param data: the set of training or test data. :param labels: training set outputs (0 or 1 that defines the class of an example). :param initial_theta: initial model parameters. :param lambda_param: regularization parameter. :param max_iteration: maximum number of gradient descent steps. """ # Initialize cost history list. cost_history = [] # Calculate the number of features. num_features = data.shape[1] # Launch gradient descent. minification_result = minimize( # Function that we're going to minimize. lambda current_theta: LogisticRegression.cost_function( data, labels, current_theta.reshape((num_features, 1)), lambda_param ), # Initial values of model parameter. initial_theta, # We will use conjugate gradient algorithm. method='CG', # Function that will help to calculate gradient direction on each step. jac=lambda current_theta: LogisticRegression.gradient_step( data, labels, current_theta.reshape((num_features, 1)), lambda_param ), # Record gradient descent progress for debugging. callback=lambda current_theta: cost_history.append(LogisticRegression.cost_function( data, labels, current_theta.reshape((num_features, 1)), lambda_param )), options={'maxiter': max_iteration} ) # Throw an error in case if gradient descent ended up with error. if not minification_result.success: raise ArithmeticError('Can not minimize cost function: ' + minification_result.message) # Reshape the final version of model parameters. optimized_theta = minification_result.x.reshape((num_features, 1)) return optimized_theta, cost_history @staticmethod def gradient_step(data, labels, theta, lambda_param): """GRADIENT STEP function. It performs one step of gradient descent for theta parameters. :param data: the set of training or test data. :param labels: training set outputs (0 or 1 that defines the class of an example). :param theta: model parameters. :param lambda_param: regularization parameter. """ # Initialize number of training examples. num_examples = labels.shape[0] # Calculate hypothesis predictions and difference with labels. predictions = LogisticRegression.hypothesis(data, theta) label_diff = predictions - labels # Calculate regularization parameter. regularization_param = (lambda_param / num_examples) * theta # Calculate gradient steps. gradients = (1 / num_examples) * (data.T @ label_diff) regularized_gradients = gradients + regularization_param # We should NOT regularize the parameter theta_zero. regularized_gradients[0] = (1 / num_examples) * (data[:, [0]].T @ label_diff) return regularized_gradients.T.flatten() @staticmethod def cost_function(data, labels, theta, lambda_param): """Cost function. It shows how accurate our model is based on current model parameters. :param data: the set of training or test data. :param labels: training set outputs (0 or 1 that defines the class of an example). :param theta: model parameters. :param lambda_param: regularization parameter. """ # Calculate the number of training examples and features. num_examples = data.shape[0] # Calculate hypothesis. predictions = LogisticRegression.hypothesis(data, theta) # Calculate regularization parameter # Remember that we should not regularize the parameter theta_zero. theta_cut = theta[1:, [0]] reg_param = (lambda_param / (2 * num_examples)) * (theta_cut.T @ theta_cut) # Calculate current predictions cost. y_is_set_cost = labels[labels == 1].T @ np.log(predictions[labels == 1]) y_is_not_set_cost = (1 - labels[labels == 0]).T @ np.log(1 - predictions[labels == 0]) cost = (-1 / num_examples) * (y_is_set_cost + y_is_not_set_cost) + reg_param # Let's extract cost value from the one and only cost numpy matrix cell. return cost[0][0]
丰富示例
理解了算法背后的数学原理,跟着作者一步一步实现了算法,要想更加深入的理解就需要把算法应用到不同方面,本项目提供了丰富的示例,其中不乏MNIST这类经典的演示样例。其中每个项目后面都包含至少一个示例,可以获取对应的数据进行实现,这样对算法的理解和应用会有更加清晰而深入的认识。
其中每个项目后面都包含至少一个示例,数据已经放在根目录下data路径里,可以获取对应的数据进行实现,这样对算法的理解和应用会有更加清晰而深入的认识。