delightfulrachel/GPUandAPIcostestimator
1
1import gradio as gr2import pandas as pd3import numpy as np4import plotly.express as px5import plotly.graph_objects as go6 7# Updated pricing data - restructured for better comparison8aws_instances = {9 # T4 GPU Instances (entry level)10 "g4dn.xlarge": {"vcpus": 4, "memory": 16, "gpu": "1x NVIDIA T4", "hourly_rate": 0.526, "gpu_memory": "16GB", "tier": "Entry"},11 "g4dn.2xlarge": {"vcpus": 8, "memory": 32, "gpu": "1x NVIDIA T4", "hourly_rate": 0.752, "gpu_memory": "16GB", "tier": "Entry"},12 13 # A10G GPU Instances (mid-tier)14 "g5.xlarge": {"vcpus": 4, "memory": 16, "gpu": "1x NVIDIA A10G", "hourly_rate": 0.65, "gpu_memory": "24GB", "tier": "Mid"},15 "g5.2xlarge": {"vcpus": 8, "memory": 32, "gpu": "1x NVIDIA A10G", "hourly_rate": 1.006, "gpu_memory": "24GB", "tier": "Mid"},16 17 # V100 GPU Instances (high-tier)18 "p3.2xlarge": {"vcpus": 8, "memory": 61, "gpu": "1x NVIDIA V100", "hourly_rate": 3.06, "gpu_memory": "16GB", "tier": "High"},19 20 21 # Added comparable instances to match GCP22 "p4d.xlarge": {"vcpus": 12, "memory": 85, "gpu": "1x NVIDIA A100", "hourly_rate": 4.10, "gpu_memory": "40GB", "tier": "Premium"},23 "p4d.2xlarge": {"vcpus": 24, "memory": 170, "gpu": "2x NVIDIA A100", "hourly_rate": 8.20, "gpu_memory": "2x40GB", "tier": "Premium"},24 "p4d.4xlarge": {"vcpus": 48, "memory": 340, "gpu": "4x NVIDIA A100", "hourly_rate": 16.40, "gpu_memory": "4x40GB", "tier": "Premium"},25}26 27gcp_instances = {28 # T4 GPU Instances (entry level)29 "n1-standard-4-t4": {"vcpus": 4, "memory": 15, "gpu": "1x NVIDIA T4", "hourly_rate": 0.49, "gpu_memory": "16GB", "tier": "Entry"},30 "n1-standard-8-t4": {"vcpus": 8, "memory": 30, "gpu": "1x NVIDIA T4", "hourly_rate": 0.69, "gpu_memory": "16GB", "tier": "Entry"},31 32 # L4 GPU Instances (mid-tier)33 "g2-standard-4": {"vcpus": 4, "memory": 16, "gpu": "1x NVIDIA L4", "hourly_rate": 0.59, "gpu_memory": "24GB", "tier": "Mid"},34 "g2-standard-8": {"vcpus": 8, "memory": 32, "gpu": "1x NVIDIA L4", "hourly_rate": 0.89, "gpu_memory": "24GB", "tier": "Mid"},35 36 # Added comparable V100 instance37 "n1-standard-8-v100": {"vcpus": 8, "memory": 60, "gpu": "1x NVIDIA V100", "hourly_rate": 2.95, "gpu_memory": "16GB", "tier": "High"},38 39 # A100 GPU Instances (premium)40 "a2-highgpu-1g": {"vcpus": 12, "memory": 85, "gpu": "1x NVIDIA A100", "hourly_rate": 1.46, "gpu_memory": "40GB", "tier": "Premium"},41 "a2-highgpu-2g": {"vcpus": 24, "memory": 170, "gpu": "2x NVIDIA A100", "hourly_rate": 2.93, "gpu_memory": "2x40GB", "tier": "Premium"},42 "a2-highgpu-4g": {"vcpus": 48, "memory": 340, "gpu": "4x NVIDIA A100", "hourly_rate": 5.86, "gpu_memory": "4x40GB", "tier": "Premium"},43}44 45api_pricing = {46 "OpenAI": {47 "GPT-3.5-Turbo": {"input_per_1M": 0.5, "output_per_1M": 1.5, "token_context": 16385},48 "GPT-4o": {"input_per_1M": 5.0, "output_per_1M": 15.0, "token_context": 32768},49 "GPT-4o-mini": {"input_per_1M": 2.5, "output_per_1M": 7.5, "token_context": 32768},50 },51 "TogetherAI": {52 "Llama-3-8B": {"input_per_1M": 0.15, "output_per_1M": 0.15, "token_context": 8192},53 "Llama-3-70B": {"input_per_1M": 0.9, "output_per_1M": 0.9, "token_context": 8192},54 "Llama-2-13B": {"input_per_1M": 0.6, "output_per_1M": 0.6, "token_context": 4096},55 "Llama-2-70B": {"input_per_1M": 2.5, "output_per_1M": 2.5, "token_context": 4096},56 "DeepSeek-Coder-33B": {"input_per_1M": 2.0, "output_per_1M": 2.0, "token_context": 16384},57 },58 "Anthropic": {59 "Claude-3-Opus": {"input_per_1M": 15.0, "output_per_1M": 75.0, "token_context": 200000},60 "Claude-3-Sonnet": {"input_per_1M": 3.0, "output_per_1M": 15.0, "token_context": 200000},61 "Claude-3-Haiku": {"input_per_1M": 0.25, "output_per_1M": 1.25, "token_context": 200000},62 }63}64 65model_sizes = {66 "Small (7B parameters)": {"memory_required": 14},67 "Medium (13B parameters)": {"memory_required": 26},68 "Large (70B parameters)": {"memory_required": 140},69 "XL (180B parameters)": {"memory_required": 360},70}71 72def calculate_aws_cost(instance, hours, storage, reserved=False, spot=False, years=1):73 data = aws_instances[instance]74 rate = data['hourly_rate']75 if spot:76 rate *= 0.377 elif reserved:78 factors = {1: 0.6, 3: 0.4}79 rate *= factors.get(years, 0.6)80 compute = rate * hours81 storage_cost = storage * 0.1082 return {'total_cost': compute + storage_cost, 'details': data}83 84def calculate_gcp_cost(instance, hours, storage, reserved=False, spot=False, years=1):85 data = gcp_instances[instance]86 rate = data['hourly_rate']87 if spot:88 rate *= 0.289 elif reserved:90 factors = {1: 0.7, 3: 0.5}91 rate *= factors.get(years, 0.7)92 compute = rate * hours93 storage_cost = storage * 0.0494 return {'total_cost': compute + storage_cost, 'details': data}95 96def calculate_api_cost(provider, model, in_tokens, out_tokens, calls):97 m = api_pricing[provider][model]98 input_cost = in_tokens * m['input_per_1M'] / 100000099 output_cost = out_tokens * m['output_per_1M'] / 1000000100 call_cost = calls * 0.0001 if provider == 'TogetherAI' else 0101 return {'total_cost': input_cost + output_cost + call_cost, 'details': m}102 103def filter_compatible(instances, min_mem):104 res = {}105 for name, data in instances.items():106 mem_str = data['gpu_memory']107 if 'x' in mem_str and not mem_str.startswith(('1x','2x','4x','8x')):108 val = int(mem_str.replace('GB',''))109 elif 'x' in mem_str:110 parts = mem_str.split('x')111 val = int(parts[0]) * int(parts[1].replace('GB',''))112 else:113 val = int(mem_str.replace('GB',''))114 if val >= min_mem:115 res[name] = data116 return res117 118def generate_cost_comparison(119 compute_hours, tokens_per_month, input_ratio, api_calls,120 model_size, storage_gb, reserved_instances, spot_instances, multi_year_commitment,121 comparison_tier122):123 years = int(multi_year_commitment)124 in_tokens = tokens_per_month * 1000000 * (input_ratio/100)125 out_tokens = tokens_per_month * 1000000 - in_tokens126 min_mem = model_sizes[model_size]['memory_required']127 128 # Filter by both memory requirements and tier if a tier is selected129 aws_comp = filter_compatible(aws_instances, min_mem)130 gcp_comp = filter_compatible(gcp_instances, min_mem)131 132 if comparison_tier != "All":133 aws_comp = {k: v for k, v in aws_comp.items() if v.get('tier', '') == comparison_tier}134 gcp_comp = {k: v for k, v in gcp_comp.items() if v.get('tier', '') == comparison_tier}135 136 results = []137 138 # AWS table139 aws_html = '<h3>AWS Instances</h3>'140 aws_html += '<table width="100%"><tr><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Tier</th><th>Monthly Cost ($)</th></tr>'141 if aws_comp:142 for inst in aws_comp:143 res = calculate_aws_cost(inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)144 aws_html += f'<tr><td>{inst}</td><td>{res["details"]["vcpus"]}</td><td>{res["details"]["memory"]}GB</td><td>{res["details"]["gpu"]}</td><td>{res["details"].get("tier", "")}</td><td>${res["total_cost"]:.2f}</td></tr>'145 # best AWS146 best_aws = min(aws_comp, key=lambda x: calculate_aws_cost(x, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost'])147 best_aws_cost = calculate_aws_cost(best_aws, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost']148 best_aws_tier = aws_instances[best_aws].get('tier', '')149 results.append({'provider': f'AWS ({best_aws})', 'cost': best_aws_cost, 'type': 'Cloud', 'tier': best_aws_tier})150 else:151 aws_html += '<tr><td colspan="6">No compatible instances</td></tr>'152 aws_html += '</table>'153 154 # GCP table155 gcp_html = '<h3>GCP Instances</h3>'156 gcp_html += '<table width="100%"><tr><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Tier</th><th>Monthly Cost ($)</th></tr>'157 if gcp_comp:158 for inst in gcp_comp:159 res = calculate_gcp_cost(inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)160 gcp_html += f'<tr><td>{inst}</td><td>{res["details"]["vcpus"]}</td><td>{res["details"]["memory"]}GB</td><td>{res["details"]["gpu"]}</td><td>{res["details"].get("tier", "")}</td><td>${res["total_cost"]:.2f}</td></tr>'161 best_gcp = min(gcp_comp, key=lambda x: calculate_gcp_cost(x, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost'])162 best_gcp_cost = calculate_gcp_cost(best_gcp, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost']163 best_gcp_tier = gcp_instances[best_gcp].get('tier', '')164 results.append({'provider': f'GCP ({best_gcp})', 'cost': best_gcp_cost, 'type': 'Cloud', 'tier': best_gcp_tier})165 else:166 gcp_html += '<tr><td colspan="6">No compatible instances</td></tr>'167 gcp_html += '</table>'168 169 # API table170 api_html = '<h3>API Options</h3>'171 api_html += '<table width="100%"><tr><th>Provider</th><th>Model</th><th>Input Cost</th><th>Output Cost</th><th>Total Cost ($)</th><th>Context</th></tr>'172 api_costs = {}173 for prov in api_pricing:174 for mdl in api_pricing[prov]:175 res = calculate_api_cost(prov, mdl, in_tokens, out_tokens, api_calls)176 details = api_pricing[prov][mdl]177 api_html += f'<tr><td>{prov}</td><td>{mdl}</td><td>${in_tokens * details["input_per_1M"] / 1000000:.2f}</td><td>${out_tokens * details["output_per_1M"] / 1000000:.2f}</td><td>${res["total_cost"]:.2f}</td><td>{details["token_context"]:,}</td></tr>'178 api_costs[(prov, mdl)] = res['total_cost']179 api_html += '</table>'180 181 if api_costs:182 best_api = min(api_costs, key=api_costs.get)183 results.append({'provider': f'{best_api[0]} ({best_api[1]})', 'cost': api_costs[best_api], 'type': 'API', 'tier': 'API'})184 185 # Direct comparison tables for similar instances186 direct_comparison_html = ""187 if comparison_tier != "All" and comparison_tier != "API":188 direct_comparison_html = f'<h3>Direct {comparison_tier} Tier Comparison</h3>'189 direct_comparison_html += '<table width="100%"><tr><th>Provider</th><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Monthly Cost ($)</th></tr>'190 191 aws_filtered = {k: v for k, v in aws_instances.items() if v.get('tier', '') == comparison_tier}192 gcp_filtered = {k: v for k, v in gcp_instances.items() if v.get('tier', '') == comparison_tier}193 194 # Group by vCPU for comparison195 vcpu_groups = {}196 for inst, data in aws_filtered.items():197 vcpu = data['vcpus']198 if vcpu not in vcpu_groups:199 vcpu_groups[vcpu] = {'aws': [], 'gcp': []}200 vcpu_groups[vcpu]['aws'].append(inst)201 202 for inst, data in gcp_filtered.items():203 vcpu = data['vcpus']204 if vcpu not in vcpu_groups:205 vcpu_groups[vcpu] = {'aws': [], 'gcp': []}206 vcpu_groups[vcpu]['gcp'].append(inst)207 208 # Display direct comparisons209 for vcpu in sorted(vcpu_groups.keys()):210 group = vcpu_groups[vcpu]211 for aws_inst in group['aws']:212 aws_cost = calculate_aws_cost(aws_inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)213 aws_data = aws_cost['details']214 direct_comparison_html += f'<tr><td>AWS</td><td>{aws_inst}</td><td>{aws_data["vcpus"]}</td><td>{aws_data["memory"]}GB</td><td>{aws_data["gpu"]}</td><td>${aws_cost["total_cost"]:.2f}</td></tr>'215 216 for gcp_inst in group['gcp']:217 gcp_cost = calculate_gcp_cost(gcp_inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)218 gcp_data = gcp_cost['details']219 direct_comparison_html += f'<tr><td>GCP</td><td>{gcp_inst}</td><td>{gcp_data["vcpus"]}</td><td>{gcp_data["memory"]}GB</td><td>{gcp_data["gpu"]}</td><td>${gcp_cost["total_cost"]:.2f}</td></tr>'220 221 # Add separator between different vCPU groups222 if vcpu != sorted(vcpu_groups.keys())[-1]:223 direct_comparison_html += '<tr><td colspan="6" style="border-bottom: 1px solid #ccc; height: 10px;"></td></tr>'224 225 direct_comparison_html += '</table>'226 227 # Chart with annotations228 df = pd.DataFrame(results)229 colors = {'Entry': '#66BB6A', 'Mid': '#42A5F5', 'High': '#FFA726', 'Premium': '#EF5350', 'API': '#AB47BC'}230 231 # Create figure using plotly graph objects for more control232 fig = go.Figure()233 234 # Add bars235 for i, row in df.iterrows():236 tier_color = colors.get(row.get('tier', 'API'), '#9E9E9E')237 fig.add_trace(go.Bar(238 x=[row['provider']], 239 y=[row['cost']], 240 name=row['provider'],241 marker_color=tier_color242 ))243 244 # Add annotations on top of each bar245 for i, row in df.iterrows():246 fig.add_annotation(247 x=row['provider'],248 y=row['cost'],249 text=f"${row['cost']:.2f}",250 showarrow=False,251 yshift=10, # Position above the bar252 font=dict(size=14)253 )254 255 # Update layout256 fig.update_layout(257 showlegend=False,258 height=500,259 yaxis=dict(title='Monthly Cost ($)', tickprefix='$'),260 xaxis=dict(title=''),261 title='Cost Comparison'262 )263 264 html = f"""265 <div style='padding:20px;font-family:Arial;'>266 {direct_comparison_html}267 {aws_html}268 {gcp_html}269 {api_html}270 </div>271 """272 return html, fig273 274# UI setup275with gr.Blocks(title="Cloud Cost Estimator", theme=gr.themes.Soft(primary_hue="indigo")) as demo:276 gr.HTML('<h1 style="text-align:center;">Cloud Cost Estimator</h1>')277 with gr.Row():278 with gr.Column(scale=1):279 compute_hours = gr.Slider(label="Compute Hours per Month", minimum=1, maximum=300, value=50)280 tokens_per_month = gr.Slider(label="Tokens per Month (M)", minimum=1, maximum=200, value=5)281 input_ratio = gr.Slider(label="Input Ratio (%)", minimum=10, maximum=70, value=25)282 api_calls = gr.Slider(label="API Calls per Month", minimum=100, maximum=100000, value=5000, step=100)283 model_size = gr.Dropdown(label="Model Size", choices=list(model_sizes.keys()), value="Medium (13B parameters)")284 storage_gb = gr.Slider(label="Storage (GB)", minimum=10, maximum=1000, value=100)285 comparison_tier = gr.Radio(label="Comparison Tier", choices=["All", "Entry", "Mid", "High", "Premium", "API"], value="All")286 reserved_instances = gr.Checkbox(label="Reserved Instances", value=False)287 spot_instances = gr.Checkbox(label="Spot Instances", value=False)288 multi_year_commitment = gr.Radio(label="Commitment Period (years)", choices=["1","3"], value="1")289 with gr.Column(scale=2):290 out_html = gr.HTML()291 out_plot = gr.Plot()292 293 # Create inputs list for the function294 inputs = [compute_hours, tokens_per_month, input_ratio, api_calls,295 model_size, storage_gb, reserved_instances, spot_instances, multi_year_commitment, comparison_tier]296 outputs = [out_html, out_plot]297 298 # Initial calculation on load299 demo.load(generate_cost_comparison, inputs, outputs)300 301 # Update on each input change302 for input_component in inputs:303 input_component.change(generate_cost_comparison, inputs, outputs)304 305demo.launch()