吴恩达老师深度学习视频课笔记:逻辑回归公式推导及C++实现

2023-11-19

逻辑回归(Logistic Regression)是一个二分分类算法。逻辑回归的目标是最小化其预测与训练数据之间的误差。为了训练逻辑回归模型中的参数w和b,需要定义一个成本函数(cost function)。

        成本函数(cost function):它是针对整个训练集的。衡量参数w和b在整个训练集上的效果。

损失函数或误差函数(loss function or error function):它是针对单个训练样本进行定义的。可以用来衡量算法的效果,衡量预测输出值与实际值有多接近。

梯度下降法的核心是最小化成本函数。使用梯度下降法可以找到一个函数的局部极小值。

关于逻辑回归的介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/78283675 

关于梯度下降法的介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/75351323 

关于激活函数sigmoid函数的介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/73848734 

关于MNIST数据集的介绍可以参考:  http://blog.csdn.net/fengbingchun/article/details/49611549

以下截图来自吴恩达老师深度学习视频课:




以下code是完全按照上面的推导公式进行实现的,训练数据集为从MNIST中train中随机选取的0、1各10个图像;测试数据集为从MNIST中test中随机选取的0、1各10个图像,如下图,其中第一排前10个0用于训练,后10个0用于测试;第二排前10个1用于训练,后10个1用于测试:


logistic_regression2.hpp:

#ifndef FBC_SRC_NN_LOGISTIC_REGRESSION2_HPP_
#define FBC_SRC_NN_LOGISTIC_REGRESSION2_HPP_

#include <vector>
#include <string>

namespace ANN {

template<typename T>
class LogisticRegression2 { // two categories
public:
	LogisticRegression2() = default;
	int init(const T* data, const T* labels, int train_num, int feature_length, T learning_rate = 0.00001, int iterations = 10000);
	int train(const std::string& model);
	int load_model(const std::string& model);
	T predict(const T* data, int feature_length) const; // y = 1/(1+exp(-(wx+b)))

private:
	int store_model(const std::string& model) const;
	T calculate_sigmoid(T value) const; // y = 1/(1+exp(-value))
	T calculate_z(const std::vector<T>& feature) const;

	std::vector<std::vector<T>> x; // training set
	std::vector<T> y; // ground truth labels
	int iterations = 1000;
	int m = 0; // train samples num
	int feature_length = 0;
	T alpha = (T)0.00001; // learning rate
	std::vector<T> w; // weights
	T b = (T)0.; // threshold
}; // class LogisticRegression2

} // namespace ANN

#endif // FBC_SRC_NN_LOGISTIC_REGRESSION2_HPP_
logistic_regression2.cpp:

#include "logistic_regression2.hpp"
#include <fstream>
#include <algorithm>
#include <random>
#include <cmath>
#include "common.hpp"

