8个版本
使用旧的Rust 2015
0.3.0 | 2018年1月25日 |
---|---|
0.2.0 | 2018年1月23日 |
0.1.3 | 2018年1月23日 |
#1166 在 算法
6MB
410 行
mvnc
围绕Movidius神经网络棒C API的包装器。
在版本0.3.0上
为了提高安全性,现在在Graph.load_tensor
和Graph.get_result
中需要可变借用。
而不是返回槽指示符,为每个加载的张量返回一个唯一ID,允许更可靠地关联结果。
其他小变化包括额外的Error
值。
版本历史
版本 | 描述 |
---|---|
0.3.0 | 改进安全性和文档 |
0.2.1 | 将存储库移动到github(未发布版本) |
0.2.0 | 包括槽指示器的完整crate |
0.1.3 | 实现了graph 模块 |
0.1.2 | 实现了device 模块 |
0.1.1 | 添加了内部IntoResult 特质和readme.md |
0.1.0 | 实现了log 模块 |
构建说明
必须存在来自Movidius™神经网络计算SDK的libmvnc.so
库。
示例
此示例的最新版本可在https://github.com/WiebeCnossen/mvnc/blob/master/examples/mnist.rs找到
extern crate half;
extern crate mvnc;
extern crate rand;
use std::fs::File;
use std::io::{self, Read};
use half::{consts, f16};
use mvnc::{Device, Graph};
use mvnc::graph::Blocking;
use mvnc::log;
use rand::{Rng, ThreadRng};
pub fn main() {
log::set_log_level(&log::LogLevel::Verbose).expect("Setting log level failed");
for i in 0.. {
if let Some(device_name) = Device::get_name(i) {
println!("Device {} = '{}'", i, device_name);
if let Err(error) = run_mnist(&device_name) {
println!("{:?}", error);
}
} else {
println!("Finished; # devices = {}", i);
break;
}
}
}
fn read_graph() -> Result<Vec<u8>, io::Error> {
let mut data = vec![];
File::open("./examples/mnist.graph")?
.read_to_end(&mut data)
.map(|_| data)
}
fn random_input(rng: &mut ThreadRng) -> Vec<f16> {
(0..768).map(|_| f16::from_f32(rng.gen())).collect()
}
fn run_mnist(device_name: &str) -> Result<(), Error> {
let mut rng = rand::thread_rng();
let device = Device::open(device_name)?;
let data = read_graph()?;
let mut graph = Graph::allocate(&device, &data)?;
graph.set_blocking(&Blocking::Block)?;
println!("Blocking -> {:?}", graph.get_blocking()?);
for _ in 0..10 {
exec_block(&mut graph, &mut rng)?;
}
graph.set_blocking(&Blocking::DontBlock)?;
println!("Blocking -> {:?}", graph.get_blocking()?);
for _ in 0..10 {
exec_dont_block(&mut graph, &mut rng)?;
}
println!(
"Thermal throttling level = {:?}",
device.get_thermal_throttling_level()?
);
Ok(())
}
fn exec_block(graph: &mut Graph, rng: &mut ThreadRng) -> Result<(), Error> {
graph.load_tensor(&random_input(rng))?;
let (id, digit) = graph
.get_result::<f16>()
.map(|(id, output)| (id, most_probable_digit(output)))?;
let time_taken: f32 = graph.get_time_taken()?.iter().cloned().sum();
print_result(id, digit, time_taken);
Ok(())
}
fn exec_dont_block(graph: &mut Graph, rng: &mut ThreadRng) -> Result<(), Error> {
loop {
match graph.load_tensor(&random_input(rng)) {
Ok(_) => (),
Err(mvnc::Error::Busy) => break, // All buffers filled
Err(e) => return Err(e.into()),
}
}
loop {
let result = graph
.get_result::<f16>()
.map(|(id, output)| (id, most_probable_digit(output)));
match result {
Ok((id, digit)) => {
let time_taken: f32 = graph.get_time_taken()?.iter().cloned().sum();
print_result(id, digit, time_taken);
}
Err(mvnc::Error::Idle) => return Ok(()), // No calculations pending
Err(mvnc::Error::NoData) => (), // Calculation not ready
Err(e) => return Err(e.into()),
}
}
}
fn most_probable_digit(output: &[f16]) -> usize {
let mut max = consts::MIN;
let mut digit = 0;
for (i, &prob) in output.iter().enumerate() {
if prob > max {
max = prob;
digit = i;
}
}
digit
}
fn print_result(id: usize, digit: usize, time_taken: f32) {
println!(
"Run {:2} in {:.2}ms, most probable digit = {}",
id, time_taken, digit
);
}
#[derive(Debug)]
enum Error {
MvncError(mvnc::Error),
IoError(io::Error),
}
impl From<mvnc::Error> for Error {
fn from(error: mvnc::Error) -> Error {
Error::MvncError(error)
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Error {
Error::IoError(error)
}
}