人工智能实战——人工神经网络(C库iOS交叉编译)

Posted 宇仔TuT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了人工智能实战——人工神经网络(C库iOS交叉编译)相关的知识,希望对你有一定的参考价值。

人工智能实战——人工神经网络
给最近人工智能辣摸火,让我忍不住也想一探究竟,首先从目前来讲我是一个人工智能领域的门外汉,尽管恶补了几天基本知识,机器学习算法看得差不多,神马线性回归啊,逻辑回归啊,SVM啊,k临近算法啊,决策树啊,随机森林啊,看的我吐血了,不过也不难理解,然后尝试着用一套开源代码FANN(c语言跨平台库)编译到ios写一个简单的小机器人

首先是准备工作,把FANN2.2.0的源代码编译成ios 64bit 模拟器的dylib库,其过程不聊了,用到了cmake...等等...

拿到dylib文件后,再拷贝所有的.h到项目中,配置好头文件搜索路径,import一下“fann.h”  编译一下,成功的话 就可以开始写我的小机器人了~~起个名字:小歪
 
技术分享

竟然一次性编译成功,模拟器跑起来了,不过什么代码也没写,先不激动,先写好工具类嘛。
先new一个工具类,用来初始化和保存大脑,并且还要能够训练,执行

//

//  XYRobotManager.h

//  小歪

//

//  Created by reese on 16/3/21.

//  Copyright © 2016 com.ifenduo. All rights reserved.

//


#import <Foundation/Foundation.h>

#include "fann.h"


@interface XYRobotManager : NSObject



//神经网络层数

