如何解决Azure Custom Vision API创建项目时的404资源未找到错误
Azure Custom Vision Java项目创建404错误排查与解决
问题描述
按照微软文档用Java实现Azure Custom Vision图像分类模型训练,执行Gradle构建运行时出现以下错误:
Exception in thread "main" com.microsoft.azure.cognitiveservices.vision.customvision.training.models.CustomVisionErrorException: Status code 404, {"error":{"code":"404","message": "Resource not found"}}
错误触发点为createProject方法中的Project project=trainer.createProject().withName("Moon-Phases-Trainer").execute();语句,目标是在Vision Studio中创建项目,但连接训练API时失败。
完整代码如下:
class CustomVisionQuickstart { final static String trainingApiKey=System.getenv("VISION_TRAINING_KEY"); final static String trainingEndpoint=System.getenv("VISION_TRAINING_ENDPOINT"); final static String predictionApiKey=System.getenv("VISION_PREDICTION_KEY"); final static String predictionEndpoint=System.getenv("VISION_PREDICTION_ENDPOINT"); final static String predictionResourceID=System.getenv("VISION_PREDICTION_RESOURCE_ID"); private static Tag newMoonTag, waxingCrescentTag, firstQuarterTag, waxingGibbousTag, fullTag, waningGibbousTag, thirdQuarterTag, waningCrescentTag; public static void main(String[] args) throws InterruptedException { // System.out.println(trainingApiKey); // System.out.println(trainingEndpoint); CustomVisionTrainingClient trainClient=CustomVisionTrainingManager .authenticate(trainingEndpoint,trainingApiKey) .withEndpoint(trainingEndpoint); CustomVisionPredictionClient predictor=CustomVisionPredictionManager .authenticate(predictionEndpoint,predictionApiKey) .withEndpoint(predictionEndpoint); Project project=createProject(trainClient); addTags(trainClient, project); uploadImages(trainClient, project); trainProject(trainClient, project); publishIteration(trainClient, project); testProject(predictor, project); } public static Project createProject(CustomVisionTrainingClient trainClient) { Trainings trainer=trainClient.trainings(); System.out.println("Creating Project"); Project project=trainer.createProject().withName("Moon-Phases-Trainer").execute(); return project; } public static void addTags(CustomVisionTrainingClient trainClient, Project project) { Trainings trainer = trainClient.trainings(); newMoonTag = trainer.createTag().withProjectId(project.id()).withName("New Moon").execute(); waxingCrescentTag = trainer.createTag().withProjectId(project.id()).withName("Waxing Crescent Moon").execute(); firstQuarterTag = trainer.createTag().withProjectId(project.id()).withName("First Quarter Moon").execute(); waxingGibbousTag = trainer.createTag().withProjectId(project.id()).withName("Waxing Gibbous Moon").execute(); fullTag = trainer.createTag().withProjectId(project.id()).withName("Full Moon").execute(); waningGibbousTag = trainer.createTag().withProjectId(project.id()).withName("Waning Gibbous Moon").execute(); thirdQuarterTag = trainer.createTag().withProjectId(project.id()).withName("Third Quarter Moon").execute(); waningCrescentTag = trainer.createTag().withProjectId(project.id()).withName("Waning Crescent Moon").execute(); } public static void uploadImages(CustomVisionTrainingClient trainClient, Project project) { Trainings trainer=trainClient.trainings(); for (int x=0;x<4;x++) { String fileName="New_Moon_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,newMoonTag.id(),null); } for (int x=0;x<9;x++) { String fileName="Waxing_Crescent_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,waxingCrescentTag.id(),null); } for (int x=0;x<8;x++) { String fileName="First_Quarter_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,firstQuarterTag.id(),null); } for (int x=0;x<13;x++) { String fileName="Waxing_Gibbous_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,waxingGibbousTag.id(),null); } for (int x=0;x<5;x++) { String fileName="Full_Moon_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,fullTag.id(),null); } for (int x=0;x<15;x++) { String fileName="Waning_Gibbous_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,waningGibbousTag.id(),null); } for (int x=0;x<6;x++) { String fileName="Third_Quarter_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,thirdQuarterTag.id(),null); } for (int x=0;x<13;x++) { String fileName="Waning_Crescent_"+x+".jpg"; byte contents[]=getImage("/Moons",fileName); addImageToProject(trainer,project,fileName,contents,waningCrescentTag.id(),null); } } private static void addImageToProject(Trainings trainer, Project project, String fileName, byte[] contents, UUID tag, double[] regionValues) { System.out.println("Adding image: "+fileName); ImageFileCreateEntry file=new ImageFileCreateEntry().withName(fileName).withContents(contents); ImageFileCreateBatch batch=new ImageFileCreateBatch().withImages(Collections.singletonList(file)); if(regionValues!=null) { Region region=new Region().withTagId(tag).withLeft(regionValues[0]).withTop(regionValues[1]).withWidth(regionValues[2]).withHeight(regionValues[3]); file=file.withRegions(Collections.singletonList(region)); } else batch = batch.withTagIds(Collections.singletonList(tag)); trainer.createImagesFromFiles(project.id(),batch); } private static byte[] getImage(String folder, String fileName) { try { return ByteStreams.toByteArray(CustomVisionQuickstart.class.getResourceAsStream(folder+"/"+fileName)); } catch(Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } return null; } public static Iteration trainProject(CustomVisionTrainingClient trainClient, Project project) throws InterruptedException { System.out.println("Training..."); Trainings trainer=trainClient.trainings(); Iteration iteration=trainer.trainProject(project.id(),new TrainProjectOptionalParameter()); while(iteration.status().equals("Training")) { System.out.println("Training Status: " + iteration.status()); Thread.sleep(1000); iteration = trainer.getIteration(project.id(), iteration.id()); } System.out.println("Training Status: " + iteration.status()); return iteration; } public static void publishIteration(CustomVisionTrainingClient trainClient, Project project) throws InterruptedException { Trainings trainer=trainClient.trainings(); Iteration iteration=trainProject(trainClient,project); String publishedModelName="myMoonPhaseModel"; trainer.publishIteration(project.id(),iteration.id(),publishedModelName,predictionResourceID); } public static void testProject(CustomVisionPredictionClient predictor, Project project) { byte[] testImeage=getImage("/Moons","testImage.jpg"); String publishedModelName = "myMoonPhaseModel"; ImagePrediction results=predictor.predictions().classifyImage().withProjectId(project.id()).withPublishedName(publishedModelName).withImageData(testImeage).execute(); for (Prediction prediction : results.predictions()) System.out.println(String.format("\t%s: %.2f%%", prediction.tagName(), prediction.probability() * 100.0f)); } }
可能原因
- 训练端点/密钥错误:使用了预测端点/密钥代替训练专用的,或者端点格式不正确(如缺失末尾斜杠、区域不匹配)。
- 环境变量未正确加载:
VISION_TRAINING_ENDPOINT或VISION_TRAINING_KEY未设置,或设置的值与Azure门户中的资源信息不符。 - Custom Vision资源状态异常:Azure上的资源未成功部署、被暂停或删除。
解决方案
验证训练端点与密钥
- 登录Azure门户,找到你的Custom Vision资源,进入「密钥和端点」页面,确认训练端点(格式示例:
https://eastus.api.cognitive.microsoft.com/)和训练密钥,注意区分训练与预测的两组密钥/端点,不要混用。 - 确保环境变量
VISION_TRAINING_ENDPOINT和VISION_TRAINING_KEY的值与上述确认的信息完全一致。
- 登录Azure门户,找到你的Custom Vision资源,进入「密钥和端点」页面,确认训练端点(格式示例:
检查环境变量加载情况
- 取消代码中
// System.out.println(trainingApiKey);和// System.out.println(trainingEndpoint);的注释,运行程序后查看控制台输出,确认变量值是否正确加载,避免因环境变量未设置导致空值或错误值。
- 取消代码中
修正客户端初始化代码
原代码中CustomVisionTrainingManager.authenticate方法已接受端点参数,无需重复调用withEndpoint,可简化为:CustomVisionTrainingClient trainClient = CustomVisionTrainingManager .authenticate(trainingApiKey) .withEndpoint(trainingEndpoint);该调整可避免潜在的端点重复配置问题。
确认资源状态与区域一致性
- 在Azure门户确认Custom Vision资源处于「运行中」状态,无异常。
- 确保训练端点的区域(如
eastus)与资源创建时选择的区域完全一致,区域不匹配会导致API请求无法找到对应资源。
内容的提问来源于stack exchange,提问作者Ppp
相关产品推荐
相关产品推荐

