Azure / Azure/azureml-examples

/bin/bash: bad substitution

Open
#3,044 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Jupyter Notebook
Stars
2k
Forks
1.7k
Avg merge
18h 18m
Merged PRs (30d)
2

Description

### Operating System

Windows

im getting /bin/bash: ${inputs.input_container_name}: bad substitution

**### Steps to reproduce**

**#this is custom environment which will run and execute code if i run as a job**
from azure.ai.ml.entities import Environment
import os

custom_env_name = "feat_env_city"
dependencies_dir = os.getcwd()

pipeline_job_env1 = Environment(
name=custom_env_name,
description="Custom environment for feature engineering",
tags={
"python": "3.7",
"pandas": "latest",
"scikit-learn": "latest",
"azure-storage-blob": ">=12.10.0",
"azure-ai-ml": "latest"
},
conda_file=os.path.join(dependencies_dir, "environment.yml"),
image="mcr.microsoft.com/azureml/openmpi3.1.2-ubuntu18.04:20210615.v1",
version="1",
)

pipeline_job_env1 = ml_client.environments.create_or_update(pipeline_job_env1)

print(f"Environment with name {pipeline_job_env1.name} is registered to workspace, the environment version is {pipeline_job_env1.version}")

**##this is environment.yml file mentioning packages.there is no issue with conflicts**

name: custom-environment-feature-city
dependencies:
- python=3.7
- pip:
- azure-storage-blob>=12.10.0
- azure-ai-ml
- pandas
- scikit-learn
channels:
- anaconda
- conda-forge

#this is to get correct code directory

import os

code_dir = "."

**#this is component registration**

from azure.ai.ml import command
from azure.ai.ml import Input, Output
import os

data_prep_component = command(
name="data_preprocessing_component_city",
display_name="Data Preprocessing Component_city",
description="Performs data preprocessing.",
inputs={
"input_container_name": Input(type="string", description="Name of the input container in Blob Storage."),
},
outputs={
"processed_data": Output(type="uri_folder", description="Local output directory for processed data."),
},
code=code_dir,
command=f"""python3 data_prep_azureml.py \
--input-container-name ${{inputs.input_container_name}} \
--output-dir ${{outputs.processed_data}}""",
environment=f"{pipeline_job_env1.name}:{pipeline_job_env1.version}",
)

data_prep_component = ml_client.create_or_update(data_prep_component.component)

print(
f"Component {data_prep_component.name} with Version {data_prep_component.version} is registered in the workspace."
)

**#this is pipeline registration**

from azure.ai.ml import MLClient, dsl
from azure.ai.ml.entities import PipelineJob
from azure.identity import DefaultAzureCredential

@dsl.pipeline(
compute="TestGpuNer",
description="A pipeline that processes data and then trains a model.",

)
def my_training_pipeline(input_container_name):

preprocess_job = data_prep_component(
input_container_name=input_container_name
)

train_job = train_component(
training_data=preprocess_job.outputs.processed_data
)

return {"processed_data": preprocess_job.outputs.processed_data}

pipeline = my_training_pipeline(input_container_name="input")
pipeline_job = ml_client.jobs.create_or_update(pipeline,
experiment_name="citydirectorytest",)

print(f"Pipeline submitted. View it at: {pipeline_job.studio_url}")

**#####please not im not sharing training environment nor training component...**

**#for your reference this is data_prep_azureml.py file i use for component registation..the code runs perfectly through terminal as well as a job**

import os
import pandas as pd
import re
import ast
import io
import argparse
from azure.storage.blob import BlobServiceClient, ContainerClient
from azure.storage.blob import ContentSettings
from azure.identity import DefaultAzureCredential
from azure.ai.ml import MLClient
from azure.ai.ml.entities import Data
from azure.ai.ml.constants import AssetTypes

def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("--input-container-name", type=str, required=True, help="Input container name")
parser.add_argument("--output-dir", type=str, required=True, help="Local output directory for processed data")
return parser.parse_args()

def advanced_tokenize(text):
"""Tokenize text, including punctuation."""
return re.findall(r'\b\w+\b|[^\s\w]', text)

def basic_tokenize(text):
"""Tokenize text into lowercase words, ignoring punctuation."""
return re.findall(r'\b\w+\b', text.lower())

def string_to_list(string):

if isinstance(string, list):
return string

if pd.isna(string):
return []

try:
return ast.literal_eval(string)
except (ValueError, SyntaxError):
print(f"Failed to convert string to list: {string}")
return []

def extract_second_element(conversion_list):
"""Extracts the second element from a list of tuples."""
return [element[1] for element in conversion_list]

