范数介绍及C++/OpenCV/Eigen的三种实现

2023-10-26

有时我们需要衡量一个向量的大小。在机器学习中,我们经常使用被称为范数(norm)的函数衡量向量大小。形式上,Lp范数定义如下:


范数(包括Lp范数)是将向量映射到非负值的函数。直观上来说,向量x的范数衡量从原点到点x的距离。更严格地说,范数是满足下列性质的任意函数:


当p=2时,L2范数被称为欧几里得范数(Euclidean norm)。它表示从原点出发到向量x确定的点的欧几里得距离。

在数学中,欧几里得距离或欧几里得度量是欧几里得空间中两点间”普通”(即直线)距离。使用这个距离,欧式空间成为度量空间。相关联的范数称为欧几里得范数。


L2范数在机器学习中出现地十分频繁,经常简化表示为‖x‖,略去了下标2。平方L2范数也经常用来衡量向量的大小,可以简单地通过点积xTx计算。

平方L2范数在数学和计算上都比L2范数本身更方便。例如,平方L2范数对x中每个元素的导数只取决于对应的元素,而L2范数对每个元素的导数却和整个向量相关。但是在很多情况下,平方L2范数也可能不受欢迎,因为它在原点附件增长得十分缓慢。在某些机器学习应用中,区分恰好是零的元素和非零但值很小的元素是很重要的。在这些情况下,我们转而使用在各个位置斜率相同,同时保持简单的数学形式的函数:L1范数。

当机器学习问题中零和非零元素之间的差异非常重要时,通常会使用L1范数。每当x中某个元素从0增加ε,对应的L1范数也会增加ε。

有时候我们会统计向量中非零元素的个数来衡量向量的大小。有些作者将这种函数称为"L0范数",但是这个术语在数学意义上是不对的。向量的非零元素的数目不是范数,因为对向量缩放α倍不会改变向量非零元素的数目。因此,L1范数经常作为表示非零元素数目的替代函数。

另外一个经常在机器学习中出现的范数是L范数,也被称为最大范数(max norm)。这个范数表示向量中具有最大幅值的元素的绝对值:‖x‖=max|xi|

有时候我们可能也希望衡量矩阵的大小。在深度学习中,最常见的做法是使用Frobenius范数:类似于向量的L2范数。


两个向量的点积(dot product)可以用范数来表示。具体地,xTy=‖x‖2‖y‖2cosθ,其中θ表示x和y之间的夹角。

以上内容摘自: 《深度学习中文版》 和 维基百科 

以下是分别用C++、OpenCV、Eigen实现的求范数正无穷、范数L1、范数L2的code:

C++和OpenCV code:

#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "common.hpp"

// 求范数
typedef enum Norm_Types_ {
	Norm_INT = 0, // 无穷大
	Norm_L1, // L1
	Norm_L2 // L2
} Norm_Types;

template<typename _Tp>
int norm(const std::vector<std::vector<_Tp>>& mat, int type, double* value)
{
	*value = 0.f;

	switch (type) {
		case Norm_INT: {
			for (int i = 0; i < mat.size(); ++i) {
				for (const auto& t : mat[i]) {
					*value = std::max(*value, (double)(fabs(t)));
				}
			}
		}
			break;
		case Norm_L1: {
			for (int i = 0; i < mat.size(); ++i) {
				for (const auto& t : mat[i]) {
					*value += (double)(fabs(t));
				}
			}
		}
			break;
		case Norm_L2: {
			for (int i = 0; i < mat.size(); ++i) {
				for (const auto& t : mat[i]) {
					*value += t * t;
				}
			}
			*value = std::sqrt(*value);
		}
			break;
		default: {
			fprintf(stderr, "norm type is not supported\n");
			return -1;
		}
	}

	return 0;
}

int test_norm()
{
	fprintf(stderr, "test norm with C++:\n");
	std::vector<int> norm_types{ 0, 1, 2 }; // 正无穷、L1、L2
	std::vector<std::string> str{ "Inf", "L1", "L2" };

	// 1. vector
	std::vector<float> vec1{ -2, 3, 1 };
	std::vector<std::vector<float>> tmp1(1);
	tmp1[0].resize(vec1.size());
	for (int i = 0; i < vec1.size(); ++i) {
		tmp1[0][i] = vec1[i];
	}

	for (int i = 0; i < str.size(); ++i) {
		double value{ 0.f };
		norm(tmp1, norm_types[i], &value);

		fprintf(stderr, "vector: %s: %f\n", str[i].c_str(), value);
	}

	// 2. matrix
	std::vector<float> vec2{ -3, 2, 0, 5, 6, 2, 7, 4, 8 };
	const int row_col{ 3 };
	std::vector<std::vector<float>> tmp2(row_col);
	for (int y = 0; y < row_col; ++y) {
		tmp2[y].resize(row_col);
		for (int x = 0; x < row_col; ++x) {
			tmp2[y][x] = vec2[y * row_col + x];
		}
	}

	for (int i = 0; i < str.size(); ++i) {
		double value{ 0.f };
		norm(tmp2, norm_types[i], &value);

		fprintf(stderr, "matrix: %s: %f\n", str[i].c_str(), value);
	}

	fprintf(stderr, "\ntest norm with opencv:\n");
	norm_types[0] = 1; norm_types[1] = 2; norm_types[2] = 4; // 正无穷、L1、L2
	cv::Mat mat1(1, vec1.size(), CV_32FC1, vec1.data());

	for (int i = 0; i < norm_types.size(); ++i) {
		double value = cv::norm(mat1, norm_types[i]);
		fprintf(stderr, "vector: %s: %f\n", str[i].c_str(), value);
	}

	cv::Mat mat2(row_col, row_col, CV_32FC1, vec2.data());
	for (int i = 0; i < norm_types.size(); ++i) {
		double value = cv::norm(mat2, norm_types[i]);
		fprintf(stderr, "matrix: %s: %f\n", str[i].c_str(), value);
	}

	return 0;
}
执行结果如下:

