opencv为我们提供了多种机器学习方法,比如adaboost、svm、神经网络等。本文主要记录其神经网络的原理和用法(参考赵春江的“机器学习经典算法剖析基于opencv”,人民邮电出版社,214-220)

下面就以照片的方式贴出其原理:
在这里插入图片描述在这里插入图片描述

OpenCV的人工神经网络是机器学习算法中的其中一种,使用的是多层感知器(Multi- Layer Perception,MLP),是常见的一种ANN算法。MLP算法一般包括三层,分别是一个输入层,一个输出层和一个或多个隐藏层的神经网络组成。每一层由一个或多个神经元互相连结。一个“神经元”的输出便是另一个“神经元”的输入。
OpenCV中的神经网络的训练,需要创建两个数据矩阵,一个是特征数据矩阵,一个是标签矩阵。但要注意的是标签矩阵是一个N*M的矩阵,N表示训练样本数,M是类标签。如果第i行的样本属于第j类,那么该标签矩阵的(i,j)位置为1。 OpenCV中ANN定义了CvANN_MLP类。使用ANN算法之前,必须先初始化参数,比如神经网络的层数、神经元数,激励函数、α和β。然后使用train函数进行训练,训练完成可以训练好的参数以xml的格式保存在本地文件夹。最后就可以使用predict函数来预测测试集。

如何利用opencv的神经网络api呢,很简单,可以看其官网或者按照下面的例子进行实践。
这个例子是人脸贴图利用opencv神经网络对脸部区域的位置和脸部器官位置信息进行训练,然后达到检测到脸部后通过神经网络即可定位相关器官。(这样免去了各个器官的检测,器官定位更快速)

代码说明:

先进行脸部、眼部、鼻子、嘴巴的检测(opencv提供的haar特征分类器)
都检测到后每帧的四个Rect信息存在一个文件中
读取该文件,face Rect 作为输入,其他作为输出,进行训练

源码:

#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/ml/ml.hpp>  
#include <iostream>   
#include <fstream>
#include<string>
using namespace std;
using namespace cv;

//从眼部得到全脸  Mat eyesdata(Mat_<float>(1,3) << eyesRect.x,eyesRect.y,eyesRect.width)
cv::Mat  getFace_Bpnet(char *bpxml,cv::Mat eyesdata)
{
   CvANN_MLP bp; //bp网络
   bp.load(bpxml);//读取模型
   Mat facedata; //一组预测结果  facedata(1, 3,CV_32FC1)(Mat_<int>(1, 3) << 3,18,3)
   bp.predict(eyesdata, facedata);
   return facedata;
}

