| by msbeta | No comments

神经网络中的非线性激活函数

为什么引入非线性激活函数

如果采用线性激活函数,无论你神经网络有多少层,输出都是输入的线性组合,与没有隐藏层效果相当,这种情况就是最原始的感知机(Perceptron),感知机连最基本的异或问题都无法解决,更别提更复杂的非线性问题,这样的神经网络就没有意义。

常见的非线性激活函数

因为上面的原因,所以我们引入了非线性激活函数,这样神经网络才具有实用意义,其不再是输入的线性组合关系,而可以非线性组合成各种任意函数的输出。常用的激活函数包括以下形式:

Sigmoid函数

Sigmoid函数将任意实数映射到[0,1]范围内,在负无穷到0的区间趋向于0,在0到正无穷的区间[……]

继续阅读

Read More
| by msbeta | 1 comment

C++多线程编程-分析每个函数的内存占用

最近遇到一个“内存占用不断增加”的问题,从代码上没有分析出任何异常,束手无策只有只有借助第三方工具Google Heap Profiler。Google Heap Profiler是Google开源性能内存检测工具GPerfTools系列工具中的一个,可以帮助我们检测代码中出现的内存泄露,帮助我们了解程序中每一行代码占用了多少内存。

1. Google Heap Profiler的安装

安装环境: Ubuntu 18.04

Google GPerfTools工具的Github: https://github.com/gperftools/gperftools

编译安装:[……]

继续阅读

Read More
| by msbeta | 1 comment

C++多线程编程-设计无锁并发堆栈

今天我们来设计一个并发堆栈(Stack),这个堆栈(Stack)虽然支持多线程访问,但是没有锁。

向堆栈压入数据

在push方法里,使用了C++11的CAS方法: compare_exchange_weak。compare_exchange_weak会比较当前值和期望值,当前值与期望值相等时,修改当前值为设定值,返回true;当前值与期望值不等时,将期望值修改为当前值,返回false。

如果compare_exchange_weak返回false,证明有其它线程更新了栈顶,此时循环会再次尝试压栈,直至压栈成功。

从堆栈弹出数据

常见的错误实现一:

[……]

继续阅读

Read More
| by msbeta | 2 comments

C++多线程编程-设计并发队列

1、最基础的并发队列

并发队列最直观的实现就是使用互斥锁管理数据同步,向队列中添加数据或者删除数据时,使用互斥锁保证访问的安全性。

如下代码所示,我们基于STL中的链表(List)实现并发队列,队列类的构造函数和析构函数负责创建和销毁互斥锁。

在并发队列中插入数据:

在并发队列中删除数据:

2. 读写互斥的并发队列

在实际的应用场景中,会有这样的场景:假设你有一个很长的队列,从队列中读取数据的线程远远多于写入数据的线程,或者队列读取数据的需求远远大于队列数据写入的需求,如果写入和读取数据使用相同的互斥锁,会大大降低系统的效率。

为了解决这个[……]

继续阅读

Read More
| by msbeta | No comments

一切皆投资

近几个月陆续读完了<小狗钱钱>、<穷爸爸富爸爸>、<时间的朋友>、<七年就是一辈子>和李笑来的专栏<财富自由之路>,对财富、复利、投资有了不少新的认知,也觉得以前的自己好蠢好蠢…

整天睡大觉的现金存款

平时由于工作比较忙碌,很少考虑应该如何管理自己的钱。每个月公司直接把工资打到自己的账户中,然后他们大部分竟然以”活期存款”的形式默默的趟在我的银行账户中,产生着近乎为零的收益。

而今年疫情原因,国家货币大放水,通胀的扩大,纸币在快速的缩水。按照<小狗钱钱>中的计算方法,假设每年的通胀率为6%,你持有的现金的[……]

继续阅读

Read More
| by msbeta | No comments

C++多线程编程-C++ Concurrency in Action

C++ Concurrency in Action可以作为C++在编写优雅多线程应用方面的权威指南。其详细描述了启动新线程到设计复杂的多线程算法和数据结构,在每一章中并发大师Anthony Williams都提供了示例和一些练习和一些独到的见解,这对于从事并发开发的同学会很有帮助。

<<Concurrency in Action>>第一版中文翻译版本的GitHub地址:

https://github.com/xiaoweiChen/Cpp_Concurrency_In_Action

<<Concurrency in Action>&g[……]

继续阅读

Read More
| by msbeta | No comments

C++多线程-GDB调试

1、GDB多线程调试基础

先看一个简单的场景,丈夫和妻子赚钱养家,丈夫每天赚6美元,妻子每天赚3美元,(生活不易,哈哈),它们每天把挣到的钱存到共用账户。C++代码示例如下:

代码编译:

g++ -std=c++11 hard_life.cpp -o hard_life -lpthread -g

运行程序:

进入GDB调试:

1.1 设置断点 break hard_life.cpp:18

GDB设置断点,运行程序:

1.2 查看运行的线程: info threads

查看当前运行的线程:info threads,可以看到当[……]

继续阅读

Read More
| by msbeta | 1 comment

C++多线程编程-智能指针shared_ptr

1、shared_ptr的引用计数是线程安全的么?

shared_ptr的引用计数是线程安全的。

2、shared_ptr对象是线程安全的么?

shared_ptr对象不是线程安全的。如果多个线程读写同一个shared_ptr对象,需要加锁。注意,这里说的shared_ptr对象本身,而不是shared_ptr所管理的内存。

以下解释shared_ptr对象为什么不是线程安全的?

如下图所示,shared_ptr<Foo> 包含两个成员:指针 ptr(指向堆内存上的Foo对象)和指针ref_count(指向堆内存上的 ref_count 对象)。ref_cou[……]

继续阅读

Read More
| by msbeta | No comments

C++多线程编程-基础入门

1. Hello Word

先从一个简单的多线程程序开始,标准的C++库中提供了对于多线程的支持,实现一个简单的多线程的代码非常容易。

在新线程启动后,主线程会继续执行到main()函数结束,然后退出程序,这时新线程可能还没有被执行。为了保证新线程一定可以被调用执行,需要调用join()函数使得调用线程等待新线程执行完成再退出。

2、std::thread的task参数

新线程的启动是通过构造std::thread对象实现的,std::thread的参数是在线程中要运行的task,最简单的情况下,task是一个void返回值的没有参数的普通函数

事实上,[……]

继续阅读

Read More
| by msbeta | No comments

C++11-shared_ptr使用的两个坑

1、禁止使用一个裸指针创建多个智能指针

先看下如下的代码,会有什么样的问题呢?没错,ptr_1和ptr_2均使用裸指针(raw pointer),指向同一块内存,但它们彼此不相知。

当ptr_2作用域结束时,它会delete关联的裸指针(raw pointer),然后ptr_1的指针就会悬空,成为一个非法值。

同理,当ptr_1作用域结束时,它会delete关联的裸指针(raw pointer),然后ptr_2的指针就会悬空,成为一个非法值。

2. 禁止从栈对象创建shared_ptr

看下面一段代码:

shared_ptr要求与它关联的内存来自[……]

继续阅读

Read More