@property (nonatomicint neuralLayerNumber;


//隐藏神经元个数 (中间层)

@property (nonatomicint hiddenNeuralNumber;


//输入原件个数

@property (nonatomicint inputNum;


//输出原件个数

@property (nonatomicint outputNum;


//预期错误均方差

@property (nonatomicfloat desiredError;


//训练数据存储路径

@property (nonatomicNSString* trainDataPath;


//神经网络保存路径

@property (nonatomicNSString* networkSavingPath;

 

//单例获取

+ (instancetype)sharedManager;


//创建大脑

- (void)createBrain;


//保存大脑

- (void)saveBrain;


//训练

- (void)trainInputDatas:(fann_type *)inputData outputDatas:(fann_type *)outputData dataCount:(int)dataCount;


//执行

- (NSArray *)runInputDatas:(fann_type *)inputData;

 

这里关于NN的配置没有写死,也就是说具体使用的时候是要能修改滴。默认情况下呢,在单例构造完之后设置一下这些配置参数的默认值:

//

//  XYRobotManager.m

//  小歪

//

//  Created by reese on 16/3/21.

//  Copyright © 2016 com.ifenduo. All rights reserved.

//


#import "XYRobotManager.h"


@implementation XYRobotManager
 

//静态c指针 神经网络对象

static struct fann *ann;


+ (instancetype)sharedManager {

    static XYRobotManager *_inst;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        _inst = [XYRobotManager new];

        

        //配置神经网络初始参数

        [_inst initConfig];

    });

    return _inst;

}


- (void)initConfig {

    //3层神经元

    _neuralLayerNumber = 3;

    

    //96个内部神经元

    _hiddenNeuralNumber = 96;

    

    //2个输入

    _inputNum = 2;

    

    //1个输出

    _outputNum = 1;

    

    //预期错误均方差

    _desiredError = 0.01;


    //训练数据保存路径

    _trainDataPath = [[XYRobotManager dataPathstringByAppendingPathComponent:@"train.data"];

    

    //大脑保存路径

    _networkSavingPath = [[XYRobotManager dataPath]stringByAppendingPathComponent:@"brain.net"];

    

    

}


+ (NSString *)cachePath {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectoryNSUserDomainMask,YES);

    

    NSString *documentsDirectory = [paths objectAtIndex:0];

    

    NSString *cacheFolder = [documentsDirectory stringByAppendingPathComponent:@"XYRobot"];

    

    if (![[NSFileManager defaultManagerfileExistsAtPath:cacheFolder]) {

        //如果不存在该文件夹 新建

        [[NSFileManager defaultManagercreateDirectoryAtPath:cacheFolderwithIntermediateDirectories:YES attributes:nil error:nil];

    }

    return cacheFolder;

}


+ (NSString *)dataPath {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectoryNSUserDomainMask,YES);

    

    NSString *documentsDirectory = [paths objectAtIndex:0];

    

    NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"XYRobot"];

    

    if (![[NSFileManager defaultManagerfileExistsAtPath:dataPath]) {

        //如果不存在该文件夹 新建

        [[NSFileManager defaultManagercreateDirectoryAtPath:dataPathwithIntermediateDirectories:YES attributes:nil error:nil];

    }

    return dataPath;

}

 
如果不知道这些参数的意义,说下,默认情况下这个机器人拥有2个输入元件(输入层用来感知环境,好比人的听觉触觉嗅觉)和一个输出元件(表达层用来反馈环境,比如说话),这些元件的输入可以是任意的float数,中间层有96个逻辑组件,相当于一堆神经元,以及各自的连接弧,第一层神经元每个组件的输入是所有连接到这个元件的输入元件的值*权重之和(就叫加权输入/输出吧),下层神经元中组件的加权输出会作为直接连接的上层神经元对应组件的加权输入,最后一层神经元的加权输出会作为表达层每个元件的加权输入…………不过如果不知道神马是NN的话,估计我说了也白说^^

配置好以后得初始化 ,我已经声明好了ann这样一个c指针,可以认为他是一个对象,所以在使用这个工具类之前必须要调用创建大脑方法,否则ann是一个空指针。

创建大脑的方法:


- (void)createBrain {

    NSLog(@"初始化神经网络");

    

    //如果之前保存过,从文件读取

    if ([[NSFileManager defaultManagerfileExistsAtPath:_networkSavingPath]) {

        ann = fann_create_from_file([_networkSavingPathcStringUsingEncoding:NSUTF8StringEncoding]);

    } else {

    

        //创建标准神经网络,配置好对应的参数

        ann =fann_create_standard(_neuralLayerNumber,_inputNum,_hiddenNeuralNumber,_outputNum);

        //给所有元件初始权重(-1~1间的随机值)

        fann_randomize_weights(ann, -1, 1);

        //设置中间层的激活坡度(0~1之间)

        fann_set_activation_steepness_hidden(ann, 1);

        //设置输出层的激活坡度(0~1之间)

        fann_set_activation_steepness_output(ann, 1);

        

        //设置激活函数(激活函数有很多种,具体每一种的效果还没去试)

        fann_set_activation_function_hidden(annFANN_SIGMOID_SYMMETRIC);

        fann_set_activation_function_output(annFANN_SIGMOID_SYMMETRIC);

    }

    

    

}



以及保存大脑的方法(总不能关闭app之后再打开,机器人变了一个"人"对吧)

- (void)saveBrain {

    fann_save(ann, [_networkSavingPath cStringUsingEncoding:NSUTF8StringEncoding]);

}

 接下来要开始训练了,如果不训练的话,这个机器人的输出是随机的。训练过程,这里相当于是监督式学习,是机器学习必不可少的一个阶段,必须要有训练数据才能合理分配每一个神经元/输入组件的权重。
 也就是说我们假设一个目标函数 y = x1 == x2 
这个目标函数符合这个程序的默认设定-->2个输入信号,一个输出信号,实际上就是最简单的让这堆神经元自己去学如何判断两个数相等啊,我们在代码里面绝对没有告诉他,x1==x2,让他自己总结出规律来给出正确的Y

由于输出组件的值域为[-1,1],因此我们通常用来表示概率,或者用于分类(识别)

输出信号在初始状态下得到的是随机的,因为权重是随机分配的,辣么我们得告诉他正确的答案。告诉他一组正确答案,他就得重新调校自己各个组件的权重,最终达到接近于全等运算的过程。也就是函数逼近y‘ = x1 ? x2 ,?就相当于机器人自己总结出来的规律,函数y‘在训练集无穷大的时候无限逼近原始目标函数y= x1 == x2, 这个过程在统计学中叫做拟合。

训练函数如下,前面说了机器学习需要监督式学习,训练的结果需要在训练过程中给出,因此这个函数既有输入也有输出,输出是我们告诉他应该输出的值,如果这个值和他当前的凭感觉输出差太远,则需要不停地训练,一直到拟合我们的输出,当所有元件(专业说法叫选择器)的平均方差值达到我们的预期_desiredError时终止训练:


//inputDataoutputDatasfloat[]类型的数组

- (void)trainInputDatas:(fann_type *)inputData outputDatas:(fann_type *)outputData dataCount:(int)dataCount {

    

    //设置训练算法

    fann_set_training_algorithm(annFANN_TRAIN_RPROP);

    

    //设置终止条件为bit fail

    fann_set_train_stop_function(annFANN_STOPFUNC_BIT);

    

    //设置bit fail limit 即所有训练结果中与预期不符合的个数上限,超出这个上限会一直训练

    fann_set_bit_fail_limit(ann, 1.0f);

以上是关于人工智能实战——人工神经网络(C库iOS交叉编译)的主要内容,如果未能解决你的问题,请参考以下文章

交叉编译适用于 iOS 的 Jansson C 库

人工神经网络之Python 实战

人工智能学习

人工智能——机器学习与深度学习思维导图

如何自学人工智能

[人工智能-深度学习-14]:神经网络基础 - 常见loss损失函数之逻辑分类,对数函数,交叉熵函数