Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to using a TryFrom trait rather than From. #683

Merged
merged 3 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-2019, macOS-latest]
os: [ubuntu-latest, macOS-latest]
rust: [stable, nightly]
steps:
- uses: actions/checkout@v2
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Automated conversion of list arguments: all the generated functions that take
as input a slice of int or float can now be used directly with int values or
fixed length arrays [682](https://github.com/LaurentMazare/tch-rs/pull/682).
- Replace the `From<Tensor>` traits with some `TryFrom` versions,
[683](https://github.com/LaurentMazare/tch-rs/pull/683). This is a breaking
change, note that also the old version would flatten the tensor if needed to
reduce the number of dimensions, this has to be done explicitely with the new
version.

## v0.11.0 - 2023-03-20
### Added
Expand Down
4 changes: 2 additions & 2 deletions examples/char-rnn/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn sample(data: &TextData, lstm: &LSTM, linear: &Linear, device: Device) -> Stri
.squeeze_dim(0)
.softmax(-1, Kind::Float)
.multinomial(1, false);
last_label = i64::from(sampled_y);
last_label = i64::try_from(sampled_y).unwrap();
result.push(data.label_to_char(last_label))
}
result
Expand All @@ -58,7 +58,7 @@ pub fn main() -> Result<()> {
.view([BATCH_SIZE * SEQ_LEN, labels])
.cross_entropy_for_logits(&ys.to_device(device).view([BATCH_SIZE * SEQ_LEN]));
opt.backward_step_clip(&loss, 0.5);
sum_loss += f64::from(loss);
sum_loss += f64::try_from(loss)?;
cnt_loss += 1.0;
}
println!("Epoch: {} loss: {:5.3}", epoch, sum_loss / cnt_loss);
Expand Down
4 changes: 2 additions & 2 deletions examples/custom-optimizer/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ pub fn run() -> Result<()> {
println!(
"epoch: {:4} train loss: {:8.5} test acc: {:5.2}%",
epoch,
f64::from(&loss),
100. * f64::from(&test_accuracy),
f64::try_from(&loss)?,
100. * f64::try_from(&test_accuracy)?,
);
}
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions examples/min-gpt/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ fn sample(data: &TextData, gpt: &impl ModuleT, input: Tensor) -> String {
for _index in 0..SAMPLING_LEN {
let logits = input.apply_t(gpt, false).i((0, -1, ..));
let sampled_y = logits.softmax(-1, Kind::Float).multinomial(1, true);
let last_label = i64::from(&sampled_y);
let last_label = i64::try_from(&sampled_y).unwrap();
result.push(data.label_to_char(last_label));
input = Tensor::cat(&[input, sampled_y.view([1, 1])], 1).narrow(1, 1, BLOCK_SIZE);
}
Expand Down Expand Up @@ -175,7 +175,7 @@ pub fn main() -> Result<()> {
.view([BATCH_SIZE * BLOCK_SIZE, labels])
.cross_entropy_for_logits(&ys.view([BATCH_SIZE * BLOCK_SIZE]));
opt.backward_step_clip(&loss, 0.5);
sum_loss += f64::from(loss);
sum_loss += f64::try_from(loss)?;
cnt_loss += 1.0;
idx += 1;
if idx % 10000 == 0 {
Expand Down
4 changes: 2 additions & 2 deletions examples/mnist/mnist_nn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ pub fn run() -> Result<()> {
println!(
"epoch: {:4} train loss: {:8.5} test acc: {:5.2}%",
epoch,
f64::from(&loss),
100. * f64::from(&test_accuracy),
f64::try_from(&loss)?,
100. * f64::try_from(&test_accuracy)?,
);
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion examples/neural-style-transfer/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn main() -> Result<()> {
let loss = style_loss * STYLE_WEIGHT + content_loss;
opt.backward_step(&loss);
if step_idx % 1000 == 0 {
println!("{} {}", step_idx, f64::from(loss));
println!("{} {}", step_idx, f64::try_from(loss)?);
imagenet::save_image(&input_var, format!("out{step_idx}.jpg"))?;
}
}
Expand Down
8 changes: 4 additions & 4 deletions examples/reinforcement-learning/a2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ pub fn train() -> cpython::PyResult<()> {
let (critic, actor) = tch::no_grad(|| model(&s_states.get(s)));
let probs = actor.softmax(-1, Float);
let actions = probs.multinomial(1, true).squeeze_dim(-1);
let step = env.step(Vec::<i64>::from(&actions))?;
let step = env.step(Vec::<i64>::try_from(&actions).unwrap())?;

sum_rewards += &step.reward;
total_rewards += f64::from((&sum_rewards * &step.is_done).sum(Float));
total_episodes += f64::from(step.is_done.sum(Float));
total_rewards += f64::try_from((&sum_rewards * &step.is_done).sum(Float)).unwrap();
total_episodes += f64::try_from(step.is_done.sum(Float)).unwrap();

let masks = Tensor::from(1f32) - step.is_done;
sum_rewards *= &masks;
Expand Down Expand Up @@ -162,7 +162,7 @@ pub fn sample<T: AsRef<std::path::Path>>(weight_file: T) -> cpython::PyResult<()
let (_critic, actor) = tch::no_grad(|| model(obs));
let probs = actor.softmax(-1, Float);
let actions = probs.multinomial(1, true).squeeze_dim(-1);
let step = env.step(Vec::<i64>::from(&actions))?;
let step = env.step(Vec::<i64>::try_from(&actions).unwrap())?;

let masks = Tensor::from(1f32) - step.is_done;
obs = frame_stack.update(&step.obs, Some(&masks));
Expand Down
2 changes: 1 addition & 1 deletion examples/reinforcement-learning/ddpg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ pub fn run() -> cpython::PyResult<()> {

let mut total_reward = 0.0;
for _ in 0..EPISODE_LENGTH {
let mut actions = 2.0 * f64::from(agent.actions(&obs));
let mut actions = 2.0 * f64::try_from(agent.actions(&obs)).unwrap();
actions = actions.clamp(-2.0, 2.0);

let action_vec = vec![actions];
Expand Down
2 changes: 1 addition & 1 deletion examples/reinforcement-learning/policy_gradient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn run() -> cpython::PyResult<()> {
let action = tch::no_grad(|| {
obs.unsqueeze(0).apply(&model).softmax(1, Float).multinomial(1, true)
});
let action = i64::from(action);
let action = i64::try_from(action).unwrap();
let step = env.step(action)?;
steps.push(step.copy_with_obs(&obs));
obs = if step.is_done { env.reset()? } else { step.obs };
Expand Down
9 changes: 5 additions & 4 deletions examples/reinforcement-learning/ppo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ pub fn train() -> cpython::PyResult<()> {
let (critic, actor) = tch::no_grad(|| model(&s_states.get(s)));
let probs = actor.softmax(-1, Kind::Float);
let actions = probs.multinomial(1, true).squeeze_dim(-1);
let step = env.step(Vec::<i64>::from(&actions))?;
let step = env.step(Vec::<i64>::try_from(&actions).unwrap())?;

sum_rewards += &step.reward;
total_rewards += f64::from((&sum_rewards * &step.is_done).sum(Kind::Float));
total_episodes += f64::from(step.is_done.sum(Kind::Float));
total_rewards +=
f64::try_from((&sum_rewards * &step.is_done).sum(Kind::Float)).unwrap();
total_episodes += f64::try_from(step.is_done.sum(Kind::Float)).unwrap();

let masks = Tensor::from(1f32) - step.is_done;
sum_rewards *= &masks;
Expand Down Expand Up @@ -171,7 +172,7 @@ pub fn sample<T: AsRef<std::path::Path>>(weight_file: T) -> cpython::PyResult<()
let (_critic, actor) = tch::no_grad(|| model(obs));
let probs = actor.softmax(-1, Kind::Float);
let actions = probs.multinomial(1, true).squeeze_dim(-1);
let step = env.step(Vec::<i64>::from(&actions))?;
let step = env.step(Vec::<i64>::try_from(&actions).unwrap())?;

let masks = Tensor::from(1f32) - step.is_done;
obs = frame_stack.update(&step.obs, Some(&masks));
Expand Down
2 changes: 1 addition & 1 deletion examples/stable-diffusion/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2418,7 +2418,7 @@ impl DDIMScheduler {
),
};
let alphas: Tensor = 1.0 - betas;
let alphas_cumprod = Vec::<f64>::from(alphas.cumprod(0, Kind::Double));
let alphas_cumprod = Vec::<f64>::try_from(alphas.cumprod(0, Kind::Double)).unwrap();
Self { alphas_cumprod, timesteps, step_ratio, config }
}

Expand Down
2 changes: 1 addition & 1 deletion examples/transfer-learning/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn main() -> Result<()> {
sgd.backward_step(&loss);

let test_accuracy = test_images.apply(&linear).accuracy_for_logits(&dataset.test_labels);
println!("{} {:.2}%", epoch_idx, 100. * f64::from(test_accuracy));
println!("{} {:.2}%", epoch_idx, 100. * f64::try_from(test_accuracy)?);
}
Ok(())
}
6 changes: 3 additions & 3 deletions examples/translation/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl Model {
let target_tensor = Tensor::of_slice(&[s as i64]).to_device(self.device);
loss = loss + output.nll_loss(&target_tensor);
let (_, output) = output.topk(1, -1, true, true);
if self.decoder_eos == i64::from(&output) as usize {
if self.decoder_eos == i64::try_from(&output).unwrap() as usize {
break;
}
prev = if use_teacher_forcing { target_tensor } else { output };
Expand All @@ -155,7 +155,7 @@ impl Model {
for _i in 0..MAX_LENGTH {
let (output, state_) = self.decoder.forward(&prev, &state, &enc_outputs, true);
let (_, output) = output.topk(1, -1, true, true);
let output_ = i64::from(&output) as usize;
let output_ = i64::try_from(&output).unwrap() as usize;
output_seq.push(output_);
if self.decoder_eos == output_ {
break;
Expand Down Expand Up @@ -208,7 +208,7 @@ pub fn main() -> Result<()> {
let (input_, target) = pairs.choose(&mut rng).unwrap();
let loss = model.train_loss(input_, target, &mut rng);
opt.backward_step(&loss);
loss_stats.update(f64::from(loss) / target.len() as f64);
loss_stats.update(f64::try_from(loss)? / target.len() as f64);
if idx % 1000 == 0 {
println!("{} {}", idx, loss_stats.avg_and_reset());
for _pred_index in 1..5 {
Expand Down
2 changes: 1 addition & 1 deletion examples/vae/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub fn main() -> Result<()> {
let (recon_batch, mu, logvar) = vae.forward(&bimages);
let loss = loss(&recon_batch, &bimages, &mu, &logvar);
opt.backward_step(&loss);
train_loss += f64::from(&loss);
train_loss += f64::try_from(&loss)?;
samples += bimages.size()[0] as f64;
}
println!("Epoch: {}, loss: {}", epoch, train_loss / samples);
Expand Down
2 changes: 1 addition & 1 deletion examples/yolo/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub fn report(pred: &Tensor, img: &Tensor, w: i64, h: i64) -> Result<Tensor> {
let mut bboxes: Vec<Vec<Bbox>> = (0..nclasses).map(|_| vec![]).collect();
// Extract the bounding boxes for which confidence is above the threshold.
for index in 0..npreds {
let pred = Vec::<f64>::from(pred.get(index));
let pred = Vec::<f64>::try_from(pred.get(index))?;
let confidence = pred[4];
if confidence > CONFIDENCE_THRESHOLD {
let mut class_index = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ impl Iterator for TextDataIter {
None
} else {
self.batch_index += 1;
let indexes = Vec::<i64>::from(&self.indexes.i(start..start + size));
let indexes = Vec::<i64>::try_from(&self.indexes.i(start..start + size)).unwrap();
let batch: Vec<_> = indexes.iter().map(|&i| self.data.i(i..i + self.seq_len)).collect();
let batch: Vec<_> = batch.iter().collect();
Some(Tensor::stack(&batch, 0))
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub enum TchError {
#[error(transparent)]
Zip(#[from] ZipError),

#[error(transparent)]
NdArray(#[from] ndarray::ShapeError),

/// Errors returned by the safetensors library.
#[error("safetensors error {path}: {err}")]
SafeTensorError { path: String, err: safetensors::SafeTensorError },
Expand Down
4 changes: 2 additions & 2 deletions src/nn/linear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ fn matches_pytorch() {
let linear = Linear { ws, bs };
let output = linear.forward(&input);

let delta_output: f32 = (&output - &expected_output).norm().into();
let delta_original: f32 = (&original_output - &expected_output).norm().into();
let delta_output: f32 = (&output - &expected_output).norm().try_into().unwrap();
let delta_original: f32 = (&original_output - &expected_output).norm().try_into().unwrap();

// The `matmul()` implementation is close, but `linear()` is at least as close or closer.
assert!(output.allclose(&expected_output, 1e-5, 1e-8, false));
Expand Down
2 changes: 1 addition & 1 deletion src/nn/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub trait ModuleT: std::fmt::Debug + Send {
for (xs, ys) in Iter2::new(xs, ys, batch_size).return_smaller_last_batch() {
let acc = self.forward_t(&xs.to_device(d), false).accuracy_for_logits(&ys.to_device(d));
let size = xs.size()[0] as f64;
sum_accuracy += f64::from(&acc) * size;
sum_accuracy += f64::try_from(&acc).unwrap() * size;
sample_count += size;
}
sum_accuracy / sample_count
Expand Down
2 changes: 1 addition & 1 deletion src/nn/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ impl Optimizer {
for var in v.trainable_variables.iter() {
norms.push(var.tensor.grad().norm());
}
let total_norm = f64::from(Tensor::stack(&norms, 0).norm());
let total_norm = f64::try_from(Tensor::stack(&norms, 0).norm()).unwrap();
let clip_coef = max / (total_norm + 1e-6);
if clip_coef < 1.0 {
for var in v.trainable_variables.iter() {
Expand Down
Loading