def convert_to_numerical(analysis):
"""Converts category tags in the analysis to numerical tags."""
category_to_number = {
'sequence number': 0,
'person name': 1,
'spouse name': 2,
'occupation': 3,
'employment place': 4,
'house number': 5,
'street': 6,
'None': 7
}
numerical_analysis = [(word, category_to_number[cat]) for word, cat in analysis]
print(f"Numerical Conversion Result: {numerical_analysis}")
return numerical_analysis

def analyze_row_with_unique_context(row):
input_text = row['value']
categories = {
'sequence number': row.get('sequence number', []),
'person name': row.get('person name', []),
'spouse name': row.get('spouse name', []),
'occupation': row.get('occupation', []),
'employment place': row.get('employment place', []),
'house number': row.get('house number', []),
'street': row.get('street', [])
}
print(f"\nInput Text: {input_text}")
print("Categories before processing:", categories)

analysis = []
for word in input_text:
found_category = 'None'
for category, cat_list in categories.items():
if word.lower() in [x.lower() for x in cat_list]:
found_category = category
break
analysis.append((word, found_category))

print("Analysis Result:", analysis)
return analysis

def register_dataset(ml_client, file_path, dataset_name="processed_dataset"):
data_asset = Data(
path=file_path,
type="uri_file",
description="Processed combined CSV dataset",
name=dataset_name,
)

registered_dataset = ml_client.data.create_or_update(data_asset)

print(f"Dataset '{dataset_name}' registered successfully.")
return registered_dataset

def process_and_combine_csv_files_from_blob(input_container_client, output_dir):
blobs_list = input_container_client.list_blobs()
combined_df = pd.DataFrame()

for blob in blobs_list:
if blob.name.endswith('.csv'):
blob_client = input_container_client.get_blob_client(blob=blob.name)
blob_data = blob_client.download_blob().readall()
blob_str = io.BytesIO(blob_data)
df = pd.read_csv(blob_str)

df['value'] = df['value'].apply(lambda x: advanced_tokenize(str(x)) if pd.notna(x) else x)
for col in ['sequence number', 'person name', 'spouse name', 'occupation', 'employment place', 'house number', 'street']:
df[col] = df[col].apply(lambda x: basic_tokenize(str(x)) if pd.notna(x) else x)
df[col] = df[col].apply(string_to_list)
df['unique_context_analysis'] = df.apply(analyze_row_with_unique_context, axis=1)
df['conversion'] = df['unique_context_analysis'].apply(convert_to_numerical)
df['final'] = df['conversion'].apply(extract_second_element)

df = df[['value', 'final']]
df.rename(columns={'value': 'tokens', 'final': 'ner_tags'}, inplace=True)
df.insert(0, 'id', range(1, 1 + len(df)))

combined_df = pd.concat([combined_df, df], ignore_index=True)

output_file_path = os.path.join(output_dir, "processed_combined_csv.csv")
combined_df.to_csv(output_file_path, index=False)
print(f"\nProcessed and combined CSV file saved locally: {output_file_path}")
return output_file_path

if __name__ == "__main__":
args = get_args()
connection_string = ""

blob_service_client = BlobServiceClient.from_connection_string(connection_string)
input_container_client = blob_service_client.get_container_client(args.input_container_name)

os.makedirs(args.output_dir, exist_ok=True)

output_file_path =process_and_combine_csv_files_from_blob(input_container_client, args.output_dir)

credential = DefaultAzureCredential()
ml_client = MLClient(
credential=credential,
subscription_id="",
resource_group_name="ai_ml",
workspace_name="AzureML_flow"
)

register_dataset(ml_client, output_file_path)

**#pls note ..i have removed ml_client and connection_string keys**

![image](https://github.com/Azure/azureml-examples/assets/114779060/ae2216cf-db8e-4679-a159-460acdacf0c8)
![image](https://github.com/Azure/azureml-examples/assets/114779060/52fd6d4c-af71-4f95-8811-a557b47d2943)
![image](https://github.com/Azure/azureml-examples/assets/114779060/e8a03a9c-e676-4887-b4e2-3c35dda1be8d)

### Actual behavior

this is an additional issue which i resolved

please note a job is taking 1.5 hrs to schedule ..also command wise i able to register the component ..whereas if i try via yaml configuration then showing

/mnt/azureml/cr/j/46aec26067694da8a26ce7eb7e8b8875/exe/wd
azureml-logs
logs
outputs
user_logs
python: can't open file '/mnt/batch/tasks/shared/LS_root/mounts/clusters/anchestrycpucompute1/code/Users/john.athappully/data_prep_azureml.py': [Errno 2] No such file or directory

also i tried runnig your github code smple nd found same issue using yaml for training code as you use for data prepration the command wise code...i had to change to command wise for training component to make it working..

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.