int test_cvNNapi(int group_data,int cmd)
{
    CvANN_MLP bp; //bp网络
    string datafile = "/home/jiang/Repositories/FaceDeal_Class/train_data/mydata.txt";
    string testfile = "/home/jiang/Repositories/FaceDeal_Class/train_data/testdata.txt";
    string resultfile = "/home/jiang/Repositories/FaceDeal_Class/train_data/resultfile.txt";
    char buffer[50];
    if(cmd == 1)
    {                      // trainning
        int *IN_data = new int[3];
        int *OUT_data = new int[3];
        //建立一个标签矩阵
        Mat labelsMat(group_data, 3, CV_32FC1);
        //建立一个训练样本矩阵
        Mat trainingDataMat(group_data, 3, CV_32FC1);           // cols = 3 ; rows = group_data  at(y,x)

        fstream ifile;
        int count_hang = 0;
        ifile.open(datafile,ios::in);
        for(int i=0;i<group_data;i++)
        {
            //每行格式          ,101,22,333,120,333,12,
            ifile.getline(buffer, 50, '\n');     //getline(char *,int,char) 表示该行字符达到 50 个或遇到换行就结束;
            int num_count = -1;
            for(int j = 0; j < 50; ){
                if(num_count >=5 )
                    break;
                else if(buffer[j] == ','){
                    num_count++;
                    if(num_count < 3){
                        if(buffer[j+4] == ','){
                            IN_data[num_count] = (buffer[j+1] - '0')*100 + (buffer[j+2] - '0')*10 + (buffer[j+3] - '0')*1;
                            j = j+4;
                        }

                        else if (buffer[j+3] == ','){
                            IN_data[num_count] = (buffer[j+1] - '0')*10 + (buffer[j+2] - '0')*1;
                            j = j+3;
                        }

                        else if(buffer[j+2] == ','){
                            IN_data[num_count] = (buffer[j+1] - '0')*1;
                            j = j+2;
                        }
                        else
                            break;
                    }
                    else {
                        if(buffer[j+4] == ','){
                            OUT_data[num_count-3] = (buffer[j+1] - '0')*100 + (buffer[j+2] - '0')*10 + (buffer[j+3] - '0')*1;
                            j = j+4;
                        }

                        else if (buffer[j+3] == ','){
                            OUT_data[num_count-3] = (buffer[j+1] - '0')*10 + (buffer[j+2] - '0')*1;
                            j = j+3;
                        }

                        else if(buffer[j+2] == ','){
                            OUT_data[num_count-3] = (buffer[j+1] - '0')*1;
                            j = j+2;
                        }
                        else
                            break;
                    }
                }
            }
            cout << count_hang++ <<endl;
            cout << IN_data[0] << ","<< IN_data[1] << ","<< IN_data[2] << " ; "<< OUT_data[0] << ","<< OUT_data[1] << ","<< OUT_data[2] << endl;
            //以上得出一行的数据
            for(int k = 0;k < 3;k ++){
                labelsMat.at<float>(i,k) = OUT_data[k];                            //at (y,x)
                trainingDataMat.at<float>(i,k) = IN_data[k];
            }
        }
        cout << labelsMat <<endl;

        ifile.close();
        cout << "训练中..."<<endl;
    //    cout << labelsMat <<endl;
    //    cout << trainingDataMat <<endl;

        /*定义神经网络及参数*/
        //CvANN_MLP bp; //bp网络
        CvANN_MLP_TrainParams params; //bp网络参数
        params.train_method = CvANN_MLP_TrainParams::BACKPROP;		//使用简单的BP算法,还可使用RPROP
        /*BACKPROP表示使用back-propagation的训练方法,使用BACKPROP有两个相关参数:bp_dw-scale,bp_moment_scale
          RPROP即最简单的propagation训练方法,使用PRPOP有四个相关参数:rp_dw0,rp-dw_plus,rp_dw_minus,rp_dw_min,rp_dw_max
         一个是权值更新率bp_dw_scale和权值更新冲量bp_moment_scale。
         这两个量一般情况设置为0.1就行了;太小了网络收敛速度会很慢,太大了可能会让网络越过最小值点
        */
        params.bp_dw_scale = 0.1;
        params.bp_moment_scale = 0.1;
        //params.term_crit=cvTermCriteria(CV_TerMCrIT_ITER+CV_TERMCRIT_EPS,5000,0.01);

        /*设置网络层数,训练数据*/
        Mat layerSizes = (Mat_<int>(1, 3) << 3,18,3);//含有两个隐含层的网络结构,输入、输出层各3个节点
        /*layerSizes设置了有两个隐含层的网络结构:输入层,两个隐含层,输出层。输入层和输出层节点数均为2,中间隐含层每层有两个节点
          create第二个参数可以设置每个神经节点的激活函数,默认为CvANN_MLP::SIGMOID_SYM
        */
        bp.create(layerSizes, CvANN_MLP::SIGMOID_SYM);//激活函数为SIGMOID函数,还可使用高斯函数(CvANN_MLP::GAUSSIAN),阶跃函数(CvANN_MLP::IDENTITY)
        bp.train(trainingDataMat, labelsMat, Mat(), Mat(), params);//训练的接口train()

        bp.save("bp.xml");//存储模型

        cout << "训练完成!"<<endl;
        delete [] IN_data;
        delete [] OUT_data;

    }
    else
    {
        bp.load("bp.xml");//读取模型
        cout << "下载完成!开始测试!"<<endl;
        //	/*使用训练好的网络结构分类新的数据*/
        Mat sampleMat(1, 3,CV_32FC1); //一组测试数据
        Mat stdresultMat(1, 3,CV_32FC1); //一组测试数据
        Mat responseMat; //一组预测结果
        fstream ifile2,ofile;
        ifile2.open(testfile,ios::in);
        ofile.open(resultfile,ios::out);
        float err[3] = {0,0,0};
        float errerr = 0;
        float sum_err = 0.0;
        //100组数据测试
        for(int i=0;i<100;i++)
        {
            //每行格式          ,101,22,333,120,333,12,
            ifile2.getline(buffer, 50, '\n');     //getline(char *,int,char) 表示该行字符达到 50 个或遇到换行就结束;
            int num1_count = -1;
            for(int j = 0; j < 50; ){
                if(num1_count >=5 )
                    break;
                else if(buffer[j] == ','){
                    num1_count++;
                    if(num1_count < 3){
                        if(buffer[j+4] == ','){
                            sampleMat.at<float>(0,num1_count) = (buffer[j+1] - '0')*100 + (buffer[j+2] - '0')*10 + (buffer[j+3] - '0')*1;
                            j = j+4;
                        }

                        else if (buffer[j+3] == ','){
                            sampleMat.at<float>(0,num1_count) = (buffer[j+1] - '0')*10 + (buffer[j+2] - '0')*1;
                            j = j+3;
                        }

                        else if(buffer[j+2] == ','){
                            sampleMat.at<float>(0,num1_count) = (buffer[j+1] - '0')*1;
                            j = j+2;
                        }
                        else
                            break;
                    }
                    else {
                        if(buffer[j+4] == ','){
                            stdresultMat.at<float>(0,num1_count-3) = (buffer[j+1] - '0')*100 + (buffer[j+2] - '0')*10 + (buffer[j+3] - '0')*1;
                            j = j+4;
                        }

                        else if (buffer[j+3] == ','){
                            stdresultMat.at<float>(0,num1_count-3) = (buffer[j+1] - '0')*10 + (buffer[j+2] - '0')*1;
                            j = j+3;
                        }

                        else if(buffer[j+2] == ','){
                            stdresultMat.at<float>(0,num1_count-3) = (buffer[j+1] - '0')*1;
                            j = j+2;
                        }
                        else
                            break;
                    }
                }
            }
            cout<<  sampleMat << "    "<< stdresultMat <<endl;
            bp.predict(sampleMat, responseMat);
            cout<< responseMat <<endl;
            cout << "第 " << i << " 组:误差:";
            for(int k=0;k<3;k++){
                err[k] = responseMat.at<float>(0,k) - stdresultMat.at<float>(0,k);
                ofile << responseMat.at<float>(0,k) <<","<<stdresultMat.at<float>(0,k)<<";";
                cout <<err[k]<< " ";
                errerr += err[k]*err[k];  //方差
                errerr /= 3;
            }
            cout <<"                        "<<errerr<<endl;
            ofile << endl;
            sum_err += errerr;
            errerr = 0.0;
        }
        cout << "sum_err = "<<sum_err <<"  arr_err ="<<sum_err/100<<endl;
        ofile.close();
        ifile2.close();
    }
    return 0;
}


