//
// XYRobotManager.h
// 小歪
//
// Created by reese on 16/3/21.
// Copyright © 2016年 com.ifenduo. All rights reserved.
//
#import
#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;
}
- (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);
}
}
- (void)saveBrain {
fann_save(ann, [_networkSavingPath cStringUsingEncoding:NSUTF8StringEncoding]);
}训练函数如下,前面说了机器学习需要监督式学习,训练的结果需要在训练过程中给出,因此这个函数既有输入也有输出,输出是我们告诉他应该输出的值,如果这个值和他当前的凭感觉输出差太远,则需要不停地训练,一直到拟合我们的输出,当所有元件(专业说法叫选择器)的平均方差值达到我们的预期_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);
//设置训练速度(0~1之间,0为不加速)
fann_set_learning_momentum(ann, 0.4f);
//由当前函数传递的输入生成一个c指针
struct fann_train_data* trainData = fann_create_train_from_callback(dataCount, _inputNum,_outputNum, callback);
trainData->input=&inputData;
trainData->output=&outputData;
//之前是否存储过训练数据,如果有,和现在的合并(merge)
if ([[NSFileManager defaultManager] fileExistsAtPath:_trainDataPath]) {
//已经存储好的训练数据
struct fann_train_data* trainDataSaved = fann_read_train_from_file([_trainDataPathcStringUsingEncoding:NSUTF8StringEncoding]);
//合并
trainData = fann_merge_train_data(trainData, trainDataSaved);
}
//开始训练,最大次数3000次,输出日志间隔:每次都输出 如果不需要重复训练,预期均方差设置为-1即可
fann_train_on_data(ann, trainData, 3000, 1, _desiredError);
//保存训练数据
fann_save_train(trainData, [_trainDataPath cStringUsingEncoding:NSUTF8StringEncoding]);
NSLog(@"训练数据路径%@",_trainDataPath);
}
接下来是执行函数,当我们人为地训练一段时间以后,给一组之前训练中没有训练过的输入,来看他的输出是多少,如果这个神经网络学会了一套规律,那么假设我们给他123 123,他的输出应该是1,假设给他123 100 它的输出应该是0
执行函数:
- (NSArray *)runInputDatas:(fann_type *)inputData {
fann_type* output = fann_run(ann, inputData);
NSMutableArray* array = [NSMutableArray arrayWithCapacity:_outputNum];
for (int i = 0; i<_outputNum ; i++) {
[array addObject:@(output[i])];
}
return array;
}
//
// ViewController.m
// 小歪
//
// Created by reese on 16/3/21.
// Copyright © 2016年 com.ifenduo. All rights reserved.
//
#import "ViewController.h"
#import "XYRobotManager.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *input1;
@property (weak, nonatomic) IBOutlet UITextField *input2;
@property (weak, nonatomic) IBOutlet UITextField *output1;
@property (weak, nonatomic) IBOutlet UILabel *output;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建大脑
[[XYRobotManager sharedManager] createBrain];
}
- (IBAction)train:(id)sender {
fann_type input[2] = {_input1.text.floatValue,_input2.text.floatValue};
fann_type output[1] = {_output1.text.floatValue};
[[XYRobotManager sharedManager] trainInputDatas:input outputDatas:output dataCount:1];
}
- (IBAction)test:(id)sender {
fann_type input[2] = {_input1.text.floatValue,_input2.text.floatValue};
NSArray *output = [[XYRobotManager sharedManager] runInputDatas:input];
[_output setText:[output.firstObject stringValue]];
}
@end
2016-03-21 10:16:57.359 小歪[1637:22219] 初始化神经网络
2016-03-21 10:29:33.054 小歪[1637:22219] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.9998188019. Bit fail 0.
2016-03-21 10:29:33.056 小歪[1637:22219] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/7BAC0013-A13F-4547-A791-D3E2CB2B917E/Documents/XYRobot/train.data
2016-03-21 10:16:57.359 小歪[1637:22219] 初始化神经网络
2016-03-21 10:29:33.054 小歪[1637:22219] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.9998188019. Bit fail 0.
2016-03-21 10:29:33.056 小歪[1637:22219] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/7BAC0013-A13F-4547-A791-D3E2CB2B917E/Documents/XYRobot/train.data
2016-03-21 10:39:58.155 小歪[1637:22219] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.0000000000. Bit fail 0.
2016-03-21 10:39:58.158 小歪[1637:22219] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/7BAC0013-A13F-4547-A791-D3E2CB2B917E/Documents/XYRobot/train.data
2016-03-21 10:50:38.147 小歪[3451:52349] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.2500000000. Bit fail 1.
Epochs 2. Current error: 0.0132444603. Bit fail 0.
2016-03-21 10:50:38.148 小歪 [3451:52349] 训练数据路径 /Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/8614765A-20FA-43C8-90F6-A423B80B0235/Documents/XYRobot/train.data2016-03-21 10:54:06.792 小歪[3451:52349] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.0000000000. Bit fail 0.
2016-03-21 10:54:06.795 小歪[3451:52349] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/8614765A-20FA-43C8-90F6-A423B80B0235/Documents/XYRobot/train.data
2016-03-21 10:54:16.583 小歪[3451:52349] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.1666666716. Bit fail 1.
Epochs 2. Current error: 0.1666666716. Bit fail 1.
Epochs 3. Current error: 0.3333332837. Bit fail 1.
Epochs 4. Current error: 0.3333333433. Bit fail 2.
Epochs 5. Current error: 0.3333333433. Bit fail 2.
Epochs 6. Current error: 0.3329019248. Bit fail 0.
2016-03-21 10:54:16.584 小歪[3451:52349] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/8614765A-20FA-43C8-90F6-A423B80B0235/Documents/XYRobot/train.data
2016-03-21 10:54:33.991 小歪[3451:52349] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.2831817567. Bit fail 0.
2016-03-21 10:54:33.992 小歪[3451:52349] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/8614765A-20FA-43C8-90F6-A423B80B0235/Documents/XYRobot/train.data
2016-03-21 10:54:46.735 小歪[3451:52349] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.3749229312. Bit fail 1.
Epochs 2. Current error: 0.3737220764. Bit fail 1.
Epochs 3. Current error: 0.2615829706. Bit fail 1.
Epochs 4. Current error: 0.2259529382. Bit fail 1.
Epochs 5. Current error: 0.2499959171. Bit fail 0.
2016-03-21 10:54:46.736 小歪[3451:52349] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/8614765A-20FA-43C8-90F6-A423B80B0235/Documents/XYRobot/train.data
2016-03-21 10:54:54.423 小歪[3451:52349] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.3330805600. Bit fail 0.
2016-03-21 10:54:54.424 小歪 [3451:52349] 训练数据路径 /Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/8614765A-20FA-43C8-90F6-A423B80B0235/Documents/XYRobot/train.data2016-03-21 10:56:49.149 小歪[3451:52349] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.4682762027. Bit fail 1.
Epochs 2. Current error: 0.5955896378. Bit fail 1.
Epochs 3. Current error: 0.5830196142. Bit fail 1.
Epochs 4. Current error: 0.3932408690. Bit fail 1.
Epochs 5. Current error: 0.3994615376. Bit fail 1.
Epochs 6. Current error: 0.3985652626. Bit fail 1.
Epochs 7. Current error: 0.4392893314. Bit fail 1.
Epochs 8. Current error: 0.2354802340. Bit fail 0.
2016-03-21 10:56:49.152 小歪[3451:52349] 训练数据路径/Users/admin/Library/Developer/CoreSimulator/Devices/6233F208-E406-4601-987A-7997263386E5/data/Containers/Data/Application/8614765A-20FA-43C8-90F6-A423B80B0235/Documents/XYRobot/train.data
2016-03-21 11:06:16.181 小歪[4267:64763] 训练完成
Max epochs 3000. Desired error: 0.0099999998.
Epochs 1. Current error: 0.5999537110. Bit fail 24.
Epochs 2. Current error: 0.4960755408. Bit fail 24.
Epochs 3. Current error: 0.4582657814. Bit fail 24.
Epochs 4. Current error: 0.4193557203. Bit fail 24.
Epochs 5. Current error: 0.5826099515. Bit fail 24.
....
Epochs 2991. Current error: 0.0503493845. Bit fail 24.
Epochs 2992. Current error: 0.0503306128. Bit fail 24.
Epochs 2993. Current error: 0.0503247045. Bit fail 24.
Epochs 2994. Current error: 0.0502951257. Bit fail 24.
Epochs 2995. Current error: 0.0504412763. Bit fail 24.
Epochs 2996. Current error: 0.0503883027. Bit fail 24.
Epochs 2997. Current error: 0.0503233038. Bit fail 24.
Epochs 2998. Current error: 0.0503678434. Bit fail 24.
Epochs 2999. Current error: 0.0503562540. Bit fail 24.
Epochs 3000. Current error: 0.0503364615. Bit fail 24.
第n次
Epochs 2987. Current error: 0.0007500528. Bit fail 28.
Epochs 2988. Current error: 0.0005287924. Bit fail 28.
Epochs 2989. Current error: 0.0006041168. Bit fail 28.
Epochs 2990. Current error: 0.0004783150. Bit fail 28.
Epochs 2991. Current error: 0.0004799517. Bit fail 28.
Epochs 2992. Current error: 0.0004323115. Bit fail 28.
Epochs 2993. Current error: 0.0004352634. Bit fail 28.
Epochs 2994. Current error: 0.0004080634. Bit fail 28.
Epochs 2995. Current error: 0.0004139747. Bit fail 28.
Epochs 2996. Current error: 0.0003935657. Bit fail 28.
Epochs 2997. Current error: 0.0004007270. Bit fail 28.
Epochs 2998. Current error: 0.0003827212. Bit fail 28.
Epochs 2999. Current error: 0.0003909847. Bit fail 28.
Epochs 3000. Current error: 0.0003752450. Bit fail 28.
训练次数越多,小歪的信心应该是越高,那么现在再让他判断下99和99.999,99和99,5和5,5和4:
我们设置的预期均方差是0.01,因此小歪给的答案恰好也逼近于正确答案+-0.01,然而我们整个程序并没有告诉他我们的规律是什么(我们在代码里面根本就没有写过x1和x2要全等~~),规律是他自己总结出来的,这就是机器学习的第一步~
今天的小歪训练的很累了,先训练到这里,训练的强度仍然相当低,因此还不足以应用。
至于3层神经网络,96个神经元能做什么,其实已经能做很多的事情了,然而我们还可以开辟更大的空间给小歪~~
下次可能给他N个输入和N个输出,也不一定~
今天的实战就到这里^^