Java調(diào)用Pytorch模型實(shí)現(xiàn)圖像識(shí)別
之前寫了個(gè)輸入是1x2向量的模型的調(diào)用文章,后來有了個(gè)需要用到圖像識(shí)別的項(xiàng)目,因此寫下此文記錄一下在java中如何借助DJL調(diào)用自己寫的pytorch模型進(jìn)行圖像識(shí)別。
我具體模型用的什么模型就不介紹了,輸入圖片是3*224*224,放入圖片前需要看一下橫縱比是否合理,不合理的話會(huì)進(jìn)行下面這樣的操作:

1. 依賴
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-engine</artifactId>
<version>0.16.0</version>
</dependency>
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-native-auto</artifactId>
<version>1.9.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-jni</artifactId>
<version>1.9.1-0.16.0</version>
<scope>runtime</scope>
</dependency>2. 準(zhǔn)備模型
1.首先將模型按下面方法保存,放到項(xiàng)目resources中
import torch
# An instance of your model.
model = MyModel(num_classes = 80)
# Switch the model to eval model
model.eval()
# An example input you would normally provide to your model's forward() method.
example = torch.rand(1, 3, 224, 224)
# Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing.
traced_script_module = torch.jit.trace(model, example)
# Save the TorchScript model
traced_script_module.save("model.pt")2.編寫工具類,用于完成識(shí)別功能
public class HerbUtil {
//規(guī)定輸入尺寸
private static final int INPUT_SIZE = 224;
//標(biāo)簽文件 一種類別名字占一行
private List<String> herbNames;
//用于識(shí)別
Predictor<Image, Classifications> predictor;
//模型
private Model model;
public HerbUtil() {
//加載標(biāo)簽到herbNames中
this.loadHerbNames();
//初始化模型工作
this.init();
}
}3.將標(biāo)簽文件放到resources中,載入標(biāo)簽
private void loadHerbNames() {
BufferedReader reader = null;
herbNames = new ArrayList<>();
try {
InputStream in = HerbUtil.class.getClassLoader().getResourceAsStream("names.txt");
reader = new BufferedReader(new InputStreamReader(in));
String name = null;
while ((name = reader.readLine()) != null) {
herbNames.add(name);
}
System.out.println(herbNames);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}4.初始化模型
private void init() {
Translator<Image, Classifications> translator = ImageClassificationTranslator.builder()
//下面的transform根據(jù)自己的改
.addTransform(new RandomResizedCrop(INPUT_SIZE, INPUT_SIZE, 0.6, 1,
3. / 4, 4. / 3))
.addTransform(new ToTensor())
.addTransform(new Normalize(
new float[] {0.5f, 0.5f, 0.5f},
new float[] {0.5f, 0.5f, 0.5f}))
//如果你的模型最后一層沒有經(jīng)過softmax就啟用它
.optApplySoftmax(true)
//載入所有標(biāo)簽進(jìn)去
.optSynset(herbNames)
//最終顯示概率最高的5個(gè)
.optTopK(5)
.build();
//隨便起名
Model model = Model.newInstance("model", Device.cpu());
try {
InputStream inputStream = HerbUtil.class.getClassLoader().getResourceAsStream("model.pt");
if (inputStream == null) {
throw new RuntimeException("找不到模型文件");
}
model.load(inputStream);
predictor = model.newPredictor(translator);
} catch (Exception e) {
e.printStackTrace();
}
}5.我開頭提到的圖片預(yù)處理 的代碼
private Image resizeImage(InputStream inputStream) {
BufferedImage input = null;
try {
input = ImageIO.read(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
int iw = input.getWidth(), ih = input.getHeight();
int w = 224, h = 224;
double scale = Math.min(1. * w / iw, 1. * h / ih);
int nw = (int) (iw * scale), nh = (int) (ih * scale);
java.awt.Image img;
//只有太長(zhǎng)或太寬才會(huì)保留橫縱比,填充顏色
boolean needResize = 1. * iw / ih > 1.4 || 1. * ih / iw > 1.4;
if (needResize) {
img = input.getScaledInstance(nw, nh, BufferedImage.SCALE_SMOOTH);
} else {
img = input.getScaledInstance(INPUT_SIZE, INPUT_SIZE, BufferedImage.SCALE_SMOOTH);
}
BufferedImage out = new BufferedImage(INPUT_SIZE, INPUT_SIZE, BufferedImage.TYPE_INT_RGB);
Graphics g = out.getGraphics();
//先將整個(gè)224*224區(qū)域填充128 128 128顏色
g.setColor(new Color(128, 128, 128));
g.fillRect(0, 0, INPUT_SIZE, INPUT_SIZE);
out.getGraphics().drawImage(img, 0, needResize ? (INPUT_SIZE - nh) / 2 : 0, null);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
ImageIO.write(out, "jpg", imageOutputStream);
//去D盤看效果
//ImageIO.write(out, "jpg", new File("D:\\out.jpg"));
InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
return ImageFactory.getInstance().fromInputStream(is);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("圖片轉(zhuǎn)換失敗");
}
}6.識(shí)別功能
public List<Classifications.Classification> predict(InputStream inputStream) {
List<Classifications.Classification> result = new ArrayList<>();
Image input = this.resizeImage(inputStream);
try {
Classifications output = predictor.predict(input);
System.out.println("推測(cè)為:" + output.best().getClassName()
+ ", 概率:" + output.best().getProbability());
System.out.println(output);
result = output.topK();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}3. 測(cè)試
@Test
public void test7() {
HerbUtil herbUtil = new HerbUtil();
String path = "E:\\深度學(xué)習(xí)專用\\data\\train\\當(dāng)歸\\24.jpeg";
try {
File file = new File(path);
InputStream inputStream = new FileInputStream(file);
herbUtil.predict(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}輸出:

加入到項(xiàng)目中后,工具類直接Autowire注入或者方法都寫static的,Controller接收前端MultipartFile,將其inputstream用于推測(cè)
如果你想加載網(wǎng)絡(luò)圖片,那就去網(wǎng)上搜索怎么把它轉(zhuǎn)成inputstream吧
測(cè)試多線程一起predict時(shí)報(bào)錯(cuò)了
4.更新
當(dāng)我打包成jar到centos7的linux中運(yùn)行時(shí),報(bào)錯(cuò)UnsatisfiedLinkError,經(jīng)過大神的指導(dǎo),問題出來我引的依賴。
修改后的依賴:
<properties>
<java.version>8</java.version>
<jna.version>5.3.0</jna.version>
</properties>
<dependencies>
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-engine</artifactId>
<version>0.16.0</version>
</dependency>
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-native-cpu-precxx11</artifactId>
<classifier>linux-x86_64</classifier>
<version>1.9.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-jni</artifactId>
<version>1.9.1-0.16.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>到此這篇關(guān)于Java調(diào)用Pytorch模型實(shí)現(xiàn)圖像識(shí)別的文章就介紹到這了,更多相關(guān)Java Pytorch圖像識(shí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot使用Editor.md構(gòu)建Markdown富文本編輯器示例
這篇文章主要介紹了SpringBoot使用Editor.md構(gòu)建Markdown富文本編輯器示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
SpringBoot集成Redis6.0的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot集成Redis6.0的實(shí)現(xiàn)示例,包括多線程I/O、ACL權(quán)限控制、RESP3協(xié)議等新特性,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2026-04-04
注入jar包里的對(duì)象,用@autowired的實(shí)例
這篇文章主要介紹了注入jar包里的對(duì)象,用@autowired的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
MyBatis-Plus速成指南之簡(jiǎn)化你的數(shù)據(jù)庫(kù)操作流程(最新推薦)
MyBatis-Plus?是一個(gè)?MyBatis?的增強(qiáng)工具,在?MyBatis?的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生,這篇文章主要介紹了MyBatis-Plus速成指南:簡(jiǎn)化你的數(shù)據(jù)庫(kù)操作流程,需要的朋友可以參考下2025-02-02
spring整合redis以及使用RedisTemplate的方法
本篇文章主要介紹了spring整合redis以及使用RedisTemplate的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
Maven學(xué)習(xí)教程之搭建多模塊企業(yè)級(jí)項(xiàng)目
本篇文章主要介紹了Maven學(xué)習(xí)教程之搭建多模塊企業(yè)級(jí)項(xiàng)目 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
Spring Boot 鉤子全集實(shí)戰(zhàn)EnvironmentPostProcessor全解
文章詳細(xì)介紹了SpringBoot中的EnvironmentPostProcessor擴(kuò)展點(diǎn),該點(diǎn)在配置加載階段提供強(qiáng)大的定制化能力,適用于配置中心化、加密解密、動(dòng)態(tài)覆蓋和校驗(yàn)等場(chǎng)景,感興趣的朋友跟隨小編一起看看吧2026-01-01
Spring Boot中使用Server-Sent Events (SSE) 實(shí)
Server-Sent Events (SSE) 是HTML5引入的一種輕量級(jí)的服務(wù)器向?yàn)g覽器客戶端單向推送實(shí)時(shí)數(shù)據(jù)的技術(shù),本文主要介紹了Spring Boot中使用Server-Sent Events (SSE) 實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送教程,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03