//cmd : 
//g++ `pkg-config --cflags opencv` -o Cv_NNapi Cv_NNapi.cpp `pkg-config --libs opencv`

BP神经网络参考的这个文章!
也附上参考该文然后推导一遍后写的bp神经网络吧,用的鸢尾花数据集。测试好后,我是移植到了stm32f405上,进行其他的训练,但找不到源文件了。区别是利用了硬件上的dsp模块进行加速运算,也就是把运算符改成其dsp等效的运算式。
源代码(c code)
源文件:

#include "DL_bpnet.h"
#include "sample.h"

double _m_w_rate ;//输入层-隐含层权值学习率
double _o_w_rate ;//隐含层-网络层权学习率
double _m_t_rate ;//输入层-隐含层阈值学习率
double _o_t_rate ;//隐含层-网络层阈值学习率
int _it_nums ;//迭代次数
double _err ;//误差限

double _m_threshold[MidLayerNodesNum];//输入层-隐含层阈值
double _o_threshold[OutLayerNodesNum];//隐含层-网络层阈值
double _m_weight[InLayerNodesNum][MidLayerNodesNum];//输入层-隐含层权值
double _o_weight[MidLayerNodesNum][OutLayerNodesNum];//隐含层-网络层权值
double _mint, _maxt;
	
	const int N = 120;
	const int n = 30;

	double a[N][InLayerNodesNum];
	double a2[n][InLayerNodesNum];
	double b[N][OutLayerNodesNum];
	double b2[n][OutLayerNodesNum];
	double result[1][1];
	