namespace ANN {

template<typename T>
int LogisticRegression2<T>::init(const T* data, const T* labels, int train_num, int feature_length, T learning_rate, int iterations)
{
	if (train_num < 2) {
		fprintf(stderr, "logistic regression train samples num is too little: %d\n", train_num);
		return -1;
	}
	if (learning_rate <= 0) {
		fprintf(stderr, "learning rate must be greater 0: %f\n", learning_rate);
		return -1;
	}
	if (iterations <= 0) {
		fprintf(stderr, "number of iterations cannot be zero or a negative number: %d\n", iterations);
		return -1;
	}

	this->alpha = learning_rate;
	this->iterations = iterations;

	this->m = train_num;
	this->feature_length = feature_length;

	this->x.resize(train_num);
	this->y.resize(train_num);

	for (int i = 0; i < train_num; ++i) {
		const T* p = data + i * feature_length;
		this->x[i].resize(feature_length);

		for (int j = 0; j < feature_length; ++j) {
			this->x[i][j] = p[j];
		}

		this->y[i] = labels[i];
	}

	return 0;
}

template<typename T>
T LogisticRegression2<T>::calculate_z(const std::vector<T>& feature) const
{
	T z{ 0. };
	for (int i = 0; i < this->feature_length; ++i) {
		z += w[i] * feature[i];
	}
	z += b;

	return z;
}

template<typename T>
int LogisticRegression2<T>::train(const std::string& model)
{
	CHECK(x.size() == y.size());

	w.resize(this->feature_length, (T)0.);
	std::random_device rd;
	std::mt19937 generator(rd());
	std::uniform_real_distribution<T> distribution(-0.1, 0.1);
	for (int i = 0; i < this->feature_length; ++i) {
		w[i] = distribution(generator);
	}
	b = distribution(generator);

	for (int iter = 0; iter < this->iterations; ++iter) {
		T J = (T)0., db = (T)0.;
		std::vector<T> dw(this->feature_length, (T)0.);
		std::vector<T> z(this->m, (T)0), a(this->m, (T)0), dz(this->m, (T)0);

		for (int i = 0; i < this->m; ++i) {
			z[i] = calculate_z(x[i]); // z(i)=w^T*x(i)+b
			a[i] = calculate_sigmoid(z[i]); // a(i)= 1/(1+e^(-z(i)))
			J += -(y[i] * std::log(a[i]) + (1 - y[i] * std::log(1 - a[i]))); // J+=-[y(i)*loga(i)+(1-y(i))*log(1-a(i))]
			dz[i] = a[i] - y[i]; // dz(i) = a(i)-y(i)

			for (int j = 0; j < this->feature_length; ++j) {
				dw[j] += x[i][j] * dz[i]; // dw(i)+=x(i)(j)*dz(i)
			}
			db += dz[i]; // db+=dz(i)
		}

		J /= this->m;
		for (int j = 0; j < this->feature_length; ++j) {
			dw[j] /= m;
		}
		db /= m;

		for (int j = 0; j < this->feature_length; ++j) {
			w[j] -= this->alpha * dw[j];
		}
		b -= this->alpha*db;
	}

	CHECK(store_model(model) == 0);

	return 0;
}

template<typename T>
int LogisticRegression2<T>::load_model(const std::string& model)
{
	std::ifstream file;
	file.open(model.c_str(), std::ios::binary);
	if (!file.is_open()) {
		fprintf(stderr, "open file fail: %s\n", model.c_str());
		return -1;
	}

	int length{ 0 };
	file.read((char*)&length, sizeof(length));
	this->w.resize(length);
	this->feature_length = length;
	file.read((char*)this->w.data(), sizeof(T)*this->w.size());
	file.read((char*)&this->b, sizeof(T));

	file.close();

	return 0;
}

template<typename T>
T LogisticRegression2<T>::predict(const T* data, int feature_length) const
{
	CHECK(feature_length == this->feature_length);

	T value{ (T)0. };
	for (int t = 0; t < this->feature_length; ++t) {
		value += data[t] * this->w[t];
	}
	value += this->b;

	return (calculate_sigmoid(value));
}

template<typename T>
int LogisticRegression2<T>::store_model(const std::string& model) const
{
	std::ofstream file;
	file.open(model.c_str(), std::ios::binary);
	if (!file.is_open()) {
		fprintf(stderr, "open file fail: %s\n", model.c_str());
		return -1;
	}

	int length = w.size();
	file.write((char*)&length, sizeof(length));
	file.write((char*)w.data(), sizeof(T) * w.size());
	file.write((char*)&b, sizeof(T));

	file.close();

	return 0;
}

template<typename T>
T LogisticRegression2<T>::calculate_sigmoid(T value) const
{
	return ((T)1 / ((T)1 + exp(-value)));
}

template class LogisticRegression2<float>;
template class LogisticRegression2<double>;

} // namespace ANN
main.cpp:

#include "funset.hpp"
#include <iostream>
#include "perceptron.hpp"
#include "BP.hpp""
#include "CNN.hpp"
#include "linear_regression.hpp"
#include "naive_bayes_classifier.hpp"
#include "logistic_regression.hpp"
#include "common.hpp"
#include "knn.hpp"
#include "decision_tree.hpp"
#include "pca.hpp"
#include <opencv2/opencv.hpp>
#include "logistic_regression2.hpp"

