人工智能实战——人工神经网络(C库iOS交叉编译)
Posted 宇仔TuT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了人工智能实战——人工神经网络(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 (nonatomic) int neuralLayerNumber;
//隐藏神经元个数 (中间层)
@property (nonatomic) int hiddenNeuralNumber;
//输入原件个数
@property (nonatomic) int inputNum;
//输出原件个数
@property (nonatomic) int outputNum;
//预期错误均方差
@property (nonatomic) float desiredError;
//训练数据存储路径
@property (nonatomic) NSString* trainDataPath;
//神经网络保存路径
@property (nonatomic) NSString* networkSavingPath;
//单例获取
+ (instancetype)sharedManager;
//创建大脑
- (void)createBrain;
//保存大脑
- (void)saveBrain;
//训练
- (void)trainInputDatas:(fann_type *)inputData outputDatas:(fann_type *)outputData dataCount:(int)dataCount;
//执行
- (NSArray *)runInputDatas:(fann_type *)inputData;
//
// 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 dataPath] stringByAppendingPathComponent:@"train.data"];
//大脑保存路径
_networkSavingPath = [[XYRobotManager dataPath]stringByAppendingPathComponent:@"brain.net"];
}
+ (NSString *)cachePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *cacheFolder = [documentsDirectory stringByAppendingPathComponent:@"XYRobot"];
if (![[NSFileManager defaultManager] fileExistsAtPath:cacheFolder]) {
//如果不存在该文件夹 新建
[[NSFileManager defaultManager] createDirectoryAtPath:cacheFolderwithIntermediateDirectories:YES attributes:nil error:nil];
}
return cacheFolder;
}
+ (NSString *)dataPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"XYRobot"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
//如果不存在该文件夹 新建
[[NSFileManager defaultManager] createDirectoryAtPath:dataPathwithIntermediateDirectories:YES attributes:nil error:nil];
}
return dataPath;
}
配置好以后得初始化 ,我已经声明好了ann这样一个c指针,可以认为他是一个对象,所以在使用这个工具类之前必须要调用创建大脑方法,否则ann是一个空指针。
创建大脑的方法:
- (void)createBrain {
NSLog(@"初始化神经网络");
//如果之前保存过,从文件读取
if ([[NSFileManager defaultManager] fileExistsAtPath:_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(ann, FANN_SIGMOID_SYMMETRIC);
fann_set_activation_function_output(ann, FANN_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时终止训练:
//inputData和outputDatas是float[]类型的数组
- (void)trainInputDatas:(fann_type *)inputData outputDatas:(fann_type *)outputData dataCount:(int)dataCount {
//设置训练算法
fann_set_training_algorithm(ann, FANN_TRAIN_RPROP);
//设置终止条件为bit fail
fann_set_train_stop_function(ann, FANN_STOPFUNC_BIT);
//设置bit fail limit 即所有训练结果中与预期不符合的个数上限,超出这个上限会一直训练
fann_set_bit_fail_limit(ann, 1.0f);
以上是关于人工智能实战——人工神经网络(C库iOS交叉编译)的主要内容,如果未能解决你的问题,请参考以下文章