void	DL_bpnet(void)
{


	int i_1 = 0, i_2 = 0;

	for (int count = 1; count < 4; count++)
	{

		for (int i = 50 * (count - 1); i < (50 * count - 10); i++) {
			for (int j = 0; j < 4; j++) {
				a[i_1][j] = Iris_Flowers[i][j];

			}
			b[i_1][0] = Iris_Flowers[i][4];
		
			i_1++;
		}
		for (int i = (50 * count - 10); i < 50 * count; i++) {
			for (int j = 0; j < 4; j++) {
				a2[i_2][j] = Iris_Flowers[i][j];
			}
			i_2++;
		}
	}

	double test[1][4] = { 6.4, 2.9, 5.9, 1.8 }; //6.5, 3.0, 5.2, 2.0


	BpNet_Init();
	BPtrain(a, b, N);
	BPsim(a2, b2, n);
	BPsim(test, result, 1);
}


void normalize(double **t, int size)
	{//归一化处理
		_mint = 0x7FFFFFFF;//这里利用了“魔数”进行处理,不是最好的方法
		_maxt = -0x7FFFFFFF;

		//找到最大和最小值
		for (int i = 0; i<size; ++i)
		{
			for (int j = 0; j<OutLayerNodesNum; ++j)
			{
				if (_mint>t[i][j])
					_mint = t[i][j];
				if (_maxt<t[i][j])
					_maxt = t[i][j];
			}
		}

		if (_mint == _maxt)
			_mint = 0;

		double range = _maxt - _mint;

		//归一化
		//找到最大和最小值
		for (int i = 0; i<size; ++i)
		{
			for (int j = 0; j < OutLayerNodesNum; ++j)
				t[i][j] = (t[i][j] - _mint) / range;
		}
}

void unnormalize(double **t, int size)
{//反归一化处理
		double range = _maxt - _mint;

		//归一化
		//找到最大和最小值
		for (int i = 0; i<size; ++i)
		{
			for (int j = 0; j<OutLayerNodesNum; ++j)
				t[i][j] = t[i][j] * range + _mint;
		}
	}

void BpNet_Init(void)
{
		_m_w_rate = 0.5;//输入层-隐含层权值学习率
		_o_w_rate = 0.5;//隐含层-网络层权值学习率
		_m_t_rate = 0.5;//输入层-隐含层权值学习率
		_o_t_rate = 0.5;//隐含层-网络层权值学习率

		_it_nums = 10000;//迭代次数
		_err = 0.01;//误差限  0.00001

		Get_Random(500);			      
		srand(rand_seed); //初始化成随机数
		
		for (int i = 0; i<InLayerNodesNum; ++i)
		{
			for (int j = 0; j<MidLayerNodesNum; ++j)
				_m_weight[i][j] = (2.0*(double)rand() / RAND_MAX) - 1;
		}

		for (int i = 0; i<MidLayerNodesNum; ++i)
		{
			for (int j = 0; j<OutLayerNodesNum; ++j)
				_o_weight[i][j] = (2.0*(double)rand() / RAND_MAX) - 1;
		}
		for (int i = 0; i<MidLayerNodesNum; ++i)
			_m_threshold[i] = (2.0*(double)rand() / RAND_MAX) - 1;
		for (int i = 0; i<OutLayerNodesNum; ++i)
			_o_threshold[i] = (2.0*(double)rand() / RAND_MAX) - 1;

}