// ================================ logistic regression =====================
int test_logistic_regression2_train()
{
	const std::string image_path{ "E:/GitCode/NN_Test/data/images/digit/handwriting_0_and_1/" };
	cv::Mat data, labels;

	for (int i = 1; i < 11; ++i) {
		const std::vector<std::string> label{ "0_", "1_" };

		for (const auto& value : label) {
			std::string name = std::to_string(i);
			name = image_path + value + name + ".jpg";

			cv::Mat image = cv::imread(name, 0);
			if (image.empty()) {
				fprintf(stderr, "read image fail: %s\n", name.c_str());
				return -1;
			}

			data.push_back(image.reshape(0, 1));
		}
	}
	data.convertTo(data, CV_32F);

	std::unique_ptr<float[]> tmp(new float[20]);
	for (int i = 0; i < 20; ++i) {
		if (i % 2 == 0) tmp[i] = 0.f;
		else tmp[i] = 1.f;
	}
	labels = cv::Mat(20, 1, CV_32FC1, tmp.get());

	ANN::LogisticRegression2<float> lr;
	const float learning_rate{ 0.0001f };
	const int iterations{ 10000 };
	int ret = lr.init((float*)data.data, (float*)labels.data, data.rows, data.cols);
	if (ret != 0) {
		fprintf(stderr, "logistic regression init fail: %d\n", ret);
		return -1;
	}

	const std::string model{ "E:/GitCode/NN_Test/data/logistic_regression2.model" };

	ret = lr.train(model);
	if (ret != 0) {
		fprintf(stderr, "logistic regression train fail: %d\n", ret);
		return -1;
	}

	return 0;
}

int test_logistic_regression2_predict()
{
	const std::string image_path{ "E:/GitCode/NN_Test/data/images/digit/handwriting_0_and_1/" };
	cv::Mat data, labels, result;

	for (int i = 11; i < 21; ++i) {
		const std::vector<std::string> label{ "0_", "1_" };

		for (const auto& value : label) {
			std::string name = std::to_string(i);
			name = image_path + value + name + ".jpg";

			cv::Mat image = cv::imread(name, 0);
			if (image.empty()) {
				fprintf(stderr, "read image fail: %s\n", name.c_str());
				return -1;
			}

			data.push_back(image.reshape(0, 1));
		}
	}
	data.convertTo(data, CV_32F);

	std::unique_ptr<int[]> tmp(new int[20]);
	for (int i = 0; i < 20; ++i) {
		if (i % 2 == 0) tmp[i] = 0;
		else tmp[i] = 1;
	}
	labels = cv::Mat(20, 1, CV_32SC1, tmp.get());

	CHECK(data.rows == labels.rows);

	const std::string model{ "E:/GitCode/NN_Test/data/logistic_regression2.model" };

	ANN::LogisticRegression2<float> lr;
	int ret = lr.load_model(model);
	if (ret != 0) {
		fprintf(stderr, "load logistic regression model fail: %d\n", ret);
		return -1;
	}

	for (int i = 0; i < data.rows; ++i) {
		float probability = lr.predict((float*)(data.row(i).data), data.cols);

		fprintf(stdout, "probability: %.6f, ", probability);
		if (probability > 0.5) fprintf(stdout, "predict result: 1, ");
		else fprintf(stdout, "predict result: 0, ");
		fprintf(stdout, "actual result: %d\n", ((int*)(labels.row(i).data))[0]);
	}

	return 0;
}
测试结果如下:由执行结果可知,测试图像全部分类正确。由于w和b初始值是随机产生的,因此每次执行的结果多少有些差异。

GitHub:  https://github.com/fengbingchun/NN_Test 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