Eigen code:

#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <vector>
#include <string>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include "common.hpp"

int test_norm()
{
	fprintf(stderr, "test norm with eigen:\n");
	// 1. vector
	std::vector<float> vec1{ -2, 3, 1 };
	Eigen::VectorXf v(vec1.size());
	for (int i = 0; i < vec1.size(); ++i) {
		v[i] = vec1[i];
	}

	double value = v.lpNorm<Eigen::Infinity>();
	fprintf(stderr, "vector: Inf: %f\n", value);
	value = v.lpNorm<1>();
	fprintf(stderr, "vector: L1: %f\n", value);
	value = v.norm(); // <==> sqrt(v.squaredNorm()) <==> v.lpNorm<2>()
	fprintf(stderr, "vector: L2: %f\n", value);

	// 2. matrix
	std::vector<float> vec2{ -3, 2, 0, 5, 6, 2, 7, 4, 8 };
	const int row_col{ 3 };
	Eigen::Map<Eigen::MatrixXf> m(vec2.data(), row_col, row_col);

	value = m.lpNorm<Eigen::Infinity>();
	fprintf(stderr, "matrix: Inf: %f\n", value);
	value = m.lpNorm<1>();
	fprintf(stderr, "matrix: L1: %f\n", value);
	value = m.norm();
	fprintf(stderr, "matrix: L2: %f\n", value);

	return 0;
}
执行结果如下:

可见使用C++、OpenCV、Eigen三种方法实现的结果是一致的。


GitHub:

https://github.com/fengbingchun/NN_Test

https://github.com/fengbingchun/Eigen_Test

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

范数介绍及C++/OpenCV/Eigen的三种实现 的相关文章

  • Latex系列3---页面设置+字体字号+颜色符号

    上一节中阐述的是简易的文本 本节在此基础上进行完善加工 页面设置 页边距 在平时写文章的时候 其实对于页边距的要求不高 但是论文这种就比较的严格 调整页边距需要使用 usepackage geometry 在这里我们平常使用此包进行调整页边
  • matlab如何读取txt文件

    格式化文本的读操作 只读形式打开txt文件 file t fopen mytxt txt r 以十进制读取 且读取的数据自动排成一列 排的顺序为 先从第一行左边到第一行右边 然后排第二行 A fscanf file t d 关闭文件 fcl
  • Proxy代理的作用

    Proxy代理的作用 Proxy 用于修改某些操作的默认行为 等同于在语言层面做出修改 所以属于一种 元编程 meta programming 即对编程语言进行编程 Proxy可以理解成 在目标对象之前架设一层 拦截 外界对该对象的访问 都
  • Babel转码器详解

    Babel转码器详解 Babel是一个广为使用的ES6转码器 可以将ES6代码转为ES5代码 从而在浏览器或其他环境运行 这意味着可以用ES6的方式编写程序而不用担心环境是否支持 Babel的配置文件是 babelrc 存放在根目录下 使用
  • 已解决 ZeroDivisionError: float division by zero 。

    问题 在使用YOLO算法系列时 需要将xml文件转换为txt文件 我在转换时遇到了这个问题ZeroDivisionError float division by zer 解决方法 简单的解决方法 找到报错的位置 将w h的值后面各加上一个极
  • Python进行ARMA模型建模

    import pandas as pd import matplotlib pyplot as plt import seaborn as sns import statsmodels api as sm from statsmodels