int BPtrain(double(*p)[InLayerNodesNum],double(*t)[OutLayerNodesNum], int size)
{//
		double o1[MidLayerNodesNum];
		double o2[OutLayerNodesNum];
		double error1[MidLayerNodesNum];
		double error2[OutLayerNodesNum];
		double max_error = 0;//记录最大误差
    //动态内存
		double *perr = (double *)malloc(size * sizeof(double));
		double **t_temp = (double **)malloc(size * sizeof(double));
		
		for (int i = 0; i<size; ++i)
		{
			t_temp[i] = (double *)malloc(OutLayerNodesNum * sizeof(double));
			for (int j = 0; j < OutLayerNodesNum; ++j)
				t_temp[i][j] = t[i][j];
		}

		normalize(t_temp, size);//归一化处理

		int i = 0;
		for (; i<_it_nums; ++i)
		{
			for (int j = 0; j<size; ++j)
			{
				//正向传播
				//计算隐含层输出
				for (int k = 0; k<MidLayerNodesNum; ++k)
				{
					o1[k] = _m_weight[0][k] * p[j][0];
					for (int m = 1; m<InLayerNodesNum; ++m)
						o1[k] += _m_weight[m][k] * p[j][m];
					//激励函数
					o1[k] = 1.0 / (1 + exp(-o1[k] - _m_threshold[k]));//隐含层各单元的输出
				}
				//计算输出层输出
				for (int k = 0; k<OutLayerNodesNum; ++k)
				{
					o2[k] = _o_weight[0][k] * o1[0];
					for (int m = 1; m<MidLayerNodesNum; ++m)
						o2[k] += _o_weight[m][k] * o1[m];
					//激励函数
					o2[k] = 1.0 / (1 + exp(-o2[k] - _o_threshold[k]));//隐含层各单元的输出 
				}

				//反向传播
				for (int k = 0; k<OutLayerNodesNum; ++k)
				{
					//计算输出层误差
					error2[k] = (t_temp[j][k] - o2[k])*o2[k] * (1 - o2[k]);
					//调整权值
					for (int m = 0; m<MidLayerNodesNum; ++m)
						_o_weight[m][k] += _o_w_rate * error2[k] * o1[m];
				}

				for (int k = 0; k<MidLayerNodesNum; ++k)
				{
					//计算隐含层误差
					double d = 0;
					for (int m = 0; m<OutLayerNodesNum; ++m)
						d += error2[m] * _o_weight[k][m];
					//调整权值
					error1[k] = d * o1[k] * (1 - o1[k]);

					for (int m = 0; m<InLayerNodesNum; ++m)
						_m_weight[m][k] += _m_w_rate * error1[k] * p[j][m];
				}

				double e = 0;
				for (int k = 0; k<OutLayerNodesNum; ++k)
					e += fabs(t_temp[j][k] - o2[k])*fabs(t_temp[j][k] - o2[k]);

				perr[j] = e / 2;
				//更新阈值
				for (int k = 0; k<OutLayerNodesNum; k++)
					_o_threshold[k] += _o_t_rate * error2[k]; //下一次的隐含层和输出层之间的新阈值  
				for (int k = 0; k<MidLayerNodesNum; k++)
					_m_threshold[k] += _m_t_rate * error1[k]; //下一次的输入层和隐含层之间的新阈值  
			}

			max_error = perr[0];
			for (int j = 1; j<size; ++j)
				if (perr[j]>max_error)
					max_error = perr[j];
			if (max_error<_err)
			{ 
//				printf("次数:%d\n",i);
				break;
			}
		}
		free(perr);
		for (int i = 0; i < size; ++i)
			free(t_temp[i]);
		free(t_temp);     //内存释放
	
		
		if (i >= _it_nums)
			return 0;
		return 1;
}

int BPsim(double(*p)[InLayerNodesNum], double(*t)[OutLayerNodesNum], int size)
{//
	
		double o1[MidLayerNodesNum];

		double **t_temp = (double **)malloc(size * sizeof(double));//保存t的数据
		for (int i = 0; i < size; ++i)
			t_temp[i] = (double *)malloc(OutLayerNodesNum * sizeof(double));

		for (int i = 0; i < size; ++i)
		{
			//正向传播
			//计算隐含层输出
			for (int k = 0; k < MidLayerNodesNum; ++k)
			{
				o1[k] = _m_weight[0][k] * p[i][0];
				for (int m = 1; m < InLayerNodesNum; ++m)
					o1[k] += _m_weight[m][k] * p[i][m];
				o1[k] = 1.0 / (1.0 + exp(-o1[k] - _m_threshold[k]));//隐含层各单元的输出 
			}
			//计算输出层输出
			for (int k = 0; k < OutLayerNodesNum; ++k)
			{
				t_temp[i][k] = _o_weight[0][k] * o1[0];
				for (int m = 1; m < MidLayerNodesNum; ++m)
					t_temp[i][k] += _o_weight[m][k] * o1[m];
				t_temp[i][k] = 1.0 / (1.0 + exp(-t_temp[i][k] - _o_threshold[k]));//隐含层各单元的输出 
			}
		}
		unnormalize(t_temp, size);         //反归一化
		for (int i = 0; i<size; ++i)
			for (int j = 0; j < OutLayerNodesNum; ++j) {
				t[i][j] = t_temp[i][j];
			}
		for (int i = 0; i < size; ++i)
			free(t_temp[i]);	
		free(t_temp);                           //内存释放
		return 1;
}