吴恩达老师深度学习视频课笔记:逻辑回归公式推导及C++实现 的相关文章

  • 如何高速安装jetson-inference,一步到位,避免踩坑!

    踩了很长时间的坑 终于弄明白怎么高速下载jetson inference 来源 安装jetson inference 自动下载模型 满速下载起飞 解决下载模型被墙问题 奈流云何的博客 CSDN博客 需要将Github的仓库复制到Gitee上
  • 图像识别中,目标分割、目标识别、目标检测和目标跟踪这几个方面区别是什么?+资料列表

    目标识别 深度学习进行目标识别的资源列表 转 https zhuanlan zhihu com p 26076489 以下转自 https www zhihu com question 36500536 作者 知乎用户 链接 https w
  • 【生成式网络】入门篇(二):GAN的 代码和结果记录

    GAN非常经典 我就不介绍具体原理了 直接上代码 感兴趣的可以阅读 里面有更多变体 https github com rasbt deeplearning models tree master pytorch ipynb gan GAN 在
  • 深度学习知识体系学习大全 牛!!

    搬来了大牛的博客 点击直接前往 https www yuque com angsweet machine learning jian jie 配一张大牛的思维导图 具体内容点进去都能看到 数学 机器学习 语言 算法 深度学习 书籍推荐 东西
  • 深度学习网络篇——VGGNet(Part1 网络结构&训练环节)

    我们上篇文章了解了一下NIN 接下来我们来了解一下VGGNet 可以说是另一波的跪舔和膜拜 VGGNet主要是分为两篇文章 第一篇文章来分享一下VGGNet的网络结构还有训练环节 第二篇文章是分享VGGNet做的分类实验和总结 此为第一篇
  • 网络安全中机器学习大合集

    目录 数据集 论文 书籍 演讲 教程 课程 杂项 数据集 安全相关数据样本集 DARPA 入侵检测数据集 Stratosphere IPS 数据集 开放数据集 NSA 的数据捕获 ADFA 入侵检测数据集 NSL KDD 数据集 恶意 UR
  • 视觉注意力的循环神经网络模型

    我们观察PPT的时候 面对整个场景 不会一下子处理全部场景信息 而会有选择地分配注意力 每次关注不同的区域 然后将信息整合来得到整个的视觉印象 进而指导后面的眼球运动 将感兴趣的东西放在视野中心 每次只处理视野中的部分 忽略视野外区域 这样
  • 目标检测基础

    什么是目标检测 简单来说就是 检测图片中物体所在的位置 本文只介绍用深度学习的方法进行目标检测 同过举出几个特性来帮助各位理解目标检测任务 同时建议学习目标检测应先具备物体人工智能算法基础和物体分类现实基础 特性1 Bounding Box
  • 深度神经网络中的Inception模块介绍

    深度神经网络 Deep Neural Networks DNN 或深度卷积网络中的Inception模块是由Google的Christian Szegedy等人提出 包括Inception v1 Inception v2 Inception
  • Could not load dynamic library ‘libcupti.so.10.0‘; dlerror: libcupti.so.10.0...

    环境 Ubuntu 16 04 CUDA 10 0 CUDNN 7 6 5 nvcc NVIDIA R Cuda compiler driver Copyright c 2005 2018 NVIDIA Corporation Built
  • libsvm库简介及使用

    libsvm是基于支持向量机 support vector machine SVM 实现的开源库 由台湾大学林智仁 Chih Jen Lin 教授等开发 它主要用于分类 支持二分类和多分类 和回归 它的License是BSD 3 Claus
  • Softmax分类和两层神经网络以及反向传播的代码推导

    发现草稿箱里还有一篇很早之前的学习笔记 希望可以帮助到有需要的童鞋 目录 序 Softmax分类器 反向传播 数据构建以及网络训练 交叉验证参数优化 序 原来都是用的c 学习的传统图像分割算法 主要学习聚类分割 水平集 图割 欢迎一起讨论学
  • cs231n: How to Train a Neuron Network 如何训练神经网络

    CS231N第六第七课时的一些笔记 如何训练神经网络是一个比较琐碎的事情 所以整理了一下 以后训练Neuron Network的时候可以看一下 Activation Functions ReLu good ELU leaky ReLu no
  • 决策树(Decision Tree)简介

    决策树 Decision Tree 及其变种是另一类将输入空间分成不同的区域 每个区域有独立参数的算法 决策树分类算法是一种基于实例的归纳学习方法 它能从给定的无序的训练样本中 提炼出树型的分类模型 树中的每个非叶子节点记录了使用哪个特征来
  • Deep Learning(深度学习)之(三)Deep Learning的常用模型或者方法

    九 Deep Learning的常用模型或者方法 9 1 AutoEncoder自动编码器 Deep Learning最简单的一种方法是利用人工神经网络的特点 人工神经网络 ANN 本身就是具有层次结构的系统 如果给定一个神经网络 我们假设
  • 谈一谈关于NLP的落地场景和商业价值

    欢迎大家关注微信公众号 baihuaML 白话机器学习 在这里 我们一起分享AI的故事 您可以在后台留言 关于机器学习 深度学习的问题 我们会选择其中的优质问题进行回答 本期的问题 你好 请问下nlp在现在的市场主要应用在哪些方面 什么是N
  • cifar数据集介绍及到图像转换的实现

    CIFAR是一个用于普通物体识别的数据集 CIFAR数据集分为两种 CIFAR 10和CIFAR 100 The CIFAR 10 and CIFAR 100 are labeled subsets of the 80 million ti
  • 【深度学习】模型评价指标

    一 分类任务 分类任务一般有二分类 多分类和多标签分类 多分类 表示分类任务中有多个类别 但是对于每个样本有且仅有一个标签 例如一张动物图片 它只可能是猫 狗 虎等中的一种标签 二分类特指分类任务中只有两个类别 多标签 一个样本可以有多个标
  • yolov5量化部署(基于openvino和tensorrt)

    yolov5 openvino量化部署 首先 下载YOLOv5源码 安装YOLOv5和OpenVINO的python依赖 git clone https github com ultralytics yolov5 git pip insta
  • Anchor是什么?

    1 选择性搜索 Selective Search 先介绍一下传统的人脸识别算法 是怎么检测出图片中的人脸的 以下图为例 如果我们要检测图中小女孩的人脸位置 一个比较简单暴力的方法就是滑窗 我们使用不同大小 不同长宽比的候选框在整幅图像上进行