随机推荐

  • 使用Virtuoso和hspice进行电路输入与模拟

    总述 在这一次实验里 我学习了电路模拟的基本办法 具体而言是virtuoso和hspice 还有custom waveform软件基本功能的使用 达到了通过电路模拟验证延迟 验证功耗 验证逻辑功能的目的 反相器的设计 反相器是可以将输入信号
  • DBeaver 连接 Google BigQuery

    DBeaver 连接 Google BigQuery 毕业设计要用到Google BigQuery 但是想要用DBeaver进行远程连接 实在用不惯浏览器端的界面 结果发现DBeaver 真 的 可 以 DBeaver提供了Google B
  • Mysql Redo Log日志

    Mysql Redo Log日志 数据日志与数据落盘机制 Redo log写入磁盘时 必须进行一次操作系统fsync操作 防止redo log只是写入操作系统磁盘缓存中 参数innodb flush log at trx commit可以控
  • C++ 动态内存

    了解动态内存在 C 中是如何工作的是成为一名合格的 C 程序员必不可少的 C 程序中的内存分为两个部分 栈 在函数内部声明的所有变量都将占用栈内存 堆 这是程序中未使用的内存 在程序运行时可用于动态分配内存 很多时候 您无法提前预知需要多少
  • 公司名称注册,公司名称查询,企业名称注册事项

    公司名称的构成 名称一般由四部分依次组成 行政区划 字号 行业特点 组织形式 登记管辖 工商行政管理机关对企业名称实行分级登记管理 国家工商总局登记管辖范围 一 冠以 中国 中华 全国 国家 国际 字样的 二 在名称中间使用 中国 中华 全
  • Python中的三引号''' '''的用法

    链接 https blog csdn net GreenHandCGL article details 79703863
  • ERP仓库管理的操作与设计--开源软件诞生20

    赤龙ERP库房管理讲解 第20篇 用日志记录 开源软件 的诞生 点亮星标 祈盼着一个鼓励 博主开源地址 码云 https gitee com redragon redragon erp GitHub https github com red
  • minkwindow安装

    装库要记住三件事 官网 csdn 耐心 装库太慢就边看剧边装 不要影响心态 首先上官网 GitHub NVIDIA MinkowskiEngine Minkowski Engine is an auto diff neural networ
  • 国产超低功耗华大单片机HC32L136开发板上手入门

    今天介绍下国产超低功耗华大单片机HC32L136开发板上手后的入门操作 开发板可以在华大MCU应用交流群 164973950 免费申请 HC32L136开发板 如下图所示 分为板载调试模块 左半部分 和MCU开发电路 右半部分 二者中间通过
  • 当你的sklearn用不了mean_absolute_percentage_error函数

    今天将一份写好的python机器学习程序换了个电脑跑的时候 出现了如下报错 ImportError cannot import name mean absolute percentage error from sklearn metrics
  • 解决K8s安装中节点初始化时 [kubelet-check] The HTTP call equal to ‘curl -sSL http://localhost:10248/healthz‘ 问题.

    问题描述 安装K8s时 在节点初始化过程中出现 kubelet check The HTTP call equal to curl sSL http localhost 10248 healthz failed with error Get
  • WINDOWS 10 设置WSL 2

    确保已安装 WSL 可以在此处找到相关说明 并且运行的是 Windows 10内部版本 18917或更高版本 可以通过在 PowerShell 中运行以下命令来执行此操作 PowerShell dism exe online enable
  • 分布式深度学习part1:神经网络的分布式训练

    这篇文章是关于神经网络分布式训练的三部系列文章中的第一篇 在第1部中 我们将了解如何通过GPU上的分布式计算显著地加速深度学习模型的训练 并讨论一些挑战并调查当前关于该主题的研究 我们还将考虑神经网络的分布式训练是否适用于特定用例 介绍 在
  • stm32关于通用定时器的周期、频率计算公式

    以下内容针对正点原子的定时器中断实验 定时器时基单元包含 计数器寄存器 TIMx CNT 预分频器寄存器 TIMx PSC 该寄存器用设置对时钟进行分频 然后提供给计数器 作为计数器的时钟 自动装载寄存器 TIMx ARR 定时器的时钟来源
  • 【适合小白】开发一个区块链应用

    前言 本篇教程是小编基于FISCO BCOS官网的教程撰写的 有不明白的地方也可以去官网上的教程看看 在开发区块链应用之前 首先得完成搭建第一个区块链应用 目的是为了搭建节点跟启动控制台 1 了解应用需求 区块链天然具有防篡改 可追溯等特性
  • MQTT协议学习

    MQTT协议是目前物联网最主要的协议 它的设计主要是运用于 低带宽 低网速 差网络环境能够保证数据的正常传输 MQTT协议基于TCP IP协议 运用订阅发布模式 解除应用之间的耦合关系 客户端与客户端之间只需要知道服务器位置 就可以传输数据
  • Github管理项目代码相关git命令

    1 Git global setup git config global user name username git config global user email user email 2 Create a new repositor
  • .classpath .project ch2.iml这三个文件如何理解?

    这三个文件通常出现在Java开发中使用的集成开发环境 IDE 项目中 如Eclipse或IntelliJ IDEA 它们在项目的组织和配置方面发挥着重要的作用 classpath 文件 classpath 是 Eclipse 项目的配置文件
  • Wireshark使用小心得

    Wireshark工作使用小结 基本概念 wireshark是个开源的好用软件 用来分析数据包 数据包 通常就是四层信息 物理层数据帧 数据链路层以太帧头部 网络层IP包头部 传输层TCP包头部 最后就是应用层信息 基础功能使用 打开软件界
  • 范数介绍及C++/OpenCV/Eigen的三种实现

    有时我们需要衡量一个向量的大小 在机器学习中 我们经常使用被称为范数 norm 的函数衡量向量大小 形式上 Lp范数定义如下 范数 包括Lp范数 是将向量映射到非负值的函数 直观上来说 向量x的范数衡量从原点到点x的距离 更严格地说 范数是