头文件:

/**
  ******************************************************************************
  * File Name          : DL_bpbet.h
  * Description        : use bpnet to train and sim 
  * Data               : 2018/4/23
	* Hardward           : 
	* Important functions {  BpNet_Init()    
                           BPtrain(a,b,c)  "a" defined a[训练/预测数据数量][输入维度]
	                         BPsim(a,b,c)    "b" defined b[训练/预测数据数量][输出维度] 
	                                         "c" 训练/预测数据数量
                	      }
	*****************************************************************************
	*/

//#include <ctime>
//#include <cmath>
//#include <cstdlib>
//#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "HW_adc.h"                //用来采集随机数

#include "arm_math.h"          //dsp

extern int rand_seed;    //产生的随机值

#define InLayerNodesNum    4//输入层节点数
#define MidLayerNodesNum   6//隐层节点数
#define OutLayerNodesNum   1


void normalize(double **t, int size);
	
void unnormalize(double **t, int size);

void BpNet_Init(void);
	

int BPtrain(double(*p)[InLayerNodesNum],  double(*t)[OutLayerNodesNum], int size);

int BPsim(double(*p)[InLayerNodesNum], double(*t)[OutLayerNodesNum], int size);
	

测试集文件(鸢尾花数据集)

#define Iris 1
#define setosa 0.9,
#define versicolor 0.8,
#define virginica 0.7,
double Iris_Flowers[150][5] = 
{
5.1, 3.5, 1.4, 0.2, Iris - setosa
4.9, 3.0, 1.4, 0.2, Iris - setosa
4.7, 3.2, 1.3, 0.2, Iris - setosa
4.6, 3.1, 1.5, 0.2, Iris - setosa
5.0, 3.6, 1.4, 0.2, Iris - setosa
5.4, 3.9, 1.7, 0.4, Iris - setosa
4.6, 3.4, 1.4, 0.3, Iris - setosa
5.0, 3.4, 1.5, 0.2, Iris - setosa
4.4, 2.9, 1.4, 0.2, Iris - setosa
4.9, 3.1, 1.5, 0.1, Iris - setosa
5.4, 3.7, 1.5, 0.2, Iris - setosa
4.8, 3.4, 1.6, 0.2, Iris - setosa
4.8, 3.0, 1.4, 0.1, Iris - setosa
4.3, 3.0, 1.1, 0.1, Iris - setosa
5.8, 4.0, 1.2, 0.2, Iris - setosa
5.7, 4.4, 1.5, 0.4, Iris - setosa
5.4, 3.9, 1.3, 0.4, Iris - setosa
5.1, 3.5, 1.4, 0.3, Iris - setosa
5.7, 3.8, 1.7, 0.3, Iris - setosa
5.1, 3.8, 1.5, 0.3, Iris - setosa
5.4, 3.4, 1.7, 0.2, Iris - setosa
5.1, 3.7, 1.5, 0.4, Iris - setosa
4.6, 3.6, 1.0, 0.2, Iris - setosa
5.1, 3.3, 1.7, 0.5, Iris - setosa
4.8, 3.4, 1.9, 0.2, Iris - setosa
5.0, 3.0, 1.6, 0.2, Iris - setosa
5.0, 3.4, 1.6, 0.4, Iris - setosa
5.2, 3.5, 1.5, 0.2, Iris - setosa
5.2, 3.4, 1.4, 0.2, Iris - setosa
4.7, 3.2, 1.6, 0.2, Iris - setosa
4.8, 3.1, 1.6, 0.2, Iris - setosa
5.4, 3.4, 1.5, 0.4, Iris - setosa
5.2, 4.1, 1.5, 0.1, Iris - setosa
5.5, 4.2, 1.4, 0.2, Iris - setosa
4.9, 3.1, 1.5, 0.1, Iris - setosa
5.0, 3.2, 1.2, 0.2, Iris - setosa
5.5, 3.5, 1.3, 0.2, Iris - setosa
4.9, 3.1, 1.5, 0.1, Iris - setosa
4.4, 3.0, 1.3, 0.2, Iris - setosa
5.1, 3.4, 1.5, 0.2, Iris - setosa
5.0, 3.5, 1.3, 0.3, Iris - setosa
4.5, 2.3, 1.3, 0.3, Iris - setosa
4.4, 3.2, 1.3, 0.2, Iris - setosa
5.0, 3.5, 1.6, 0.6, Iris - setosa
5.1, 3.8, 1.9, 0.4, Iris - setosa
4.8, 3.0, 1.4, 0.3, Iris - setosa
5.1, 3.8, 1.6, 0.2, Iris - setosa
4.6, 3.2, 1.4, 0.2, Iris - setosa
5.3, 3.7, 1.5, 0.2, Iris - setosa
5.0, 3.3, 1.4, 0.2, Iris - setosa
7.0, 3.2, 4.7, 1.4, Iris - versicolor
6.4, 3.2, 4.5, 1.5, Iris - versicolor
6.9, 3.1, 4.9, 1.5, Iris - versicolor
5.5, 2.3, 4.0, 1.3, Iris - versicolor
6.5, 2.8, 4.6, 1.5, Iris - versicolor
5.7, 2.8, 4.5, 1.3, Iris - versicolor
6.3, 3.3, 4.7, 1.6, Iris - versicolor
4.9, 2.4, 3.3, 1.0, Iris - versicolor
6.6, 2.9, 4.6, 1.3, Iris - versicolor
5.2, 2.7, 3.9, 1.4, Iris - versicolor
5.0, 2.0, 3.5, 1.0, Iris - versicolor
5.9, 3.0, 4.2, 1.5, Iris - versicolor
6.0, 2.2, 4.0, 1.0, Iris - versicolor
6.1, 2.9, 4.7, 1.4, Iris - versicolor
5.6, 2.9, 3.6, 1.3, Iris - versicolor
6.7, 3.1, 4.4, 1.4, Iris - versicolor
5.6, 3.0, 4.5, 1.5, Iris - versicolor
5.8, 2.7, 4.1, 1.0, Iris - versicolor
6.2, 2.2, 4.5, 1.5, Iris - versicolor
5.6, 2.5, 3.9, 1.1, Iris - versicolor
5.9, 3.2, 4.8, 1.8, Iris - versicolor
6.1, 2.8, 4.0, 1.3, Iris - versicolor
6.3, 2.5, 4.9, 1.5, Iris - versicolor
6.1, 2.8, 4.7, 1.2, Iris - versicolor
6.4, 2.9, 4.3, 1.3, Iris - versicolor
6.6, 3.0, 4.4, 1.4, Iris - versicolor
6.8, 2.8, 4.8, 1.4, Iris - versicolor
6.7, 3.0, 5.0, 1.7, Iris - versicolor
6.0, 2.9, 4.5, 1.5, Iris - versicolor
5.7, 2.6, 3.5, 1.0, Iris - versicolor
5.5, 2.4, 3.8, 1.1, Iris - versicolor
5.5, 2.4, 3.7, 1.0, Iris - versicolor
5.8, 2.7, 3.9, 1.2, Iris - versicolor
6.0, 2.7, 5.1, 1.6, Iris - versicolor
5.4, 3.0, 4.5, 1.5, Iris - versicolor
6.0, 3.4, 4.5, 1.6, Iris - versicolor
6.7, 3.1, 4.7, 1.5, Iris - versicolor
6.3, 2.3, 4.4, 1.3, Iris - versicolor
5.6, 3.0, 4.1, 1.3, Iris - versicolor
5.5, 2.5, 4.0, 1.3, Iris - versicolor
5.5, 2.6, 4.4, 1.2, Iris - versicolor
6.1, 3.0, 4.6, 1.4, Iris - versicolor
5.8, 2.6, 4.0, 1.2, Iris - versicolor
5.0, 2.3, 3.3, 1.0, Iris - versicolor
5.6, 2.7, 4.2, 1.3, Iris - versicolor
5.7, 3.0, 4.2, 1.2, Iris - versicolor
5.7, 2.9, 4.2, 1.3, Iris - versicolor
6.2, 2.9, 4.3, 1.3, Iris - versicolor
5.1, 2.5, 3.0, 1.1, Iris - versicolor
5.7, 2.8, 4.1, 1.3, Iris - versicolor
6.3, 3.3, 6.0, 2.5, Iris - virginica
5.8, 2.7, 5.1, 1.9, Iris - virginica
7.1, 3.0, 5.9, 2.1, Iris - virginica
6.3, 2.9, 5.6, 1.8, Iris - virginica
6.5, 3.0, 5.8, 2.2, Iris - virginica
7.6, 3.0, 6.6, 2.1, Iris - virginica
4.9, 2.5, 4.5, 1.7, Iris - virginica
7.3, 2.9, 6.3, 1.8, Iris - virginica
6.7, 2.5, 5.8, 1.8, Iris - virginica
7.2, 3.6, 6.1, 2.5, Iris - virginica
6.5, 3.2, 5.1, 2.0, Iris - virginica
6.4, 2.7, 5.3, 1.9, Iris - virginica
6.8, 3.0, 5.5, 2.1, Iris - virginica
5.7, 2.5, 5.0, 2.0, Iris - virginica
5.8, 2.8, 5.1, 2.4, Iris - virginica
6.4, 3.2, 5.3, 2.3, Iris - virginica
6.5, 3.0, 5.5, 1.8, Iris - virginica
7.7, 3.8, 6.7, 2.2, Iris - virginica
7.7, 2.6, 6.9, 2.3, Iris - virginica
6.0, 2.2, 5.0, 1.5, Iris - virginica
6.9, 3.2, 5.7, 2.3, Iris - virginica
5.6, 2.8, 4.9, 2.0, Iris - virginica
7.7, 2.8, 6.7, 2.0, Iris - virginica
6.3, 2.7, 4.9, 1.8, Iris - virginica
6.7, 3.3, 5.7, 2.1, Iris - virginica
7.2, 3.2, 6.0, 1.8, Iris - virginica
6.2, 2.8, 4.8, 1.8, Iris - virginica
6.1, 3.0, 4.9, 1.8, Iris - virginica
6.4, 2.8, 5.6, 2.1, Iris - virginica
7.2, 3.0, 5.8, 1.6, Iris - virginica
7.4, 2.8, 6.1, 1.9, Iris - virginica
7.9, 3.8, 6.4, 2.0, Iris - virginica
6.4, 2.8, 5.6, 2.2, Iris - virginica
6.3, 2.8, 5.1, 1.5, Iris - virginica
6.1, 2.6, 5.6, 1.4, Iris - virginica
7.7, 3.0, 6.1, 2.3, Iris - virginica
6.3, 3.4, 5.6, 2.4, Iris - virginica
6.4, 3.1, 5.5, 1.8, Iris - virginica
6.0, 3.0, 4.8, 1.8, Iris - virginica
6.9, 3.1, 5.4, 2.1, Iris - virginica
6.7, 3.1, 5.6, 2.4, Iris - virginica
6.9, 3.1, 5.1, 2.3, Iris - virginica
5.8, 2.7, 5.1, 1.9, Iris - virginica
6.8, 3.2, 5.9, 2.3, Iris - virginica
6.7, 3.3, 5.7, 2.5, Iris - virginica
6.7, 3.0, 5.2, 2.3, Iris - virginica
6.3, 2.5, 5.0, 1.9, Iris - virginica
6.5, 3.0, 5.2, 2.0, Iris - virginica
6.2, 3.4, 5.4, 2.3, Iris - virginica
5.9, 3.0, 5.1, 1.8, Iris - virginica
};
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