随机推荐

  • ADS2020.2安装

    双击安装包中的 exe文件 开始安装 安装结束后 直接点击退出 然后将crack文件夹中的两个文件夹 分别复制到刚刚的安装路径下 分别替换12个和2个同名文件 注意 这两个文件夹的名字要和刚刚安装的文件夹的名字一致 就是将Crack文件夹中
  • C++头文件

    作为一个二手的 net程序员 你看到了C 头文件一定就犯迷糊了 这到底是个啥玩意 再我纠结了24个小时 google20次 度娘10下 看过10来骗文章以后 我可能稍微开窍了 我对C 头文件总结 与 net比较如下 一 C 头文件究竟是什么
  • onvif协议服务器,Onvif第四课 服务器端发现实现

    场景 需要开发一个服务器发现模块 等待客户端的探测报文 在Linux服务器下组播地址imr interface可以不绑定 mcast imr multiaddr s addr inet addr 239 255 255 250 mcast
  • Python实现企业微信群告警

    Python实现企业微信告警 1 创建企业微信群机器人 1 1 什么是企业微信群机器人 企业微信群机器人是企业微信平台提供的一种功能 可以通过Webhook方式将消息发送到指定的企业微信群中 它可以用于自动化发送通知 告警等信息 实现监控和
  • 证据理论(1)—— DS证据理论基本理论

    证据理论 证据理论 Theory of Evidence 是由 Dempster 首先提出 由Shafer进一步发展起来的一种不精确推理理论 也称为 Dempster Shafer DS 证据理论 证据理论可以在没有先验概率的情况下 灵活并
  • 基于Matlab分析的电力系统可视化研究

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及数据 1 概述 电力系统可视化研究是电力系统分析中一项具
  • IKE协议与实现

    一 IKE的作用 当应用环境的规模较小时 可以用手工配置SA 当应用环境规模较大 参与的节点位置不固定时 IKE可自动地为参与通信的实体协商SA 并对安全关联库 SAD 维护 保障通信安全 二 IKE的机制 IKE属于一种混合型协议 由In
  • php curl ajax get请求,PHP的curl的get,post请求-Fun言

    GET请求如下 param string url return mixed public function doGet url 初始化 ch curl init curl setopt ch CURLOPT URL url 执行后不直接打印
  • 面试题:从用户在浏览器输入域名,到浏览器显示出页面,这中间发生了什么(工作过程)?

    这是一道很基础的题 但是也容易被忽视 主要是要进行域名解析 1 在浏览器中输入地址 如 www baidu com 2 向DNS服务器查询网站IP地址 3 DNS服务器返回网站IP地址 如 119 75 217 56 4 浏览器得到IP地址
  • 使用pipeline加速Redis

    面试官 怎么快速删除10万个key 某厂面试题 prod环境 如何快速删除10万个key 带着思考 我们一来研究Redis pipeline why pipeline Redis客户端与server的请求 响应模型 前面的文章 Redis底
  • C#开发WinForm之DataGridView开发

    C 开发WinForm之DataGridView开发 原文 https blog csdn net achenyuan article details 84632751 文章目录 C 开发WinForm之DataGridView开发 基本的
  • 在Linux中使用selenium(环境部署)

    在Linux中使用selenium 环境部署 1 安装chrome 用下面的命令安装Google Chrome yum install https dl google com linux direct google chrome stabl
  • 【单片机笔记】K型热电偶单运放放大,单片机ADC采集电路

    以下内容来自百科 K型热电偶作为一种温度传感器 K型热电偶通常和显示仪表 记录仪表和电子调节器配套使用 K型热电偶可以直接测量各种生产中从0 到1300 范围的液体蒸汽和气体介质以及固体的表面温度 高清K型热电偶图片 K型热电偶是目前用量最
  • 【RuoYi-Vue-Plus】学习笔记 09 - 数据权限调用流程分析(参照 Mybatis Plus 数据权限插件)

    文章目录 前言 参考目录 代码分析 1 数据权限配置 MybatisPlusConfig 2 数据权限拦截器 PlusDataPermissionInterceptor 3 数据权限处理器 PlusDataPermissionHandler
  • 20-Docker-常用命令详解-docker attach

    常用命令详解 docker attach 前言 docker attach 语法格式 options 说明 使用示例 进入容器 和docker exec 的区别 前言 本篇来学习docker attach命令 docker attach 作
  • 解决 -bash: ifconfig: command not found 实测有效

    1 查看是否已经联网 输入ip addr 或 ip a 发现ens33 中不包含IP内容 2 修改配置步骤 1 输入 cd etc sysconfig network scripts 回车 找到ifcfg ens33 注意 cd后面有空格
  • 坐标系和投影 知识的内容介绍

    回想一下 接触遥感专业也有几个年头了 而现在越来越偏离遥感了 突然想着把自己脑中的遥感知识整理出来 首先想到的便是坐标系和投影 我想这个东西困扰着80 以上的测绘 遥感和GIS领域的从业人员吧 群里经常有人问 我自己曾经也很迷糊 什么大地坐
  • Java测试题_1

    单选题 1 class Base Base System out print Base public class Alpha extends Base public static void main String args new Alph
  • JavaScript 获取 input 输入框内容的方法

    在 JavaScript 中获取 input 输入框内容的方法有以下几种 使用 document getElementById 方法获取输入框元素 再通过 value 属性获取输入框内容 示例代码如下 var input document
  • 吴恩达老师深度学习视频课笔记:逻辑回归公式推导及C++实现

    逻辑回归 Logistic Regression 是一个二分分类算法 逻辑回归的目标是最小化其预测与训练数据之间的误差 为了训练逻辑回归模型中的参数w和b 需要定义一个成本函数 cost function 成本函数 cost functio