BP神经网络公式推导及实现(MNIST)
BP神经网络的基础介绍见:http://blog.csdn.net/fengbingchun/article/details/50274471,这里主要以公式推导为主。
BP神经网络又称为误差反向传播网络,其结构例如以下图。
这样的网络实质是一种前向无反馈网络,具有结构清晰、易实现、计算功能强大等特点。
BP神经网络有一个输入层。一个输出层。一个或多个隐含层。每一层上包括了若干个节点。每个节点代表一个神经元,同一层上各节点之间无不论什么耦合连接关系,层间各神经元之间实现全连接,即后一层(如输入层)的每个神经元与前一层(如隐含层)的每个神经元实现全连接。网络依照监督学习的方式学习,当信息被输入网络后神经元受到刺激。激活值从输入层依次经过各隐含层节点。最后在输出层的各节点获得网络的输入响应。
BP神经网络的基本思想:BP神经网络的学习採用误差反向传播算法。BP算法是一种有监督的学习方法。其主要思想是把整个学习过程分为正向传播、反向(逆向)传播和记忆训练三个部分。正向传播时,输入样本从输入层输入。经各隐含层处理后传向输出层,每一层神经元的状态仅仅影响下一层神经元的状态。
假设在输出层得不到期望的输出。则转入误差的反向传播阶段。将输出误差以某种形式通过隐含层向输入层反传,并将误差分摊给各层的全部单元,从而获得各层单元的误差信号并将其作为修正各单元权值的根据。这样的网络的信号正向传播与误差反向传播是重复交替进行的,权值的不断调整就是网络的记忆训练过程。
网络的记忆训练过程一直进行到网络趋向收敛,即输出误差达到要求的标准。
三层BP神经网络的学习算法:为了使BP网络具有某种功能,完毕某项任务。必须调整层间连接权值和节点阈值,使全部样品的实际输出和期望输出之间的误差稳定在一个较小的值之内。三层BP网络学习过程主要由四部分组成:(1)、输入模式顺传播(输入模式由输入层经隐含层向输出层传播计算);(2)、输出误差逆传播(输出的误差由输出层经隐含层传向输入层);(3)、循环记忆训练(模式顺传播与误差逆传播的计算过程重复交替循环进行);(4)、学习结果判别(判定全局误差是否趋向极小值或是否已达到设定的最大迭代次数)。
(1)、输入模式顺传播:这一过程主要是利用输入模式求出它所相应的实际输出。
确定输入向量Xk:
式中,k=1,2,…,m;m是学习模式对数(训练模式对数)。n是输入层单元数。
确定期望输出向量Yk:
式中,k=1,2,…,m;m是学习模式对数(训练模式对数)。q为输出层单元数。
计算隐含层各神经元的激活值sj:
式中,n是输入层单元数。wij是输入层至隐含层的连接权值。θj是隐含层单元的阈值;j=1,2…p。p是隐含层单元数。
激活函数採用s型函数:
计算隐含层j单元的输出值:将上面的激活值即公式(3)代入激活函数即公式(4)中可得隐含层j单元的输出值:
阈值θj在学习过程中与权值wij一样也不断地被修正。
计算输出层第t个单元的激活值ot:
计算输出层第t个单元的实际输出值ct:
式中,wjt是隐含层至输出层的权值;θt是输出层单元阈值;j=1,2…p,p是隐含层单元数;xj为隐含层第j个节点的输出值。f是s型激活函数。t=1,2…,q。q为输出层单元数。
利用以上各公式就能够计算出一个输入模式的顺传播过程。
(2)、输出误差的逆传播:在第一步的模式顺传播计算中得到了网络的实际输出值,当这些实际的输出值与希望的输出值不一样或者误差大于所限定的数值时,就要对网络进行校正。
这里的校正是从前往后进行的。所以叫做误差逆传播,计算时是从输出层到隐含层,再从隐含层到输入层。
输出层的校正误差:
式中,t=1,2,…,q。q是输出层单元数。k=1,2,…,m,m是训练(学习)模式对数;ytk是希望输出;ctk是实际输出;f’(.)是对输出函数的导数。
隐含层各单元的校正误差:
式中,t=1,2,…,q。q是输出层单元数。j=1,2,…,p; p是隐含层单元数;k=1,2,…,m,m是训练(学习)模式对数。
对于输出层至隐含层连接权和输出层阈值的校正量:
式中,bjk是隐含层j单元的输出。dtk是输出层的校正误差;j=1,2…,p。t=1,2,…,q;k=1,2,…,m; α>0(输出层至隐含层学习率)。
隐含层至输入层的校正量:
式中,ejk是隐含层j单元的校正误差;xik是标准输入,i=1,2,…,n ,n是输入层单元数;0<β<1(隐含层至输入层学习率)。
(3)、循环记忆训练:为使网络的输出误差趋向于极小值,对于BP网输入的每一组训练模式,一般要经过数百次甚至上万次的循环记忆训练,才干使网络记住这一模式。这样的循环记忆实际上就是重复重复上面介绍的输入模式顺传播和输出误差逆传播。
(4)、学习结果的判别:当每次循环记忆训练结束后,都要进行学习结果的判别。判别的目的主要是检查输出误差是否已经小到能够同意的程度。
假设小到能够同意的程度,就能够结束整个学习过程。否则还要继续进行循环训练。
确定隐含层节点数:一般有3个经验公式:
式中,m为要设置的隐含层节点数。n为输入层节点数;l为输出层节点数。α为1至10之间的常数。
下面依照上面的公式实现的BP,通过MNIST库測试,识别率能够达到96.5%以上。
BP.hpp:
#ifndef _BP_HPP_
#define _BP_HPP_ namespace ANN { #define num_node_input_BP 784 //输入层节点数
#define width_image_BP 28 //归一化图像宽
#define height_image_BP 28 //归一化图像高
#define num_node_hidden_BP 120 //隐含层节点数
#define num_node_output_BP 10 //输出层节点数
#define alpha_learning_BP 0.8 //输出层至隐含层学习率
#define beta_learning_BP 0.6 //隐含层至输入层学习率
#define patterns_train_BP 60000 //训练模式对数(总数)
#define patterns_test_BP 10000 //測试模式对数(总数)
#define iterations_BP 10000 //最大训练次数
#define accuracy_rate_BP 0.965 //要求达到的准确率 class BP {
public:
BP();
~BP(); void init(); //初始化,分配空间
bool train(); //训练
int predict(const int* data, int width, int height); //预測
bool readModelFile(const char* name); //读取已训练好的BP model protected:
void release(); //释放申请的空间
bool saveModelFile(const char* name); //将训练好的model保存起来,包括各层的节点数,权值和阈值
bool initWeightThreshold(); //初始化,产生[-1, 1]之间的随机小数
bool getSrcData(); //读取MNIST数据
void calcHiddenLayer(const int* data); //计算隐含层输出
void calcOutputLayer(); //计算输出层输出
void calcAdjuctOutputLayer(const int* data); //计算输出层校正误差
void calcAdjuctHiddenLayer(); //计算隐含层校正误差
float calcActivationFunction(float x); //计算激活函数,对数S形函数
void updateWeightThresholdOutputLayer(); //更新输出层至隐含层权值和阈值
void updateWeightThresholdHiddenLayer(const int* data); //更新隐含层至输入层权值和阈值
float test(); //训练完一次计算一次准确率 private:
float weight1[num_node_input_BP][num_node_hidden_BP]; //输入层至隐含层连接权值
float weight2[num_node_hidden_BP][num_node_output_BP]; //隐含层至输出层连接权值
float threshold1[num_node_hidden_BP]; //隐含层阈值
float threshold2[num_node_output_BP]; //输出层阈值
float output_hiddenLayer[num_node_hidden_BP]; //顺传播。隐含层输出值
float output_outputLayer[num_node_output_BP]; //顺传播,输出层输出值
float adjust_error_outputLayer[num_node_output_BP]; //逆传播,输出层校正误差
float adjust_error_hiddenLayer[num_node_hidden_BP]; //逆传播,隐含层校正误差 int* data_input_train; //原始标准输入数据,训练
int* data_output_train; //原始标准期望结果,训练
int* data_input_test; //原始标准输入数据,測试
int* data_output_test; //原始标准期望结果,測试
}; } #endif //_BP_HPP_
BP.cpp:
#include <assert.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <windows.h> #include "BP.hpp" namespace ANN { BP::BP()
{
data_input_train = NULL;
data_output_train = NULL;
data_input_test = NULL;
data_output_test = NULL;
} BP::~BP()
{
release();
} void BP::release()
{
if (data_input_train) {
delete[] data_input_train;
}
if (data_output_train) {
delete[] data_output_train;
}
if (data_input_test) {
delete[] data_input_test;
}
if (data_output_test) {
delete[] data_output_test;
}
} bool BP::initWeightThreshold()
{
srand(time(0) + rand()); for (int i = 0; i < num_node_input_BP; i++) {
for (int j = 0; j < num_node_hidden_BP; j++) {
weight1[i][j] = -1 + 2 * ((float)rand()) / RAND_MAX; //[-1, 1]
}
} for (int i = 0; i < num_node_hidden_BP; i++) {
for (int j = 0; j < num_node_output_BP; j++) {
weight2[i][j] = -1 + 2 * ((float)rand()) / RAND_MAX;
}
} for (int i = 0; i < num_node_hidden_BP; i++) {
threshold1[i] = -1 + 2 * ((float)rand()) / RAND_MAX;
} for (int i = 0; i < num_node_output_BP; i++) {
threshold2[i] = -1 + 2 * ((float)rand()) / RAND_MAX;
} return true;
} static int reverseInt(int i)
{
unsigned char ch1, ch2, ch3, ch4;
ch1 = i & 255;
ch2 = (i >> 8) & 255;
ch3 = (i >> 16) & 255;
ch4 = (i >> 24) & 255;
return((int)ch1 << 24) + ((int)ch2 << 16) + ((int)ch3 << 8) + ch4;
} static void readMnistImages(std::string filename, int* data_dst, int num_image)
{
std::ifstream file(filename, std::ios::binary);
assert(file.is_open()); int magic_number = 0;
int number_of_images = 0;
int n_rows = 0;
int n_cols = 0;
file.read((char*)&magic_number, sizeof(magic_number));
magic_number = reverseInt(magic_number);
file.read((char*)&number_of_images, sizeof(number_of_images));
number_of_images = reverseInt(number_of_images);
assert(number_of_images == num_image);
file.read((char*)&n_rows, sizeof(n_rows));
n_rows = reverseInt(n_rows);
file.read((char*)&n_cols, sizeof(n_cols));
n_cols = reverseInt(n_cols);
assert(n_rows == height_image_BP && n_cols == width_image_BP); for (int i = 0; i < number_of_images; ++i) {
for (int r = 0; r < n_rows; ++r) {
for (int c = 0; c < n_cols; ++c) {
unsigned char temp = 0;
file.read((char*)&temp, sizeof(temp));
//data_dst[i * num_node_input_BP + r * n_cols + c] = (int)temp; //formula[1]
if (temp > 128) {
data_dst[i * num_node_input_BP + r * n_cols + c] = 1;
} else {
data_dst[i * num_node_input_BP + r * n_cols + c] = 0;
}
}
}
}
} static void readMnistLabels(std::string filename, int* data_dst, int num_image)
{
std::ifstream file(filename, std::ios::binary);
assert(file.is_open()); int magic_number = 0;
int number_of_images = 0;
file.read((char*)&magic_number, sizeof(magic_number));
magic_number = reverseInt(magic_number);
file.read((char*)&number_of_images, sizeof(number_of_images));
number_of_images = reverseInt(number_of_images);
assert(number_of_images == num_image); for (int i = 0; i < number_of_images; ++i) {
unsigned char temp = 0;
file.read((char*)&temp, sizeof(temp));
data_dst[i * num_node_output_BP + temp] = 1; //formula[2]
}
} bool BP::getSrcData()
{
assert(data_input_train && data_output_train && data_input_test && data_output_test); std::string filename_train_images = "D:/Download/MNIST/train-images.idx3-ubyte";
std::string filename_train_labels = "D:/Download/MNIST/train-labels.idx1-ubyte";
readMnistImages(filename_train_images, data_input_train, patterns_train_BP);
/*unsigned char* p = new unsigned char[784];
memset(p, 0, sizeof(unsigned char) * 784);
for (int j = 0, i = 59998 * 784; j< 784; j++, i++) {
p[j] = (unsigned char)data_input_train[i];
}
delete[] p;*/
readMnistLabels(filename_train_labels, data_output_train, patterns_train_BP);
/*int* q = new int[10];
memset(q, 0, sizeof(int) * 10);
for (int j = 0, i = 59998 * 10; j < 10; j++, i++) {
q[j] = data_output_train[i];
}
delete[] q;*/ std::string filename_test_images = "D:/Download/MNIST/t10k-images.idx3-ubyte";
std::string filename_test_labels = "D:/Download/MNIST/t10k-labels.idx1-ubyte";
readMnistImages(filename_test_images, data_input_test, patterns_test_BP);
readMnistLabels(filename_test_labels, data_output_test, patterns_test_BP); return true;
} void BP::init()
{
data_input_train = new int[patterns_train_BP * num_node_input_BP];
memset(data_input_train, 0, sizeof(int) * patterns_train_BP * num_node_input_BP);
data_output_train = new int[patterns_train_BP * num_node_output_BP];
memset(data_output_train, 0, sizeof(int) * patterns_train_BP * num_node_output_BP);
data_input_test = new int[patterns_test_BP * num_node_input_BP];
memset(data_input_test, 0, sizeof(int) * patterns_test_BP * num_node_input_BP);
data_output_test = new int[patterns_test_BP * num_node_output_BP];
memset(data_output_test, 0, sizeof(int) * patterns_test_BP * num_node_output_BP); initWeightThreshold();
getSrcData();
} float BP::calcActivationFunction(float x)
{
return 1.0 / (1.0 + exp(-x)); //formula[4] formula[5] formula[7]
} void BP::calcHiddenLayer(const int* data)
{
for (int i = 0; i < num_node_hidden_BP; i++) {
float tmp = 0;
for (int j = 0; j < num_node_input_BP; j++) {
tmp += data[j] * weight1[j][i];
} tmp -= threshold1[i]; //formula[3]
output_hiddenLayer[i] = calcActivationFunction(tmp);
}
} void BP::calcOutputLayer()
{
for (int i = 0; i < num_node_output_BP; i++) {
float tmp = 0;
for (int j = 0; j < num_node_hidden_BP; j++) {
tmp += output_hiddenLayer[j] * weight2[j][i];
} tmp -= threshold2[i]; //formula[6]
output_outputLayer[i] = calcActivationFunction(tmp);
}
} void BP::calcAdjuctOutputLayer(const int* data)
{
for (int i = 0; i < num_node_output_BP; i++) {
adjust_error_outputLayer[i] = (data[i] - output_outputLayer[i]) *
output_outputLayer[i] * (1.0 - output_outputLayer[i]); //formula[8], f'(x)= f(x)*(1. - f(x))
}
} void BP::calcAdjuctHiddenLayer()
{
for (int i = 0; i < num_node_hidden_BP; i++) {
float tmp = 0;
for (int j = 0; j < num_node_output_BP; j++) {
tmp += weight2[i][j] * adjust_error_outputLayer[j];
} adjust_error_hiddenLayer[i] = tmp * (output_hiddenLayer[i] * (1.0 - output_hiddenLayer[i])); //formula[9]
}
} void BP::updateWeightThresholdOutputLayer()
{
for (int i = 0; i < num_node_output_BP; i++) {
for (int j = 0; j < num_node_hidden_BP; j++) {
weight2[j][i] += (alpha_learning_BP * adjust_error_outputLayer[i] * output_hiddenLayer[j]); //formula[10]
} threshold2[i] += (alpha_learning_BP * adjust_error_outputLayer[i]); //formula[11]
}
} void BP::updateWeightThresholdHiddenLayer(const int* data)
{
for (int i = 0; i < num_node_hidden_BP; i++) {
for (int j = 0; j < num_node_input_BP; j++) {
weight1[j][i] += (beta_learning_BP * adjust_error_hiddenLayer[i] * data[j]); //formula[12]
} threshold1[i] += (beta_learning_BP * adjust_error_hiddenLayer[i]); //formula[13]
}
} float BP::test()
{
int count_accuracy = 0; for (int num = 0; num < patterns_test_BP; num++) {
int* p1 = data_input_test + num * num_node_input_BP;
calcHiddenLayer(p1);
calcOutputLayer(); float max_value = -9999;
int pos = -1; for (int i = 0; i < num_node_output_BP; i++) {
if (output_outputLayer[i] > max_value) {
max_value = output_outputLayer[i];
pos = i;
}
} int* p2 = data_output_test + num * num_node_output_BP;
if (p2[pos] == 1) {
count_accuracy++;
}
Sleep(1);
} return (count_accuracy * 1.0 / patterns_test_BP);
} bool BP::saveModelFile(const char* name)
{
FILE* fp = fopen(name, "wb");
if (fp == NULL) {
return false;
} int num_node_input = num_node_input_BP;
int num_node_hidden = num_node_hidden_BP;
int num_node_output = num_node_output_BP;
fwrite(&num_node_input, sizeof(int), 1, fp);
fwrite(&num_node_hidden, sizeof(int), 1, fp);
fwrite(&num_node_output, sizeof(int), 1, fp);
fwrite(weight1, sizeof(weight1), 1, fp);
fwrite(threshold1, sizeof(threshold1), 1, fp);
fwrite(weight2, sizeof(weight2), 1, fp);
fwrite(threshold2, sizeof(threshold2), 1, fp); fflush(fp);
fclose(fp); return true;
} bool BP::readModelFile(const char* name)
{
FILE* fp = fopen(name, "rb");
if (fp == NULL) {
return false;
} int num_node_input, num_node_hidden, num_node_output; fread(&num_node_input, sizeof(int), 1, fp);
assert(num_node_input == num_node_input_BP);
fread(&num_node_hidden, sizeof(int), 1, fp);
assert(num_node_hidden == num_node_hidden_BP);
fread(&num_node_output, sizeof(int), 1, fp);
assert(num_node_output == num_node_output_BP);
fread(weight1, sizeof(weight1), 1, fp);
fread(threshold1, sizeof(threshold1), 1, fp);
fread(weight2, sizeof(weight2), 1, fp);
fread(threshold2, sizeof(threshold2), 1, fp); fflush(fp);
fclose(fp); return true;
} int BP::predict(const int* data, int width, int height)
{
assert(data && width == width_image_BP && height == height_image_BP); const int* p = data;
calcHiddenLayer(p);
calcOutputLayer(); float max_value = -9999;
int ret = -1; for (int i = 0; i < num_node_output_BP; i++) {
if (output_outputLayer[i] > max_value) {
max_value = output_outputLayer[i];
ret = i;
}
} return ret;
} bool BP::train()
{
int i = 0;
for (i = 0; i < iterations_BP; i++) {
std::cout << "iterations : " << i; float accuracyRate = test();
std::cout << ", accuray rate: " << accuracyRate << std::endl;
if (accuracyRate > accuracy_rate_BP) {
saveModelFile("bp.model");
std::cout << "generate bp model" << std::endl;
break;
} for (int j = 0; j < patterns_train_BP; j++) {
int* p1 = data_input_train + j * num_node_input_BP;
calcHiddenLayer(p1);
calcOutputLayer(); int* p2 = data_output_train + j * num_node_output_BP;
calcAdjuctOutputLayer(p2);
calcAdjuctHiddenLayer(); updateWeightThresholdOutputLayer();
int* p3 = data_input_train + j * num_node_input_BP;
updateWeightThresholdHiddenLayer(p3);
}
} if (i == iterations_BP) {
saveModelFile("bp.model");
std::cout << "generate bp model" << std::endl;
} return true;
} }
test.cpp:
#include <iostream>
#include "BP.hpp"
#include <opencv2/opencv.hpp> int test_BP(); int main()
{
test_BP();
std::cout << "ok!" << std::endl;
} int test_BP()
{
//1. bp train
ANN::BP bp1;
bp1.init();
bp1.train(); //2. bp predict
ANN::BP bp2;
bool flag = bp2.readModelFile("bp.model");
if (!flag) {
std::cout << "read bp model error" << std::endl;
return -1;
} int target[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::string path_images = "../../../../test-images/"; int* data_image = new int[width_image_BP * height_image_BP]; for (int i = 0; i < 10; i++) {
char ch[15];
sprintf(ch, "%d", i);
std::string str;
str = std::string(ch);
str += ".jpg";
str = path_images + str; cv::Mat mat = cv::imread(str, 2 | 4);
if (!mat.data) {
std::cout << "read image error" << std::endl;
return -1;
} if (mat.channels() == 3) {
cv::cvtColor(mat, mat, cv::COLOR_BGR2GRAY);
} if (mat.cols != width_image_BP || mat.rows != height_image_BP) {
cv::resize(mat, mat, cv::Size(width_image_BP, height_image_BP));
} memset(data_image, 0, sizeof(int) * (width_image_BP * height_image_BP)); for (int h = 0; h < mat.rows; h++) {
uchar* p = mat.ptr(h);
for (int w = 0; w < mat.cols; w++) {
if (p[w] > 128) {
data_image[h* mat.cols + w] = 1;
}
}
} int ret = bp2.predict(data_image, mat.cols, mat.rows);
std::cout << "correct result: " << i << ", actual result: " << ret << std::endl;
} delete[] data_image; return 0;
}
train结果例如以下图所看到的:
predict结果例如以下图所看到的,測试图像是从MNIST test集合中选取的:
BP神经网络公式推导及实现(MNIST)的更多相关文章
- Python实现bp神经网络识别MNIST数据集
title: "Python实现bp神经网络识别MNIST数据集" date: 2018-06-18T14:01:49+08:00 tags: [""] cat ...
- BP神经网络的公式推导
如果感觉自己看不懂,那就看看我博客的梯度下降法,博文最后的感知机也算最简单的BP神经网络吧,用的也是反馈(w,b):典型梯度下降法 BP网络的结构 BP网络的结构如下图所示,分为输入层(Input), ...
- BP神经网络原理及python实现
[废话外传]:终于要讲神经网络了,这个让我踏进机器学习大门,让我读研,改变我人生命运的四个字!话说那么一天,我在乱点百度,看到了这样的内容: 看到这么高大上,这么牛逼的定义,怎么能不让我这个技术宅男心 ...
- 【机器学习】BP神经网络实现手写数字识别
最近用python写了一个实现手写数字识别的BP神经网络,BP的推导到处都是,但是一动手才知道,会理论推导跟实现它是两回事.关于BP神经网络的实现网上有一些代码,可惜或多或少都有各种问题,在下手写了一 ...
- 神经网络中的BP神经网络和贝叶斯
1 贝叶斯网络在地学中的应用 1 1.1基本原理及发展过程 1 1.2 具体的研究与应用 4 2 BP神经网络在地学中的应用 6 2.1BP神经网络简介 6 2.2基本原理 7 2.3 在地学中的具体 ...
- BP神经网络在python下的自主搭建梳理
本实验使用mnist数据集完成手写数字识别的测试.识别正确率认为是95% 完整代码如下: #!/usr/bin/env python # coding: utf-8 # In[1]: import n ...
- 机器学习(4):BP神经网络原理及其python实现
BP神经网络是深度学习的重要基础,它是深度学习的重要前行算法之一,因此理解BP神经网络原理以及实现技巧非常有必要.接下来,我们对原理和实现展开讨论. 1.原理 有空再慢慢补上,请先参考老外一篇不错的 ...
- 基于BP神经网络的简单字符识别算法自小结(C语言版)
本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前面的闲话: 自我感觉自己应该不是一个非常 ...
- 三.BP神经网络
BP神经网络是包含多个隐含层的网络,具备处理线性不可分问题的能力.以往主要是没有适合多层神经网络的学习算法,,所以神经网络的研究一直处于低迷期. 20世纪80年代中期,Rumelhart,McClel ...
随机推荐
- tomcat 分别在window 和 Linux上配置SSL-安全问题
公司项目收尾后.通过压力測试后的安全測试.安全測试后中,对于网络传输中数据加密问题存在安全隐患. 须要配置SSL. 简介下SSL协议:SSL或者Secure Socket Layer,是一种同意web ...
- words2
餐具:coffee pot 咖啡壶coffee cup 咖啡杯paper towel 纸巾napkin 餐巾table cloth 桌布tea -pot 茶壶tea set 茶具tea tray 茶盘 ...
- JavaScript--数据结构与算法之图
图和图的算法:图的定义:由边的集合及顶点的集合组成. 例如地图,每个城镇是顶点,道路是边,由顶点对来定义(城镇1,城镇2)简称(v1,v2)顶点也有权重——成本.基本概念: 有向图:图的顶点对是有序的 ...
- last---显示用户最近登录信息
last命令用于显示用户最近登录信息.单独执行last命令,它会读取/var/log/wtmp的文件,并把该给文件的内容记录的登入系统的用户名单全部显示出来. 语法 last(选项)(参数) 选项 - ...
- Android 阅读器架构图,网上收集,留做存货
这个结构图是网上收集的图片.基结构明晰简洁.易于后期维护.本文会继续收集很多其他其他优秀的结构图,望有图的朋友推荐~
- 1.22 Python基础知识 - 正则表达式
Python正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式. re ...
- 基于Linux系统的Nagios网络管理模块的实现
基于Linux 系统的Nagios网络管理模块的实现 1.引言 随着计算机网络的普及,网络管理已成为信息时代中最重要的问题之一.在现有的技术条件下,人们希望有一个更加稳定可靠的网络环境.计算机网络管理 ...
- Java学习笔记三.2
5.继承 //Java中所有对象都显式/隐式的继承子Object类 class fu{ fu(){ System.out.println("fu..."+getNum()); sh ...
- 洛谷 P2978 [USACO10JAN]下午茶时间Tea Time
P2978 [USACO10JAN]下午茶时间Tea Time 题目描述 N (1 <= N <= 1000) cows, conveniently numbered 1..N all a ...
- ubuntu14中 memcached安装与使用
第一步,先安装lib-event 下载lib-event 的包http://libevent.org/ 下载完之后,解压安装 ./configure –prefix=/usr (或 ./config ...