Expand description
Neural network library.
This library needs alloc crate.
This AI works on single thread, but is able to work on no_std.
(But you can devise to do machine learning in multithread. See the following list.)
§Example of Single Thread Machine Learning
Letter classifier.
- If inputs Japanese letter, outputs ‘日’.
- If inputs English letter, outputs ‘E’.
(1) Defines letter generator and ID.
extern crate chobitlibs;
use chobitlibs::chobit_ai::{
MathVec,
Activation,
ChobitAi,
ChobitMlAi,
MlAiCache
};
use chobitlibs::chobit_rand::ChobitRand;
fn japanese_letter(rng: &mut ChobitRand) -> char {
let letters = [
'あ', 'い', 'う', 'え', 'お',
'か', 'き', 'く', 'け', 'こ',
'さ', 'し', 'す', 'せ', 'そ'
];
letters[(rng.next_u64() as usize) % letters.len()]
}
fn english_letter(rng: &mut ChobitRand) -> char {
let letters = [
'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o'
];
letters[(rng.next_u64() as usize) % letters.len()]
}
const JAPANESE_ID: char = '日';
const ENGLISH_ID: char = 'E';(2) Creates ChobitAi and randomises weights.
const OUT: usize = 32;
const MIDDLE: usize = 64;
const IN: usize = 32;
let mut rng = ChobitRand::new(b"ChobitAi Example");
let mut ai = ChobitAi::<OUT, MIDDLE, IN>::new(Activation::SoftSign);
// Randomises weights.
ai.for_each_weight_mut(|weight| {
*weight = ((rng.next_f64() as f32) * 2.0) - 1.0;
});
let mut input = MathVec::<IN>::new();
let mut output = MathVec::<OUT>::new();(3) Wraps AI with ChobitMlAi for machine learning.
let mut ai = ChobitMlAi::<OUT, MIDDLE, IN>::new(ai);
let mut cache = MlAiCache::<OUT, MIDDLE, IN>::new();
let mut input_error = MathVec::<IN>::new();
let mut output_error = MathVec::<OUT>::new();(4) Machine learning.
const EPOCH: usize = 1000;
const BATCH_SIZE: usize = 100;
const RATE: f32 = 0.01;
for _ in 0..EPOCH {
for _ in 0..BATCH_SIZE {
//--- Learns Japanese ---//
input.load_u32_label(japanese_letter(&mut rng) as u32);
output.load_u32_label(JAPANESE_ID as u32);
// Writes cache.
ai.ready(&input, &mut cache);
// Calculates error.
cache.calc_output_error(&output, &mut output_error);
// Studies.
ai.study(&output_error, &cache, &mut input_error);
//--- Learns English ---//
input.load_u32_label(english_letter(&mut rng) as u32);
output.load_u32_label(ENGLISH_ID as u32);
// Writes cache.
ai.ready(&input, &mut cache);
// Calculates error.
cache.calc_output_error(&output, &mut output_error);
// Studies.
ai.study(&output_error, &cache, &mut input_error);
}
// Updates weights.
ai.update(RATE);
}(5) Tests AI.
// Unwrap Ai.
let ai = ai.drop();
let mut tmpbuf = MathVec::<MIDDLE>::new();
// Tests Japanese.
for _ in 0..10 {
input.load_u32_label(japanese_letter(&mut rng) as u32);
ai.calc(&input, &mut output, &mut tmpbuf);
assert_eq!(output.to_u32_label(), JAPANESE_ID as u32);
}
// Tests English.
for _ in 0..10 {
input.load_u32_label(english_letter(&mut rng) as u32);
ai.calc(&input, &mut output, &mut tmpbuf);
assert_eq!(output.to_u32_label(), ENGLISH_ID as u32);
}§Example of Multithread Machine Learning
Letter classifier.
- If inputs Japanese letter, outputs ‘日’.
- If inputs English letter, outputs ‘E’.
(1) Imports libraries.
extern crate chobitlibs;
use std::{
thread,
sync::{
mpsc,
Arc,
Mutex
}
};
use chobitlibs::chobit_ai::{
MathVec,
Activation,
ChobitAi,
ChobitMlAi,
MlAiCache
};
use chobitlibs::chobit_rand::ChobitRand;(2) Defines constants.
const OUT: usize = 32;
const MIDDLE: usize = 64;
const IN: usize = 32;
const EPOCH: usize = 10000;
const BATCH_SIZE: usize = 30;
const RATE: f32 = 0.01;(3) Commands between threads.
// Command from parent to child.
enum P2C {
StartEpoch,
Break
}
// Command from child to parent.
enum C2P {
EndedOneEpoch,
}(4) Defines letter generator and letter ID.
fn japanese_letter(rng: &mut ChobitRand) -> char {
let letters = [
'あ', 'い', 'う', 'え', 'お',
'か', 'き', 'く', 'け', 'こ',
'さ', 'し', 'す', 'せ', 'そ'
];
letters[(rng.next_u64() as usize) % letters.len()]
}
fn english_letter(rng: &mut ChobitRand) -> char {
let letters = [
'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o'
];
letters[(rng.next_u64() as usize) % letters.len()]
}
const JAPANESE_ID: char = '日';
const ENGLISH_ID: char = 'E';(4) Defines functions to operate shared gradient.
// Initializes shared gradient.
fn init_grad(
ai: &ChobitMlAi<OUT, MIDDLE, IN>,
grads: &Arc<Mutex<(Vec<f32>, Vec<f32>)>>
) {
let mut lock = grads.lock().unwrap();
ai.for_each_total_grad(|_| {
lock.0.push(0.0);
lock.1.push(0.0);
});
}
// Loads from shared gradient to AI's gradient.
fn load_grad(
ai: &mut ChobitMlAi<OUT, MIDDLE, IN>,
grads: &Arc<Mutex<(Vec<f32>, Vec<f32>)>>
) {
let lock = grads.lock().unwrap();
let mut iter = lock.0.iter();
ai.for_each_total_grad_mut(|grad| {
if let Some(shared_grad) = iter.next() {
*grad = *shared_grad;
}
});
}
// Adds AI's gradient to shared gradient.
fn save_grad(
ai: &ChobitMlAi<OUT, MIDDLE, IN>,
grads: &Arc<Mutex<(Vec<f32>, Vec<f32>)>>
) {
let mut lock = grads.lock().unwrap();
let mut iter = lock.1.iter_mut();
ai.for_each_total_grad(|grad| {
if let Some(shared_grad) = iter.next() {
*shared_grad += *grad;
}
});
}
// Prepares to load_grad().
fn move_grad(
grads: &Arc<Mutex<(Vec<f32>, Vec<f32>)>>,
tmpbuf: &mut Vec<f32>
) {
let mut lock = grads.lock().unwrap();
lock.0.clear();
tmpbuf.clear();
tmpbuf.extend_from_slice(&lock.1);
lock.0.extend_from_slice(&tmpbuf);
lock.1.fill(0.0);
}(5) Defines child thread.
fn run_thread(
rng_seed: &[u8],
p2c_rx: mpsc::Receiver<P2C>,
c2p_tx: mpsc::Sender<C2P>,
ai: ChobitAi<OUT, MIDDLE, IN>,
grads: Arc<Mutex<(Vec<f32>, Vec<f32>)>>
) -> thread::JoinHandle<()> {
let rng_seed = rng_seed.to_vec();
thread::spawn(move || {
// Wraps AI for machine learning.
let mut ai = ChobitMlAi::<OUT, MIDDLE, IN>::new(ai);
let mut rng = ChobitRand::new(&rng_seed);
let mut cache = MlAiCache::<OUT, MIDDLE, IN>::new();
let mut input = MathVec::<IN>::new();
let mut output = MathVec::<OUT>::new();
let mut input_error = MathVec::<IN>::new();
let mut output_error = MathVec::<OUT>::new();
// Machine learning.
for cmd in p2c_rx { // Waits for command from parent.
match cmd {
P2C::StartEpoch => {
// To load shared gradient and update itself,
// all children and parent become same state.
load_grad(&mut ai, &grads);
ai.update(RATE);
for _ in 0..BATCH_SIZE {
//--- Learns Japanese ---//
input.load_u32_label(japanese_letter(&mut rng) as u32);
output.load_u32_label(JAPANESE_ID as u32);
// Writes cache.
ai.ready(&input, &mut cache);
// Calculates error.
cache.calc_output_error(&output, &mut output_error);
// Studies.
ai.study(&output_error, &cache, &mut input_error);
//--- Learns English ---//
input.load_u32_label(english_letter(&mut rng) as u32);
output.load_u32_label(ENGLISH_ID as u32);
// Writes cache.
ai.ready(&input, &mut cache);
// Calculates error.
cache.calc_output_error(&output, &mut output_error);
// Studies.
ai.study(&output_error, &cache, &mut input_error);
}
// Adds its own gradient to shared gradient.
save_grad(&ai, &grads);
// Notifies ended one epoch to parent.
c2p_tx.send(C2P::EndedOneEpoch).unwrap();
},
P2C::Break => {
break;
}
}
}
})
}(6) Defines AI test.
fn test_ai(ai: &ChobitAi<OUT, MIDDLE, IN>, rng: &mut ChobitRand) {
let mut input = MathVec::<IN>::new();
let mut output = MathVec::<OUT>::new();
let mut tmpbuf = MathVec::<MIDDLE>::new();
// Tests Japanese.
for _ in 0..10 {
input.load_u32_label(japanese_letter(rng) as u32);
ai.calc(&input, &mut output, &mut tmpbuf);
assert_eq!(output.to_u32_label(), JAPANESE_ID as u32);
}
// Tests English.
for _ in 0..10 {
input.load_u32_label(english_letter(rng) as u32);
ai.calc(&input, &mut output, &mut tmpbuf);
assert_eq!(output.to_u32_label(), ENGLISH_ID as u32);
}
}(7) Starts main thread and Creates AI and randomise weights.
fn main() {
let mut rng = ChobitRand::new(b"ChobitAi Example");
let mut ai = ChobitAi::<OUT, MIDDLE, IN>::new(Activation::SoftSign);
// Randomises weights.
ai.for_each_weight_mut(|weight| {
*weight = ((rng.next_f64() as f32) * 2.0) - 1.0;
});(8) Creates shared gradient.
let grads = Arc::new(Mutex::new(
(Vec::<f32>::new(), Vec::<f32>::new())
));(9) Creates commands for a parent and 2 children.
// Channel from parent to child.
let (p2c_1_tx, p2c_1_rx) = mpsc::channel::<P2C>();
let (p2c_2_tx, p2c_2_rx) = mpsc::channel::<P2C>();
let p2c_tx = [p2c_1_tx, p2c_2_tx];
// Channel from child to parent.
let (c2p_1_tx, c2p_1_rx) = mpsc::channel::<C2P>();
let (c2p_2_tx, c2p_2_rx) = mpsc::channel::<C2P>();
let c2p_rx = [c2p_1_rx, c2p_2_rx];(10) Runs 2 children.
let handle_1 =
run_thread(b"child_1", p2c_1_rx, c2p_1_tx, ai.clone(), grads.clone());
let handle_2 =
run_thread(b"child_2", p2c_2_rx, c2p_2_tx, ai.clone(), grads.clone());(11) Process on parent thread.
// Wraps AI for machine learning.
let mut ai = ChobitMlAi::<OUT, MIDDLE, IN>::new(ai);
let mut tmpbuf = Vec::<f32>::new();
// Initialize shared gradient.
init_grad(&ai, &grads);
// Loop each epoch.
for _ in 0..EPOCH {
load_grad(&mut ai, &grads);
ai.update(RATE);
p2c_tx.iter().for_each(|tx| {tx.send(P2C::StartEpoch).unwrap();});
c2p_rx.iter().for_each(|rx| {
let _ = rx.recv().unwrap();
});
move_grad(&grads, &mut tmpbuf);
}
p2c_tx.iter().for_each(|tx| {tx.send(P2C::Break).unwrap();});
// Updates by gradient of last epoch.
move_grad(&grads, &mut tmpbuf);
load_grad(&mut ai, &grads);
ai.update(RATE);
handle_1.join().unwrap();
handle_2.join().unwrap();(12) Tests and ends main thread.
let ai = ai.drop();
test_ai(&ai, &mut rng);
}Structs§
- Chobit
Ai - AI for fixed length data.
- Chobit
Chain Ai - AI that inputs data and state, and outputs calculated data and next state.
- Chobit
Decoder - Decoder from fixed length data to sequence data.
- Chobit
Encoder - Encoder from sequence data to fixed length data.
- Chobit
MlAi - Wrapper of
ChobitAifor machine learning. - Chobit
MlChain Ai - Wrapper of
ChobitChainAifor machine learning. - Chobit
MlDecoder - Wrapper of
ChobitDecoderfor machine learning. - Chobit
MlEncoder - Wrapper of
ChobitEncoderfor machine learning. - Chobit
MlSeq Ai - Wrapper of
ChobitSeqAifor machine learning. - Chobit
SeqAi - Seq2Seq AI.
- Layer
- Layer for neural network only for calculating.
- Lstm
- Peephole LSTM
- MathVec
- Vector for mathematics.
- MlAi
Cache - Cache for
ChobitMlAi. - MlCache
- Cache for
MlLayer. - MlChain
AiCache - Cache for
ChobitMlChainAi. - MlDecoder
Cache - Cache for
ChobitMlDecoder. - MlEncoder
Cache - Cache for
ChobitMlEncoder. - MlLayer
- Layer for neural network only for machine learning.
- MlLstm
- LSTM for machine learning.
- MlLstm
Output Cache - Cache for output error of
MlLstm. - MlLstm
State Cache - Cache for state error of
MlLstm. - MlSeq
AiCache - Cache for
ChobitMlSeqAi. - Weights
- Weights of a linear function.
Enums§
- Activation
- Activation function for Neuron.